1356843Sdim//===- RemarkLinker.cpp ---------------------------------------------------===//
2356843Sdim//
3356843Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4356843Sdim// See https://llvm.org/LICENSE.txt for license information.
5356843Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6356843Sdim//
7356843Sdim//===----------------------------------------------------------------------===//
8356843Sdim//
9356843Sdim// This file provides an implementation of the remark linker.
10356843Sdim//
11356843Sdim//===----------------------------------------------------------------------===//
12356843Sdim
13356843Sdim#include "llvm/Remarks/RemarkLinker.h"
14356843Sdim#include "llvm/ADT/StringRef.h"
15356843Sdim#include "llvm/Remarks/BitstreamRemarkContainer.h"
16356843Sdim#include "llvm/Remarks/RemarkParser.h"
17356843Sdim#include "llvm/Remarks/RemarkSerializer.h"
18356843Sdim#include "llvm/Support/Error.h"
19356843Sdim
20356843Sdimusing namespace llvm;
21356843Sdimusing namespace llvm::remarks;
22356843Sdim
23356843Sdimstatic Expected<StringRef>
24356843SdimgetRemarksSectionName(const object::ObjectFile &Obj) {
25356843Sdim  if (Obj.isMachO())
26356843Sdim    return StringRef("__remarks");
27356843Sdim  // ELF -> .remarks, but there is no ELF support at this point.
28356843Sdim  return createStringError(std::errc::illegal_byte_sequence,
29356843Sdim                           "Unsupported file format.");
30356843Sdim}
31356843Sdim
32356843SdimExpected<Optional<StringRef>>
33356843Sdimllvm::remarks::getRemarksSectionContents(const object::ObjectFile &Obj) {
34356843Sdim  Expected<StringRef> SectionName = getRemarksSectionName(Obj);
35356843Sdim  if (!SectionName)
36356843Sdim    return SectionName.takeError();
37356843Sdim
38356843Sdim  for (const object::SectionRef &Section : Obj.sections()) {
39356843Sdim    Expected<StringRef> MaybeName = Section.getName();
40356843Sdim    if (!MaybeName)
41356843Sdim      return MaybeName.takeError();
42356843Sdim    if (*MaybeName != *SectionName)
43356843Sdim      continue;
44356843Sdim
45356843Sdim    if (Expected<StringRef> Contents = Section.getContents())
46356843Sdim      return *Contents;
47356843Sdim    else
48356843Sdim      return Contents.takeError();
49356843Sdim  }
50356843Sdim  return Optional<StringRef>{};
51356843Sdim}
52356843Sdim
53356843SdimRemark &RemarkLinker::keep(std::unique_ptr<Remark> Remark) {
54356843Sdim  StrTab.internalize(*Remark);
55356843Sdim  auto Inserted = Remarks.insert(std::move(Remark));
56356843Sdim  return **Inserted.first;
57356843Sdim}
58356843Sdim
59356843Sdimvoid RemarkLinker::setExternalFilePrependPath(StringRef PrependPathIn) {
60356843Sdim  PrependPath = PrependPathIn;
61356843Sdim}
62356843Sdim
63356843Sdim// Discard remarks with no source location.
64356843Sdimstatic bool shouldKeepRemark(const Remark &R) { return R.Loc.hasValue(); }
65356843Sdim
66356843SdimError RemarkLinker::link(StringRef Buffer, Optional<Format> RemarkFormat) {
67356843Sdim  if (!RemarkFormat) {
68356843Sdim    Expected<Format> ParserFormat = magicToFormat(Buffer);
69356843Sdim    if (!ParserFormat)
70356843Sdim      return ParserFormat.takeError();
71356843Sdim    RemarkFormat = *ParserFormat;
72356843Sdim  }
73356843Sdim
74356843Sdim  Expected<std::unique_ptr<RemarkParser>> MaybeParser =
75356843Sdim      createRemarkParserFromMeta(
76356843Sdim          *RemarkFormat, Buffer, /*StrTab=*/None,
77356843Sdim          PrependPath ? Optional<StringRef>(StringRef(*PrependPath))
78356843Sdim                      : Optional<StringRef>(None));
79356843Sdim  if (!MaybeParser)
80356843Sdim    return MaybeParser.takeError();
81356843Sdim
82356843Sdim  RemarkParser &Parser = **MaybeParser;
83356843Sdim
84356843Sdim  while (true) {
85356843Sdim    Expected<std::unique_ptr<Remark>> Next = Parser.next();
86356843Sdim    if (Error E = Next.takeError()) {
87356843Sdim      if (E.isA<EndOfFileError>()) {
88356843Sdim        consumeError(std::move(E));
89356843Sdim        break;
90356843Sdim      }
91356843Sdim      return E;
92356843Sdim    }
93356843Sdim
94356843Sdim    assert(*Next != nullptr);
95356843Sdim
96356843Sdim    if (shouldKeepRemark(**Next))
97356843Sdim      keep(std::move(*Next));
98356843Sdim  }
99356843Sdim  return Error::success();
100356843Sdim}
101356843Sdim
102356843SdimError RemarkLinker::link(const object::ObjectFile &Obj,
103356843Sdim                         Optional<Format> RemarkFormat) {
104356843Sdim  Expected<Optional<StringRef>> SectionOrErr = getRemarksSectionContents(Obj);
105356843Sdim  if (!SectionOrErr)
106356843Sdim    return SectionOrErr.takeError();
107356843Sdim
108356843Sdim  if (Optional<StringRef> Section = *SectionOrErr)
109356843Sdim    return link(*Section, RemarkFormat);
110356843Sdim  return Error::success();
111356843Sdim}
112356843Sdim
113356843SdimError RemarkLinker::serialize(raw_ostream &OS, Format RemarksFormat) const {
114356843Sdim  Expected<std::unique_ptr<RemarkSerializer>> MaybeSerializer =
115356843Sdim      createRemarkSerializer(RemarksFormat, SerializerMode::Standalone, OS,
116356843Sdim                             std::move(const_cast<StringTable &>(StrTab)));
117356843Sdim  if (!MaybeSerializer)
118356843Sdim    return MaybeSerializer.takeError();
119356843Sdim
120356843Sdim  std::unique_ptr<remarks::RemarkSerializer> Serializer =
121356843Sdim      std::move(*MaybeSerializer);
122356843Sdim
123356843Sdim  for (const Remark &R : remarks())
124356843Sdim    Serializer->emit(R);
125356843Sdim  return Error::success();
126356843Sdim}
127