| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <libunwind.h> |
| |
|
| | #include "libunwind_ext.h" |
| | #include "config.h" |
| |
|
| | #include <stdlib.h> |
| |
|
| |
|
| | #if !defined(__USING_SJLJ_EXCEPTIONS__) |
| | #include "AddressSpace.hpp" |
| | #include "UnwindCursor.hpp" |
| |
|
| | using namespace libunwind; |
| |
|
| | |
| | LocalAddressSpace LocalAddressSpace::sThisAddressSpace; |
| |
|
| | _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = |
| | (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; |
| |
|
| | |
| | |
| | _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor, |
| | unw_context_t *context) { |
| | _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)", |
| | static_cast<void *>(cursor), |
| | static_cast<void *>(context)); |
| | #if defined(__i386__) |
| | # define REGISTER_KIND Registers_x86 |
| | #elif defined(__x86_64__) |
| | # define REGISTER_KIND Registers_x86_64 |
| | #elif defined(__powerpc64__) |
| | # define REGISTER_KIND Registers_ppc64 |
| | #elif defined(__ppc__) |
| | # define REGISTER_KIND Registers_ppc |
| | #elif defined(__aarch64__) |
| | # define REGISTER_KIND Registers_arm64 |
| | #elif defined(__arm__) |
| | # define REGISTER_KIND Registers_arm |
| | #elif defined(__or1k__) |
| | # define REGISTER_KIND Registers_or1k |
| | #elif defined(__hexagon__) |
| | # define REGISTER_KIND Registers_hexagon |
| | #elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32 |
| | # define REGISTER_KIND Registers_mips_o32 |
| | #elif defined(__mips64) |
| | # define REGISTER_KIND Registers_mips_newabi |
| | #elif defined(__mips__) |
| | # error The MIPS architecture is not supported with this ABI and environment! |
| | #elif defined(__sparc__) |
| | # define REGISTER_KIND Registers_sparc |
| | #elif defined(__riscv) && __riscv_xlen == 64 |
| | # define REGISTER_KIND Registers_riscv |
| | #else |
| | # error Architecture not supported |
| | #endif |
| | |
| | new (static_cast<void *>(cursor)) |
| | UnwindCursor<LocalAddressSpace, REGISTER_KIND>( |
| | context, LocalAddressSpace::sThisAddressSpace); |
| | #undef REGISTER_KIND |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | co->setInfoBasedOnIPRegister(); |
| |
|
| | return UNW_ESUCCESS; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, |
| | unw_word_t *value) { |
| | _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)", |
| | static_cast<void *>(cursor), regNum, |
| | static_cast<void *>(value)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | if (co->validReg(regNum)) { |
| | *value = co->getReg(regNum); |
| | return UNW_ESUCCESS; |
| | } |
| | return UNW_EBADREG; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, |
| | unw_word_t value) { |
| | _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR |
| | ")", |
| | static_cast<void *>(cursor), regNum, value); |
| | typedef LocalAddressSpace::pint_t pint_t; |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | if (co->validReg(regNum)) { |
| | co->setReg(regNum, (pint_t)value); |
| | |
| | |
| | if (regNum == UNW_REG_IP) { |
| | unw_proc_info_t info; |
| | |
| | co->getInfo(&info); |
| | co->setInfoBasedOnIPRegister(false); |
| | |
| | |
| | |
| | |
| | |
| | |
| | if (info.gp) |
| | co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp); |
| | } |
| | return UNW_ESUCCESS; |
| | } |
| | return UNW_EBADREG; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, |
| | unw_fpreg_t *value) { |
| | _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)", |
| | static_cast<void *>(cursor), regNum, |
| | static_cast<void *>(value)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | if (co->validFloatReg(regNum)) { |
| | *value = co->getFloatReg(regNum); |
| | return UNW_ESUCCESS; |
| | } |
| | return UNW_EBADREG; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, |
| | unw_fpreg_t value) { |
| | #if defined(_LIBUNWIND_ARM_EHABI) |
| | _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)", |
| | static_cast<void *>(cursor), regNum, value); |
| | #else |
| | _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)", |
| | static_cast<void *>(cursor), regNum, value); |
| | #endif |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | if (co->validFloatReg(regNum)) { |
| | co->setFloatReg(regNum, value); |
| | return UNW_ESUCCESS; |
| | } |
| | return UNW_EBADREG; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) { |
| | _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast<void *>(cursor)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | return co->step(); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor, |
| | unw_proc_info_t *info) { |
| | _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)", |
| | static_cast<void *>(cursor), static_cast<void *>(info)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | co->getInfo(info); |
| | if (info->end_ip == 0) |
| | return UNW_ENOINFO; |
| | return UNW_ESUCCESS; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) { |
| | _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | co->jumpto(); |
| | return UNW_EUNSPEC; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf, |
| | size_t bufLen, unw_word_t *offset) { |
| | _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)", |
| | static_cast<void *>(cursor), static_cast<void *>(buf), |
| | static_cast<unsigned long>(bufLen)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | if (co->getFunctionName(buf, bufLen, offset)) |
| | return UNW_ESUCCESS; |
| | return UNW_EUNSPEC; |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor, |
| | unw_regnum_t regNum) { |
| | _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)", |
| | static_cast<void *>(cursor), regNum); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | return co->validFloatReg(regNum); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor, |
| | unw_regnum_t regNum) { |
| | _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)", |
| | static_cast<void *>(cursor), regNum); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | return co->getRegisterName(regNum); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname) |
| |
|
| | |
| | _LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) { |
| | _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)", |
| | static_cast<void *>(cursor)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | return co->isSignalFrame(); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame) |
| |
|
| | #ifdef __arm__ |
| | |
| | _LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) { |
| | _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)", |
| | static_cast<void *>(cursor)); |
| | AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; |
| | return co->saveVFPAsX(); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X) |
| | #endif |
| |
|
| |
|
| | #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) |
| | |
| | _LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)( |
| | unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { |
| | _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)", |
| | reinterpret_cast<void *>(func)); |
| | DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func); |
| | } |
| | _LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache, |
| | unw_iterate_dwarf_unwind_cache) |
| |
|
| | |
| | void __unw_add_dynamic_fde(unw_word_t fde) { |
| | CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; |
| | CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; |
| | const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( |
| | LocalAddressSpace::sThisAddressSpace, |
| | (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); |
| | if (message == NULL) { |
| | |
| | |
| | unw_word_t mh_group = fdeInfo.fdeStart; |
| | DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, |
| | fdeInfo.pcStart, fdeInfo.pcEnd, |
| | fdeInfo.fdeStart); |
| | } else { |
| | _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message); |
| | } |
| | } |
| |
|
| | |
| | void __unw_remove_dynamic_fde(unw_word_t fde) { |
| | |
| | DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); |
| | } |
| | #endif |
| | #endif |
| |
|
| |
|
| |
|
| | |
| | #ifndef NDEBUG |
| | #include <stdlib.h> |
| |
|
| | _LIBUNWIND_HIDDEN |
| | bool logAPIs() { |
| | |
| | static bool checked = false; |
| | static bool log = false; |
| | if (!checked) { |
| | log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); |
| | checked = true; |
| | } |
| | return log; |
| | } |
| |
|
| | _LIBUNWIND_HIDDEN |
| | bool logUnwinding() { |
| | |
| | static bool checked = false; |
| | static bool log = false; |
| | if (!checked) { |
| | log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); |
| | checked = true; |
| | } |
| | return log; |
| | } |
| |
|
| | _LIBUNWIND_HIDDEN |
| | bool logDWARF() { |
| | |
| | static bool checked = false; |
| | static bool log = false; |
| | if (!checked) { |
| | log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL); |
| | checked = true; |
| | } |
| | return log; |
| | } |
| |
|
| | #endif |
| |
|
| |
|