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