1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 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 // Implements unw_* functions from <libunwind.h> 90b57cec5SDimitry Andric // 100b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <libunwind.h> 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "config.h" 15349cc55cSDimitry Andric #include "libunwind_ext.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include <stdlib.h> 180b57cec5SDimitry Andric 19fe6060f1SDimitry Andric // Define the __has_feature extension for compilers that do not support it so 20fe6060f1SDimitry Andric // that we can later check for the presence of ASan in a compiler-neutral way. 21fe6060f1SDimitry Andric #if !defined(__has_feature) 22fe6060f1SDimitry Andric #define __has_feature(feature) 0 23fe6060f1SDimitry Andric #endif 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) 26fe6060f1SDimitry Andric #include <sanitizer/asan_interface.h> 27fe6060f1SDimitry Andric #endif 280b57cec5SDimitry Andric 29*0fca6ea1SDimitry Andric #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) 300b57cec5SDimitry Andric #include "AddressSpace.hpp" 310b57cec5SDimitry Andric #include "UnwindCursor.hpp" 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace libunwind; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric /// internal object to represent this processes address space 360b57cec5SDimitry Andric LocalAddressSpace LocalAddressSpace::sThisAddressSpace; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = 390b57cec5SDimitry Andric (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric /// Create a cursor of a thread in this process given 'context' recorded by 420b57cec5SDimitry Andric /// __unw_getcontext(). 430b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, 440b57cec5SDimitry Andric unw_context_t *context) { 450b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)", 460b57cec5SDimitry Andric static_cast<void *>(cursor), 470b57cec5SDimitry Andric static_cast<void *>(context)); 480b57cec5SDimitry Andric #if defined(__i386__) 490b57cec5SDimitry Andric # define REGISTER_KIND Registers_x86 500b57cec5SDimitry Andric #elif defined(__x86_64__) 510b57cec5SDimitry Andric # define REGISTER_KIND Registers_x86_64 520b57cec5SDimitry Andric #elif defined(__powerpc64__) 530b57cec5SDimitry Andric # define REGISTER_KIND Registers_ppc64 541fd87a68SDimitry Andric #elif defined(__powerpc__) 550b57cec5SDimitry Andric # define REGISTER_KIND Registers_ppc 560b57cec5SDimitry Andric #elif defined(__aarch64__) 570b57cec5SDimitry Andric # define REGISTER_KIND Registers_arm64 580b57cec5SDimitry Andric #elif defined(__arm__) 590b57cec5SDimitry Andric # define REGISTER_KIND Registers_arm 600b57cec5SDimitry Andric #elif defined(__or1k__) 610b57cec5SDimitry Andric # define REGISTER_KIND Registers_or1k 625ffd83dbSDimitry Andric #elif defined(__hexagon__) 635ffd83dbSDimitry Andric # define REGISTER_KIND Registers_hexagon 640b57cec5SDimitry Andric #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 650b57cec5SDimitry Andric # define REGISTER_KIND Registers_mips_o32 660b57cec5SDimitry Andric #elif defined(__mips64) 670b57cec5SDimitry Andric # define REGISTER_KIND Registers_mips_newabi 680b57cec5SDimitry Andric #elif defined(__mips__) 690b57cec5SDimitry Andric # warning The MIPS architecture is not supported with this ABI and environment! 70d56accc7SDimitry Andric #elif defined(__sparc__) && defined(__arch64__) 71d56accc7SDimitry Andric #define REGISTER_KIND Registers_sparc64 720b57cec5SDimitry Andric #elif defined(__sparc__) 730b57cec5SDimitry Andric # define REGISTER_KIND Registers_sparc 74fe6060f1SDimitry Andric #elif defined(__riscv) 75480093f4SDimitry Andric # define REGISTER_KIND Registers_riscv 76e8d8bef9SDimitry Andric #elif defined(__ve__) 77e8d8bef9SDimitry Andric # define REGISTER_KIND Registers_ve 7881ad6265SDimitry Andric #elif defined(__s390x__) 7981ad6265SDimitry Andric # define REGISTER_KIND Registers_s390x 80bdd1243dSDimitry Andric #elif defined(__loongarch__) && __loongarch_grlen == 64 81bdd1243dSDimitry Andric #define REGISTER_KIND Registers_loongarch 820b57cec5SDimitry Andric #else 830b57cec5SDimitry Andric # error Architecture not supported 840b57cec5SDimitry Andric #endif 850b57cec5SDimitry Andric // Use "placement new" to allocate UnwindCursor in the cursor buffer. 860b57cec5SDimitry Andric new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor)) 870b57cec5SDimitry Andric UnwindCursor<LocalAddressSpace, REGISTER_KIND>( 880b57cec5SDimitry Andric context, LocalAddressSpace::sThisAddressSpace); 890b57cec5SDimitry Andric #undef REGISTER_KIND 900b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 910b57cec5SDimitry Andric co->setInfoBasedOnIPRegister(); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric return UNW_ESUCCESS; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local) 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric /// Get value of specified register at cursor position in stack frame. 980b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, 990b57cec5SDimitry Andric unw_word_t *value) { 1000b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)", 1010b57cec5SDimitry Andric static_cast<void *>(cursor), regNum, 1020b57cec5SDimitry Andric static_cast<void *>(value)); 1030b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 1040b57cec5SDimitry Andric if (co->validReg(regNum)) { 1050b57cec5SDimitry Andric *value = co->getReg(regNum); 1060b57cec5SDimitry Andric return UNW_ESUCCESS; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric return UNW_EBADREG; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg) 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric /// Set value of specified register at cursor position in stack frame. 1130b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, 1140b57cec5SDimitry Andric unw_word_t value) { 1150b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR 1160b57cec5SDimitry Andric ")", 1170b57cec5SDimitry Andric static_cast<void *>(cursor), regNum, value); 1180b57cec5SDimitry Andric typedef LocalAddressSpace::pint_t pint_t; 1190b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 1200b57cec5SDimitry Andric if (co->validReg(regNum)) { 1210b57cec5SDimitry Andric co->setReg(regNum, (pint_t)value); 122bdd1243dSDimitry Andric // special case altering IP to re-find info (being called by personality 1230b57cec5SDimitry Andric // function) 1240b57cec5SDimitry Andric if (regNum == UNW_REG_IP) { 1250b57cec5SDimitry Andric unw_proc_info_t info; 1260b57cec5SDimitry Andric // First, get the FDE for the old location and then update it. 1270b57cec5SDimitry Andric co->getInfo(&info); 1280b57cec5SDimitry Andric co->setInfoBasedOnIPRegister(false); 1290b57cec5SDimitry Andric // If the original call expects stack adjustment, perform this now. 1300b57cec5SDimitry Andric // Normal frame unwinding would have included the offset already in the 1310b57cec5SDimitry Andric // CFA computation. 1320b57cec5SDimitry Andric // Note: for PA-RISC and other platforms where the stack grows up, 1330b57cec5SDimitry Andric // this should actually be - info.gp. LLVM doesn't currently support 1340b57cec5SDimitry Andric // any such platforms and Clang doesn't export a macro for them. 1350b57cec5SDimitry Andric if (info.gp) 1360b57cec5SDimitry Andric co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric return UNW_ESUCCESS; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric return UNW_EBADREG; 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg) 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric /// Get value of specified float register at cursor position in stack frame. 1450b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, 1460b57cec5SDimitry Andric unw_fpreg_t *value) { 1470b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", 1480b57cec5SDimitry Andric static_cast<void *>(cursor), regNum, 1490b57cec5SDimitry Andric static_cast<void *>(value)); 1500b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 1510b57cec5SDimitry Andric if (co->validFloatReg(regNum)) { 1520b57cec5SDimitry Andric *value = co->getFloatReg(regNum); 1530b57cec5SDimitry Andric return UNW_ESUCCESS; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric return UNW_EBADREG; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg) 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric /// Set value of specified float register at cursor position in stack frame. 1600b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, 1610b57cec5SDimitry Andric unw_fpreg_t value) { 1620b57cec5SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI) 1630b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", 1640b57cec5SDimitry Andric static_cast<void *>(cursor), regNum, value); 1650b57cec5SDimitry Andric #else 1660b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", 1670b57cec5SDimitry Andric static_cast<void *>(cursor), regNum, value); 1680b57cec5SDimitry Andric #endif 1690b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 1700b57cec5SDimitry Andric if (co->validFloatReg(regNum)) { 1710b57cec5SDimitry Andric co->setFloatReg(regNum, value); 1720b57cec5SDimitry Andric return UNW_ESUCCESS; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric return UNW_EBADREG; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg) 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric /// Move cursor to next frame. 1790b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) { 1800b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast<void *>(cursor)); 1810b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 1820b57cec5SDimitry Andric return co->step(); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step) 1850b57cec5SDimitry Andric 186bdd1243dSDimitry Andric // Move cursor to next frame and for stage2 of unwinding. 187bdd1243dSDimitry Andric // This resets MTE tags of tagged frames to zero. 188bdd1243dSDimitry Andric extern "C" _LIBUNWIND_HIDDEN int __unw_step_stage2(unw_cursor_t *cursor) { 189bdd1243dSDimitry Andric _LIBUNWIND_TRACE_API("__unw_step_stage2(cursor=%p)", 190bdd1243dSDimitry Andric static_cast<void *>(cursor)); 191bdd1243dSDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 192bdd1243dSDimitry Andric return co->step(true); 193bdd1243dSDimitry Andric } 194bdd1243dSDimitry Andric 1950b57cec5SDimitry Andric /// Get unwind info at cursor position in stack frame. 1960b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor, 1970b57cec5SDimitry Andric unw_proc_info_t *info) { 1980b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)", 1990b57cec5SDimitry Andric static_cast<void *>(cursor), static_cast<void *>(info)); 2000b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2010b57cec5SDimitry Andric co->getInfo(info); 2020b57cec5SDimitry Andric if (info->end_ip == 0) 2030b57cec5SDimitry Andric return UNW_ENOINFO; 2040b57cec5SDimitry Andric return UNW_ESUCCESS; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info) 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric /// Resume execution at cursor position (aka longjump). 2090b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) { 2100b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor)); 211fe6060f1SDimitry Andric #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) 212fe6060f1SDimitry Andric // Inform the ASan runtime that now might be a good time to clean stuff up. 213fe6060f1SDimitry Andric __asan_handle_no_return(); 214fe6060f1SDimitry Andric #endif 2150b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2160b57cec5SDimitry Andric co->jumpto(); 2170b57cec5SDimitry Andric return UNW_EUNSPEC; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume) 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric /// Get name of function at cursor position in stack frame. 2220b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf, 2230b57cec5SDimitry Andric size_t bufLen, unw_word_t *offset) { 2240b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", 2250b57cec5SDimitry Andric static_cast<void *>(cursor), static_cast<void *>(buf), 2260b57cec5SDimitry Andric static_cast<unsigned long>(bufLen)); 2270b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2280b57cec5SDimitry Andric if (co->getFunctionName(buf, bufLen, offset)) 2290b57cec5SDimitry Andric return UNW_ESUCCESS; 2300b57cec5SDimitry Andric return UNW_EUNSPEC; 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name) 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric /// Checks if a register is a floating-point register. 2350b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor, 2360b57cec5SDimitry Andric unw_regnum_t regNum) { 2370b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)", 2380b57cec5SDimitry Andric static_cast<void *>(cursor), regNum); 2390b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2400b57cec5SDimitry Andric return co->validFloatReg(regNum); 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg) 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric /// Checks if a register is a floating-point register. 2450b57cec5SDimitry Andric _LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor, 2460b57cec5SDimitry Andric unw_regnum_t regNum) { 2470b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)", 2480b57cec5SDimitry Andric static_cast<void *>(cursor), regNum); 2490b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2500b57cec5SDimitry Andric return co->getRegisterName(regNum); 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname) 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric /// Checks if current frame is signal trampoline. 2550b57cec5SDimitry Andric _LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) { 2560b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)", 2570b57cec5SDimitry Andric static_cast<void *>(cursor)); 2580b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2590b57cec5SDimitry Andric return co->isSignalFrame(); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame) 2620b57cec5SDimitry Andric 26381ad6265SDimitry Andric #ifdef _AIX 26481ad6265SDimitry Andric _LIBUNWIND_EXPORT uintptr_t __unw_get_data_rel_base(unw_cursor_t *cursor) { 26581ad6265SDimitry Andric _LIBUNWIND_TRACE_API("unw_get_data_rel_base(cursor=%p)", 26681ad6265SDimitry Andric static_cast<void *>(cursor)); 26781ad6265SDimitry Andric AbstractUnwindCursor *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 26881ad6265SDimitry Andric return co->getDataRelBase(); 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_get_data_rel_base, unw_get_data_rel_base) 27181ad6265SDimitry Andric #endif 27281ad6265SDimitry Andric 2730b57cec5SDimitry Andric #ifdef __arm__ 2740b57cec5SDimitry Andric // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD 2750b57cec5SDimitry Andric _LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) { 2760b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)", 2770b57cec5SDimitry Andric static_cast<void *>(cursor)); 2780b57cec5SDimitry Andric AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 2790b57cec5SDimitry Andric return co->saveVFPAsX(); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X) 2820b57cec5SDimitry Andric #endif 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 2860b57cec5SDimitry Andric /// SPI: walks cached DWARF entries 2870b57cec5SDimitry Andric _LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)( 2880b57cec5SDimitry Andric unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { 2890b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)", 2900b57cec5SDimitry Andric reinterpret_cast<void *>(func)); 2910b57cec5SDimitry Andric DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric _LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache, 2940b57cec5SDimitry Andric unw_iterate_dwarf_unwind_cache) 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric /// IPI: for __register_frame() 2970b57cec5SDimitry Andric void __unw_add_dynamic_fde(unw_word_t fde) { 2980b57cec5SDimitry Andric CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 2990b57cec5SDimitry Andric CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 3000b57cec5SDimitry Andric const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( 3010b57cec5SDimitry Andric LocalAddressSpace::sThisAddressSpace, 3020b57cec5SDimitry Andric (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); 3030b57cec5SDimitry Andric if (message == NULL) { 3040b57cec5SDimitry Andric // dynamically registered FDEs don't have a mach_header group they are in. 3050b57cec5SDimitry Andric // Use fde as mh_group 3060b57cec5SDimitry Andric unw_word_t mh_group = fdeInfo.fdeStart; 3070b57cec5SDimitry Andric DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, 3080b57cec5SDimitry Andric fdeInfo.pcStart, fdeInfo.pcEnd, 3090b57cec5SDimitry Andric fdeInfo.fdeStart); 3100b57cec5SDimitry Andric } else { 3110b57cec5SDimitry Andric _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric /// IPI: for __deregister_frame() 3160b57cec5SDimitry Andric void __unw_remove_dynamic_fde(unw_word_t fde) { 3170b57cec5SDimitry Andric // fde is own mh_group 3180b57cec5SDimitry Andric DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); 3190b57cec5SDimitry Andric } 320349cc55cSDimitry Andric 321349cc55cSDimitry Andric void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) { 322349cc55cSDimitry Andric // The eh_frame section start serves as the mh_group 323349cc55cSDimitry Andric unw_word_t mh_group = eh_frame_start; 324349cc55cSDimitry Andric CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 325349cc55cSDimitry Andric CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 326349cc55cSDimitry Andric auto p = (LocalAddressSpace::pint_t)eh_frame_start; 3277a6dacacSDimitry Andric while (LocalAddressSpace::sThisAddressSpace.get32(p)) { 328349cc55cSDimitry Andric if (CFI_Parser<LocalAddressSpace>::decodeFDE( 329349cc55cSDimitry Andric LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo, 330349cc55cSDimitry Andric true) == NULL) { 331349cc55cSDimitry Andric DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, 332349cc55cSDimitry Andric fdeInfo.pcStart, fdeInfo.pcEnd, 333349cc55cSDimitry Andric fdeInfo.fdeStart); 334349cc55cSDimitry Andric p += fdeInfo.fdeLength; 335349cc55cSDimitry Andric } else if (CFI_Parser<LocalAddressSpace>::parseCIE( 336349cc55cSDimitry Andric LocalAddressSpace::sThisAddressSpace, p, &cieInfo) == NULL) { 337349cc55cSDimitry Andric p += cieInfo.cieLength; 338349cc55cSDimitry Andric } else 339349cc55cSDimitry Andric return; 340349cc55cSDimitry Andric } 341349cc55cSDimitry Andric } 342349cc55cSDimitry Andric 343349cc55cSDimitry Andric void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) { 344349cc55cSDimitry Andric // The eh_frame section start serves as the mh_group 345349cc55cSDimitry Andric DwarfFDECache<LocalAddressSpace>::removeAllIn( 346349cc55cSDimitry Andric (LocalAddressSpace::pint_t)eh_frame_start); 347349cc55cSDimitry Andric } 348349cc55cSDimitry Andric 3490b57cec5SDimitry Andric #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) 350*0fca6ea1SDimitry Andric #endif // !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__) 3510b57cec5SDimitry Andric 35206c3fb27SDimitry Andric #ifdef __APPLE__ 3530b57cec5SDimitry Andric 35406c3fb27SDimitry Andric namespace libunwind { 35506c3fb27SDimitry Andric 35606c3fb27SDimitry Andric static constexpr size_t MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS = 8; 35706c3fb27SDimitry Andric 35806c3fb27SDimitry Andric static RWMutex findDynamicUnwindSectionsLock; 35906c3fb27SDimitry Andric static size_t numDynamicUnwindSectionsFinders = 0; 36006c3fb27SDimitry Andric static unw_find_dynamic_unwind_sections 36106c3fb27SDimitry Andric dynamicUnwindSectionsFinders[MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS] = {0}; 36206c3fb27SDimitry Andric 36306c3fb27SDimitry Andric bool findDynamicUnwindSections(void *addr, unw_dynamic_unwind_sections *info) { 36406c3fb27SDimitry Andric bool found = false; 36506c3fb27SDimitry Andric findDynamicUnwindSectionsLock.lock_shared(); 36606c3fb27SDimitry Andric for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) { 36706c3fb27SDimitry Andric if (dynamicUnwindSectionsFinders[i]((unw_word_t)addr, info)) { 36806c3fb27SDimitry Andric found = true; 36906c3fb27SDimitry Andric break; 37006c3fb27SDimitry Andric } 37106c3fb27SDimitry Andric } 37206c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock_shared(); 37306c3fb27SDimitry Andric return found; 37406c3fb27SDimitry Andric } 37506c3fb27SDimitry Andric 37606c3fb27SDimitry Andric } // namespace libunwind 37706c3fb27SDimitry Andric 37806c3fb27SDimitry Andric int __unw_add_find_dynamic_unwind_sections( 37906c3fb27SDimitry Andric unw_find_dynamic_unwind_sections find_dynamic_unwind_sections) { 38006c3fb27SDimitry Andric findDynamicUnwindSectionsLock.lock(); 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric // Check that we have enough space... 38306c3fb27SDimitry Andric if (numDynamicUnwindSectionsFinders == MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS) { 38406c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock(); 38506c3fb27SDimitry Andric return UNW_ENOMEM; 38606c3fb27SDimitry Andric } 38706c3fb27SDimitry Andric 38806c3fb27SDimitry Andric // Check for value already present... 38906c3fb27SDimitry Andric for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) { 39006c3fb27SDimitry Andric if (dynamicUnwindSectionsFinders[i] == find_dynamic_unwind_sections) { 39106c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock(); 39206c3fb27SDimitry Andric return UNW_EINVAL; 39306c3fb27SDimitry Andric } 39406c3fb27SDimitry Andric } 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric // Success -- add callback entry. 39706c3fb27SDimitry Andric dynamicUnwindSectionsFinders[numDynamicUnwindSectionsFinders++] = 39806c3fb27SDimitry Andric find_dynamic_unwind_sections; 39906c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock(); 40006c3fb27SDimitry Andric 40106c3fb27SDimitry Andric return UNW_ESUCCESS; 40206c3fb27SDimitry Andric } 40306c3fb27SDimitry Andric 40406c3fb27SDimitry Andric int __unw_remove_find_dynamic_unwind_sections( 40506c3fb27SDimitry Andric unw_find_dynamic_unwind_sections find_dynamic_unwind_sections) { 40606c3fb27SDimitry Andric findDynamicUnwindSectionsLock.lock(); 40706c3fb27SDimitry Andric 40806c3fb27SDimitry Andric // Find index to remove. 40906c3fb27SDimitry Andric size_t finderIdx = numDynamicUnwindSectionsFinders; 41006c3fb27SDimitry Andric for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) { 41106c3fb27SDimitry Andric if (dynamicUnwindSectionsFinders[i] == find_dynamic_unwind_sections) { 41206c3fb27SDimitry Andric finderIdx = i; 41306c3fb27SDimitry Andric break; 41406c3fb27SDimitry Andric } 41506c3fb27SDimitry Andric } 41606c3fb27SDimitry Andric 41706c3fb27SDimitry Andric // If no such registration is present then error out. 41806c3fb27SDimitry Andric if (finderIdx == numDynamicUnwindSectionsFinders) { 41906c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock(); 42006c3fb27SDimitry Andric return UNW_EINVAL; 42106c3fb27SDimitry Andric } 42206c3fb27SDimitry Andric 42306c3fb27SDimitry Andric // Remove entry. 42406c3fb27SDimitry Andric for (size_t i = finderIdx; i != numDynamicUnwindSectionsFinders - 1; ++i) 42506c3fb27SDimitry Andric dynamicUnwindSectionsFinders[i] = dynamicUnwindSectionsFinders[i + 1]; 42606c3fb27SDimitry Andric dynamicUnwindSectionsFinders[--numDynamicUnwindSectionsFinders] = nullptr; 42706c3fb27SDimitry Andric 42806c3fb27SDimitry Andric findDynamicUnwindSectionsLock.unlock(); 42906c3fb27SDimitry Andric return UNW_ESUCCESS; 43006c3fb27SDimitry Andric } 43106c3fb27SDimitry Andric 43206c3fb27SDimitry Andric #endif // __APPLE__ 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric // Add logging hooks in Debug builds only 4350b57cec5SDimitry Andric #ifndef NDEBUG 4360b57cec5SDimitry Andric #include <stdlib.h> 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric _LIBUNWIND_HIDDEN 4390b57cec5SDimitry Andric bool logAPIs() { 4400b57cec5SDimitry Andric // do manual lock to avoid use of _cxa_guard_acquire or initializers 4410b57cec5SDimitry Andric static bool checked = false; 4420b57cec5SDimitry Andric static bool log = false; 4430b57cec5SDimitry Andric if (!checked) { 4440b57cec5SDimitry Andric log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); 4450b57cec5SDimitry Andric checked = true; 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric return log; 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric _LIBUNWIND_HIDDEN 4510b57cec5SDimitry Andric bool logUnwinding() { 4520b57cec5SDimitry Andric // do manual lock to avoid use of _cxa_guard_acquire or initializers 4530b57cec5SDimitry Andric static bool checked = false; 4540b57cec5SDimitry Andric static bool log = false; 4550b57cec5SDimitry Andric if (!checked) { 4560b57cec5SDimitry Andric log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); 4570b57cec5SDimitry Andric checked = true; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric return log; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric _LIBUNWIND_HIDDEN 4630b57cec5SDimitry Andric bool logDWARF() { 4640b57cec5SDimitry Andric // do manual lock to avoid use of _cxa_guard_acquire or initializers 4650b57cec5SDimitry Andric static bool checked = false; 4660b57cec5SDimitry Andric static bool log = false; 4670b57cec5SDimitry Andric if (!checked) { 4680b57cec5SDimitry Andric log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); 4690b57cec5SDimitry Andric checked = true; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric return log; 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric #endif // NDEBUG 4750b57cec5SDimitry Andric 476