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   struct BlockEdgesInfo {
64     DenseMap<Edge::OffsetT, EdgeTarget> TargetMap;
65     DenseSet<Edge::OffsetT> Multiple;
66   };
67 
68   using CIEInfosMap = DenseMap<orc::ExecutorAddr, CIEInformation>;
69 
70   struct ParseContext {
71     ParseContext(LinkGraph &G) : G(G) {}
72 
73     Expected<CIEInformation *> findCIEInfo(orc::ExecutorAddr Address) {
74       auto I = CIEInfos.find(Address);
75       if (I == CIEInfos.end())
76         return make_error<JITLinkError>("No CIE found at address " +
77                                         formatv("{0:x16}", Address));
78       return &I->second;
79     }
80 
81     LinkGraph &G;
82     CIEInfosMap CIEInfos;
83     BlockAddressMap AddrToBlock;
84     DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym;
85   };
86 
87   Error processBlock(ParseContext &PC, Block &B);
88   Error processCIE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
89                    const BlockEdgesInfo &BlockEdges);
90   Error processFDE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
91                    uint32_t CIEDelta, const BlockEdgesInfo &BlockEdges);
92 
93   Expected<AugmentationInfo>
94   parseAugmentationString(BinaryStreamReader &RecordReader);
95 
96   Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader,
97                                         Block &InBlock, const char *FieldName);
98   Error skipEncodedPointer(uint8_t PointerEncoding,
99                            BinaryStreamReader &RecordReader);
100   Expected<Symbol *> getOrCreateEncodedPointerEdge(
101       ParseContext &PC, const BlockEdgesInfo &BlockEdges,
102       uint8_t PointerEncoding, BinaryStreamReader &RecordReader,
103       Block &BlockToFix, size_t PointerFieldOffset, const char *FieldName);
104 
105   Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
106                                        orc::ExecutorAddr Addr);
107 
108   StringRef EHFrameSectionName;
109   unsigned PointerSize;
110   Edge::Kind Pointer32;
111   Edge::Kind Pointer64;
112   Edge::Kind Delta32;
113   Edge::Kind Delta64;
114   Edge::Kind NegDelta32;
115 };
116 
117 /// Add a 32-bit null-terminator to the end of the eh-frame section.
118 class EHFrameNullTerminator {
119 public:
120   EHFrameNullTerminator(StringRef EHFrameSectionName);
121   Error operator()(LinkGraph &G);
122 
123 private:
124   static char NullTerminatorBlockContent[];
125   StringRef EHFrameSectionName;
126 };
127 
128 } // end namespace jitlink
129 } // end namespace llvm
130 
131 #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
132