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>
getRemarksSectionName(const object::ObjectFile & Obj)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>>
getRemarksSectionContents(const object::ObjectFile & Obj)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
keep(std::unique_ptr<Remark> Remark)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
setExternalFilePrependPath(StringRef PrependPathIn)65 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
66 PrependPath = std::string(PrependPathIn);
67 }
68
link(StringRef Buffer,std::optional<Format> RemarkFormat)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
link(const object::ObjectFile & Obj,std::optional<Format> RemarkFormat)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
serialize(raw_ostream & OS,Format RemarksFormat) const117 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