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