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 21 using namespace llvm; 22 using namespace llvm::remarks; 23 24 namespace llvm { 25 class raw_ostream; 26 } 27 28 static Expected<StringRef> 29 getRemarksSectionName(const object::ObjectFile &Obj) { 30 if (Obj.isMachO()) 31 return StringRef("__remarks"); 32 // ELF -> .remarks, but there is no ELF support at this point. 33 return createStringError(std::errc::illegal_byte_sequence, 34 "Unsupported file format."); 35 } 36 37 Expected<Optional<StringRef>> 38 llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) { 39 Expected<StringRef> SectionName = getRemarksSectionName(Obj); 40 if (!SectionName) 41 return SectionName.takeError(); 42 43 for (const object::SectionRef &Section : Obj.sections()) { 44 Expected<StringRef> MaybeName = Section.getName(); 45 if (!MaybeName) 46 return MaybeName.takeError(); 47 if (*MaybeName != *SectionName) 48 continue; 49 50 if (Expected<StringRef> Contents = Section.getContents()) 51 return *Contents; 52 else 53 return Contents.takeError(); 54 } 55 return Optional<StringRef>{}; 56 } 57 58 Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) { 59 StrTab.internalize(*Remark); 60 auto Inserted = Remarks.insert(std::move(Remark)); 61 return **Inserted.first; 62 } 63 64 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) { 65 PrependPath = std::string(PrependPathIn); 66 } 67 68 // Discard remarks with no source location. 69 static bool shouldKeepRemark(const Remark &R) { return R.Loc.has_value(); } 70 71 Error RemarkLinker::link(StringRef Buffer, Optional<Format> RemarkFormat) { 72 if (!RemarkFormat) { 73 Expected<Format> ParserFormat = magicToFormat(Buffer); 74 if (!ParserFormat) 75 return ParserFormat.takeError(); 76 RemarkFormat = *ParserFormat; 77 } 78 79 Expected<std::unique_ptr<RemarkParser>> MaybeParser = 80 createRemarkParserFromMeta( 81 *RemarkFormat, Buffer, /*StrTab=*/None, 82 PrependPath ? Optional<StringRef>(StringRef(*PrependPath)) 83 : Optional<StringRef>(None)); 84 if (!MaybeParser) 85 return MaybeParser.takeError(); 86 87 RemarkParser &Parser = **MaybeParser; 88 89 while (true) { 90 Expected<std::unique_ptr<Remark>> Next = Parser.next(); 91 if (Error E = Next.takeError()) { 92 if (E.isA<EndOfFileError>()) { 93 consumeError(std::move(E)); 94 break; 95 } 96 return E; 97 } 98 99 assert(*Next != nullptr); 100 101 if (shouldKeepRemark(**Next)) 102 keep(std::move(*Next)); 103 } 104 return Error::success(); 105 } 106 107 Error RemarkLinker::link(const object::ObjectFile &Obj, 108 Optional<Format> RemarkFormat) { 109 Expected<Optional<StringRef>> SectionOrErr = getRemarksSectionContents(Obj); 110 if (!SectionOrErr) 111 return SectionOrErr.takeError(); 112 113 if (Optional<StringRef> Section = *SectionOrErr) 114 return link(*Section, RemarkFormat); 115 return Error::success(); 116 } 117 118 Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const { 119 Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = 120 createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS, 121 std::move(const_cast<StringTable &>(StrTab))); 122 if (!MaybeSerializer) 123 return MaybeSerializer.takeError(); 124 125 std::unique_ptr<remarks::RemarkSerializer> Serializer = 126 std::move(*MaybeSerializer); 127 128 for (const Remark &R : remarks()) 129 Serializer->emit(R); 130 return Error::success(); 131 } 132