1 //===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Frontend/SerializedDiagnosticReader.h" 10 #include "clang/Basic/FileManager.h" 11 #include "clang/Basic/FileSystemOptions.h" 12 #include "clang/Frontend/SerializedDiagnostics.h" 13 #include "llvm/ADT/Optional.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/Bitstream/BitCodes.h" 17 #include "llvm/Bitstream/BitstreamReader.h" 18 #include "llvm/Support/Compiler.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include "llvm/Support/ErrorOr.h" 21 #include "llvm/Support/ManagedStatic.h" 22 #include <cstdint> 23 #include <system_error> 24 25 using namespace clang; 26 using namespace serialized_diags; 27 28 std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { 29 // Open the diagnostics file. 30 FileSystemOptions FO; 31 FileManager FileMgr(FO); 32 33 auto Buffer = FileMgr.getBufferForFile(File); 34 if (!Buffer) 35 return SDError::CouldNotLoad; 36 37 llvm::BitstreamCursor Stream(**Buffer); 38 Optional<llvm::BitstreamBlockInfo> BlockInfo; 39 40 if (Stream.AtEndOfStream()) 41 return SDError::InvalidSignature; 42 43 // Sniff for the signature. 44 for (unsigned char C : {'D', 'I', 'A', 'G'}) { 45 if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) { 46 if (Res.get() == C) 47 continue; 48 } else { 49 // FIXME this drops the error on the floor. 50 consumeError(Res.takeError()); 51 } 52 return SDError::InvalidSignature; 53 } 54 55 // Read the top level blocks. 56 while (!Stream.AtEndOfStream()) { 57 if (Expected<unsigned> Res = Stream.ReadCode()) { 58 if (Res.get() != llvm::bitc::ENTER_SUBBLOCK) 59 return SDError::InvalidDiagnostics; 60 } else { 61 // FIXME this drops the error on the floor. 62 consumeError(Res.takeError()); 63 return SDError::InvalidDiagnostics; 64 } 65 66 std::error_code EC; 67 Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID(); 68 if (!MaybeSubBlockID) { 69 // FIXME this drops the error on the floor. 70 consumeError(MaybeSubBlockID.takeError()); 71 return SDError::InvalidDiagnostics; 72 } 73 74 switch (MaybeSubBlockID.get()) { 75 case llvm::bitc::BLOCKINFO_BLOCK_ID: { 76 Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo = 77 Stream.ReadBlockInfoBlock(); 78 if (!MaybeBlockInfo) { 79 // FIXME this drops the error on the floor. 80 consumeError(MaybeBlockInfo.takeError()); 81 return SDError::InvalidDiagnostics; 82 } 83 BlockInfo = std::move(MaybeBlockInfo.get()); 84 } 85 if (!BlockInfo) 86 return SDError::MalformedBlockInfoBlock; 87 Stream.setBlockInfo(&*BlockInfo); 88 continue; 89 case BLOCK_META: 90 if ((EC = readMetaBlock(Stream))) 91 return EC; 92 continue; 93 case BLOCK_DIAG: 94 if ((EC = readDiagnosticBlock(Stream))) 95 return EC; 96 continue; 97 default: 98 if (llvm::Error Err = Stream.SkipBlock()) { 99 // FIXME this drops the error on the floor. 100 consumeError(std::move(Err)); 101 return SDError::MalformedTopLevelBlock; 102 } 103 continue; 104 } 105 } 106 return {}; 107 } 108 109 enum class SerializedDiagnosticReader::Cursor { 110 Record = 1, 111 BlockEnd, 112 BlockBegin 113 }; 114 115 llvm::ErrorOr<SerializedDiagnosticReader::Cursor> 116 SerializedDiagnosticReader::skipUntilRecordOrBlock( 117 llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) { 118 BlockOrRecordID = 0; 119 120 while (!Stream.AtEndOfStream()) { 121 unsigned Code; 122 if (Expected<unsigned> Res = Stream.ReadCode()) 123 Code = Res.get(); 124 else 125 return llvm::errorToErrorCode(Res.takeError()); 126 127 switch ((llvm::bitc::FixedAbbrevIDs)Code) { 128 case llvm::bitc::ENTER_SUBBLOCK: 129 if (Expected<unsigned> Res = Stream.ReadSubBlockID()) 130 BlockOrRecordID = Res.get(); 131 else 132 return llvm::errorToErrorCode(Res.takeError()); 133 return Cursor::BlockBegin; 134 135 case llvm::bitc::END_BLOCK: 136 if (Stream.ReadBlockEnd()) 137 return SDError::InvalidDiagnostics; 138 return Cursor::BlockEnd; 139 140 case llvm::bitc::DEFINE_ABBREV: 141 if (llvm::Error Err = Stream.ReadAbbrevRecord()) 142 return llvm::errorToErrorCode(std::move(Err)); 143 continue; 144 145 case llvm::bitc::UNABBREV_RECORD: 146 return SDError::UnsupportedConstruct; 147 148 default: 149 // We found a record. 150 BlockOrRecordID = Code; 151 return Cursor::Record; 152 } 153 } 154 155 return SDError::InvalidDiagnostics; 156 } 157 158 std::error_code 159 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { 160 if (llvm::Error Err = 161 Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { 162 // FIXME this drops the error on the floor. 163 consumeError(std::move(Err)); 164 return SDError::MalformedMetadataBlock; 165 } 166 167 bool VersionChecked = false; 168 169 while (true) { 170 unsigned BlockOrCode = 0; 171 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 172 if (!Res) 173 Res.getError(); 174 175 switch (Res.get()) { 176 case Cursor::Record: 177 break; 178 case Cursor::BlockBegin: 179 if (llvm::Error Err = Stream.SkipBlock()) { 180 // FIXME this drops the error on the floor. 181 consumeError(std::move(Err)); 182 return SDError::MalformedMetadataBlock; 183 } 184 LLVM_FALLTHROUGH; 185 case Cursor::BlockEnd: 186 if (!VersionChecked) 187 return SDError::MissingVersion; 188 return {}; 189 } 190 191 SmallVector<uint64_t, 1> Record; 192 Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record); 193 if (!MaybeRecordID) 194 return errorToErrorCode(MaybeRecordID.takeError()); 195 unsigned RecordID = MaybeRecordID.get(); 196 197 if (RecordID == RECORD_VERSION) { 198 if (Record.size() < 1) 199 return SDError::MissingVersion; 200 if (Record[0] > VersionNumber) 201 return SDError::VersionMismatch; 202 VersionChecked = true; 203 } 204 } 205 } 206 207 std::error_code 208 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) { 209 if (llvm::Error Err = 210 Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { 211 // FIXME this drops the error on the floor. 212 consumeError(std::move(Err)); 213 return SDError::MalformedDiagnosticBlock; 214 } 215 216 std::error_code EC; 217 if ((EC = visitStartOfDiagnostic())) 218 return EC; 219 220 SmallVector<uint64_t, 16> Record; 221 while (true) { 222 unsigned BlockOrCode = 0; 223 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 224 if (!Res) 225 Res.getError(); 226 227 switch (Res.get()) { 228 case Cursor::BlockBegin: 229 // The only blocks we care about are subdiagnostics. 230 if (BlockOrCode == serialized_diags::BLOCK_DIAG) { 231 if ((EC = readDiagnosticBlock(Stream))) 232 return EC; 233 } else if (llvm::Error Err = Stream.SkipBlock()) { 234 // FIXME this drops the error on the floor. 235 consumeError(std::move(Err)); 236 return SDError::MalformedSubBlock; 237 } 238 continue; 239 case Cursor::BlockEnd: 240 if ((EC = visitEndOfDiagnostic())) 241 return EC; 242 return {}; 243 case Cursor::Record: 244 break; 245 } 246 247 // Read the record. 248 Record.clear(); 249 StringRef Blob; 250 Expected<unsigned> MaybeRecID = 251 Stream.readRecord(BlockOrCode, Record, &Blob); 252 if (!MaybeRecID) 253 return errorToErrorCode(MaybeRecID.takeError()); 254 unsigned RecID = MaybeRecID.get(); 255 256 if (RecID < serialized_diags::RECORD_FIRST || 257 RecID > serialized_diags::RECORD_LAST) 258 continue; 259 260 switch ((RecordIDs)RecID) { 261 case RECORD_CATEGORY: 262 // A category has ID and name size. 263 if (Record.size() != 2) 264 return SDError::MalformedDiagnosticRecord; 265 if ((EC = visitCategoryRecord(Record[0], Blob))) 266 return EC; 267 continue; 268 case RECORD_DIAG: 269 // A diagnostic has severity, location (4), category, flag, and message 270 // size. 271 if (Record.size() != 8) 272 return SDError::MalformedDiagnosticRecord; 273 if ((EC = visitDiagnosticRecord( 274 Record[0], Location(Record[1], Record[2], Record[3], Record[4]), 275 Record[5], Record[6], Blob))) 276 return EC; 277 continue; 278 case RECORD_DIAG_FLAG: 279 // A diagnostic flag has ID and name size. 280 if (Record.size() != 2) 281 return SDError::MalformedDiagnosticRecord; 282 if ((EC = visitDiagFlagRecord(Record[0], Blob))) 283 return EC; 284 continue; 285 case RECORD_FILENAME: 286 // A filename has ID, size, timestamp, and name size. The size and 287 // timestamp are legacy fields that are always zero these days. 288 if (Record.size() != 4) 289 return SDError::MalformedDiagnosticRecord; 290 if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob))) 291 return EC; 292 continue; 293 case RECORD_FIXIT: 294 // A fixit has two locations (4 each) and message size. 295 if (Record.size() != 9) 296 return SDError::MalformedDiagnosticRecord; 297 if ((EC = visitFixitRecord( 298 Location(Record[0], Record[1], Record[2], Record[3]), 299 Location(Record[4], Record[5], Record[6], Record[7]), Blob))) 300 return EC; 301 continue; 302 case RECORD_SOURCE_RANGE: 303 // A source range is two locations (4 each). 304 if (Record.size() != 8) 305 return SDError::MalformedDiagnosticRecord; 306 if ((EC = visitSourceRangeRecord( 307 Location(Record[0], Record[1], Record[2], Record[3]), 308 Location(Record[4], Record[5], Record[6], Record[7])))) 309 return EC; 310 continue; 311 case RECORD_VERSION: 312 // A version is just a number. 313 if (Record.size() != 1) 314 return SDError::MalformedDiagnosticRecord; 315 if ((EC = visitVersionRecord(Record[0]))) 316 return EC; 317 continue; 318 } 319 } 320 } 321 322 namespace { 323 324 class SDErrorCategoryType final : public std::error_category { 325 const char *name() const noexcept override { 326 return "clang.serialized_diags"; 327 } 328 329 std::string message(int IE) const override { 330 auto E = static_cast<SDError>(IE); 331 switch (E) { 332 case SDError::CouldNotLoad: 333 return "Failed to open diagnostics file"; 334 case SDError::InvalidSignature: 335 return "Invalid diagnostics signature"; 336 case SDError::InvalidDiagnostics: 337 return "Parse error reading diagnostics"; 338 case SDError::MalformedTopLevelBlock: 339 return "Malformed block at top-level of diagnostics"; 340 case SDError::MalformedSubBlock: 341 return "Malformed sub-block in a diagnostic"; 342 case SDError::MalformedBlockInfoBlock: 343 return "Malformed BlockInfo block"; 344 case SDError::MalformedMetadataBlock: 345 return "Malformed Metadata block"; 346 case SDError::MalformedDiagnosticBlock: 347 return "Malformed Diagnostic block"; 348 case SDError::MalformedDiagnosticRecord: 349 return "Malformed Diagnostic record"; 350 case SDError::MissingVersion: 351 return "No version provided in diagnostics"; 352 case SDError::VersionMismatch: 353 return "Unsupported diagnostics version"; 354 case SDError::UnsupportedConstruct: 355 return "Bitcode constructs that are not supported in diagnostics appear"; 356 case SDError::HandlerFailed: 357 return "Generic error occurred while handling a record"; 358 } 359 llvm_unreachable("Unknown error type!"); 360 } 361 }; 362 363 } // namespace 364 365 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory; 366 const std::error_category &clang::serialized_diags::SDErrorCategory() { 367 return *ErrorCategory; 368 } 369