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>
getRemarksSectionName(const object::ObjectFile & Obj)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>>
getRemarksSectionContents(const object::ObjectFile & Obj)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
keep(std::unique_ptr<Remark> Remark)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
setExternalFilePrependPath(StringRef PrependPathIn)59 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
60 PrependPath = PrependPathIn;
61 }
62
63 // Discard remarks with no source location.
shouldKeepRemark(const Remark & R)64 static bool shouldKeepRemark(const Remark &R) { return R.Loc.hasValue(); }
65
link(StringRef Buffer,Optional<Format> RemarkFormat)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
link(const object::ObjectFile & Obj,Optional<Format> RemarkFormat)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
serialize(raw_ostream & OS,Format RemarksFormat) const113 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