//===- 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 "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::remarks; static Expected 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> llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) { Expected SectionName = getRemarksSectionName(Obj); if (!SectionName) return SectionName.takeError(); for (const object::SectionRef &Section : Obj.sections()) { Expected MaybeName = Section.getName(); if (!MaybeName) return MaybeName.takeError(); if (*MaybeName != *SectionName) continue; if (Expected Contents = Section.getContents()) return *Contents; else return Contents.takeError(); } return Optional{}; } Remark &RemarkLinker::keep(std::unique_ptr 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.hasValue(); } Error RemarkLinker::link(StringRef Buffer, Optional RemarkFormat) { if (!RemarkFormat) { Expected ParserFormat = magicToFormat(Buffer); if (!ParserFormat) return ParserFormat.takeError(); RemarkFormat = *ParserFormat; } Expected> MaybeParser = createRemarkParserFromMeta( *RemarkFormat, Buffer, /*StrTab=*/None, PrependPath ? Optional(StringRef(*PrependPath)) : Optional(None)); if (!MaybeParser) return MaybeParser.takeError(); RemarkParser &Parser = **MaybeParser; while (true) { Expected> Next = Parser.next(); if (Error E = Next.takeError()) { if (E.isA()) { 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, Optional RemarkFormat) { Expected> SectionOrErr = getRemarksSectionContents(Obj); if (!SectionOrErr) return SectionOrErr.takeError(); if (Optional Section = *SectionOrErr) return link(*Section, RemarkFormat); return Error::success(); } Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { Expected> MaybeSerializer = createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, std::move(const_cast(StrTab))); if (!MaybeSerializer) return MaybeSerializer.takeError(); std::unique_ptr Serializer = std::move(*MaybeSerializer); for (const Remark &R : remarks()) Serializer->emit(R); return Error::success(); }