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, Format RemarkFormat) { 70 Expected<std::unique_ptr<RemarkParser>> MaybeParser = 71 createRemarkParserFromMeta( 72 RemarkFormat, Buffer, 73 PrependPath ? std::optional<StringRef>(StringRef(*PrependPath)) 74 : std::optional<StringRef>()); 75 if (!MaybeParser) 76 return MaybeParser.takeError(); 77 78 RemarkParser &Parser = **MaybeParser; 79 80 while (true) { 81 Expected<std::unique_ptr<Remark>> Next = Parser.next(); 82 if (Error E = Next.takeError()) { 83 if (E.isA<EndOfFileError>()) { 84 consumeError(std::move(E)); 85 break; 86 } 87 return E; 88 } 89 90 assert(*Next != nullptr); 91 92 if (shouldKeepRemark(**Next)) 93 keep(std::move(*Next)); 94 } 95 return Error::success(); 96 } 97 98 Error RemarkLinker::link(const object::ObjectFile &Obj, Format RemarkFormat) { 99 Expected<std::optional<StringRef>> SectionOrErr = 100 getRemarksSectionContents(Obj); 101 if (!SectionOrErr) 102 return SectionOrErr.takeError(); 103 104 if (std::optional<StringRef> Section = *SectionOrErr) 105 return link(*Section, RemarkFormat); 106 return Error::success(); 107 } 108 109 Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { 110 Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = 111 createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, 112 std::move(const_cast<StringTable &>(StrTab))); 113 if (!MaybeSerializer) 114 return MaybeSerializer.takeError(); 115 116 std::unique_ptr<remarks::RemarkSerializer> Serializer = 117 std::move(*MaybeSerializer); 118 119 for (const Remark &R : remarks()) 120 Serializer->emit(R); 121 return Error::success(); 122 } 123