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