123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- //===- BitstreamRemarkParser.cpp ------------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file provides utility methods used by clients that want to use the
- // parser for remark diagnostics in LLVM.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/Remarks/BitstreamRemarkParser.h"
- #include "BitstreamRemarkParser.h"
- #include "llvm/Remarks/Remark.h"
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/Path.h"
- using namespace llvm;
- using namespace llvm::remarks;
- static Error unknownRecord(const char *BlockName, unsigned RecordID) {
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing %s: unknown record entry (%lu).", BlockName,
- RecordID);
- }
- static Error malformedRecord(const char *BlockName, const char *RecordName) {
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing %s: malformed record entry (%s).", BlockName,
- RecordName);
- }
- BitstreamMetaParserHelper::BitstreamMetaParserHelper(
- BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo)
- : Stream(Stream), BlockInfo(BlockInfo) {}
- /// Parse a record and fill in the fields in the parser.
- static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) {
- BitstreamCursor &Stream = Parser.Stream;
- // Note: 2 is used here because it's the max number of fields we have per
- // record.
- SmallVector<uint64_t, 2> Record;
- StringRef Blob;
- Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
- if (!RecordID)
- return RecordID.takeError();
- switch (*RecordID) {
- case RECORD_META_CONTAINER_INFO: {
- if (Record.size() != 2)
- return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO");
- Parser.ContainerVersion = Record[0];
- Parser.ContainerType = Record[1];
- break;
- }
- case RECORD_META_REMARK_VERSION: {
- if (Record.size() != 1)
- return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION");
- Parser.RemarkVersion = Record[0];
- break;
- }
- case RECORD_META_STRTAB: {
- if (Record.size() != 0)
- return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
- Parser.StrTabBuf = Blob;
- break;
- }
- case RECORD_META_EXTERNAL_FILE: {
- if (Record.size() != 0)
- return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE");
- Parser.ExternalFilePath = Blob;
- break;
- }
- default:
- return unknownRecord("BLOCK_META", *RecordID);
- }
- return Error::success();
- }
- BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
- BitstreamCursor &Stream)
- : Stream(Stream) {}
- /// Parse a record and fill in the fields in the parser.
- static Error parseRecord(BitstreamRemarkParserHelper &Parser, unsigned Code) {
- BitstreamCursor &Stream = Parser.Stream;
- // Note: 5 is used here because it's the max number of fields we have per
- // record.
- SmallVector<uint64_t, 5> Record;
- StringRef Blob;
- Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
- if (!RecordID)
- return RecordID.takeError();
- switch (*RecordID) {
- case RECORD_REMARK_HEADER: {
- if (Record.size() != 4)
- return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER");
- Parser.Type = Record[0];
- Parser.RemarkNameIdx = Record[1];
- Parser.PassNameIdx = Record[2];
- Parser.FunctionNameIdx = Record[3];
- break;
- }
- case RECORD_REMARK_DEBUG_LOC: {
- if (Record.size() != 3)
- return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC");
- Parser.SourceFileNameIdx = Record[0];
- Parser.SourceLine = Record[1];
- Parser.SourceColumn = Record[2];
- break;
- }
- case RECORD_REMARK_HOTNESS: {
- if (Record.size() != 1)
- return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS");
- Parser.Hotness = Record[0];
- break;
- }
- case RECORD_REMARK_ARG_WITH_DEBUGLOC: {
- if (Record.size() != 5)
- return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_ARG_WITH_DEBUGLOC");
- // Create a temporary argument. Use that as a valid memory location for this
- // argument entry.
- Parser.TmpArgs.emplace_back();
- Parser.TmpArgs.back().KeyIdx = Record[0];
- Parser.TmpArgs.back().ValueIdx = Record[1];
- Parser.TmpArgs.back().SourceFileNameIdx = Record[2];
- Parser.TmpArgs.back().SourceLine = Record[3];
- Parser.TmpArgs.back().SourceColumn = Record[4];
- Parser.Args =
- ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
- break;
- }
- case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: {
- if (Record.size() != 2)
- return malformedRecord("BLOCK_REMARK",
- "RECORD_REMARK_ARG_WITHOUT_DEBUGLOC");
- // Create a temporary argument. Use that as a valid memory location for this
- // argument entry.
- Parser.TmpArgs.emplace_back();
- Parser.TmpArgs.back().KeyIdx = Record[0];
- Parser.TmpArgs.back().ValueIdx = Record[1];
- Parser.Args =
- ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
- break;
- }
- default:
- return unknownRecord("BLOCK_REMARK", *RecordID);
- }
- return Error::success();
- }
- template <typename T>
- static Error parseBlock(T &ParserHelper, unsigned BlockID,
- const char *BlockName) {
- BitstreamCursor &Stream = ParserHelper.Stream;
- Expected<BitstreamEntry> Next = Stream.advance();
- if (!Next)
- return Next.takeError();
- if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != BlockID)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...].",
- BlockName, BlockName);
- if (Stream.EnterSubBlock(BlockID))
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while entering %s.", BlockName);
- // Stop when there is nothing to read anymore or when we encounter an
- // END_BLOCK.
- while (!Stream.AtEndOfStream()) {
- Next = Stream.advance();
- if (!Next)
- return Next.takeError();
- switch (Next->Kind) {
- case BitstreamEntry::EndBlock:
- return Error::success();
- case BitstreamEntry::Error:
- case BitstreamEntry::SubBlock:
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing %s: expecting records.", BlockName);
- case BitstreamEntry::Record:
- if (Error E = parseRecord(ParserHelper, Next->ID))
- return E;
- continue;
- }
- }
- // If we're here, it means we didn't get an END_BLOCK yet, but we're at the
- // end of the stream. In this case, error.
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing %s: unterminated block.", BlockName);
- }
- Error BitstreamMetaParserHelper::parse() {
- return parseBlock(*this, META_BLOCK_ID, "META_BLOCK");
- }
- Error BitstreamRemarkParserHelper::parse() {
- return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK");
- }
- BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
- : Stream(Buffer) {}
- Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() {
- std::array<char, 4> Result;
- for (unsigned i = 0; i < 4; ++i)
- if (Expected<unsigned> R = Stream.Read(8))
- Result[i] = *R;
- else
- return R.takeError();
- return Result;
- }
- Error BitstreamParserHelper::parseBlockInfoBlock() {
- Expected<BitstreamEntry> Next = Stream.advance();
- if (!Next)
- return Next.takeError();
- if (Next->Kind != BitstreamEntry::SubBlock ||
- Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "
- "BLOCKINFO_BLOCK, ...].");
- Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo =
- Stream.ReadBlockInfoBlock();
- if (!MaybeBlockInfo)
- return MaybeBlockInfo.takeError();
- if (!*MaybeBlockInfo)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCKINFO_BLOCK.");
- BlockInfo = **MaybeBlockInfo;
- Stream.setBlockInfo(&BlockInfo);
- return Error::success();
- }
- static Expected<bool> isBlock(BitstreamCursor &Stream, unsigned BlockID) {
- bool Result = false;
- uint64_t PreviousBitNo = Stream.GetCurrentBitNo();
- Expected<BitstreamEntry> Next = Stream.advance();
- if (!Next)
- return Next.takeError();
- switch (Next->Kind) {
- case BitstreamEntry::SubBlock:
- // Check for the block id.
- Result = Next->ID == BlockID;
- break;
- case BitstreamEntry::Error:
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Unexpected error while parsing bitstream.");
- default:
- Result = false;
- break;
- }
- if (Error E = Stream.JumpToBit(PreviousBitNo))
- return std::move(E);
- return Result;
- }
- Expected<bool> BitstreamParserHelper::isMetaBlock() {
- return isBlock(Stream, META_BLOCK_ID);
- }
- Expected<bool> BitstreamParserHelper::isRemarkBlock() {
- return isBlock(Stream, META_BLOCK_ID);
- }
- static Error validateMagicNumber(StringRef MagicNumber) {
- if (MagicNumber != remarks::ContainerMagic)
- return createStringError(std::make_error_code(std::errc::invalid_argument),
- "Unknown magic number: expecting %s, got %.4s.",
- remarks::ContainerMagic.data(), MagicNumber.data());
- return Error::success();
- }
- static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
- Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
- if (!MagicNumber)
- return MagicNumber.takeError();
- if (Error E = validateMagicNumber(
- StringRef(MagicNumber->data(), MagicNumber->size())))
- return E;
- if (Error E = Helper.parseBlockInfoBlock())
- return E;
- Expected<bool> isMetaBlock = Helper.isMetaBlock();
- if (!isMetaBlock)
- return isMetaBlock.takeError();
- if (!*isMetaBlock)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Expecting META_BLOCK after the BLOCKINFO_BLOCK.");
- return Error::success();
- }
- Expected<std::unique_ptr<BitstreamRemarkParser>>
- remarks::createBitstreamParserFromMeta(
- StringRef Buf, Optional<ParsedStringTable> StrTab,
- Optional<StringRef> ExternalFilePrependPath) {
- BitstreamParserHelper Helper(Buf);
- Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
- if (!MagicNumber)
- return MagicNumber.takeError();
- if (Error E = validateMagicNumber(
- StringRef(MagicNumber->data(), MagicNumber->size())))
- return std::move(E);
- auto Parser =
- StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab))
- : std::make_unique<BitstreamRemarkParser>(Buf);
- if (ExternalFilePrependPath)
- Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath);
- return std::move(Parser);
- }
- Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
- if (ParserHelper.atEndOfStream())
- return make_error<EndOfFileError>();
- if (!ReadyToParseRemarks) {
- if (Error E = parseMeta())
- return std::move(E);
- ReadyToParseRemarks = true;
- }
- return parseRemark();
- }
- Error BitstreamRemarkParser::parseMeta() {
- // Advance and to the meta block.
- if (Error E = advanceToMetaBlock(ParserHelper))
- return E;
- BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream,
- ParserHelper.BlockInfo);
- if (Error E = MetaHelper.parse())
- return E;
- if (Error E = processCommonMeta(MetaHelper))
- return E;
- switch (ContainerType) {
- case BitstreamRemarkContainerType::Standalone:
- return processStandaloneMeta(MetaHelper);
- case BitstreamRemarkContainerType::SeparateRemarksFile:
- return processSeparateRemarksFileMeta(MetaHelper);
- case BitstreamRemarkContainerType::SeparateRemarksMeta:
- return processSeparateRemarksMetaMeta(MetaHelper);
- }
- llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
- }
- Error BitstreamRemarkParser::processCommonMeta(
- BitstreamMetaParserHelper &Helper) {
- if (Optional<uint64_t> Version = Helper.ContainerVersion)
- ContainerVersion = *Version;
- else
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: missing container version.");
- if (Optional<uint8_t> Type = Helper.ContainerType) {
- // Always >= BitstreamRemarkContainerType::First since it's unsigned.
- if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: invalid container type.");
- ContainerType = static_cast<BitstreamRemarkContainerType>(*Type);
- } else
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: missing container type.");
- return Error::success();
- }
- static Error processStrTab(BitstreamRemarkParser &P,
- Optional<StringRef> StrTabBuf) {
- if (!StrTabBuf)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: missing string table.");
- // Parse and assign the string table.
- P.StrTab.emplace(*StrTabBuf);
- return Error::success();
- }
- static Error processRemarkVersion(BitstreamRemarkParser &P,
- Optional<uint64_t> RemarkVersion) {
- if (!RemarkVersion)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: missing remark version.");
- P.RemarkVersion = *RemarkVersion;
- return Error::success();
- }
- Error BitstreamRemarkParser::processExternalFilePath(
- Optional<StringRef> ExternalFilePath) {
- if (!ExternalFilePath)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_META: missing external file path.");
- SmallString<80> FullPath(ExternalFilePrependPath);
- sys::path::append(FullPath, *ExternalFilePath);
- // External file: open the external file, parse it, check if its metadata
- // matches the one from the separate metadata, then replace the current parser
- // with the one parsing the remarks.
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
- MemoryBuffer::getFile(FullPath);
- if (std::error_code EC = BufferOrErr.getError())
- return createFileError(FullPath, EC);
- TmpRemarkBuffer = std::move(*BufferOrErr);
- // Don't try to parse the file if it's empty.
- if (TmpRemarkBuffer->getBufferSize() == 0)
- return make_error<EndOfFileError>();
- // Create a separate parser used for parsing the separate file.
- ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
- // Advance and check until we can parse the meta block.
- if (Error E = advanceToMetaBlock(ParserHelper))
- return E;
- // Parse the meta from the separate file.
- // Note: here we overwrite the BlockInfo with the one from the file. This will
- // be used to parse the rest of the file.
- BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream,
- ParserHelper.BlockInfo);
- if (Error E = SeparateMetaHelper.parse())
- return E;
- uint64_t PreviousContainerVersion = ContainerVersion;
- if (Error E = processCommonMeta(SeparateMetaHelper))
- return E;
- if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing external file's BLOCK_META: wrong container "
- "type.");
- if (PreviousContainerVersion != ContainerVersion)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing external file's BLOCK_META: mismatching versions: "
- "original meta: %lu, external file meta: %lu.",
- PreviousContainerVersion, ContainerVersion);
- // Process the meta from the separate file.
- return processSeparateRemarksFileMeta(SeparateMetaHelper);
- }
- Error BitstreamRemarkParser::processStandaloneMeta(
- BitstreamMetaParserHelper &Helper) {
- if (Error E = processStrTab(*this, Helper.StrTabBuf))
- return E;
- return processRemarkVersion(*this, Helper.RemarkVersion);
- }
- Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
- BitstreamMetaParserHelper &Helper) {
- return processRemarkVersion(*this, Helper.RemarkVersion);
- }
- Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
- BitstreamMetaParserHelper &Helper) {
- if (Error E = processStrTab(*this, Helper.StrTabBuf))
- return E;
- return processExternalFilePath(Helper.ExternalFilePath);
- }
- Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
- BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
- if (Error E = RemarkHelper.parse())
- return std::move(E);
- return processRemark(RemarkHelper);
- }
- Expected<std::unique_ptr<Remark>>
- BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
- std::unique_ptr<Remark> Result = std::make_unique<Remark>();
- Remark &R = *Result;
- if (StrTab == None)
- return createStringError(
- std::make_error_code(std::errc::invalid_argument),
- "Error while parsing BLOCK_REMARK: missing string table.");
- if (!Helper.Type)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing remark type.");
- // Always >= Type::First since it's unsigned.
- if (*Helper.Type > static_cast<uint8_t>(Type::Last))
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: unknown remark type.");
- R.RemarkType = static_cast<Type>(*Helper.Type);
- if (!Helper.RemarkNameIdx)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing remark name.");
- if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
- R.RemarkName = *RemarkName;
- else
- return RemarkName.takeError();
- if (!Helper.PassNameIdx)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing remark pass.");
- if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
- R.PassName = *PassName;
- else
- return PassName.takeError();
- if (!Helper.FunctionNameIdx)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing remark function name.");
- if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
- R.FunctionName = *FunctionName;
- else
- return FunctionName.takeError();
- if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) {
- Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx];
- if (!SourceFileName)
- return SourceFileName.takeError();
- R.Loc.emplace();
- R.Loc->SourceFilePath = *SourceFileName;
- R.Loc->SourceLine = *Helper.SourceLine;
- R.Loc->SourceColumn = *Helper.SourceColumn;
- }
- if (Helper.Hotness)
- R.Hotness = *Helper.Hotness;
- if (!Helper.Args)
- return std::move(Result);
- for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) {
- if (!Arg.KeyIdx)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing key in remark argument.");
- if (!Arg.ValueIdx)
- return createStringError(
- std::make_error_code(std::errc::illegal_byte_sequence),
- "Error while parsing BLOCK_REMARK: missing value in remark "
- "argument.");
- // We have at least a key and a value, create an entry.
- R.Args.emplace_back();
- if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
- R.Args.back().Key = *Key;
- else
- return Key.takeError();
- if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
- R.Args.back().Val = *Value;
- else
- return Value.takeError();
- if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) {
- if (Expected<StringRef> SourceFileName =
- (*StrTab)[*Arg.SourceFileNameIdx]) {
- R.Args.back().Loc.emplace();
- R.Args.back().Loc->SourceFilePath = *SourceFileName;
- R.Args.back().Loc->SourceLine = *Arg.SourceLine;
- R.Args.back().Loc->SourceColumn = *Arg.SourceColumn;
- } else
- return SourceFileName.takeError();
- }
- }
- return std::move(Result);
- }
|