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