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
20using namespace llvm;
21using namespace llvm::remarks;
22
23static Expected<StringRef>
24getRemarksSectionName(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
32Expected<Optional<StringRef>>
33llvm::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
53Remark &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
59void RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
60  PrependPath = PrependPathIn;
61}
62
63// Discard remarks with no source location.
64static bool shouldKeepRemark(const Remark &R) { return R.Loc.hasValue(); }
65
66Error 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
102Error 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
113Error 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