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 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>>
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 
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 
65 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
66   PrependPath = std::string(PrependPathIn);
67 }
68 
69 // Discard remarks with no source location.
70 static bool shouldKeepRemark(const Remark &R) { return R.Loc.has_value(); }
71 
72 Error RemarkLinker::link(StringRef Buffer, std::optional<Format> RemarkFormat) {
73   if (!RemarkFormat) {
74     Expected<Format> ParserFormat = magicToFormat(Buffer);
75     if (!ParserFormat)
76       return ParserFormat.takeError();
77     RemarkFormat = *ParserFormat;
78   }
79 
80   Expected<std::unique_ptr<RemarkParser>> MaybeParser =
81       createRemarkParserFromMeta(
82           *RemarkFormat, Buffer, /*StrTab=*/std::nullopt,
83           PrependPath ? std::optional<StringRef>(StringRef(*PrependPath))
84                       : std::optional<StringRef>());
85   if (!MaybeParser)
86     return MaybeParser.takeError();
87 
88   RemarkParser &Parser = **MaybeParser;
89 
90   while (true) {
91     Expected<std::unique_ptr<Remark>> Next = Parser.next();
92     if (Error E = Next.takeError()) {
93       if (E.isA<EndOfFileError>()) {
94         consumeError(std::move(E));
95         break;
96       }
97       return E;
98     }
99 
100     assert(*Next != nullptr);
101 
102     if (shouldKeepRemark(**Next))
103       keep(std::move(*Next));
104   }
105   return Error::success();
106 }
107 
108 Error RemarkLinker::link(const object::ObjectFile &Obj,
109                          std::optional<Format> RemarkFormat) {
110   Expected<std::optional<StringRef>> SectionOrErr =
111       getRemarksSectionContents(Obj);
112   if (!SectionOrErr)
113     return SectionOrErr.takeError();
114 
115   if (std::optional<StringRef> Section = *SectionOrErr)
116     return link(*Section, RemarkFormat);
117   return Error::success();
118 }
119 
120 Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const {
121   Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer =
122       createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS,
123                              std::move(const_cast<StringTable &>(StrTab)));
124   if (!MaybeSerializer)
125     return MaybeSerializer.takeError();
126 
127   std::unique_ptr<remarks::RemarkSerializer> Serializer =
128       std::move(*MaybeSerializer);
129 
130   for (const Remark &R : remarks())
131     Serializer->emit(R);
132   return Error::success();
133 }
134