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