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 | (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(EC: std::errc::illegal_byte_sequence, |
35 | Fmt: "Unsupported file format." ); |
36 | } |
37 | |
38 | Expected<std::optional<StringRef>> |
39 | llvm::remarks::(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::(std::unique_ptr<Remark> ) { |
60 | StrTab.internalize(R&: *Remark); |
61 | auto Inserted = Remarks.insert(x: std::move(Remark)); |
62 | return **Inserted.first; |
63 | } |
64 | |
65 | void RemarkLinker::(StringRef PrependPathIn) { |
66 | PrependPath = std::string(PrependPathIn); |
67 | } |
68 | |
69 | Error RemarkLinker::(StringRef Buffer, std::optional<Format> ) { |
70 | if (!RemarkFormat) { |
71 | Expected<Format> ParserFormat = magicToFormat(Magic: Buffer); |
72 | if (!ParserFormat) |
73 | return ParserFormat.takeError(); |
74 | RemarkFormat = *ParserFormat; |
75 | } |
76 | |
77 | Expected<std::unique_ptr<RemarkParser>> MaybeParser = |
78 | createRemarkParserFromMeta( |
79 | ParserFormat: *RemarkFormat, Buf: Buffer, /*StrTab=*/std::nullopt, |
80 | ExternalFilePrependPath: 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(Err: std::move(E)); |
92 | break; |
93 | } |
94 | return E; |
95 | } |
96 | |
97 | assert(*Next != nullptr); |
98 | |
99 | if (shouldKeepRemark(R: **Next)) |
100 | keep(Remark: std::move(*Next)); |
101 | } |
102 | return Error::success(); |
103 | } |
104 | |
105 | Error RemarkLinker::(const object::ObjectFile &Obj, |
106 | std::optional<Format> ) { |
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(Buffer: *Section, RemarkFormat); |
114 | return Error::success(); |
115 | } |
116 | |
117 | Error RemarkLinker::(raw_ostream &OS, Format ) const { |
118 | Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer = |
119 | createRemarkSerializer(RemarksFormat, Mode: SerializerMode::Standalone, OS, |
120 | StrTab: 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(Remark: R); |
129 | return Error::success(); |
130 | } |
131 | |