1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/Frontend/SerializedDiagnosticReader.h" |
10 | #include "clang/Basic/FileManager.h" |
11 | #include "clang/Basic/FileSystemOptions.h" |
12 | #include "clang/Frontend/SerializedDiagnostics.h" |
13 | #include "llvm/ADT/Optional.h" |
14 | #include "llvm/ADT/SmallVector.h" |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/Bitcode/BitCodes.h" |
17 | #include "llvm/Bitcode/BitstreamReader.h" |
18 | #include "llvm/Support/Compiler.h" |
19 | #include "llvm/Support/ErrorHandling.h" |
20 | #include "llvm/Support/ErrorOr.h" |
21 | #include "llvm/Support/ManagedStatic.h" |
22 | #include <cstdint> |
23 | #include <system_error> |
24 | |
25 | using namespace clang; |
26 | using namespace serialized_diags; |
27 | |
28 | std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { |
29 | |
30 | FileSystemOptions FO; |
31 | FileManager FileMgr(FO); |
32 | |
33 | auto Buffer = FileMgr.getBufferForFile(File); |
34 | if (!Buffer) |
35 | return SDError::CouldNotLoad; |
36 | |
37 | llvm::BitstreamCursor Stream(**Buffer); |
38 | Optional<llvm::BitstreamBlockInfo> BlockInfo; |
39 | |
40 | if (Stream.AtEndOfStream()) |
41 | return SDError::InvalidSignature; |
42 | |
43 | |
44 | if (Stream.Read(8) != 'D' || |
45 | Stream.Read(8) != 'I' || |
46 | Stream.Read(8) != 'A' || |
47 | Stream.Read(8) != 'G') |
48 | return SDError::InvalidSignature; |
49 | |
50 | |
51 | while (!Stream.AtEndOfStream()) { |
52 | if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK) |
53 | return SDError::InvalidDiagnostics; |
54 | |
55 | std::error_code EC; |
56 | switch (Stream.ReadSubBlockID()) { |
57 | case llvm::bitc::BLOCKINFO_BLOCK_ID: |
58 | BlockInfo = Stream.ReadBlockInfoBlock(); |
59 | if (!BlockInfo) |
60 | return SDError::MalformedBlockInfoBlock; |
61 | Stream.setBlockInfo(&*BlockInfo); |
62 | continue; |
63 | case BLOCK_META: |
64 | if ((EC = readMetaBlock(Stream))) |
65 | return EC; |
66 | continue; |
67 | case BLOCK_DIAG: |
68 | if ((EC = readDiagnosticBlock(Stream))) |
69 | return EC; |
70 | continue; |
71 | default: |
72 | if (!Stream.SkipBlock()) |
73 | return SDError::MalformedTopLevelBlock; |
74 | continue; |
75 | } |
76 | } |
77 | return {}; |
78 | } |
79 | |
80 | enum class SerializedDiagnosticReader::Cursor { |
81 | Record = 1, |
82 | BlockEnd, |
83 | BlockBegin |
84 | }; |
85 | |
86 | llvm::ErrorOr<SerializedDiagnosticReader::Cursor> |
87 | SerializedDiagnosticReader::skipUntilRecordOrBlock( |
88 | llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) { |
89 | BlockOrRecordID = 0; |
90 | |
91 | while (!Stream.AtEndOfStream()) { |
92 | unsigned Code = Stream.ReadCode(); |
93 | |
94 | switch ((llvm::bitc::FixedAbbrevIDs)Code) { |
95 | case llvm::bitc::ENTER_SUBBLOCK: |
96 | BlockOrRecordID = Stream.ReadSubBlockID(); |
97 | return Cursor::BlockBegin; |
98 | |
99 | case llvm::bitc::END_BLOCK: |
100 | if (Stream.ReadBlockEnd()) |
101 | return SDError::InvalidDiagnostics; |
102 | return Cursor::BlockEnd; |
103 | |
104 | case llvm::bitc::DEFINE_ABBREV: |
105 | Stream.ReadAbbrevRecord(); |
106 | continue; |
107 | |
108 | case llvm::bitc::UNABBREV_RECORD: |
109 | return SDError::UnsupportedConstruct; |
110 | |
111 | default: |
112 | |
113 | BlockOrRecordID = Code; |
114 | return Cursor::Record; |
115 | } |
116 | } |
117 | |
118 | return SDError::InvalidDiagnostics; |
119 | } |
120 | |
121 | std::error_code |
122 | SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { |
123 | if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) |
124 | return SDError::MalformedMetadataBlock; |
125 | |
126 | bool VersionChecked = false; |
127 | |
128 | while (true) { |
129 | unsigned BlockOrCode = 0; |
130 | llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); |
131 | if (!Res) |
132 | Res.getError(); |
133 | |
134 | switch (Res.get()) { |
135 | case Cursor::Record: |
136 | break; |
137 | case Cursor::BlockBegin: |
138 | if (Stream.SkipBlock()) |
139 | return SDError::MalformedMetadataBlock; |
140 | LLVM_FALLTHROUGH; |
141 | case Cursor::BlockEnd: |
142 | if (!VersionChecked) |
143 | return SDError::MissingVersion; |
144 | return {}; |
145 | } |
146 | |
147 | SmallVector<uint64_t, 1> Record; |
148 | unsigned RecordID = Stream.readRecord(BlockOrCode, Record); |
149 | |
150 | if (RecordID == RECORD_VERSION) { |
151 | if (Record.size() < 1) |
152 | return SDError::MissingVersion; |
153 | if (Record[0] > VersionNumber) |
154 | return SDError::VersionMismatch; |
155 | VersionChecked = true; |
156 | } |
157 | } |
158 | } |
159 | |
160 | std::error_code |
161 | SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) { |
162 | if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) |
163 | return SDError::MalformedDiagnosticBlock; |
164 | |
165 | std::error_code EC; |
166 | if ((EC = visitStartOfDiagnostic())) |
167 | return EC; |
168 | |
169 | SmallVector<uint64_t, 16> Record; |
170 | while (true) { |
171 | unsigned BlockOrCode = 0; |
172 | llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); |
173 | if (!Res) |
174 | Res.getError(); |
175 | |
176 | switch (Res.get()) { |
177 | case Cursor::BlockBegin: |
178 | |
179 | if (BlockOrCode == serialized_diags::BLOCK_DIAG) { |
180 | if ((EC = readDiagnosticBlock(Stream))) |
181 | return EC; |
182 | } else if (!Stream.SkipBlock()) |
183 | return SDError::MalformedSubBlock; |
184 | continue; |
185 | case Cursor::BlockEnd: |
186 | if ((EC = visitEndOfDiagnostic())) |
187 | return EC; |
188 | return {}; |
189 | case Cursor::Record: |
190 | break; |
191 | } |
192 | |
193 | |
194 | Record.clear(); |
195 | StringRef Blob; |
196 | unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob); |
197 | |
198 | if (RecID < serialized_diags::RECORD_FIRST || |
199 | RecID > serialized_diags::RECORD_LAST) |
200 | continue; |
201 | |
202 | switch ((RecordIDs)RecID) { |
203 | case RECORD_CATEGORY: |
204 | |
205 | if (Record.size() != 2) |
206 | return SDError::MalformedDiagnosticRecord; |
207 | if ((EC = visitCategoryRecord(Record[0], Blob))) |
208 | return EC; |
209 | continue; |
210 | case RECORD_DIAG: |
211 | |
212 | |
213 | if (Record.size() != 8) |
214 | return SDError::MalformedDiagnosticRecord; |
215 | if ((EC = visitDiagnosticRecord( |
216 | Record[0], Location(Record[1], Record[2], Record[3], Record[4]), |
217 | Record[5], Record[6], Blob))) |
218 | return EC; |
219 | continue; |
220 | case RECORD_DIAG_FLAG: |
221 | |
222 | if (Record.size() != 2) |
223 | return SDError::MalformedDiagnosticRecord; |
224 | if ((EC = visitDiagFlagRecord(Record[0], Blob))) |
225 | return EC; |
226 | continue; |
227 | case RECORD_FILENAME: |
228 | |
229 | |
230 | if (Record.size() != 4) |
231 | return SDError::MalformedDiagnosticRecord; |
232 | if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob))) |
233 | return EC; |
234 | continue; |
235 | case RECORD_FIXIT: |
236 | |
237 | if (Record.size() != 9) |
238 | return SDError::MalformedDiagnosticRecord; |
239 | if ((EC = visitFixitRecord( |
240 | Location(Record[0], Record[1], Record[2], Record[3]), |
241 | Location(Record[4], Record[5], Record[6], Record[7]), Blob))) |
242 | return EC; |
243 | continue; |
244 | case RECORD_SOURCE_RANGE: |
245 | |
246 | if (Record.size() != 8) |
247 | return SDError::MalformedDiagnosticRecord; |
248 | if ((EC = visitSourceRangeRecord( |
249 | Location(Record[0], Record[1], Record[2], Record[3]), |
250 | Location(Record[4], Record[5], Record[6], Record[7])))) |
251 | return EC; |
252 | continue; |
253 | case RECORD_VERSION: |
254 | |
255 | if (Record.size() != 1) |
256 | return SDError::MalformedDiagnosticRecord; |
257 | if ((EC = visitVersionRecord(Record[0]))) |
258 | return EC; |
259 | continue; |
260 | } |
261 | } |
262 | } |
263 | |
264 | namespace { |
265 | |
266 | class SDErrorCategoryType final : public std::error_category { |
267 | const char *name() const noexcept override { |
268 | return "clang.serialized_diags"; |
269 | } |
270 | |
271 | std::string message(int IE) const override { |
272 | auto E = static_cast<SDError>(IE); |
273 | switch (E) { |
274 | case SDError::CouldNotLoad: |
275 | return "Failed to open diagnostics file"; |
276 | case SDError::InvalidSignature: |
277 | return "Invalid diagnostics signature"; |
278 | case SDError::InvalidDiagnostics: |
279 | return "Parse error reading diagnostics"; |
280 | case SDError::MalformedTopLevelBlock: |
281 | return "Malformed block at top-level of diagnostics"; |
282 | case SDError::MalformedSubBlock: |
283 | return "Malformed sub-block in a diagnostic"; |
284 | case SDError::MalformedBlockInfoBlock: |
285 | return "Malformed BlockInfo block"; |
286 | case SDError::MalformedMetadataBlock: |
287 | return "Malformed Metadata block"; |
288 | case SDError::MalformedDiagnosticBlock: |
289 | return "Malformed Diagnostic block"; |
290 | case SDError::MalformedDiagnosticRecord: |
291 | return "Malformed Diagnostic record"; |
292 | case SDError::MissingVersion: |
293 | return "No version provided in diagnostics"; |
294 | case SDError::VersionMismatch: |
295 | return "Unsupported diagnostics version"; |
296 | case SDError::UnsupportedConstruct: |
297 | return "Bitcode constructs that are not supported in diagnostics appear"; |
298 | case SDError::HandlerFailed: |
299 | return "Generic error occurred while handling a record"; |
300 | } |
301 | llvm_unreachable("Unknown error type!"); |
302 | } |
303 | }; |
304 | |
305 | } |
306 | |
307 | static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory; |
308 | const std::error_category &clang::serialized_diags::SDErrorCategory() { |
309 | return *ErrorCategory; |
310 | } |
311 | |