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/SmallVector.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Bitstream/BitCodes.h" 16 #include "llvm/Bitstream/BitstreamReader.h" 17 #include "llvm/Support/Compiler.h" 18 #include "llvm/Support/ErrorHandling.h" 19 #include "llvm/Support/ErrorOr.h" 20 #include "llvm/Support/ManagedStatic.h" 21 #include <cstdint> 22 #include <optional> 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 std::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<std::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 if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) { 128 // We found a record. 129 BlockOrRecordID = Code; 130 return Cursor::Record; 131 } 132 switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) { 133 case llvm::bitc::ENTER_SUBBLOCK: 134 if (Expected<unsigned> Res = Stream.ReadSubBlockID()) 135 BlockOrRecordID = Res.get(); 136 else 137 return llvm::errorToErrorCode(Res.takeError()); 138 return Cursor::BlockBegin; 139 140 case llvm::bitc::END_BLOCK: 141 if (Stream.ReadBlockEnd()) 142 return SDError::InvalidDiagnostics; 143 return Cursor::BlockEnd; 144 145 case llvm::bitc::DEFINE_ABBREV: 146 if (llvm::Error Err = Stream.ReadAbbrevRecord()) 147 return llvm::errorToErrorCode(std::move(Err)); 148 continue; 149 150 case llvm::bitc::UNABBREV_RECORD: 151 return SDError::UnsupportedConstruct; 152 153 case llvm::bitc::FIRST_APPLICATION_ABBREV: 154 llvm_unreachable("Unexpected abbrev id."); 155 } 156 } 157 158 return SDError::InvalidDiagnostics; 159 } 160 161 std::error_code 162 SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { 163 if (llvm::Error Err = 164 Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { 165 // FIXME this drops the error on the floor. 166 consumeError(std::move(Err)); 167 return SDError::MalformedMetadataBlock; 168 } 169 170 bool VersionChecked = false; 171 172 while (true) { 173 unsigned BlockOrCode = 0; 174 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 175 if (!Res) 176 Res.getError(); 177 178 switch (Res.get()) { 179 case Cursor::Record: 180 break; 181 case Cursor::BlockBegin: 182 if (llvm::Error Err = Stream.SkipBlock()) { 183 // FIXME this drops the error on the floor. 184 consumeError(std::move(Err)); 185 return SDError::MalformedMetadataBlock; 186 } 187 [[fallthrough]]; 188 case Cursor::BlockEnd: 189 if (!VersionChecked) 190 return SDError::MissingVersion; 191 return {}; 192 } 193 194 SmallVector<uint64_t, 1> Record; 195 Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record); 196 if (!MaybeRecordID) 197 return errorToErrorCode(MaybeRecordID.takeError()); 198 unsigned RecordID = MaybeRecordID.get(); 199 200 if (RecordID == RECORD_VERSION) { 201 if (Record.size() < 1) 202 return SDError::MissingVersion; 203 if (Record[0] > VersionNumber) 204 return SDError::VersionMismatch; 205 VersionChecked = true; 206 } 207 } 208 } 209 210 std::error_code 211 SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) { 212 if (llvm::Error Err = 213 Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { 214 // FIXME this drops the error on the floor. 215 consumeError(std::move(Err)); 216 return SDError::MalformedDiagnosticBlock; 217 } 218 219 std::error_code EC; 220 if ((EC = visitStartOfDiagnostic())) 221 return EC; 222 223 SmallVector<uint64_t, 16> Record; 224 while (true) { 225 unsigned BlockOrCode = 0; 226 llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 227 if (!Res) 228 Res.getError(); 229 230 switch (Res.get()) { 231 case Cursor::BlockBegin: 232 // The only blocks we care about are subdiagnostics. 233 if (BlockOrCode == serialized_diags::BLOCK_DIAG) { 234 if ((EC = readDiagnosticBlock(Stream))) 235 return EC; 236 } else if (llvm::Error Err = Stream.SkipBlock()) { 237 // FIXME this drops the error on the floor. 238 consumeError(std::move(Err)); 239 return SDError::MalformedSubBlock; 240 } 241 continue; 242 case Cursor::BlockEnd: 243 if ((EC = visitEndOfDiagnostic())) 244 return EC; 245 return {}; 246 case Cursor::Record: 247 break; 248 } 249 250 // Read the record. 251 Record.clear(); 252 StringRef Blob; 253 Expected<unsigned> MaybeRecID = 254 Stream.readRecord(BlockOrCode, Record, &Blob); 255 if (!MaybeRecID) 256 return errorToErrorCode(MaybeRecID.takeError()); 257 unsigned RecID = MaybeRecID.get(); 258 259 if (RecID < serialized_diags::RECORD_FIRST || 260 RecID > serialized_diags::RECORD_LAST) 261 continue; 262 263 switch ((RecordIDs)RecID) { 264 case RECORD_CATEGORY: 265 // A category has ID and name size. 266 if (Record.size() != 2) 267 return SDError::MalformedDiagnosticRecord; 268 if ((EC = visitCategoryRecord(Record[0], Blob))) 269 return EC; 270 continue; 271 case RECORD_DIAG: 272 // A diagnostic has severity, location (4), category, flag, and message 273 // size. 274 if (Record.size() != 8) 275 return SDError::MalformedDiagnosticRecord; 276 if ((EC = visitDiagnosticRecord( 277 Record[0], Location(Record[1], Record[2], Record[3], Record[4]), 278 Record[5], Record[6], Blob))) 279 return EC; 280 continue; 281 case RECORD_DIAG_FLAG: 282 // A diagnostic flag has ID and name size. 283 if (Record.size() != 2) 284 return SDError::MalformedDiagnosticRecord; 285 if ((EC = visitDiagFlagRecord(Record[0], Blob))) 286 return EC; 287 continue; 288 case RECORD_FILENAME: 289 // A filename has ID, size, timestamp, and name size. The size and 290 // timestamp are legacy fields that are always zero these days. 291 if (Record.size() != 4) 292 return SDError::MalformedDiagnosticRecord; 293 if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob))) 294 return EC; 295 continue; 296 case RECORD_FIXIT: 297 // A fixit has two locations (4 each) and message size. 298 if (Record.size() != 9) 299 return SDError::MalformedDiagnosticRecord; 300 if ((EC = visitFixitRecord( 301 Location(Record[0], Record[1], Record[2], Record[3]), 302 Location(Record[4], Record[5], Record[6], Record[7]), Blob))) 303 return EC; 304 continue; 305 case RECORD_SOURCE_RANGE: 306 // A source range is two locations (4 each). 307 if (Record.size() != 8) 308 return SDError::MalformedDiagnosticRecord; 309 if ((EC = visitSourceRangeRecord( 310 Location(Record[0], Record[1], Record[2], Record[3]), 311 Location(Record[4], Record[5], Record[6], Record[7])))) 312 return EC; 313 continue; 314 case RECORD_VERSION: 315 // A version is just a number. 316 if (Record.size() != 1) 317 return SDError::MalformedDiagnosticRecord; 318 if ((EC = visitVersionRecord(Record[0]))) 319 return EC; 320 continue; 321 } 322 } 323 } 324 325 namespace { 326 327 class SDErrorCategoryType final : public std::error_category { 328 const char *name() const noexcept override { 329 return "clang.serialized_diags"; 330 } 331 332 std::string message(int IE) const override { 333 auto E = static_cast<SDError>(IE); 334 switch (E) { 335 case SDError::CouldNotLoad: 336 return "Failed to open diagnostics file"; 337 case SDError::InvalidSignature: 338 return "Invalid diagnostics signature"; 339 case SDError::InvalidDiagnostics: 340 return "Parse error reading diagnostics"; 341 case SDError::MalformedTopLevelBlock: 342 return "Malformed block at top-level of diagnostics"; 343 case SDError::MalformedSubBlock: 344 return "Malformed sub-block in a diagnostic"; 345 case SDError::MalformedBlockInfoBlock: 346 return "Malformed BlockInfo block"; 347 case SDError::MalformedMetadataBlock: 348 return "Malformed Metadata block"; 349 case SDError::MalformedDiagnosticBlock: 350 return "Malformed Diagnostic block"; 351 case SDError::MalformedDiagnosticRecord: 352 return "Malformed Diagnostic record"; 353 case SDError::MissingVersion: 354 return "No version provided in diagnostics"; 355 case SDError::VersionMismatch: 356 return "Unsupported diagnostics version"; 357 case SDError::UnsupportedConstruct: 358 return "Bitcode constructs that are not supported in diagnostics appear"; 359 case SDError::HandlerFailed: 360 return "Generic error occurred while handling a record"; 361 } 362 llvm_unreachable("Unknown error type!"); 363 } 364 }; 365 366 } // namespace 367 368 static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory; 369 const std::error_category &clang::serialized_diags::SDErrorCategory() { 370 return *ErrorCategory; 371 } 372