1 //===- RemarkLinker.cpp ---------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides an implementation of the remark linker. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Remarks/RemarkLinker.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Object/ObjectFile.h" 16 #include "llvm/Object/SymbolicFile.h" 17 #include "llvm/Remarks/RemarkParser.h" 18 #include "llvm/Remarks/RemarkSerializer.h" 19 #include "llvm/Support/Error.h" 20 #include <optional> 21 22 using namespace llvm; 23 using namespace llvm::remarks; 24 25 namespace llvm { 26 class raw_ostream; 27 } 28 29 static Expected<StringRef> 30 getRemarksSectionName(const object::ObjectFile &Obj) { 31 if (Obj.isMachO()) 32 return StringRef("__remarks"); 33 // ELF -> .remarks, but there is no ELF support at this point. 34 return createStringError(std::errc::illegal_byte_sequence, 35 "Unsupported file format."); 36 } 37 38 Expected<std::optional<StringRef>> 39 llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) { 40 Expected<StringRef> SectionName = getRemarksSectionName(Obj); 41 if (!SectionName) 42 return SectionName.takeError(); 43 44 for (const object::SectionRef &Section : Obj.sections()) { 45 Expected<StringRef> MaybeName = Section.getName(); 46 if (!MaybeName) 47 return MaybeName.takeError(); 48 if (*MaybeName != *SectionName) 49 continue; 50 51 if (Expected<StringRef> Contents = Section.getContents()) 52 return *Contents; 53 else 54 return Contents.takeError(); 55 } 56 return std::optional<StringRef>{}; 57 } 58 59 Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) { 60 StrTab.internalize(*Remark); 61 auto Inserted = Remarks.insert(std::move(Remark)); 62 return **Inserted.first; 63 } 64 65 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) { 66 PrependPath = std::string(PrependPathIn); 67 } 68 69 Error RemarkLinker::link(StringRef Buffer, std::optional<Format> RemarkFormat) { 70 if (!RemarkFormat) { 71 Expected<Format> ParserFormat = magicToFormat(Buffer); 72 if (!ParserFormat) 73 return ParserFormat.takeError(); 74 RemarkFormat = *ParserFormat; 75 } 76 77 Expected<std::unique_ptr<RemarkParser>> MaybeParser = 78 createRemarkParserFromMeta( 79 *RemarkFormat, Buffer, /*StrTab=*/std::nullopt, 80 PrependPath ? std::optional<StringRef>(StringRef(*PrependPath)) 81 : std::optional<StringRef>()); 82 if (!MaybeParser) 83 return MaybeParser.takeError(); 84 85 RemarkParser &Parser = **MaybeParser; 86 87 while (true) { 88 Expected<std::unique_ptr<Remark>> Next = Parser.next(); 89 if (Error E = Next.takeError()) { 90 if (E.isA<EndOfFileError>()) { 91 consumeError(std::move(E)); 92 break; 93 } 94 return E; 95 } 96 97 assert(*Next != nullptr); 98 99 if (shouldKeepRemark(**Next)) 100 keep(std::move(*Next)); 101 } 102 return Error::success(); 103 } 104 105 Error RemarkLinker::link(const object::ObjectFile &Obj, 106 std::optional<Format> RemarkFormat) { 107 Expected<std::optional<StringRef>> SectionOrErr = 108 getRemarksSectionContents(Obj); 109 if (!SectionOrErr) 110 return SectionOrErr.takeError(); 111 112 if (std::optional<StringRef> Section = *SectionOrErr) 113 return link(*Section, RemarkFormat); 114 return Error::success(); 115 } 116 117 Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { 118 Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = 119 createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, 120 std::move(const_cast<StringTable &>(StrTab))); 121 if (!MaybeSerializer) 122 return MaybeSerializer.takeError(); 123 124 std::unique_ptr<remarks::RemarkSerializer> Serializer = 125 std::move(*MaybeSerializer); 126 127 for (const Remark &R : remarks()) 128 Serializer->emit(R); 129 return Error::success(); 130 } 131