Path: blob/main/contrib/llvm-project/clang/lib/Frontend/SerializedDiagnosticReader.cpp
35234 views
//===- SerializedDiagnosticReader.cpp - Reads diagnostics -----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Frontend/SerializedDiagnosticReader.h"9#include "clang/Basic/FileManager.h"10#include "clang/Basic/FileSystemOptions.h"11#include "clang/Frontend/SerializedDiagnostics.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/Bitstream/BitCodes.h"15#include "llvm/Bitstream/BitstreamReader.h"16#include "llvm/Support/Compiler.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/ErrorOr.h"19#include "llvm/Support/ManagedStatic.h"20#include <cstdint>21#include <optional>22#include <system_error>2324using namespace clang;25using namespace serialized_diags;2627std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {28// Open the diagnostics file.29FileSystemOptions FO;30FileManager FileMgr(FO);3132auto Buffer = FileMgr.getBufferForFile(File);33if (!Buffer)34return SDError::CouldNotLoad;3536llvm::BitstreamCursor Stream(**Buffer);37std::optional<llvm::BitstreamBlockInfo> BlockInfo;3839if (Stream.AtEndOfStream())40return SDError::InvalidSignature;4142// Sniff for the signature.43for (unsigned char C : {'D', 'I', 'A', 'G'}) {44if (Expected<llvm::SimpleBitstreamCursor::word_t> Res = Stream.Read(8)) {45if (Res.get() == C)46continue;47} else {48// FIXME this drops the error on the floor.49consumeError(Res.takeError());50}51return SDError::InvalidSignature;52}5354// Read the top level blocks.55while (!Stream.AtEndOfStream()) {56if (Expected<unsigned> Res = Stream.ReadCode()) {57if (Res.get() != llvm::bitc::ENTER_SUBBLOCK)58return SDError::InvalidDiagnostics;59} else {60// FIXME this drops the error on the floor.61consumeError(Res.takeError());62return SDError::InvalidDiagnostics;63}6465std::error_code EC;66Expected<unsigned> MaybeSubBlockID = Stream.ReadSubBlockID();67if (!MaybeSubBlockID) {68// FIXME this drops the error on the floor.69consumeError(MaybeSubBlockID.takeError());70return SDError::InvalidDiagnostics;71}7273switch (MaybeSubBlockID.get()) {74case llvm::bitc::BLOCKINFO_BLOCK_ID: {75Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =76Stream.ReadBlockInfoBlock();77if (!MaybeBlockInfo) {78// FIXME this drops the error on the floor.79consumeError(MaybeBlockInfo.takeError());80return SDError::InvalidDiagnostics;81}82BlockInfo = std::move(MaybeBlockInfo.get());83}84if (!BlockInfo)85return SDError::MalformedBlockInfoBlock;86Stream.setBlockInfo(&*BlockInfo);87continue;88case BLOCK_META:89if ((EC = readMetaBlock(Stream)))90return EC;91continue;92case BLOCK_DIAG:93if ((EC = readDiagnosticBlock(Stream)))94return EC;95continue;96default:97if (llvm::Error Err = Stream.SkipBlock()) {98// FIXME this drops the error on the floor.99consumeError(std::move(Err));100return SDError::MalformedTopLevelBlock;101}102continue;103}104}105return {};106}107108enum class SerializedDiagnosticReader::Cursor {109Record = 1,110BlockEnd,111BlockBegin112};113114llvm::ErrorOr<SerializedDiagnosticReader::Cursor>115SerializedDiagnosticReader::skipUntilRecordOrBlock(116llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {117BlockOrRecordID = 0;118119while (!Stream.AtEndOfStream()) {120unsigned Code;121if (Expected<unsigned> Res = Stream.ReadCode())122Code = Res.get();123else124return llvm::errorToErrorCode(Res.takeError());125126if (Code >= static_cast<unsigned>(llvm::bitc::FIRST_APPLICATION_ABBREV)) {127// We found a record.128BlockOrRecordID = Code;129return Cursor::Record;130}131switch (static_cast<llvm::bitc::FixedAbbrevIDs>(Code)) {132case llvm::bitc::ENTER_SUBBLOCK:133if (Expected<unsigned> Res = Stream.ReadSubBlockID())134BlockOrRecordID = Res.get();135else136return llvm::errorToErrorCode(Res.takeError());137return Cursor::BlockBegin;138139case llvm::bitc::END_BLOCK:140if (Stream.ReadBlockEnd())141return SDError::InvalidDiagnostics;142return Cursor::BlockEnd;143144case llvm::bitc::DEFINE_ABBREV:145if (llvm::Error Err = Stream.ReadAbbrevRecord())146return llvm::errorToErrorCode(std::move(Err));147continue;148149case llvm::bitc::UNABBREV_RECORD:150return SDError::UnsupportedConstruct;151152case llvm::bitc::FIRST_APPLICATION_ABBREV:153llvm_unreachable("Unexpected abbrev id.");154}155}156157return SDError::InvalidDiagnostics;158}159160std::error_code161SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {162if (llvm::Error Err =163Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {164// FIXME this drops the error on the floor.165consumeError(std::move(Err));166return SDError::MalformedMetadataBlock;167}168169bool VersionChecked = false;170171while (true) {172unsigned BlockOrCode = 0;173llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);174if (!Res)175Res.getError();176177switch (Res.get()) {178case Cursor::Record:179break;180case Cursor::BlockBegin:181if (llvm::Error Err = Stream.SkipBlock()) {182// FIXME this drops the error on the floor.183consumeError(std::move(Err));184return SDError::MalformedMetadataBlock;185}186[[fallthrough]];187case Cursor::BlockEnd:188if (!VersionChecked)189return SDError::MissingVersion;190return {};191}192193SmallVector<uint64_t, 1> Record;194Expected<unsigned> MaybeRecordID = Stream.readRecord(BlockOrCode, Record);195if (!MaybeRecordID)196return errorToErrorCode(MaybeRecordID.takeError());197unsigned RecordID = MaybeRecordID.get();198199if (RecordID == RECORD_VERSION) {200if (Record.size() < 1)201return SDError::MissingVersion;202if (Record[0] > VersionNumber)203return SDError::VersionMismatch;204VersionChecked = true;205}206}207}208209std::error_code210SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {211if (llvm::Error Err =212Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {213// FIXME this drops the error on the floor.214consumeError(std::move(Err));215return SDError::MalformedDiagnosticBlock;216}217218std::error_code EC;219if ((EC = visitStartOfDiagnostic()))220return EC;221222SmallVector<uint64_t, 16> Record;223while (true) {224unsigned BlockOrCode = 0;225llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);226if (!Res)227Res.getError();228229switch (Res.get()) {230case Cursor::BlockBegin:231// The only blocks we care about are subdiagnostics.232if (BlockOrCode == serialized_diags::BLOCK_DIAG) {233if ((EC = readDiagnosticBlock(Stream)))234return EC;235} else if (llvm::Error Err = Stream.SkipBlock()) {236// FIXME this drops the error on the floor.237consumeError(std::move(Err));238return SDError::MalformedSubBlock;239}240continue;241case Cursor::BlockEnd:242if ((EC = visitEndOfDiagnostic()))243return EC;244return {};245case Cursor::Record:246break;247}248249// Read the record.250Record.clear();251StringRef Blob;252Expected<unsigned> MaybeRecID =253Stream.readRecord(BlockOrCode, Record, &Blob);254if (!MaybeRecID)255return errorToErrorCode(MaybeRecID.takeError());256unsigned RecID = MaybeRecID.get();257258if (RecID < serialized_diags::RECORD_FIRST ||259RecID > serialized_diags::RECORD_LAST)260continue;261262switch ((RecordIDs)RecID) {263case RECORD_CATEGORY:264// A category has ID and name size.265if (Record.size() != 2)266return SDError::MalformedDiagnosticRecord;267if ((EC = visitCategoryRecord(Record[0], Blob)))268return EC;269continue;270case RECORD_DIAG:271// A diagnostic has severity, location (4), category, flag, and message272// size.273if (Record.size() != 8)274return SDError::MalformedDiagnosticRecord;275if ((EC = visitDiagnosticRecord(276Record[0], Location(Record[1], Record[2], Record[3], Record[4]),277Record[5], Record[6], Blob)))278return EC;279continue;280case RECORD_DIAG_FLAG:281// A diagnostic flag has ID and name size.282if (Record.size() != 2)283return SDError::MalformedDiagnosticRecord;284if ((EC = visitDiagFlagRecord(Record[0], Blob)))285return EC;286continue;287case RECORD_FILENAME:288// A filename has ID, size, timestamp, and name size. The size and289// timestamp are legacy fields that are always zero these days.290if (Record.size() != 4)291return SDError::MalformedDiagnosticRecord;292if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))293return EC;294continue;295case RECORD_FIXIT:296// A fixit has two locations (4 each) and message size.297if (Record.size() != 9)298return SDError::MalformedDiagnosticRecord;299if ((EC = visitFixitRecord(300Location(Record[0], Record[1], Record[2], Record[3]),301Location(Record[4], Record[5], Record[6], Record[7]), Blob)))302return EC;303continue;304case RECORD_SOURCE_RANGE:305// A source range is two locations (4 each).306if (Record.size() != 8)307return SDError::MalformedDiagnosticRecord;308if ((EC = visitSourceRangeRecord(309Location(Record[0], Record[1], Record[2], Record[3]),310Location(Record[4], Record[5], Record[6], Record[7]))))311return EC;312continue;313case RECORD_VERSION:314// A version is just a number.315if (Record.size() != 1)316return SDError::MalformedDiagnosticRecord;317if ((EC = visitVersionRecord(Record[0])))318return EC;319continue;320}321}322}323324namespace {325326class SDErrorCategoryType final : public std::error_category {327const char *name() const noexcept override {328return "clang.serialized_diags";329}330331std::string message(int IE) const override {332auto E = static_cast<SDError>(IE);333switch (E) {334case SDError::CouldNotLoad:335return "Failed to open diagnostics file";336case SDError::InvalidSignature:337return "Invalid diagnostics signature";338case SDError::InvalidDiagnostics:339return "Parse error reading diagnostics";340case SDError::MalformedTopLevelBlock:341return "Malformed block at top-level of diagnostics";342case SDError::MalformedSubBlock:343return "Malformed sub-block in a diagnostic";344case SDError::MalformedBlockInfoBlock:345return "Malformed BlockInfo block";346case SDError::MalformedMetadataBlock:347return "Malformed Metadata block";348case SDError::MalformedDiagnosticBlock:349return "Malformed Diagnostic block";350case SDError::MalformedDiagnosticRecord:351return "Malformed Diagnostic record";352case SDError::MissingVersion:353return "No version provided in diagnostics";354case SDError::VersionMismatch:355return "Unsupported diagnostics version";356case SDError::UnsupportedConstruct:357return "Bitcode constructs that are not supported in diagnostics appear";358case SDError::HandlerFailed:359return "Generic error occurred while handling a record";360}361llvm_unreachable("Unknown error type!");362}363};364365} // namespace366367static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;368const std::error_category &clang::serialized_diags::SDErrorCategory() {369return *ErrorCategory;370}371372373