xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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/SmallVector.h"
14 #include "llvm/Bitstream/BitstreamReader.h"
15 #include "llvm/Support/Compiler.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/ErrorOr.h"
18 #include "llvm/Support/ManagedStatic.h"
19 #include <cstdint>
20 #include <optional>
21 #include <system_error>
22 
23 using namespace clang;
24 using namespace serialized_diags;
25 
26 std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
27   // Open the diagnostics file.
28   FileSystemOptions FO;
29   FileManager FileMgr(FO);
30 
31   auto Buffer = FileMgr.getBufferForFile(File);
32   if (!Buffer)
33     return SDError::CouldNotLoad;
34 
35   llvm::BitstreamCursor Stream(**Buffer);
36   std::optional<llvm::BitstreamBlockInfo> BlockInfo;
37 
38   if (Stream.AtEndOfStream())
39     return SDError::InvalidSignature;
40 
41   // Sniff for the signature.
42   for (unsigned char C : {'D', 'I', 'A', 'G'}) {
43     if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {
44       if (Res.get() == C)
45         continue;
46     } else {
47       // FIXME this drops the error on the floor.
48       consumeError(Res.takeError());
49     }
50     return SDError::InvalidSignature;
51   }
52 
53   // Read the top level blocks.
54   while (!Stream.AtEndOfStream()) {
55     if (Expected<unsigned> Res = Stream.ReadCode()) {
56       if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)
57         return SDError::InvalidDiagnostics;
58     } else {
59       // FIXME this drops the error on the floor.
60       consumeError(Res.takeError());
61       return SDError::InvalidDiagnostics;
62     }
63 
64     std::error_code EC;
65     Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();
66     if (!MaybeSubBlockID) {
67       // FIXME this drops the error on the floor.
68       consumeError(MaybeSubBlockID.takeError());
69       return SDError::InvalidDiagnostics;
70     }
71 
72     switch (MaybeSubBlockID.get()) {
73     case llvm::bitc::BLOCKINFO_BLOCK_ID: {
74       Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
75           Stream.ReadBlockInfoBlock();
76       if (!MaybeBlockInfo) {
77         // FIXME this drops the error on the floor.
78         consumeError(MaybeBlockInfo.takeError());
79         return SDError::InvalidDiagnostics;
80       }
81       BlockInfo = std::move(MaybeBlockInfo.get());
82     }
83       if (!BlockInfo)
84         return SDError::MalformedBlockInfoBlock;
85       Stream.setBlockInfo(&*BlockInfo);
86       continue;
87     case BLOCK_META:
88       if ((EC = readMetaBlock(Stream)))
89         return EC;
90       continue;
91     case BLOCK_DIAG:
92       if ((EC = readDiagnosticBlock(Stream)))
93         return EC;
94       continue;
95     default:
96       if (llvm::Error Err = Stream.SkipBlock()) {
97         // FIXME this drops the error on the floor.
98         consumeError(std::move(Err));
99         return SDError::MalformedTopLevelBlock;
100       }
101       continue;
102     }
103   }
104   return {};
105 }
106 
107 enum class SerializedDiagnosticReader::Cursor {
108   Record = 1,
109   BlockEnd,
110   BlockBegin
111 };
112 
113 llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
114 SerializedDiagnosticReader::skipUntilRecordOrBlock(
115     llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
116   BlockOrRecordID = 0;
117 
118   while (!Stream.AtEndOfStream()) {
119     unsigned Code;
120     if (Expected<unsigned> Res = Stream.ReadCode())
121       Code = Res.get();
122     else
123       return llvm::errorToErrorCode(Res.takeError());
124 
125     if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {
126       // We found a record.
127       BlockOrRecordID = Code;
128       return Cursor::Record;
129     }
130     switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {
131     case llvm::bitc::ENTER_SUBBLOCK:
132       if (Expected<unsigned> Res = Stream.ReadSubBlockID())
133         BlockOrRecordID = Res.get();
134       else
135         return llvm::errorToErrorCode(Res.takeError());
136       return Cursor::BlockBegin;
137 
138     case llvm::bitc::END_BLOCK:
139       if (Stream.ReadBlockEnd())
140         return SDError::InvalidDiagnostics;
141       return Cursor::BlockEnd;
142 
143     case llvm::bitc::DEFINE_ABBREV:
144       if (llvm::Error Err = Stream.ReadAbbrevRecord())
145         return llvm::errorToErrorCode(std::move(Err));
146       continue;
147 
148     case llvm::bitc::UNABBREV_RECORD:
149       return SDError::UnsupportedConstruct;
150 
151     case llvm::bitc::FIRST_APPLICATION_ABBREV:
152       llvm_unreachable("Unexpected abbrev id.");
153     }
154   }
155 
156   return SDError::InvalidDiagnostics;
157 }
158 
159 std::error_code
160 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
161   if (llvm::Error Err =
162           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
163     // FIXME this drops the error on the floor.
164     consumeError(std::move(Err));
165     return SDError::MalformedMetadataBlock;
166   }
167 
168   bool VersionChecked = false;
169 
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::Record:
178       break;
179     case Cursor::BlockBegin:
180       if (llvm::Error Err = Stream.SkipBlock()) {
181         // FIXME this drops the error on the floor.
182         consumeError(std::move(Err));
183         return SDError::MalformedMetadataBlock;
184       }
185       [[fallthrough]];
186     case Cursor::BlockEnd:
187       if (!VersionChecked)
188         return SDError::MissingVersion;
189       return {};
190     }
191 
192     SmallVector<uint64_t, 1> Record;
193     Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);
194     if (!MaybeRecordID)
195       return errorToErrorCode(MaybeRecordID.takeError());
196     unsigned RecordID = MaybeRecordID.get();
197 
198     if (RecordID == RECORD_VERSION) {
199       if (Record.size() < 1)
200         return SDError::MissingVersion;
201       if (Record[0] > VersionNumber)
202         return SDError::VersionMismatch;
203       VersionChecked = true;
204     }
205   }
206 }
207 
208 std::error_code
209 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
210   if (llvm::Error Err =
211           Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
212     // FIXME this drops the error on the floor.
213     consumeError(std::move(Err));
214     return SDError::MalformedDiagnosticBlock;
215   }
216 
217   std::error_code EC;
218   if ((EC = visitStartOfDiagnostic()))
219     return EC;
220 
221   SmallVector<uint64_t, 16> Record;
222   while (true) {
223     unsigned BlockOrCode = 0;
224     llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
225     if (!Res)
226       Res.getError();
227 
228     switch (Res.get()) {
229     case Cursor::BlockBegin:
230       // The only blocks we care about are subdiagnostics.
231       if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
232         if ((EC = readDiagnosticBlock(Stream)))
233           return EC;
234       } else if (llvm::Error Err = Stream.SkipBlock()) {
235         // FIXME this drops the error on the floor.
236         consumeError(std::move(Err));
237         return SDError::MalformedSubBlock;
238       }
239       continue;
240     case Cursor::BlockEnd:
241       if ((EC = visitEndOfDiagnostic()))
242         return EC;
243       return {};
244     case Cursor::Record:
245       break;
246     }
247 
248     // Read the record.
249     Record.clear();
250     StringRef Blob;
251     Expected<unsigned> MaybeRecID =
252         Stream.readRecord(BlockOrCode, Record, &Blob);
253     if (!MaybeRecID)
254       return errorToErrorCode(MaybeRecID.takeError());
255     unsigned RecID = MaybeRecID.get();
256 
257     if (RecID < serialized_diags::RECORD_FIRST ||
258         RecID > serialized_diags::RECORD_LAST)
259       continue;
260 
261     switch ((RecordIDs)RecID) {
262     case RECORD_CATEGORY:
263       // A category has ID and name size.
264       if (Record.size() != 2)
265         return SDError::MalformedDiagnosticRecord;
266       if ((EC = visitCategoryRecord(Record[0], Blob)))
267         return EC;
268       continue;
269     case RECORD_DIAG:
270       // A diagnostic has severity, location (4), category, flag, and message
271       // size.
272       if (Record.size() != 8)
273         return SDError::MalformedDiagnosticRecord;
274       if ((EC = visitDiagnosticRecord(
275                Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
276                Record[5], Record[6], Blob)))
277         return EC;
278       continue;
279     case RECORD_DIAG_FLAG:
280       // A diagnostic flag has ID and name size.
281       if (Record.size() != 2)
282         return SDError::MalformedDiagnosticRecord;
283       if ((EC = visitDiagFlagRecord(Record[0], Blob)))
284         return EC;
285       continue;
286     case RECORD_FILENAME:
287       // A filename has ID, size, timestamp, and name size. The size and
288       // timestamp are legacy fields that are always zero these days.
289       if (Record.size() != 4)
290         return SDError::MalformedDiagnosticRecord;
291       if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
292         return EC;
293       continue;
294     case RECORD_FIXIT:
295       // A fixit has two locations (4 each) and message size.
296       if (Record.size() != 9)
297         return SDError::MalformedDiagnosticRecord;
298       if ((EC = visitFixitRecord(
299                Location(Record[0], Record[1], Record[2], Record[3]),
300                Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
301         return EC;
302       continue;
303     case RECORD_SOURCE_RANGE:
304       // A source range is two locations (4 each).
305       if (Record.size() != 8)
306         return SDError::MalformedDiagnosticRecord;
307       if ((EC = visitSourceRangeRecord(
308                Location(Record[0], Record[1], Record[2], Record[3]),
309                Location(Record[4], Record[5], Record[6], Record[7]))))
310         return EC;
311       continue;
312     case RECORD_VERSION:
313       // A version is just a number.
314       if (Record.size() != 1)
315         return SDError::MalformedDiagnosticRecord;
316       if ((EC = visitVersionRecord(Record[0])))
317         return EC;
318       continue;
319     }
320   }
321 }
322 
323 namespace {
324 
325 class SDErrorCategoryType final : public std::error_category {
326   const char *name() const noexcept override {
327     return "clang.serialized_diags";
328   }
329 
330   std::string message(int IE) const override {
331     auto E = static_cast<SDError>(IE);
332     switch (E) {
333     case SDError::CouldNotLoad:
334       return "Failed to open diagnostics file";
335     case SDError::InvalidSignature:
336       return "Invalid diagnostics signature";
337     case SDError::InvalidDiagnostics:
338       return "Parse error reading diagnostics";
339     case SDError::MalformedTopLevelBlock:
340       return "Malformed block at top-level of diagnostics";
341     case SDError::MalformedSubBlock:
342       return "Malformed sub-block in a diagnostic";
343     case SDError::MalformedBlockInfoBlock:
344       return "Malformed BlockInfo block";
345     case SDError::MalformedMetadataBlock:
346       return "Malformed Metadata block";
347     case SDError::MalformedDiagnosticBlock:
348       return "Malformed Diagnostic block";
349     case SDError::MalformedDiagnosticRecord:
350       return "Malformed Diagnostic record";
351     case SDError::MissingVersion:
352       return "No version provided in diagnostics";
353     case SDError::VersionMismatch:
354       return "Unsupported diagnostics version";
355     case SDError::UnsupportedConstruct:
356       return "Bitcode constructs that are not supported in diagnostics appear";
357     case SDError::HandlerFailed:
358       return "Generic error occurred while handling a record";
359     }
360     llvm_unreachable("Unknown error type!");
361   }
362 };
363 
364 } // namespace
365 
366 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
367 const std::error_category &clang::serialized_diags::SDErrorCategory() {
368   return *ErrorCategory;
369 }
370