1 //===--------- EHFrameSupport.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_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
14 #define LLVM_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
15 
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/TargetParser/Triple.h"
20 
21 namespace llvm {
22 namespace jitlink {
23 
24 /// Inspect an eh-frame CFI record.
25 class EHFrameCFIBlockInspector {
26 public:
27   /// Identify CFI record type and edges based on number and order of edges
28   /// in the given block only. This assumes that the block contains one CFI
29   /// record that has already been split out and fixed by the
30   /// DWARFRecordSplitter and EHFrameEdgeFixer passes.
31   ///
32   /// Zero or one outgoing edges: Record is CIE. If present, edge points to
33   /// personality.
34   ///
35   /// Two or three outgoing edges: Record is an FDE. First edge points to CIE,
36   /// second to PC-begin, third (if present) to LSDA.
37   ///
38   /// It is illegal to call this function on a block with four or more edges.
39   static EHFrameCFIBlockInspector FromEdgeScan(Block &B);
40 
41   /// Returns true if this frame is an FDE, false for a CIE.
isFDE()42   bool isFDE() const { return CIEEdge != nullptr; }
43 
44   /// Returns true if this frame is a CIE, false for an FDE.
isCIE()45   bool isCIE() const { return CIEEdge == nullptr; }
46 
47   /// If this is a CIE record, returns the Edge pointing at the personality
48   /// function, if any.
49   /// It is illegal to call this method on FDE records.
getPersonalityEdge()50   Edge *getPersonalityEdge() const {
51     assert(isCIE() && "CFI record is not a CIE");
52     return PersonalityEdge;
53   }
54 
55   /// If this is an FDE record, returns the Edge pointing to the CIE.
56   /// If this is a CIE record, returns null.
57   ///
58   /// The result is not valid if any modification has been made to the block
59   /// after parsing.
getCIEEdge()60   Edge *getCIEEdge() const { return CIEEdge; }
61 
62   /// If this is an FDE record, returns the Edge pointing at the PC-begin
63   /// symbol.
64   /// If this a CIE record, returns null.
getPCBeginEdge()65   Edge *getPCBeginEdge() const { return PCBeginEdge; }
66 
67   /// If this is an FDE record, returns the Edge pointing at the LSDA, if any.
68   /// It is illegal to call this method on CIE records.
getLSDAEdge()69   Edge *getLSDAEdge() const {
70     assert(isFDE() && "CFI record is not an FDE");
71     return LSDAEdge;
72   }
73 
74 private:
75   EHFrameCFIBlockInspector(Edge *PersonalityEdge);
76   EHFrameCFIBlockInspector(Edge &CIEEdge, Edge &PCBeginEdge, Edge *LSDAEdge);
77 
78   Edge *CIEEdge = nullptr;
79   Edge *PCBeginEdge = nullptr;
80   union {
81     Edge *PersonalityEdge;
82     Edge *LSDAEdge;
83   };
84 };
85 
86 /// Supports registration/deregistration of EH-frames in a target process.
87 class EHFrameRegistrar {
88 public:
89   virtual ~EHFrameRegistrar();
90   virtual Error registerEHFrames(orc::ExecutorAddrRange EHFrameSection) = 0;
91   virtual Error deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection) = 0;
92 };
93 
94 /// Registers / Deregisters EH-frames in the current process.
95 class InProcessEHFrameRegistrar final : public EHFrameRegistrar {
96 public:
97   Error registerEHFrames(orc::ExecutorAddrRange EHFrameSection) override;
98 
99   Error deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection) override;
100 };
101 
102 using StoreFrameRangeFunction = std::function<void(
103     orc::ExecutorAddr EHFrameSectionAddr, size_t EHFrameSectionSize)>;
104 
105 /// Creates a pass that records the address and size of the EH frame section.
106 /// If no eh-frame section is found then the address and size will both be given
107 /// as zero.
108 ///
109 /// Authors of JITLinkContexts can use this function to register a post-fixup
110 /// pass that records the range of the eh-frame section. This range can
111 /// be used after finalization to register and deregister the frame.
112 LinkGraphPassFunction
113 createEHFrameRecorderPass(const Triple &TT,
114                           StoreFrameRangeFunction StoreFrameRange);
115 
116 } // end namespace jitlink
117 } // end namespace llvm
118 
119 #endif // LLVM_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
120