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