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>
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>>
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 
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 
59 void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
60   PrependPath = std::string(PrependPathIn);
61 }
62 
63 // Discard remarks with no source location.
64 static bool shouldKeepRemark(const Remark &R) { return R.Loc.hasValue(); }
65 
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 
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 
113 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