xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
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   class MachOEHFrameBinaryParser : public EHFrameBinaryParser {
34   public:
35     MachOEHFrameBinaryParser(MachOLinkGraphBuilder &Builder,
36                              JITTargetAddress EHFrameAddress,
37                              StringRef EHFrameContent, Section &EHFrameSection,
38                              uint64_t CIEAlignment, uint64_t FDEAlignment,
39                              Edge::Kind FDEToCIERelocKind,
40                              Edge::Kind FDEToTargetRelocKind)
41         : EHFrameBinaryParser(EHFrameAddress, EHFrameContent,
42                               Builder.getGraph().getPointerSize(),
43                               Builder.getGraph().getEndianness()),
44           Builder(Builder), EHFrameSection(EHFrameSection),
45           CIEAlignment(CIEAlignment), FDEAlignment(FDEAlignment),
46           FDEToCIERelocKind(FDEToCIERelocKind),
47           FDEToTargetRelocKind(FDEToTargetRelocKind) {}
48 
49     Symbol *getSymbolAtAddress(JITTargetAddress Address) override {
50       if (auto *Sym = Builder.getSymbolByAddress(Address))
51         if (Sym->getAddress() == Address)
52           return Sym;
53       return nullptr;
54     }
55 
56     Symbol &createCIERecord(JITTargetAddress RecordAddr,
57                             StringRef RecordContent) override {
58       auto &G = Builder.getGraph();
59       auto &B = G.createContentBlock(EHFrameSection, RecordContent, RecordAddr,
60                                      CIEAlignment, 0);
61       auto &CIESymbol =
62           G.addAnonymousSymbol(B, 0, RecordContent.size(), false, false);
63       Builder.setCanonicalSymbol(CIESymbol);
64       return CIESymbol;
65     }
66 
67     Expected<Symbol &> createFDERecord(JITTargetAddress RecordAddr,
68                                        StringRef RecordContent, Symbol &CIE,
69                                        size_t CIEOffset, Symbol &Func,
70                                        size_t FuncOffset, Symbol *LSDA,
71                                        size_t LSDAOffset) override {
72       auto &G = Builder.getGraph();
73       auto &B = G.createContentBlock(EHFrameSection, RecordContent, RecordAddr,
74                                      FDEAlignment, 0);
75 
76       // Add edges to CIE, Func, and (conditionally) LSDA.
77       B.addEdge(FDEToCIERelocKind, CIEOffset, CIE, 0);
78       B.addEdge(FDEToTargetRelocKind, FuncOffset, Func, 0);
79 
80       if (LSDA)
81         B.addEdge(FDEToTargetRelocKind, LSDAOffset, *LSDA, 0);
82 
83       auto &FDESymbol =
84           G.addAnonymousSymbol(B, 0, RecordContent.size(), false, false);
85 
86       // Add a keep-alive relocation from the function to the FDE to ensure it
87       // is not dead stripped.
88       Func.getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
89 
90       return FDESymbol;
91     }
92 
93   private:
94     MachOLinkGraphBuilder &Builder;
95     Section &EHFrameSection;
96     uint64_t CIEAlignment;
97     uint64_t FDEAlignment;
98     Edge::Kind FDEToCIERelocKind;
99     Edge::Kind FDEToTargetRelocKind;
100   };
101 
102   struct NormalizedSymbol {
103     friend class MachOLinkGraphBuilder;
104 
105   private:
106     NormalizedSymbol(Optional<StringRef> Name, uint64_t Value, uint8_t Type,
107                      uint8_t Sect, uint16_t Desc, Linkage L, Scope S)
108         : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L),
109           S(S) {
110       assert((!Name || !Name->empty()) && "Name must be none or non-empty");
111     }
112 
113   public:
114     NormalizedSymbol(const NormalizedSymbol &) = delete;
115     NormalizedSymbol &operator=(const NormalizedSymbol &) = delete;
116     NormalizedSymbol(NormalizedSymbol &&) = delete;
117     NormalizedSymbol &operator=(NormalizedSymbol &&) = delete;
118 
119     Optional<StringRef> Name;
120     uint64_t Value = 0;
121     uint8_t Type = 0;
122     uint8_t Sect = 0;
123     uint16_t Desc = 0;
124     Linkage L = Linkage::Strong;
125     Scope S = Scope::Default;
126     Symbol *GraphSymbol = nullptr;
127   };
128 
129   class NormalizedSection {
130     friend class MachOLinkGraphBuilder;
131 
132   private:
133     NormalizedSection() = default;
134 
135   public:
136     Section *GraphSection = nullptr;
137     uint64_t Address = 0;
138     uint64_t Size = 0;
139     uint64_t Alignment = 0;
140     uint32_t Flags = 0;
141     const char *Data = nullptr;
142   };
143 
144   using SectionParserFunction = std::function<Error(NormalizedSection &S)>;
145 
146   MachOLinkGraphBuilder(const object::MachOObjectFile &Obj);
147 
148   LinkGraph &getGraph() const { return *G; }
149 
150   const object::MachOObjectFile &getObject() const { return Obj; }
151 
152   void addCustomSectionParser(StringRef SectionName,
153                               SectionParserFunction Parse);
154 
155   virtual Error addRelocations() = 0;
156 
157   /// Create a symbol.
158   template <typename... ArgTs>
159   NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) {
160     NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>(
161         Allocator.Allocate<NormalizedSymbol>());
162     new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...);
163     return *Sym;
164   }
165 
166   /// Index is zero-based (MachO section indexes are usually one-based) and
167   /// assumed to be in-range. Client is responsible for checking.
168   NormalizedSection &getSectionByIndex(unsigned Index) {
169     auto I = IndexToSection.find(Index);
170     assert(I != IndexToSection.end() && "No section recorded at index");
171     return I->second;
172   }
173 
174   /// Try to get the section at the given index. Will return an error if the
175   /// given index is out of range, or if no section has been added for the given
176   /// index.
177   Expected<NormalizedSection &> findSectionByIndex(unsigned Index) {
178     auto I = IndexToSection.find(Index);
179     if (I == IndexToSection.end())
180       return make_error<JITLinkError>("No section recorded for index " +
181                                       formatv("{0:u}", Index));
182     return I->second;
183   }
184 
185   /// Try to get the symbol at the given index. Will return an error if the
186   /// given index is out of range, or if no symbol has been added for the given
187   /// index.
188   Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) {
189     if (Index >= IndexToSymbol.size())
190       return make_error<JITLinkError>("Symbol index out of range");
191     auto *Sym = IndexToSymbol[Index];
192     if (!Sym)
193       return make_error<JITLinkError>("No symbol at index " +
194                                       formatv("{0:u}", Index));
195     return *Sym;
196   }
197 
198   /// Returns the symbol with the highest address not greater than the search
199   /// address, or null if no such symbol exists.
200   Symbol *getSymbolByAddress(JITTargetAddress Address) {
201     auto I = AddrToCanonicalSymbol.upper_bound(Address);
202     if (I == AddrToCanonicalSymbol.begin())
203       return nullptr;
204     return std::prev(I)->second;
205   }
206 
207   /// Returns the symbol with the highest address not greater than the search
208   /// address, or an error if no such symbol exists.
209   Expected<Symbol &> findSymbolByAddress(JITTargetAddress Address) {
210     auto *Sym = getSymbolByAddress(Address);
211     if (Sym)
212       if (Address < Sym->getAddress() + Sym->getSize())
213         return *Sym;
214     return make_error<JITLinkError>("No symbol covering address " +
215                                     formatv("{0:x16}", Address));
216   }
217 
218   static Linkage getLinkage(uint16_t Desc);
219   static Scope getScope(StringRef Name, uint8_t Type);
220   static bool isAltEntry(const NormalizedSymbol &NSym);
221 
222 private:
223   static unsigned getPointerSize(const object::MachOObjectFile &Obj);
224   static support::endianness getEndianness(const object::MachOObjectFile &Obj);
225 
226   void setCanonicalSymbol(Symbol &Sym) {
227     auto *&CanonicalSymEntry = AddrToCanonicalSymbol[Sym.getAddress()];
228     // There should be no symbol at this address, or, if there is,
229     // it should be a zero-sized symbol from an empty section (which
230     // we can safely override).
231     assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) &&
232            "Duplicate canonical symbol at address");
233     CanonicalSymEntry = &Sym;
234   }
235 
236   Section &getCommonSection();
237   void addSectionStartSymAndBlock(Section &GraphSec, uint64_t Address,
238                                   const char *Data, uint64_t Size,
239                                   uint32_t Alignment, bool IsLive);
240 
241   Error createNormalizedSections();
242   Error createNormalizedSymbols();
243 
244   /// Create graph blocks and symbols for externals, absolutes, commons and
245   /// all defined symbols in sections without custom parsers.
246   Error graphifyRegularSymbols();
247 
248   /// Create graph blocks and symbols for all sections.
249   Error graphifySectionsWithCustomParsers();
250 
251   // Put the BumpPtrAllocator first so that we don't free any of the underlying
252   // memory until the Symbol/Addressable destructors have been run.
253   BumpPtrAllocator Allocator;
254 
255   const object::MachOObjectFile &Obj;
256   std::unique_ptr<LinkGraph> G;
257 
258   DenseMap<unsigned, NormalizedSection> IndexToSection;
259   Section *CommonSection = nullptr;
260 
261   DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol;
262   std::map<JITTargetAddress, Symbol *> AddrToCanonicalSymbol;
263   StringMap<SectionParserFunction> CustomSectionParserFunctions;
264 };
265 
266 } // end namespace jitlink
267 } // end namespace llvm
268 
269 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
270