MachOLinkGraphBuilder.h revision 360784
1//===----- MachOLinkGraphBuilder.h - MachO LinkGraph builder ----*- C++ -*-===//
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// Generic MachO LinkGraph building code.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
14#define LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
15
16#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17
18#include "EHFrameSupportImpl.h"
19#include "JITLinkGeneric.h"
20#include "llvm/Object/MachO.h"
21
22#include <list>
23
24namespace llvm {
25namespace jitlink {
26
27class MachOLinkGraphBuilder {
28public:
29  virtual ~MachOLinkGraphBuilder();
30  Expected<std::unique_ptr<LinkGraph>> buildGraph();
31
32protected:
33
34  struct NormalizedSymbol {
35    friend class MachOLinkGraphBuilder;
36
37  private:
38    NormalizedSymbol(Optional<StringRef> Name, uint64_t Value, uint8_t Type,
39                     uint8_t Sect, uint16_t Desc, Linkage L, Scope S)
40        : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L),
41          S(S) {
42      assert((!Name || !Name->empty()) && "Name must be none or non-empty");
43    }
44
45  public:
46    NormalizedSymbol(const NormalizedSymbol &) = delete;
47    NormalizedSymbol &operator=(const NormalizedSymbol &) = delete;
48    NormalizedSymbol(NormalizedSymbol &&) = delete;
49    NormalizedSymbol &operator=(NormalizedSymbol &&) = delete;
50
51    Optional<StringRef> Name;
52    uint64_t Value = 0;
53    uint8_t Type = 0;
54    uint8_t Sect = 0;
55    uint16_t Desc = 0;
56    Linkage L = Linkage::Strong;
57    Scope S = Scope::Default;
58    Symbol *GraphSymbol = nullptr;
59  };
60
61  class NormalizedSection {
62    friend class MachOLinkGraphBuilder;
63
64  private:
65    NormalizedSection() = default;
66
67  public:
68    Section *GraphSection = nullptr;
69    uint64_t Address = 0;
70    uint64_t Size = 0;
71    uint64_t Alignment = 0;
72    uint32_t Flags = 0;
73    const char *Data = nullptr;
74  };
75
76  using SectionParserFunction = std::function<Error(NormalizedSection &S)>;
77
78  MachOLinkGraphBuilder(const object::MachOObjectFile &Obj);
79
80  LinkGraph &getGraph() const { return *G; }
81
82  const object::MachOObjectFile &getObject() const { return Obj; }
83
84  void addCustomSectionParser(StringRef SectionName,
85                              SectionParserFunction Parse);
86
87  virtual Error addRelocations() = 0;
88
89  /// Create a symbol.
90  template <typename... ArgTs>
91  NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) {
92    NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>(
93        Allocator.Allocate<NormalizedSymbol>());
94    new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...);
95    return *Sym;
96  }
97
98  /// Index is zero-based (MachO section indexes are usually one-based) and
99  /// assumed to be in-range. Client is responsible for checking.
100  NormalizedSection &getSectionByIndex(unsigned Index) {
101    auto I = IndexToSection.find(Index);
102    assert(I != IndexToSection.end() && "No section recorded at index");
103    return I->second;
104  }
105
106  /// Try to get the section at the given index. Will return an error if the
107  /// given index is out of range, or if no section has been added for the given
108  /// index.
109  Expected<NormalizedSection &> findSectionByIndex(unsigned Index) {
110    auto I = IndexToSection.find(Index);
111    if (I == IndexToSection.end())
112      return make_error<JITLinkError>("No section recorded for index " +
113                                      formatv("{0:u}", Index));
114    return I->second;
115  }
116
117  /// Try to get the symbol at the given index. Will return an error if the
118  /// given index is out of range, or if no symbol has been added for the given
119  /// index.
120  Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) {
121    if (Index >= IndexToSymbol.size())
122      return make_error<JITLinkError>("Symbol index out of range");
123    auto *Sym = IndexToSymbol[Index];
124    if (!Sym)
125      return make_error<JITLinkError>("No symbol at index " +
126                                      formatv("{0:u}", Index));
127    return *Sym;
128  }
129
130  /// Returns the symbol with the highest address not greater than the search
131  /// address, or null if no such symbol exists.
132  Symbol *getSymbolByAddress(JITTargetAddress Address) {
133    auto I = AddrToCanonicalSymbol.upper_bound(Address);
134    if (I == AddrToCanonicalSymbol.begin())
135      return nullptr;
136    return std::prev(I)->second;
137  }
138
139  /// Returns the symbol with the highest address not greater than the search
140  /// address, or an error if no such symbol exists.
141  Expected<Symbol &> findSymbolByAddress(JITTargetAddress Address) {
142    auto *Sym = getSymbolByAddress(Address);
143    if (Sym)
144      if (Address < Sym->getAddress() + Sym->getSize())
145        return *Sym;
146    return make_error<JITLinkError>("No symbol covering address " +
147                                    formatv("{0:x16}", Address));
148  }
149
150  static Linkage getLinkage(uint16_t Desc);
151  static Scope getScope(StringRef Name, uint8_t Type);
152  static bool isAltEntry(const NormalizedSymbol &NSym);
153
154private:
155  static unsigned getPointerSize(const object::MachOObjectFile &Obj);
156  static support::endianness getEndianness(const object::MachOObjectFile &Obj);
157
158  void setCanonicalSymbol(Symbol &Sym) {
159    auto *&CanonicalSymEntry = AddrToCanonicalSymbol[Sym.getAddress()];
160    // There should be no symbol at this address, or, if there is,
161    // it should be a zero-sized symbol from an empty section (which
162    // we can safely override).
163    assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) &&
164           "Duplicate canonical symbol at address");
165    CanonicalSymEntry = &Sym;
166  }
167
168  Section &getCommonSection();
169  void addSectionStartSymAndBlock(Section &GraphSec, uint64_t Address,
170                                  const char *Data, uint64_t Size,
171                                  uint32_t Alignment, bool IsLive);
172
173  Error createNormalizedSections();
174  Error createNormalizedSymbols();
175
176  /// Create graph blocks and symbols for externals, absolutes, commons and
177  /// all defined symbols in sections without custom parsers.
178  Error graphifyRegularSymbols();
179
180  /// Create graph blocks and symbols for all sections.
181  Error graphifySectionsWithCustomParsers();
182
183  // Put the BumpPtrAllocator first so that we don't free any of the underlying
184  // memory until the Symbol/Addressable destructors have been run.
185  BumpPtrAllocator Allocator;
186
187  const object::MachOObjectFile &Obj;
188  std::unique_ptr<LinkGraph> G;
189
190  DenseMap<unsigned, NormalizedSection> IndexToSection;
191  Section *CommonSection = nullptr;
192
193  DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol;
194  std::map<JITTargetAddress, Symbol *> AddrToCanonicalSymbol;
195  StringMap<SectionParserFunction> CustomSectionParserFunctions;
196};
197
198} // end namespace jitlink
199} // end namespace llvm
200
201#endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
202