• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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