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