1e8d8bef9SDimitry Andric //===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===//
2e8d8bef9SDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric
9e8d8bef9SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
10e8d8bef9SDimitry Andric
11e8d8bef9SDimitry Andric #include "llvm/Config/config.h"
12e8d8bef9SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h"
13e8d8bef9SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
14e8d8bef9SDimitry Andric #include "llvm/Support/Compiler.h"
15e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
16e8d8bef9SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
17e8d8bef9SDimitry Andric #include "llvm/Support/raw_ostream.h"
18e8d8bef9SDimitry Andric
19e8d8bef9SDimitry Andric #include "llvm/Support/FormatVariadic.h"
20e8d8bef9SDimitry Andric
21e8d8bef9SDimitry Andric #define DEBUG_TYPE "orc"
22e8d8bef9SDimitry Andric
23e8d8bef9SDimitry Andric using namespace llvm;
24e8d8bef9SDimitry Andric using namespace llvm::orc;
25fe6060f1SDimitry Andric using namespace llvm::orc::shared;
26e8d8bef9SDimitry Andric
27e8d8bef9SDimitry Andric namespace llvm {
28e8d8bef9SDimitry Andric namespace orc {
29e8d8bef9SDimitry Andric
30e8d8bef9SDimitry Andric #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \
31e8d8bef9SDimitry Andric !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
32e8d8bef9SDimitry Andric
33e8d8bef9SDimitry Andric extern "C" void __register_frame(const void *);
34e8d8bef9SDimitry Andric extern "C" void __deregister_frame(const void *);
35e8d8bef9SDimitry Andric
registerFrameWrapper(const void * P)36e8d8bef9SDimitry Andric Error registerFrameWrapper(const void *P) {
37e8d8bef9SDimitry Andric __register_frame(P);
38e8d8bef9SDimitry Andric return Error::success();
39e8d8bef9SDimitry Andric }
40e8d8bef9SDimitry Andric
deregisterFrameWrapper(const void * P)41e8d8bef9SDimitry Andric Error deregisterFrameWrapper(const void *P) {
42e8d8bef9SDimitry Andric __deregister_frame(P);
43e8d8bef9SDimitry Andric return Error::success();
44e8d8bef9SDimitry Andric }
45e8d8bef9SDimitry Andric
46e8d8bef9SDimitry Andric #else
47e8d8bef9SDimitry Andric
48e8d8bef9SDimitry Andric // The building compiler does not have __(de)register_frame but
49e8d8bef9SDimitry Andric // it may be found at runtime in a dynamically-loaded library.
50e8d8bef9SDimitry Andric // For example, this happens when building LLVM with Visual C++
51e8d8bef9SDimitry Andric // but using the MingW runtime.
52e8d8bef9SDimitry Andric static Error registerFrameWrapper(const void *P) {
53e8d8bef9SDimitry Andric static void((*RegisterFrame)(const void *)) = 0;
54e8d8bef9SDimitry Andric
55e8d8bef9SDimitry Andric if (!RegisterFrame)
56e8d8bef9SDimitry Andric *(void **)&RegisterFrame =
57e8d8bef9SDimitry Andric llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
58e8d8bef9SDimitry Andric
59e8d8bef9SDimitry Andric if (RegisterFrame) {
60e8d8bef9SDimitry Andric RegisterFrame(P);
61e8d8bef9SDimitry Andric return Error::success();
62e8d8bef9SDimitry Andric }
63e8d8bef9SDimitry Andric
64e8d8bef9SDimitry Andric return make_error<StringError>("could not register eh-frame: "
65e8d8bef9SDimitry Andric "__register_frame function not found",
66e8d8bef9SDimitry Andric inconvertibleErrorCode());
67e8d8bef9SDimitry Andric }
68e8d8bef9SDimitry Andric
69e8d8bef9SDimitry Andric static Error deregisterFrameWrapper(const void *P) {
70e8d8bef9SDimitry Andric static void((*DeregisterFrame)(const void *)) = 0;
71e8d8bef9SDimitry Andric
72e8d8bef9SDimitry Andric if (!DeregisterFrame)
73e8d8bef9SDimitry Andric *(void **)&DeregisterFrame =
74e8d8bef9SDimitry Andric llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
75e8d8bef9SDimitry Andric "__deregister_frame");
76e8d8bef9SDimitry Andric
77e8d8bef9SDimitry Andric if (DeregisterFrame) {
78e8d8bef9SDimitry Andric DeregisterFrame(P);
79e8d8bef9SDimitry Andric return Error::success();
80e8d8bef9SDimitry Andric }
81e8d8bef9SDimitry Andric
82e8d8bef9SDimitry Andric return make_error<StringError>("could not deregister eh-frame: "
83e8d8bef9SDimitry Andric "__deregister_frame function not found",
84e8d8bef9SDimitry Andric inconvertibleErrorCode());
85e8d8bef9SDimitry Andric }
86e8d8bef9SDimitry Andric #endif
87e8d8bef9SDimitry Andric
88349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
89e8d8bef9SDimitry Andric
90e8d8bef9SDimitry Andric template <typename HandleFDEFn>
walkLibunwindEHFrameSection(const char * const SectionStart,size_t SectionSize,HandleFDEFn HandleFDE)91349cc55cSDimitry Andric Error walkLibunwindEHFrameSection(const char *const SectionStart,
92e8d8bef9SDimitry Andric size_t SectionSize, HandleFDEFn HandleFDE) {
93e8d8bef9SDimitry Andric const char *CurCFIRecord = SectionStart;
94e8d8bef9SDimitry Andric const char *End = SectionStart + SectionSize;
95e8d8bef9SDimitry Andric uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
96e8d8bef9SDimitry Andric
97e8d8bef9SDimitry Andric while (CurCFIRecord != End && Size != 0) {
98e8d8bef9SDimitry Andric const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
99e8d8bef9SDimitry Andric if (Size == 0xffffffff)
100e8d8bef9SDimitry Andric Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
101e8d8bef9SDimitry Andric else
102e8d8bef9SDimitry Andric Size += 4;
103e8d8bef9SDimitry Andric uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
104e8d8bef9SDimitry Andric
105e8d8bef9SDimitry Andric LLVM_DEBUG({
106e8d8bef9SDimitry Andric dbgs() << "Registering eh-frame section:\n";
107e8d8bef9SDimitry Andric dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
108e8d8bef9SDimitry Andric << (void *)CurCFIRecord << ": [";
109e8d8bef9SDimitry Andric for (unsigned I = 0; I < Size; ++I)
110e8d8bef9SDimitry Andric dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
111e8d8bef9SDimitry Andric dbgs() << " ]\n";
112e8d8bef9SDimitry Andric });
113e8d8bef9SDimitry Andric
114e8d8bef9SDimitry Andric if (Offset != 0)
115e8d8bef9SDimitry Andric if (auto Err = HandleFDE(CurCFIRecord))
116e8d8bef9SDimitry Andric return Err;
117e8d8bef9SDimitry Andric
118e8d8bef9SDimitry Andric CurCFIRecord += Size;
119e8d8bef9SDimitry Andric
120e8d8bef9SDimitry Andric Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
121e8d8bef9SDimitry Andric }
122e8d8bef9SDimitry Andric
123e8d8bef9SDimitry Andric return Error::success();
124e8d8bef9SDimitry Andric }
125e8d8bef9SDimitry Andric
126349cc55cSDimitry Andric #endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__
127e8d8bef9SDimitry Andric
registerEHFrameSection(const void * EHFrameSectionAddr,size_t EHFrameSectionSize)128e8d8bef9SDimitry Andric Error registerEHFrameSection(const void *EHFrameSectionAddr,
129e8d8bef9SDimitry Andric size_t EHFrameSectionSize) {
130349cc55cSDimitry Andric /* libgcc and libunwind __register_frame behave differently. We use the
131349cc55cSDimitry Andric * presence of __unw_add_dynamic_fde to detect libunwind. */
132349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
133349cc55cSDimitry Andric // With libunwind, __register_frame has to be called for each FDE entry.
134349cc55cSDimitry Andric return walkLibunwindEHFrameSection(
135349cc55cSDimitry Andric static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
136349cc55cSDimitry Andric registerFrameWrapper);
137e8d8bef9SDimitry Andric #else
138349cc55cSDimitry Andric // With libgcc, __register_frame takes a single argument:
139e8d8bef9SDimitry Andric // a pointer to the start of the .eh_frame section.
140e8d8bef9SDimitry Andric
141e8d8bef9SDimitry Andric // How can it find the end? Because crtendS.o is linked
142e8d8bef9SDimitry Andric // in and it has an .eh_frame section with four zero chars.
143e8d8bef9SDimitry Andric return registerFrameWrapper(EHFrameSectionAddr);
144e8d8bef9SDimitry Andric #endif
145e8d8bef9SDimitry Andric }
146e8d8bef9SDimitry Andric
deregisterEHFrameSection(const void * EHFrameSectionAddr,size_t EHFrameSectionSize)147e8d8bef9SDimitry Andric Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
148e8d8bef9SDimitry Andric size_t EHFrameSectionSize) {
149349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
150349cc55cSDimitry Andric return walkLibunwindEHFrameSection(
151349cc55cSDimitry Andric static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
152349cc55cSDimitry Andric deregisterFrameWrapper);
153e8d8bef9SDimitry Andric #else
154e8d8bef9SDimitry Andric return deregisterFrameWrapper(EHFrameSectionAddr);
155e8d8bef9SDimitry Andric #endif
156e8d8bef9SDimitry Andric }
157e8d8bef9SDimitry Andric
158e8d8bef9SDimitry Andric } // end namespace orc
159e8d8bef9SDimitry Andric } // end namespace llvm
160e8d8bef9SDimitry Andric
registerEHFrameWrapper(ExecutorAddrRange EHFrame)161*04eeddc0SDimitry Andric static Error registerEHFrameWrapper(ExecutorAddrRange EHFrame) {
162*04eeddc0SDimitry Andric return llvm::orc::registerEHFrameSection(EHFrame.Start.toPtr<const void *>(),
163*04eeddc0SDimitry Andric EHFrame.size());
164fe6060f1SDimitry Andric }
165fe6060f1SDimitry Andric
deregisterEHFrameWrapper(ExecutorAddrRange EHFrame)166*04eeddc0SDimitry Andric static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) {
167*04eeddc0SDimitry Andric return llvm::orc::deregisterEHFrameSection(
168*04eeddc0SDimitry Andric EHFrame.Start.toPtr<const void *>(), EHFrame.size());
169349cc55cSDimitry Andric }
170349cc55cSDimitry Andric
171349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerEHFrameSectionWrapper(const char * Data,uint64_t Size)172fe6060f1SDimitry Andric llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) {
173*04eeddc0SDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
174fe6060f1SDimitry Andric Data, Size, registerEHFrameWrapper)
175e8d8bef9SDimitry Andric .release();
176e8d8bef9SDimitry Andric }
177e8d8bef9SDimitry Andric
178349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_deregisterEHFrameSectionWrapper(const char * Data,uint64_t Size)179fe6060f1SDimitry Andric llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) {
180*04eeddc0SDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
181fe6060f1SDimitry Andric Data, Size, deregisterEHFrameWrapper)
182e8d8bef9SDimitry Andric .release();
183e8d8bef9SDimitry Andric }
184