| //===- RemarkLinker.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 an implementation of the remark linker. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Remarks/RemarkLinker.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/Object/ObjectFile.h" | |
| #include "llvm/Object/SymbolicFile.h" | |
| #include "llvm/Remarks/RemarkParser.h" | |
| #include "llvm/Remarks/RemarkSerializer.h" | |
| #include "llvm/Support/Error.h" | |
| #include <optional> | |
| using namespace llvm; | |
| using namespace llvm::remarks; | |
| namespace llvm { | |
| class raw_ostream; | |
| } | |
| static Expected<StringRef> | |
| getRemarksSectionName(const object::ObjectFile &Obj) { | |
| if (Obj.isMachO()) | |
| return StringRef("__remarks"); | |
| // ELF -> .remarks, but there is no ELF support at this point. | |
| return createStringError(std::errc::illegal_byte_sequence, | |
| "Unsupported file format."); | |
| } | |
| Expected<std::optional<StringRef>> | |
| llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) { | |
| Expected<StringRef> SectionName = getRemarksSectionName(Obj); | |
| if (!SectionName) | |
| return SectionName.takeError(); | |
| for (const object::SectionRef &Section : Obj.sections()) { | |
| Expected<StringRef> MaybeName = Section.getName(); | |
| if (!MaybeName) | |
| return MaybeName.takeError(); | |
| if (*MaybeName != *SectionName) | |
| continue; | |
| if (Expected<StringRef> Contents = Section.getContents()) | |
| return *Contents; | |
| else | |
| return Contents.takeError(); | |
| } | |
| return std::optional<StringRef>{}; | |
| } | |
| Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) { | |
| StrTab.internalize(*Remark); | |
| auto Inserted = Remarks.insert(std::move(Remark)); | |
| return **Inserted.first; | |
| } | |
| void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) { | |
| PrependPath = std::string(PrependPathIn); | |
| } | |
| // Discard remarks with no source location. | |
| static bool shouldKeepRemark(const Remark &R) { return R.Loc.has_value(); } | |
| Error RemarkLinker::link(StringRef Buffer, std::optional<Format> RemarkFormat) { | |
| if (!RemarkFormat) { | |
| Expected<Format> ParserFormat = magicToFormat(Buffer); | |
| if (!ParserFormat) | |
| return ParserFormat.takeError(); | |
| RemarkFormat = *ParserFormat; | |
| } | |
| Expected<std::unique_ptr<RemarkParser>> MaybeParser = | |
| createRemarkParserFromMeta( | |
| *RemarkFormat, Buffer, /*StrTab=*/std::nullopt, | |
| PrependPath ? std::optional<StringRef>(StringRef(*PrependPath)) | |
| : std::optional<StringRef>()); | |
| if (!MaybeParser) | |
| return MaybeParser.takeError(); | |
| RemarkParser &Parser = **MaybeParser; | |
| while (true) { | |
| Expected<std::unique_ptr<Remark>> Next = Parser.next(); | |
| if (Error E = Next.takeError()) { | |
| if (E.isA<EndOfFileError>()) { | |
| consumeError(std::move(E)); | |
| break; | |
| } | |
| return E; | |
| } | |
| assert(*Next != nullptr); | |
| if (shouldKeepRemark(**Next)) | |
| keep(std::move(*Next)); | |
| } | |
| return Error::success(); | |
| } | |
| Error RemarkLinker::link(const object::ObjectFile &Obj, | |
| std::optional<Format> RemarkFormat) { | |
| Expected<std::optional<StringRef>> SectionOrErr = | |
| getRemarksSectionContents(Obj); | |
| if (!SectionOrErr) | |
| return SectionOrErr.takeError(); | |
| if (std::optional<StringRef> Section = *SectionOrErr) | |
| return link(*Section, RemarkFormat); | |
| return Error::success(); | |
| } | |
| Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { | |
| Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = | |
| createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, | |
| std::move(const_cast<StringTable &>(StrTab))); | |
| if (!MaybeSerializer) | |
| return MaybeSerializer.takeError(); | |
| std::unique_ptr<remarks::RemarkSerializer> Serializer = | |
| std::move(*MaybeSerializer); | |
| for (const Remark &R : remarks()) | |
| Serializer->emit(R); | |
| return Error::success(); | |
| } |