diff --git a/src/unwinder/sentry_unwinder_libbacktrace.c b/src/unwinder/sentry_unwinder_libbacktrace.c index dd671a958..31ba6643c 100644 --- a/src/unwinder/sentry_unwinder_libbacktrace.c +++ b/src/unwinder/sentry_unwinder_libbacktrace.c @@ -6,10 +6,115 @@ # define HAS_EXECINFO_H #endif +#if defined(SENTRY_PLATFORM_MACOS) && defined(MAC_OS_X_VERSION_10_6) +# define HAS_LIBUNWIND +#endif + #ifdef HAS_EXECINFO_H # include #endif +#ifdef HAS_LIBUNWIND +# include + +# define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) + +static size_t +sentry__unwind_stack_libbacktrace_libnuwind( + const sentry_ucontext_t *uctx, void **ptrs, size_t max_frames) +{ + unw_context_t ctx; + if (unw_getcontext(&ctx)) + return 0; + + unw_cursor_t cursor; + if (unw_init_local(&cursor, &ctx)) + return 0; + +# if defined(__x86_64__) + if (unw_set_reg(&cursor, UNW_X86_64_RAX, + uctx->user_context->uc_mcontext->__ss.__rax) + || unw_set_reg(&cursor, UNW_X86_64_RDX, + uctx->user_context->uc_mcontext->__ss.__rdx) + || unw_set_reg(&cursor, UNW_X86_64_RCX, + uctx->user_context->uc_mcontext->__ss.__rcx) + || unw_set_reg(&cursor, UNW_X86_64_RBX, + uctx->user_context->uc_mcontext->__ss.__rbx) + || unw_set_reg(&cursor, UNW_X86_64_RSI, + uctx->user_context->uc_mcontext->__ss.__rsi) + || unw_set_reg(&cursor, UNW_X86_64_RDI, + uctx->user_context->uc_mcontext->__ss.__rdi) + || unw_set_reg(&cursor, UNW_X86_64_RBP, + uctx->user_context->uc_mcontext->__ss.__rbp) + || unw_set_reg(&cursor, UNW_X86_64_RSP, + uctx->user_context->uc_mcontext->__ss.__rsp) + || unw_set_reg( + &cursor, UNW_X86_64_R8, uctx->user_context->uc_mcontext->__ss.__r8) + || unw_set_reg( + &cursor, UNW_X86_64_R9, uctx->user_context->uc_mcontext->__ss.__r9) + || unw_set_reg(&cursor, UNW_X86_64_R10, + uctx->user_context->uc_mcontext->__ss.__r10) + || unw_set_reg(&cursor, UNW_X86_64_R11, + uctx->user_context->uc_mcontext->__ss.__r11) + || unw_set_reg(&cursor, UNW_X86_64_R12, + uctx->user_context->uc_mcontext->__ss.__r12) + || unw_set_reg(&cursor, UNW_X86_64_R13, + uctx->user_context->uc_mcontext->__ss.__r13) + || unw_set_reg(&cursor, UNW_X86_64_R14, + uctx->user_context->uc_mcontext->__ss.__r14) + || unw_set_reg(&cursor, UNW_X86_64_R15, + uctx->user_context->uc_mcontext->__ss.__r15) + || unw_set_reg( + &cursor, UNW_REG_IP, uctx->user_context->uc_mcontext->__ss.__rip)) + return 0; + +# elif defined(__arm64__) + for (size_t i = 0; + i < ARRAY_SIZE(uctx->user_context->uc_mcontext->__ss.__x); ++i) { + if (unw_set_reg(&cursor, UNW_AARCH64_X0 + i, + uctx->user_context->uc_mcontext->__ss.__x[i])) { + return 0; + } + } + + if (unw_set_reg( + &cursor, UNW_AARCH64_FP, uctx->user_context->uc_mcontext->__ss.__fp) + || unw_set_reg( + &cursor, UNW_AARCH64_LR, uctx->user_context->uc_mcontext->__ss.__lr) + || unw_set_reg( + &cursor, UNW_AARCH64_SP, uctx->user_context->uc_mcontext->__ss.__sp) + || unw_set_reg( + &cursor, UNW_REG_IP, uctx->user_context->uc_mcontext->__ss.__pc)) + return 0; + +# endif + + size_t n = 0; + for (int err = 1; err >= 0 && n < max_frames; err = unw_step(&cursor)) { + unw_word_t ip; + if (unw_get_reg(&cursor, UNW_REG_IP, &ip)) { + break; + } + +# if defined(__arm64__) + // Strip pointer authentication, for some reason ptrauth_strip() not + // working + // https://developer.apple.com/documentation/security/preparing_your_app_to_work_with_pointer_authentication + ip &= 0x7fffffffffffull; +# endif + + ptrs[n++] = (void *)ip; + + // last frame + if (err == 0) { + break; + } + } + + return n; +} +#endif + size_t sentry__unwind_stack_libbacktrace( void *addr, const sentry_ucontext_t *uctx, void **ptrs, size_t max_frames) @@ -23,7 +128,12 @@ sentry__unwind_stack_libbacktrace( #endif return 0; } else if (uctx) { +#ifdef HAS_LIBUNWIND + return sentry__unwind_stack_libbacktrace_libnuwind( + uctx, ptrs, max_frames); +#else return 0; +#endif } #ifdef HAS_EXECINFO_H return (size_t)backtrace(ptrs, (int)max_frames);