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