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 
24 namespace llvm {
25 namespace jitlink {
26 
27 class MachOLinkGraphBuilder {
28 public:
29   virtual ~MachOLinkGraphBuilder();
30   Expected<std::unique_ptr<LinkGraph>> buildGraph();
31 
32 protected:
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 
154 private:
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