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 
21 using namespace llvm;
22 using namespace llvm::remarks;
23 
24 namespace llvm {
25 class raw_ostream;
26 }
27 
28 static Expected<StringRef>
29 getRemarksSectionName(const object::ObjectFile &Obj) {
30   if (Obj.isMachO())
31     return StringRef("__remarks");
32   // ELF -> .remarks, but there is no ELF support at this point.
33   return createStringError(std::errc::illegal_byte_sequence,
34                            "Unsupported file format.");
35 }
36 
37 Expected<Optional<StringRef>>
38 llvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) {
39   Expected<StringRef> SectionName = getRemarksSectionName(Obj);
40   if (!SectionName)
41     return SectionName.takeError();
42 
43   for (const object::SectionRef &Section : Obj.sections()) {
44     Expected<StringRef> MaybeName = Section.getName();
45     if (!MaybeName)
46       return MaybeName.takeError();
47     if (*MaybeName != *SectionName)
48       continue;
49 
50     if (Expected<StringRef> Contents = Section.getContents())
51       return *Contents;
52     else
53       return Contents.takeError();
54   }
55   return Optional<StringRef>{};
56 }
57 
58 Remark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) {
59   StrTab.internalize(*Remark);
60   auto Inserted = Remarks.insert(std::move(Remark));
61   return **Inserted.first;
62 }
63 
64 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
65   PrependPath = std::string(PrependPathIn);
66 }
67 
68 // Discard remarks with no source location.
69 static bool shouldKeepRemark(const Remark &R) { return R.Loc.has_value(); }
70 
71 Error RemarkLinker::link(StringRef Buffer, Optional<Format> RemarkFormat) {
72   if (!RemarkFormat) {
73     Expected<Format> ParserFormat = magicToFormat(Buffer);
74     if (!ParserFormat)
75       return ParserFormat.takeError();
76     RemarkFormat = *ParserFormat;
77   }
78 
79   Expected<std::unique_ptr<RemarkParser>> MaybeParser =
80       createRemarkParserFromMeta(
81           *RemarkFormat, Buffer, /*StrTab=*/None,
82           PrependPath ? Optional<StringRef>(StringRef(*PrependPath))
83                       : Optional<StringRef>(None));
84   if (!MaybeParser)
85     return MaybeParser.takeError();
86 
87   RemarkParser &Parser = **MaybeParser;
88 
89   while (true) {
90     Expected<std::unique_ptr<Remark>> Next = Parser.next();
91     if (Error E = Next.takeError()) {
92       if (E.isA<EndOfFileError>()) {
93         consumeError(std::move(E));
94         break;
95       }
96       return E;
97     }
98 
99     assert(*Next != nullptr);
100 
101     if (shouldKeepRemark(**Next))
102       keep(std::move(*Next));
103   }
104   return Error::success();
105 }
106 
107 Error RemarkLinker::link(const object::ObjectFile &Obj,
108                          Optional<Format> RemarkFormat) {
109   Expected<Optional<StringRef>> SectionOrErr = getRemarksSectionContents(Obj);
110   if (!SectionOrErr)
111     return SectionOrErr.takeError();
112 
113   if (Optional<StringRef> Section = *SectionOrErr)
114     return link(*Section, RemarkFormat);
115   return Error::success();
116 }
117 
118 Error RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const {
119   Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer =
120       createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS,
121                              std::move(const_cast<StringTable &>(StrTab)));
122   if (!MaybeSerializer)
123     return MaybeSerializer.takeError();
124 
125   std::unique_ptr<remarks::RemarkSerializer> Serializer =
126       std::move(*MaybeSerializer);
127 
128   for (const Remark &R : remarks())
129     Serializer->emit(R);
130   return Error::success();
131 }
132