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