1277325Sdim//===--- SerializedDiagnosticReader.cpp - Reads diagnostics ---------------===//
2277325Sdim//
3277325Sdim//                     The LLVM Compiler Infrastructure
4277325Sdim//
5277325Sdim// This file is distributed under the University of Illinois Open Source
6277325Sdim// License. See LICENSE.TXT for details.
7277325Sdim//
8277325Sdim//===----------------------------------------------------------------------===//
9277325Sdim
10277325Sdim#include "clang/Frontend/SerializedDiagnosticReader.h"
11277325Sdim#include "clang/Basic/FileManager.h"
12277325Sdim#include "clang/Frontend/SerializedDiagnostics.h"
13277325Sdim#include "llvm/Support/ManagedStatic.h"
14277325Sdim#include "llvm/Support/MemoryBuffer.h"
15277325Sdim
16277325Sdimusing namespace clang;
17277325Sdimusing namespace clang::serialized_diags;
18277325Sdim
19277325Sdimstd::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
20277325Sdim  // Open the diagnostics file.
21277325Sdim  FileSystemOptions FO;
22277325Sdim  FileManager FileMgr(FO);
23277325Sdim
24277325Sdim  auto Buffer = FileMgr.getBufferForFile(File);
25277325Sdim  if (!Buffer)
26277325Sdim    return SDError::CouldNotLoad;
27277325Sdim
28277325Sdim  llvm::BitstreamReader StreamFile;
29277325Sdim  StreamFile.init((const unsigned char *)(*Buffer)->getBufferStart(),
30277325Sdim                  (const unsigned char *)(*Buffer)->getBufferEnd());
31277325Sdim
32277325Sdim  llvm::BitstreamCursor Stream(StreamFile);
33277325Sdim
34277325Sdim  // Sniff for the signature.
35277325Sdim  if (Stream.Read(8) != 'D' ||
36277325Sdim      Stream.Read(8) != 'I' ||
37277325Sdim      Stream.Read(8) != 'A' ||
38277325Sdim      Stream.Read(8) != 'G')
39277325Sdim    return SDError::InvalidSignature;
40277325Sdim
41277325Sdim  // Read the top level blocks.
42277325Sdim  while (!Stream.AtEndOfStream()) {
43277325Sdim    if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
44277325Sdim      return SDError::InvalidDiagnostics;
45277325Sdim
46277325Sdim    std::error_code EC;
47277325Sdim    switch (Stream.ReadSubBlockID()) {
48277325Sdim    case llvm::bitc::BLOCKINFO_BLOCK_ID:
49277325Sdim      if (Stream.ReadBlockInfoBlock())
50277325Sdim        return SDError::MalformedBlockInfoBlock;
51277325Sdim      continue;
52277325Sdim    case BLOCK_META:
53277325Sdim      if ((EC = readMetaBlock(Stream)))
54277325Sdim        return EC;
55277325Sdim      continue;
56277325Sdim    case BLOCK_DIAG:
57277325Sdim      if ((EC = readDiagnosticBlock(Stream)))
58277325Sdim        return EC;
59277325Sdim      continue;
60277325Sdim    default:
61277325Sdim      if (!Stream.SkipBlock())
62277325Sdim        return SDError::MalformedTopLevelBlock;
63277325Sdim      continue;
64277325Sdim    }
65277325Sdim  }
66277325Sdim  return std::error_code();
67277325Sdim}
68277325Sdim
69277325Sdimenum class SerializedDiagnosticReader::Cursor {
70277325Sdim  Record = 1,
71277325Sdim  BlockEnd,
72277325Sdim  BlockBegin
73277325Sdim};
74277325Sdim
75277325Sdimllvm::ErrorOr<SerializedDiagnosticReader::Cursor>
76277325SdimSerializedDiagnosticReader::skipUntilRecordOrBlock(
77277325Sdim    llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
78277325Sdim  BlockOrRecordID = 0;
79277325Sdim
80277325Sdim  while (!Stream.AtEndOfStream()) {
81277325Sdim    unsigned Code = Stream.ReadCode();
82277325Sdim
83277325Sdim    switch ((llvm::bitc::FixedAbbrevIDs)Code) {
84277325Sdim    case llvm::bitc::ENTER_SUBBLOCK:
85277325Sdim      BlockOrRecordID = Stream.ReadSubBlockID();
86277325Sdim      return Cursor::BlockBegin;
87277325Sdim
88277325Sdim    case llvm::bitc::END_BLOCK:
89277325Sdim      if (Stream.ReadBlockEnd())
90277325Sdim        return SDError::InvalidDiagnostics;
91277325Sdim      return Cursor::BlockEnd;
92277325Sdim
93277325Sdim    case llvm::bitc::DEFINE_ABBREV:
94277325Sdim      Stream.ReadAbbrevRecord();
95277325Sdim      continue;
96277325Sdim
97277325Sdim    case llvm::bitc::UNABBREV_RECORD:
98277325Sdim      return SDError::UnsupportedConstruct;
99277325Sdim
100277325Sdim    default:
101277325Sdim      // We found a record.
102277325Sdim      BlockOrRecordID = Code;
103277325Sdim      return Cursor::Record;
104277325Sdim    }
105277325Sdim  }
106277325Sdim
107277325Sdim  return SDError::InvalidDiagnostics;
108277325Sdim}
109277325Sdim
110277325Sdimstd::error_code
111277325SdimSerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
112277325Sdim  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
113277325Sdim    return SDError::MalformedMetadataBlock;
114277325Sdim
115277325Sdim  bool VersionChecked = false;
116277325Sdim
117277325Sdim  while (true) {
118277325Sdim    unsigned BlockOrCode = 0;
119277325Sdim    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
120277325Sdim    if (!Res)
121277325Sdim      Res.getError();
122277325Sdim
123277325Sdim    switch (Res.get()) {
124277325Sdim    case Cursor::Record:
125277325Sdim      break;
126277325Sdim    case Cursor::BlockBegin:
127277325Sdim      if (Stream.SkipBlock())
128277325Sdim        return SDError::MalformedMetadataBlock;
129277325Sdim    case Cursor::BlockEnd:
130277325Sdim      if (!VersionChecked)
131277325Sdim        return SDError::MissingVersion;
132277325Sdim      return std::error_code();
133277325Sdim    }
134277325Sdim
135277325Sdim    SmallVector<uint64_t, 1> Record;
136277325Sdim    unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
137277325Sdim
138277325Sdim    if (RecordID == RECORD_VERSION) {
139277325Sdim      if (Record.size() < 1)
140277325Sdim        return SDError::MissingVersion;
141277325Sdim      if (Record[0] > VersionNumber)
142277325Sdim        return SDError::VersionMismatch;
143277325Sdim      VersionChecked = true;
144277325Sdim    }
145277325Sdim  }
146277325Sdim}
147277325Sdim
148277325Sdimstd::error_code
149277325SdimSerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
150277325Sdim  if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
151277325Sdim    return SDError::MalformedDiagnosticBlock;
152277325Sdim
153277325Sdim  std::error_code EC;
154277325Sdim  if ((EC = visitStartOfDiagnostic()))
155277325Sdim    return EC;
156277325Sdim
157277325Sdim  SmallVector<uint64_t, 16> Record;
158277325Sdim  while (true) {
159277325Sdim    unsigned BlockOrCode = 0;
160277325Sdim    llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
161277325Sdim    if (!Res)
162277325Sdim      Res.getError();
163277325Sdim
164277325Sdim    switch (Res.get()) {
165277325Sdim    case Cursor::BlockBegin:
166277325Sdim      // The only blocks we care about are subdiagnostics.
167277325Sdim      if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
168277325Sdim        if ((EC = readDiagnosticBlock(Stream)))
169277325Sdim          return EC;
170277325Sdim      } else if (!Stream.SkipBlock())
171277325Sdim        return SDError::MalformedSubBlock;
172277325Sdim      continue;
173277325Sdim    case Cursor::BlockEnd:
174277325Sdim      if ((EC = visitEndOfDiagnostic()))
175277325Sdim        return EC;
176277325Sdim      return std::error_code();
177277325Sdim    case Cursor::Record:
178277325Sdim      break;
179277325Sdim    }
180277325Sdim
181277325Sdim    // Read the record.
182277325Sdim    Record.clear();
183277325Sdim    StringRef Blob;
184277325Sdim    unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
185277325Sdim
186277325Sdim    if (RecID < serialized_diags::RECORD_FIRST ||
187277325Sdim        RecID > serialized_diags::RECORD_LAST)
188277325Sdim      continue;
189277325Sdim
190277325Sdim    switch ((RecordIDs)RecID) {
191277325Sdim    case RECORD_CATEGORY:
192277325Sdim      // A category has ID and name size.
193277325Sdim      if (Record.size() != 2)
194277325Sdim        return SDError::MalformedDiagnosticRecord;
195277325Sdim      if ((EC = visitCategoryRecord(Record[0], Blob)))
196277325Sdim        return EC;
197277325Sdim      continue;
198277325Sdim    case RECORD_DIAG:
199277325Sdim      // A diagnostic has severity, location (4), category, flag, and message
200277325Sdim      // size.
201277325Sdim      if (Record.size() != 8)
202277325Sdim        return SDError::MalformedDiagnosticRecord;
203277325Sdim      if ((EC = visitDiagnosticRecord(
204277325Sdim               Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
205277325Sdim               Record[5], Record[6], Blob)))
206277325Sdim        return EC;
207277325Sdim      continue;
208277325Sdim    case RECORD_DIAG_FLAG:
209277325Sdim      // A diagnostic flag has ID and name size.
210277325Sdim      if (Record.size() != 2)
211277325Sdim        return SDError::MalformedDiagnosticRecord;
212277325Sdim      if ((EC = visitDiagFlagRecord(Record[0], Blob)))
213277325Sdim        return EC;
214277325Sdim      continue;
215277325Sdim    case RECORD_FILENAME:
216277325Sdim      // A filename has ID, size, timestamp, and name size. The size and
217277325Sdim      // timestamp are legacy fields that are always zero these days.
218277325Sdim      if (Record.size() != 4)
219277325Sdim        return SDError::MalformedDiagnosticRecord;
220277325Sdim      if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
221277325Sdim        return EC;
222277325Sdim      continue;
223277325Sdim    case RECORD_FIXIT:
224277325Sdim      // A fixit has two locations (4 each) and message size.
225277325Sdim      if (Record.size() != 9)
226277325Sdim        return SDError::MalformedDiagnosticRecord;
227277325Sdim      if ((EC = visitFixitRecord(
228277325Sdim               Location(Record[0], Record[1], Record[2], Record[3]),
229277325Sdim               Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
230277325Sdim        return EC;
231277325Sdim      continue;
232277325Sdim    case RECORD_SOURCE_RANGE:
233277325Sdim      // A source range is two locations (4 each).
234277325Sdim      if (Record.size() != 8)
235277325Sdim        return SDError::MalformedDiagnosticRecord;
236277325Sdim      if ((EC = visitSourceRangeRecord(
237277325Sdim               Location(Record[0], Record[1], Record[2], Record[3]),
238277325Sdim               Location(Record[4], Record[5], Record[6], Record[7]))))
239277325Sdim        return EC;
240277325Sdim      continue;
241277325Sdim    case RECORD_VERSION:
242277325Sdim      // A version is just a number.
243277325Sdim      if (Record.size() != 1)
244277325Sdim        return SDError::MalformedDiagnosticRecord;
245277325Sdim      if ((EC = visitVersionRecord(Record[0])))
246277325Sdim        return EC;
247277325Sdim      continue;
248277325Sdim    }
249277325Sdim  }
250277325Sdim}
251277325Sdim
252277325Sdimnamespace {
253277325Sdimclass SDErrorCategoryType final : public std::error_category {
254277325Sdim  const char *name() const LLVM_NOEXCEPT override {
255277325Sdim    return "clang.serialized_diags";
256277325Sdim  }
257277325Sdim  std::string message(int IE) const override {
258277325Sdim    SDError E = static_cast<SDError>(IE);
259277325Sdim    switch (E) {
260277325Sdim    case SDError::CouldNotLoad:
261277325Sdim      return "Failed to open diagnostics file";
262277325Sdim    case SDError::InvalidSignature:
263277325Sdim      return "Invalid diagnostics signature";
264277325Sdim    case SDError::InvalidDiagnostics:
265277325Sdim      return "Parse error reading diagnostics";
266277325Sdim    case SDError::MalformedTopLevelBlock:
267277325Sdim      return "Malformed block at top-level of diagnostics";
268277325Sdim    case SDError::MalformedSubBlock:
269277325Sdim      return "Malformed sub-block in a diagnostic";
270277325Sdim    case SDError::MalformedBlockInfoBlock:
271277325Sdim      return "Malformed BlockInfo block";
272277325Sdim    case SDError::MalformedMetadataBlock:
273277325Sdim      return "Malformed Metadata block";
274277325Sdim    case SDError::MalformedDiagnosticBlock:
275277325Sdim      return "Malformed Diagnostic block";
276277325Sdim    case SDError::MalformedDiagnosticRecord:
277277325Sdim      return "Malformed Diagnostic record";
278277325Sdim    case SDError::MissingVersion:
279277325Sdim      return "No version provided in diagnostics";
280277325Sdim    case SDError::VersionMismatch:
281277325Sdim      return "Unsupported diagnostics version";
282277325Sdim    case SDError::UnsupportedConstruct:
283277325Sdim      return "Bitcode constructs that are not supported in diagnostics appear";
284277325Sdim    case SDError::HandlerFailed:
285277325Sdim      return "Generic error occurred while handling a record";
286277325Sdim    }
287277325Sdim    llvm_unreachable("Unknown error type!");
288277325Sdim  }
289277325Sdim};
290277325Sdim}
291277325Sdim
292277325Sdimstatic llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
293277325Sdimconst std::error_category &clang::serialized_diags::SDErrorCategory() {
294277325Sdim  return *ErrorCategory;
295277325Sdim}
296