1 //===------- EHFrameSupportImpl.h - JITLink eh-frame utils ------*- 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 // EHFrame registration support for JITLink.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
14 #define LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
15 
16 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
17 
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/Support/BinaryStreamReader.h"
20 
21 namespace llvm {
22 namespace jitlink {
23 
24 /// A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA
25 /// edges.
26 class EHFrameEdgeFixer {
27 public:
28   /// Create an eh-frame edge fixer.
29   /// If a given edge-kind is not supported on the target architecture then
30   /// Edge::Invalid should be used.
31   EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize,
32                    Edge::Kind Pointer32, Edge::Kind Pointer64,
33                    Edge::Kind Delta32, Edge::Kind Delta64,
34                    Edge::Kind NegDelta32);
35   Error operator()(LinkGraph &G);
36 
37 private:
38 
39   struct AugmentationInfo {
40     bool AugmentationDataPresent = false;
41     bool EHDataFieldPresent = false;
42     uint8_t Fields[4] = {0x0, 0x0, 0x0, 0x0};
43   };
44 
45   struct CIEInformation {
46     CIEInformation() = default;
47     CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {}
48     Symbol *CIESymbol = nullptr;
49     bool AugmentationDataPresent = false;
50     bool LSDAPresent = false;
51     uint8_t LSDAEncoding = 0;
52     uint8_t AddressEncoding = 0;
53   };
54 
55   struct EdgeTarget {
56     EdgeTarget() = default;
57     EdgeTarget(const Edge &E) : Target(&E.getTarget()), Addend(E.getAddend()) {}
58 
59     Symbol *Target = nullptr;
60     Edge::AddendT Addend = 0;
61   };
62 
63   using BlockEdgeMap = DenseMap<Edge::OffsetT, EdgeTarget>;
64   using CIEInfosMap = DenseMap<orc::ExecutorAddr, CIEInformation>;
65 
66   struct ParseContext {
67     ParseContext(LinkGraph &G) : G(G) {}
68 
69     Expected<CIEInformation *> findCIEInfo(orc::ExecutorAddr Address) {
70       auto I = CIEInfos.find(Address);
71       if (I == CIEInfos.end())
72         return make_error<JITLinkError>("No CIE found at address " +
73                                         formatv("{0:x16}", Address));
74       return &I->second;
75     }
76 
77     LinkGraph &G;
78     CIEInfosMap CIEInfos;
79     BlockAddressMap AddrToBlock;
80     DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym;
81   };
82 
83   Error processBlock(ParseContext &PC, Block &B);
84   Error processCIE(ParseContext &PC, Block &B, size_t RecordOffset,
85                    size_t RecordLength, size_t CIEDeltaFieldOffset,
86                    const BlockEdgeMap &BlockEdges);
87   Error processFDE(ParseContext &PC, Block &B, size_t RecordOffset,
88                    size_t RecordLength, size_t CIEDeltaFieldOffset,
89                    uint32_t CIEDelta, const BlockEdgeMap &BlockEdges);
90 
91   Expected<AugmentationInfo>
92   parseAugmentationString(BinaryStreamReader &RecordReader);
93 
94   Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader,
95                                         Block &InBlock, const char *FieldName);
96   Error skipEncodedPointer(uint8_t PointerEncoding,
97                            BinaryStreamReader &RecordReader);
98   Expected<Symbol *> getOrCreateEncodedPointerEdge(
99       ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
100       BinaryStreamReader &RecordReader, Block &BlockToFix,
101       size_t PointerFieldOffset, const char *FieldName);
102 
103   Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
104                                        orc::ExecutorAddr Addr);
105 
106   StringRef EHFrameSectionName;
107   unsigned PointerSize;
108   Edge::Kind Pointer32;
109   Edge::Kind Pointer64;
110   Edge::Kind Delta32;
111   Edge::Kind Delta64;
112   Edge::Kind NegDelta32;
113 };
114 
115 /// Add a 32-bit null-terminator to the end of the eh-frame section.
116 class EHFrameNullTerminator {
117 public:
118   EHFrameNullTerminator(StringRef EHFrameSectionName);
119   Error operator()(LinkGraph &G);
120 
121 private:
122   static char NullTerminatorBlockContent[];
123   StringRef EHFrameSectionName;
124 };
125 
126 } // end namespace jitlink
127 } // end namespace llvm
128 
129 #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
130