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