xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===------- EHFrameSupportImpl.h - JITLink eh-frame utils ------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // EHFrame registration support for JITLink.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
140b57cec5SDimitry Andric #define LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
190b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace llvm {
220b57cec5SDimitry Andric namespace jitlink {
230b57cec5SDimitry Andric 
24480093f4SDimitry Andric /// A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA
25480093f4SDimitry Andric /// edges.
26480093f4SDimitry Andric class EHFrameEdgeFixer {
27480093f4SDimitry Andric public:
2881ad6265SDimitry Andric   /// Create an eh-frame edge fixer.
2981ad6265SDimitry Andric   /// If a given edge-kind is not supported on the target architecture then
3081ad6265SDimitry Andric   /// Edge::Invalid should be used.
31e8d8bef9SDimitry Andric   EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize,
3281ad6265SDimitry Andric                    Edge::Kind Pointer32, Edge::Kind Pointer64,
3381ad6265SDimitry Andric                    Edge::Kind Delta32, Edge::Kind Delta64,
34e8d8bef9SDimitry Andric                    Edge::Kind NegDelta32);
35480093f4SDimitry Andric   Error operator()(LinkGraph &G);
36480093f4SDimitry Andric 
37480093f4SDimitry Andric private:
388bcb0991SDimitry Andric 
390b57cec5SDimitry Andric   struct AugmentationInfo {
400b57cec5SDimitry Andric     bool AugmentationDataPresent = false;
410b57cec5SDimitry Andric     bool EHDataFieldPresent = false;
420b57cec5SDimitry Andric     uint8_t Fields[4] = {0x0, 0x0, 0x0, 0x0};
430b57cec5SDimitry Andric   };
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   struct CIEInformation {
460b57cec5SDimitry Andric     CIEInformation() = default;
478bcb0991SDimitry Andric     CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {}
488bcb0991SDimitry Andric     Symbol *CIESymbol = nullptr;
4981ad6265SDimitry Andric     bool AugmentationDataPresent = false;
5081ad6265SDimitry Andric     bool LSDAPresent = false;
5181ad6265SDimitry Andric     uint8_t LSDAEncoding = 0;
5281ad6265SDimitry Andric     uint8_t AddressEncoding = 0;
530b57cec5SDimitry Andric   };
540b57cec5SDimitry Andric 
55480093f4SDimitry Andric   struct EdgeTarget {
56480093f4SDimitry Andric     EdgeTarget() = default;
57480093f4SDimitry Andric     EdgeTarget(const Edge &E) : Target(&E.getTarget()), Addend(E.getAddend()) {}
58480093f4SDimitry Andric 
59480093f4SDimitry Andric     Symbol *Target = nullptr;
60480093f4SDimitry Andric     Edge::AddendT Addend = 0;
61480093f4SDimitry Andric   };
62480093f4SDimitry Andric 
63*5f757f3fSDimitry Andric   struct BlockEdgesInfo {
64*5f757f3fSDimitry Andric     DenseMap<Edge::OffsetT, EdgeTarget> TargetMap;
65*5f757f3fSDimitry Andric     DenseSet<Edge::OffsetT> Multiple;
66*5f757f3fSDimitry Andric   };
67*5f757f3fSDimitry Andric 
6804eeddc0SDimitry Andric   using CIEInfosMap = DenseMap<orc::ExecutorAddr, CIEInformation>;
69480093f4SDimitry Andric 
70480093f4SDimitry Andric   struct ParseContext {
71480093f4SDimitry Andric     ParseContext(LinkGraph &G) : G(G) {}
72480093f4SDimitry Andric 
7304eeddc0SDimitry Andric     Expected<CIEInformation *> findCIEInfo(orc::ExecutorAddr Address) {
74480093f4SDimitry Andric       auto I = CIEInfos.find(Address);
75480093f4SDimitry Andric       if (I == CIEInfos.end())
76480093f4SDimitry Andric         return make_error<JITLinkError>("No CIE found at address " +
77480093f4SDimitry Andric                                         formatv("{0:x16}", Address));
78480093f4SDimitry Andric       return &I->second;
79480093f4SDimitry Andric     }
80480093f4SDimitry Andric 
81480093f4SDimitry Andric     LinkGraph &G;
82480093f4SDimitry Andric     CIEInfosMap CIEInfos;
83480093f4SDimitry Andric     BlockAddressMap AddrToBlock;
8481ad6265SDimitry Andric     DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym;
85480093f4SDimitry Andric   };
86480093f4SDimitry Andric 
87480093f4SDimitry Andric   Error processBlock(ParseContext &PC, Block &B);
88*5f757f3fSDimitry Andric   Error processCIE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
89*5f757f3fSDimitry Andric                    const BlockEdgesInfo &BlockEdges);
90*5f757f3fSDimitry Andric   Error processFDE(ParseContext &PC, Block &B, size_t CIEDeltaFieldOffset,
91*5f757f3fSDimitry Andric                    uint32_t CIEDelta, const BlockEdgesInfo &BlockEdges);
92480093f4SDimitry Andric 
93480093f4SDimitry Andric   Expected<AugmentationInfo>
94480093f4SDimitry Andric   parseAugmentationString(BinaryStreamReader &RecordReader);
95e8d8bef9SDimitry Andric 
9681ad6265SDimitry Andric   Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader,
9781ad6265SDimitry Andric                                         Block &InBlock, const char *FieldName);
9881ad6265SDimitry Andric   Error skipEncodedPointer(uint8_t PointerEncoding,
99e8d8bef9SDimitry Andric                            BinaryStreamReader &RecordReader);
10081ad6265SDimitry Andric   Expected<Symbol *> getOrCreateEncodedPointerEdge(
101*5f757f3fSDimitry Andric       ParseContext &PC, const BlockEdgesInfo &BlockEdges,
102*5f757f3fSDimitry Andric       uint8_t PointerEncoding, BinaryStreamReader &RecordReader,
103*5f757f3fSDimitry Andric       Block &BlockToFix, size_t PointerFieldOffset, const char *FieldName);
104e8d8bef9SDimitry Andric 
10504eeddc0SDimitry Andric   Expected<Symbol &> getOrCreateSymbol(ParseContext &PC,
10604eeddc0SDimitry Andric                                        orc::ExecutorAddr Addr);
107480093f4SDimitry Andric 
108480093f4SDimitry Andric   StringRef EHFrameSectionName;
109e8d8bef9SDimitry Andric   unsigned PointerSize;
11081ad6265SDimitry Andric   Edge::Kind Pointer32;
11181ad6265SDimitry Andric   Edge::Kind Pointer64;
112e8d8bef9SDimitry Andric   Edge::Kind Delta32;
11381ad6265SDimitry Andric   Edge::Kind Delta64;
114e8d8bef9SDimitry Andric   Edge::Kind NegDelta32;
1150b57cec5SDimitry Andric };
1160b57cec5SDimitry Andric 
117fe6060f1SDimitry Andric /// Add a 32-bit null-terminator to the end of the eh-frame section.
118fe6060f1SDimitry Andric class EHFrameNullTerminator {
119fe6060f1SDimitry Andric public:
120fe6060f1SDimitry Andric   EHFrameNullTerminator(StringRef EHFrameSectionName);
121fe6060f1SDimitry Andric   Error operator()(LinkGraph &G);
122fe6060f1SDimitry Andric 
123fe6060f1SDimitry Andric private:
124fe6060f1SDimitry Andric   static char NullTerminatorBlockContent[];
125fe6060f1SDimitry Andric   StringRef EHFrameSectionName;
126fe6060f1SDimitry Andric };
127fe6060f1SDimitry Andric 
1280b57cec5SDimitry Andric } // end namespace jitlink
1290b57cec5SDimitry Andric } // end namespace llvm
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
132