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