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