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