2019-09-10 01:43:50 +08:00
|
|
|
//===- 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/Support/MemoryBuffer.h"
|
2019-10-16 23:40:59 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2019-09-10 01:43:50 +08:00
|
|
|
|
|
|
|
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()) {
|
2019-11-09 21:00:36 +08:00
|
|
|
Next = Stream.advance();
|
2019-09-10 01:43:50 +08:00
|
|
|
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))
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(E);
|
2019-09-10 01:43:50 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<bool> BitstreamParserHelper::isMetaBlock() {
|
|
|
|
return isBlock(Stream, META_BLOCK_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<bool> BitstreamParserHelper::isRemarkBlock() {
|
|
|
|
return isBlock(Stream, META_BLOCK_ID);
|
|
|
|
}
|
|
|
|
|
2019-11-09 06:30:12 +08:00
|
|
|
static Error validateMagicNumber(StringRef MagicNumber) {
|
|
|
|
if (MagicNumber != remarks::ContainerMagic)
|
2019-09-10 01:43:50 +08:00
|
|
|
return createStringError(std::make_error_code(std::errc::invalid_argument),
|
|
|
|
"Unknown magic number: expecting %s, got %.4s.",
|
2019-11-09 06:30:12 +08:00
|
|
|
remarks::ContainerMagic.data(), MagicNumber.data());
|
2019-09-10 01:43:50 +08:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
|
2019-11-09 06:30:12 +08:00
|
|
|
Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
|
|
|
|
if (!MagicNumber)
|
|
|
|
return MagicNumber.takeError();
|
|
|
|
if (Error E = validateMagicNumber(
|
|
|
|
StringRef(MagicNumber->data(), MagicNumber->size())))
|
2019-09-10 01:43:50 +08:00
|
|
|
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>>
|
2019-10-16 23:40:59 +08:00
|
|
|
remarks::createBitstreamParserFromMeta(
|
|
|
|
StringRef Buf, Optional<ParsedStringTable> StrTab,
|
|
|
|
Optional<StringRef> ExternalFilePrependPath) {
|
2019-09-10 01:43:50 +08:00
|
|
|
BitstreamParserHelper Helper(Buf);
|
2019-11-09 06:30:12 +08:00
|
|
|
Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
|
|
|
|
if (!MagicNumber)
|
|
|
|
return MagicNumber.takeError();
|
2019-09-10 01:43:50 +08:00
|
|
|
|
2019-11-09 06:30:12 +08:00
|
|
|
if (Error E = validateMagicNumber(
|
|
|
|
StringRef(MagicNumber->data(), MagicNumber->size())))
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(E);
|
2019-09-10 01:43:50 +08:00
|
|
|
|
2019-10-16 23:40:59 +08:00
|
|
|
auto Parser =
|
|
|
|
StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab))
|
2019-09-10 01:43:50 +08:00
|
|
|
: std::make_unique<BitstreamRemarkParser>(Buf);
|
2019-10-16 23:40:59 +08:00
|
|
|
|
|
|
|
if (ExternalFilePrependPath)
|
2020-01-29 03:23:46 +08:00
|
|
|
Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath);
|
2019-10-16 23:40:59 +08:00
|
|
|
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(Parser);
|
2019-09-10 01:43:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
|
|
|
|
if (ParserHelper.atEndOfStream())
|
|
|
|
return make_error<EndOfFileError>();
|
|
|
|
|
|
|
|
if (!ReadyToParseRemarks) {
|
|
|
|
if (Error E = parseMeta())
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(E);
|
2019-09-10 01:43:50 +08:00
|
|
|
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);
|
|
|
|
}
|
2019-09-10 05:30:11 +08:00
|
|
|
llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
|
2019-09-10 01:43:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Error BitstreamRemarkParser::processCommonMeta(
|
2019-11-09 21:00:36 +08:00
|
|
|
BitstreamMetaParserHelper &Helper) {
|
|
|
|
if (Optional<uint64_t> Version = Helper.ContainerVersion)
|
2019-09-10 01:43:50 +08:00
|
|
|
ContainerVersion = *Version;
|
|
|
|
else
|
|
|
|
return createStringError(
|
|
|
|
std::make_error_code(std::errc::illegal_byte_sequence),
|
|
|
|
"Error while parsing BLOCK_META: missing container version.");
|
|
|
|
|
2019-11-09 21:00:36 +08:00
|
|
|
if (Optional<uint8_t> Type = Helper.ContainerType) {
|
2019-09-10 03:47:25 +08:00
|
|
|
// Always >= BitstreamRemarkContainerType::First since it's unsigned.
|
|
|
|
if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
|
2019-09-10 01:43:50 +08:00
|
|
|
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.");
|
|
|
|
|
2019-10-16 23:40:59 +08:00
|
|
|
SmallString<80> FullPath(ExternalFilePrependPath);
|
|
|
|
sys::path::append(FullPath, *ExternalFilePath);
|
|
|
|
|
2019-09-10 01:43:50 +08:00
|
|
|
// 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 =
|
2019-10-16 23:40:59 +08:00
|
|
|
MemoryBuffer::getFile(FullPath);
|
2019-09-10 01:43:50 +08:00
|
|
|
if (std::error_code EC = BufferOrErr.getError())
|
2019-10-16 23:40:59 +08:00
|
|
|
return createFileError(FullPath, EC);
|
2019-11-23 06:27:47 +08:00
|
|
|
|
2019-09-10 01:43:50 +08:00
|
|
|
TmpRemarkBuffer = std::move(*BufferOrErr);
|
|
|
|
|
2019-11-23 06:27:47 +08:00
|
|
|
// Don't try to parse the file if it's empty.
|
|
|
|
if (TmpRemarkBuffer->getBufferSize() == 0)
|
|
|
|
return make_error<EndOfFileError>();
|
|
|
|
|
2019-09-10 01:43:50 +08:00
|
|
|
// 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())
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(E);
|
2019-09-10 01:43:50 +08:00
|
|
|
|
|
|
|
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.");
|
|
|
|
|
2019-09-10 03:47:25 +08:00
|
|
|
// Always >= Type::First since it's unsigned.
|
|
|
|
if (*Helper.Type > static_cast<uint8_t>(Type::Last))
|
2019-09-10 01:43:50 +08:00
|
|
|
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)
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(Result);
|
2019-09-10 01:43:50 +08:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(Result);
|
2019-09-10 01:43:50 +08:00
|
|
|
}
|