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