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
22using namespace llvm;
23using namespace llvm::remarks;
24
25namespace llvm {
26class raw_ostream;
27}
28
29static Expected<StringRef>
30getRemarksSectionName(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
38Expected<std::optional<StringRef>>
39llvm::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
59Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) {
60 StrTab.internalize(R&: *Remark);
61 auto Inserted = Remarks.insert(x: std::move(Remark));
62 return **Inserted.first;
63}
64
65void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
66 PrependPath = std::string(PrependPathIn);
67}
68
69Error RemarkLinker::link(StringRef Buffer, Format RemarkFormat) {
70 Expected<std::unique_ptr<RemarkParser>> MaybeParser =
71 createRemarkParserFromMeta(
72 ParserFormat: RemarkFormat, Buf: Buffer,
73 ExternalFilePrependPath: PrependPath ? std::optional<StringRef>(StringRef(*PrependPath))
74 : std::optional<StringRef>());
75 if (!MaybeParser)
76 return MaybeParser.takeError();
77
78 RemarkParser &Parser = **MaybeParser;
79
80 while (true) {
81 Expected<std::unique_ptr<Remark>> Next = Parser.next();
82 if (Error E = Next.takeError()) {
83 if (E.isA<EndOfFileError>()) {
84 consumeError(Err: std::move(E));
85 break;
86 }
87 return E;
88 }
89
90 assert(*Next != nullptr);
91
92 if (shouldKeepRemark(R: **Next))
93 keep(Remark: std::move(*Next));
94 }
95 return Error::success();
96}
97
98Error RemarkLinker::link(const object::ObjectFile &Obj, Format RemarkFormat) {
99 Expected<std::optional<StringRef>> SectionOrErr =
100 getRemarksSectionContents(Obj);
101 if (!SectionOrErr)
102 return SectionOrErr.takeError();
103
104 if (std::optional<StringRef> Section = *SectionOrErr)
105 return link(Buffer: *Section, RemarkFormat);
106 return Error::success();
107}
108
109Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const {
110 Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer =
111 createRemarkSerializer(RemarksFormat, Mode: SerializerMode::Standalone, OS,
112 StrTab: std::move(const_cast<StringTable &>(StrTab)));
113 if (!MaybeSerializer)
114 return MaybeSerializer.takeError();
115
116 std::unique_ptr<remarks::RemarkSerializer> Serializer =
117 std::move(*MaybeSerializer);
118
119 for (const Remark &R : remarks())
120 Serializer->emit(Remark: R);
121 return Error::success();
122}
123