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