1341825Sdim//===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===// 2277325Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6277325Sdim// 7277325Sdim//===----------------------------------------------------------------------===// 8277325Sdim 9277325Sdim#include "clang/Frontend/SerializedDiagnosticReader.h" 10277325Sdim#include "clang/Basic/FileManager.h" 11341825Sdim#include "clang/Basic/FileSystemOptions.h" 12277325Sdim#include "clang/Frontend/SerializedDiagnostics.h" 13341825Sdim#include "llvm/ADT/Optional.h" 14341825Sdim#include "llvm/ADT/SmallVector.h" 15341825Sdim#include "llvm/ADT/StringRef.h" 16353358Sdim#include "llvm/Bitstream/BitCodes.h" 17353358Sdim#include "llvm/Bitstream/BitstreamReader.h" 18341825Sdim#include "llvm/Support/Compiler.h" 19341825Sdim#include "llvm/Support/ErrorHandling.h" 20341825Sdim#include "llvm/Support/ErrorOr.h" 21277325Sdim#include "llvm/Support/ManagedStatic.h" 22341825Sdim#include <cstdint> 23341825Sdim#include <system_error> 24277325Sdim 25277325Sdimusing namespace clang; 26341825Sdimusing namespace serialized_diags; 27277325Sdim 28277325Sdimstd::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { 29277325Sdim // Open the diagnostics file. 30277325Sdim FileSystemOptions FO; 31277325Sdim FileManager FileMgr(FO); 32277325Sdim 33277325Sdim auto Buffer = FileMgr.getBufferForFile(File); 34277325Sdim if (!Buffer) 35277325Sdim return SDError::CouldNotLoad; 36277325Sdim 37314564Sdim llvm::BitstreamCursor Stream(**Buffer); 38314564Sdim Optional<llvm::BitstreamBlockInfo> BlockInfo; 39277325Sdim 40321369Sdim if (Stream.AtEndOfStream()) 41321369Sdim return SDError::InvalidSignature; 42321369Sdim 43277325Sdim // Sniff for the signature. 44353358Sdim for (unsigned char C : {'D', 'I', 'A', 'G'}) { 45353358Sdim if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) { 46353358Sdim if (Res.get() == C) 47353358Sdim continue; 48353358Sdim } else { 49353358Sdim // FIXME this drops the error on the floor. 50353358Sdim consumeError(Res.takeError()); 51353358Sdim } 52277325Sdim return SDError::InvalidSignature; 53353358Sdim } 54277325Sdim 55277325Sdim // Read the top level blocks. 56277325Sdim while (!Stream.AtEndOfStream()) { 57353358Sdim if (Expected<unsigned> Res = Stream.ReadCode()) { 58353358Sdim if (Res.get() != llvm::bitc::ENTER_SUBBLOCK) 59353358Sdim return SDError::InvalidDiagnostics; 60353358Sdim } else { 61353358Sdim // FIXME this drops the error on the floor. 62353358Sdim consumeError(Res.takeError()); 63277325Sdim return SDError::InvalidDiagnostics; 64353358Sdim } 65277325Sdim 66277325Sdim std::error_code EC; 67353358Sdim Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID(); 68353358Sdim if (!MaybeSubBlockID) { 69353358Sdim // FIXME this drops the error on the floor. 70353358Sdim consumeError(MaybeSubBlockID.takeError()); 71353358Sdim return SDError::InvalidDiagnostics; 72353358Sdim } 73353358Sdim 74353358Sdim switch (MaybeSubBlockID.get()) { 75353358Sdim case llvm::bitc::BLOCKINFO_BLOCK_ID: { 76353358Sdim Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo = 77353358Sdim Stream.ReadBlockInfoBlock(); 78353358Sdim if (!MaybeBlockInfo) { 79353358Sdim // FIXME this drops the error on the floor. 80353358Sdim consumeError(MaybeBlockInfo.takeError()); 81353358Sdim return SDError::InvalidDiagnostics; 82353358Sdim } 83353358Sdim BlockInfo = std::move(MaybeBlockInfo.get()); 84353358Sdim } 85314564Sdim if (!BlockInfo) 86277325Sdim return SDError::MalformedBlockInfoBlock; 87314564Sdim Stream.setBlockInfo(&*BlockInfo); 88277325Sdim continue; 89277325Sdim case BLOCK_META: 90277325Sdim if ((EC = readMetaBlock(Stream))) 91277325Sdim return EC; 92277325Sdim continue; 93277325Sdim case BLOCK_DIAG: 94277325Sdim if ((EC = readDiagnosticBlock(Stream))) 95277325Sdim return EC; 96277325Sdim continue; 97277325Sdim default: 98353358Sdim if (llvm::Error Err = Stream.SkipBlock()) { 99353358Sdim // FIXME this drops the error on the floor. 100353358Sdim consumeError(std::move(Err)); 101277325Sdim return SDError::MalformedTopLevelBlock; 102353358Sdim } 103277325Sdim continue; 104277325Sdim } 105277325Sdim } 106341825Sdim return {}; 107277325Sdim} 108277325Sdim 109277325Sdimenum class SerializedDiagnosticReader::Cursor { 110277325Sdim Record = 1, 111277325Sdim BlockEnd, 112277325Sdim BlockBegin 113277325Sdim}; 114277325Sdim 115277325Sdimllvm::ErrorOr<SerializedDiagnosticReader::Cursor> 116277325SdimSerializedDiagnosticReader::skipUntilRecordOrBlock( 117277325Sdim llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) { 118277325Sdim BlockOrRecordID = 0; 119277325Sdim 120277325Sdim while (!Stream.AtEndOfStream()) { 121353358Sdim unsigned Code; 122353358Sdim if (Expected<unsigned> Res = Stream.ReadCode()) 123353358Sdim Code = Res.get(); 124353358Sdim else 125353358Sdim return llvm::errorToErrorCode(Res.takeError()); 126277325Sdim 127353358Sdim if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) { 128353358Sdim // We found a record. 129353358Sdim BlockOrRecordID = Code; 130353358Sdim return Cursor::Record; 131353358Sdim } 132353358Sdim switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) { 133277325Sdim case llvm::bitc::ENTER_SUBBLOCK: 134353358Sdim if (Expected<unsigned> Res = Stream.ReadSubBlockID()) 135353358Sdim BlockOrRecordID = Res.get(); 136353358Sdim else 137353358Sdim return llvm::errorToErrorCode(Res.takeError()); 138277325Sdim return Cursor::BlockBegin; 139277325Sdim 140277325Sdim case llvm::bitc::END_BLOCK: 141277325Sdim if (Stream.ReadBlockEnd()) 142277325Sdim return SDError::InvalidDiagnostics; 143277325Sdim return Cursor::BlockEnd; 144277325Sdim 145277325Sdim case llvm::bitc::DEFINE_ABBREV: 146353358Sdim if (llvm::Error Err = Stream.ReadAbbrevRecord()) 147353358Sdim return llvm::errorToErrorCode(std::move(Err)); 148277325Sdim continue; 149277325Sdim 150277325Sdim case llvm::bitc::UNABBREV_RECORD: 151277325Sdim return SDError::UnsupportedConstruct; 152277325Sdim 153353358Sdim case llvm::bitc::FIRST_APPLICATION_ABBREV: 154353358Sdim llvm_unreachable("Unexpected abbrev id."); 155277325Sdim } 156277325Sdim } 157277325Sdim 158277325Sdim return SDError::InvalidDiagnostics; 159277325Sdim} 160277325Sdim 161277325Sdimstd::error_code 162277325SdimSerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) { 163353358Sdim if (llvm::Error Err = 164353358Sdim Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { 165353358Sdim // FIXME this drops the error on the floor. 166353358Sdim consumeError(std::move(Err)); 167277325Sdim return SDError::MalformedMetadataBlock; 168353358Sdim } 169277325Sdim 170277325Sdim bool VersionChecked = false; 171277325Sdim 172277325Sdim while (true) { 173277325Sdim unsigned BlockOrCode = 0; 174277325Sdim llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 175277325Sdim if (!Res) 176277325Sdim Res.getError(); 177277325Sdim 178277325Sdim switch (Res.get()) { 179277325Sdim case Cursor::Record: 180277325Sdim break; 181277325Sdim case Cursor::BlockBegin: 182353358Sdim if (llvm::Error Err = Stream.SkipBlock()) { 183353358Sdim // FIXME this drops the error on the floor. 184353358Sdim consumeError(std::move(Err)); 185277325Sdim return SDError::MalformedMetadataBlock; 186353358Sdim } 187321369Sdim LLVM_FALLTHROUGH; 188277325Sdim case Cursor::BlockEnd: 189277325Sdim if (!VersionChecked) 190277325Sdim return SDError::MissingVersion; 191341825Sdim return {}; 192277325Sdim } 193277325Sdim 194277325Sdim SmallVector<uint64_t, 1> Record; 195353358Sdim Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record); 196353358Sdim if (!MaybeRecordID) 197353358Sdim return errorToErrorCode(MaybeRecordID.takeError()); 198353358Sdim unsigned RecordID = MaybeRecordID.get(); 199277325Sdim 200277325Sdim if (RecordID == RECORD_VERSION) { 201277325Sdim if (Record.size() < 1) 202277325Sdim return SDError::MissingVersion; 203277325Sdim if (Record[0] > VersionNumber) 204277325Sdim return SDError::VersionMismatch; 205277325Sdim VersionChecked = true; 206277325Sdim } 207277325Sdim } 208277325Sdim} 209277325Sdim 210277325Sdimstd::error_code 211277325SdimSerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) { 212353358Sdim if (llvm::Error Err = 213353358Sdim Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { 214353358Sdim // FIXME this drops the error on the floor. 215353358Sdim consumeError(std::move(Err)); 216277325Sdim return SDError::MalformedDiagnosticBlock; 217353358Sdim } 218277325Sdim 219277325Sdim std::error_code EC; 220277325Sdim if ((EC = visitStartOfDiagnostic())) 221277325Sdim return EC; 222277325Sdim 223277325Sdim SmallVector<uint64_t, 16> Record; 224277325Sdim while (true) { 225277325Sdim unsigned BlockOrCode = 0; 226277325Sdim llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode); 227277325Sdim if (!Res) 228277325Sdim Res.getError(); 229277325Sdim 230277325Sdim switch (Res.get()) { 231277325Sdim case Cursor::BlockBegin: 232277325Sdim // The only blocks we care about are subdiagnostics. 233277325Sdim if (BlockOrCode == serialized_diags::BLOCK_DIAG) { 234277325Sdim if ((EC = readDiagnosticBlock(Stream))) 235277325Sdim return EC; 236353358Sdim } else if (llvm::Error Err = Stream.SkipBlock()) { 237353358Sdim // FIXME this drops the error on the floor. 238353358Sdim consumeError(std::move(Err)); 239277325Sdim return SDError::MalformedSubBlock; 240353358Sdim } 241277325Sdim continue; 242277325Sdim case Cursor::BlockEnd: 243277325Sdim if ((EC = visitEndOfDiagnostic())) 244277325Sdim return EC; 245341825Sdim return {}; 246277325Sdim case Cursor::Record: 247277325Sdim break; 248277325Sdim } 249277325Sdim 250277325Sdim // Read the record. 251277325Sdim Record.clear(); 252277325Sdim StringRef Blob; 253353358Sdim Expected<unsigned> MaybeRecID = 254353358Sdim Stream.readRecord(BlockOrCode, Record, &Blob); 255353358Sdim if (!MaybeRecID) 256353358Sdim return errorToErrorCode(MaybeRecID.takeError()); 257353358Sdim unsigned RecID = MaybeRecID.get(); 258277325Sdim 259277325Sdim if (RecID < serialized_diags::RECORD_FIRST || 260277325Sdim RecID > serialized_diags::RECORD_LAST) 261277325Sdim continue; 262277325Sdim 263277325Sdim switch ((RecordIDs)RecID) { 264277325Sdim case RECORD_CATEGORY: 265277325Sdim // A category has ID and name size. 266277325Sdim if (Record.size() != 2) 267277325Sdim return SDError::MalformedDiagnosticRecord; 268277325Sdim if ((EC = visitCategoryRecord(Record[0], Blob))) 269277325Sdim return EC; 270277325Sdim continue; 271277325Sdim case RECORD_DIAG: 272277325Sdim // A diagnostic has severity, location (4), category, flag, and message 273277325Sdim // size. 274277325Sdim if (Record.size() != 8) 275277325Sdim return SDError::MalformedDiagnosticRecord; 276277325Sdim if ((EC = visitDiagnosticRecord( 277277325Sdim Record[0], Location(Record[1], Record[2], Record[3], Record[4]), 278277325Sdim Record[5], Record[6], Blob))) 279277325Sdim return EC; 280277325Sdim continue; 281277325Sdim case RECORD_DIAG_FLAG: 282277325Sdim // A diagnostic flag has ID and name size. 283277325Sdim if (Record.size() != 2) 284277325Sdim return SDError::MalformedDiagnosticRecord; 285277325Sdim if ((EC = visitDiagFlagRecord(Record[0], Blob))) 286277325Sdim return EC; 287277325Sdim continue; 288277325Sdim case RECORD_FILENAME: 289277325Sdim // A filename has ID, size, timestamp, and name size. The size and 290277325Sdim // timestamp are legacy fields that are always zero these days. 291277325Sdim if (Record.size() != 4) 292277325Sdim return SDError::MalformedDiagnosticRecord; 293277325Sdim if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob))) 294277325Sdim return EC; 295277325Sdim continue; 296277325Sdim case RECORD_FIXIT: 297277325Sdim // A fixit has two locations (4 each) and message size. 298277325Sdim if (Record.size() != 9) 299277325Sdim return SDError::MalformedDiagnosticRecord; 300277325Sdim if ((EC = visitFixitRecord( 301277325Sdim Location(Record[0], Record[1], Record[2], Record[3]), 302277325Sdim Location(Record[4], Record[5], Record[6], Record[7]), Blob))) 303277325Sdim return EC; 304277325Sdim continue; 305277325Sdim case RECORD_SOURCE_RANGE: 306277325Sdim // A source range is two locations (4 each). 307277325Sdim if (Record.size() != 8) 308277325Sdim return SDError::MalformedDiagnosticRecord; 309277325Sdim if ((EC = visitSourceRangeRecord( 310277325Sdim Location(Record[0], Record[1], Record[2], Record[3]), 311277325Sdim Location(Record[4], Record[5], Record[6], Record[7])))) 312277325Sdim return EC; 313277325Sdim continue; 314277325Sdim case RECORD_VERSION: 315277325Sdim // A version is just a number. 316277325Sdim if (Record.size() != 1) 317277325Sdim return SDError::MalformedDiagnosticRecord; 318277325Sdim if ((EC = visitVersionRecord(Record[0]))) 319277325Sdim return EC; 320277325Sdim continue; 321277325Sdim } 322277325Sdim } 323277325Sdim} 324277325Sdim 325277325Sdimnamespace { 326341825Sdim 327277325Sdimclass SDErrorCategoryType final : public std::error_category { 328314564Sdim const char *name() const noexcept override { 329277325Sdim return "clang.serialized_diags"; 330277325Sdim } 331341825Sdim 332277325Sdim std::string message(int IE) const override { 333341825Sdim auto E = static_cast<SDError>(IE); 334277325Sdim switch (E) { 335277325Sdim case SDError::CouldNotLoad: 336277325Sdim return "Failed to open diagnostics file"; 337277325Sdim case SDError::InvalidSignature: 338277325Sdim return "Invalid diagnostics signature"; 339277325Sdim case SDError::InvalidDiagnostics: 340277325Sdim return "Parse error reading diagnostics"; 341277325Sdim case SDError::MalformedTopLevelBlock: 342277325Sdim return "Malformed block at top-level of diagnostics"; 343277325Sdim case SDError::MalformedSubBlock: 344277325Sdim return "Malformed sub-block in a diagnostic"; 345277325Sdim case SDError::MalformedBlockInfoBlock: 346277325Sdim return "Malformed BlockInfo block"; 347277325Sdim case SDError::MalformedMetadataBlock: 348277325Sdim return "Malformed Metadata block"; 349277325Sdim case SDError::MalformedDiagnosticBlock: 350277325Sdim return "Malformed Diagnostic block"; 351277325Sdim case SDError::MalformedDiagnosticRecord: 352277325Sdim return "Malformed Diagnostic record"; 353277325Sdim case SDError::MissingVersion: 354277325Sdim return "No version provided in diagnostics"; 355277325Sdim case SDError::VersionMismatch: 356277325Sdim return "Unsupported diagnostics version"; 357277325Sdim case SDError::UnsupportedConstruct: 358277325Sdim return "Bitcode constructs that are not supported in diagnostics appear"; 359277325Sdim case SDError::HandlerFailed: 360277325Sdim return "Generic error occurred while handling a record"; 361277325Sdim } 362277325Sdim llvm_unreachable("Unknown error type!"); 363277325Sdim } 364277325Sdim}; 365277325Sdim 366341825Sdim} // namespace 367341825Sdim 368277325Sdimstatic llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory; 369277325Sdimconst std::error_category &clang::serialized_diags::SDErrorCategory() { 370277325Sdim return *ErrorCategory; 371277325Sdim} 372