From a6504fa17da7e0303c398a20ea6c8d46b3483566 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 27 Mar 2026 21:08:38 +0100 Subject: [PATCH 01/14] feat(native): add remote DWARF unwinding + symbol names for Linux Add libunwind remote unwinding support to the native backend's crash daemon, enabling DWARF-based stack walking and symbol name resolution for all threads (not just the crashing thread) on Linux. - Re-add upstream libunwind src/ptrace/ (_UPT_* accessors) - Add `unwind_remote` CMake target with G-prefix + ptrace sources, only built when SENTRY_BACKEND=native on Linux - New sentry_remote_unwind.c using unw_init_remote() + unw_get_proc_name() - Integrate into daemon's build_stacktrace_for_thread() with fallback to pre-captured backtrace and FP-walking Co-Authored-By: Claude Opus 4.6 (1M context) --- CMakeLists.txt | 12 +- src/CMakeLists.txt | 7 + src/backends/native/sentry_crash_daemon.c | 70 +- src/backends/native/sentry_remote_unwind.c | 111 +++ src/backends/native/sentry_remote_unwind.h | 28 + vendor/libunwind/CMakeLists.txt | 167 +++- vendor/libunwind/VENDORING.md | 35 +- .../libunwind/src/ptrace/_UPT_access_fpreg.c | 146 ++++ vendor/libunwind/src/ptrace/_UPT_access_mem.c | 123 +++ vendor/libunwind/src/ptrace/_UPT_access_reg.c | 402 ++++++++++ vendor/libunwind/src/ptrace/_UPT_accessors.c | 40 + vendor/libunwind/src/ptrace/_UPT_create.c | 48 ++ vendor/libunwind/src/ptrace/_UPT_destroy.c | 34 + vendor/libunwind/src/ptrace/_UPT_elf.c | 5 + .../src/ptrace/_UPT_find_proc_info.c | 145 ++++ .../src/ptrace/_UPT_get_dyn_info_list_addr.c | 112 +++ .../src/ptrace/_UPT_get_elf_filename.c | 38 + .../libunwind/src/ptrace/_UPT_get_proc_name.c | 42 + vendor/libunwind/src/ptrace/_UPT_internal.h | 59 ++ .../src/ptrace/_UPT_ptrauth_insn_mask.c | 58 ++ .../src/ptrace/_UPT_put_unwind_info.c | 35 + vendor/libunwind/src/ptrace/_UPT_reg_offset.c | 740 ++++++++++++++++++ vendor/libunwind/src/ptrace/_UPT_resume.c | 42 + 23 files changed, 2481 insertions(+), 18 deletions(-) create mode 100644 src/backends/native/sentry_remote_unwind.c create mode 100644 src/backends/native/sentry_remote_unwind.h create mode 100644 vendor/libunwind/src/ptrace/_UPT_access_fpreg.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_access_mem.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_access_reg.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_accessors.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_create.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_destroy.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_elf.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_find_proc_info.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_get_elf_filename.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_get_proc_name.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_internal.h create mode 100644 vendor/libunwind/src/ptrace/_UPT_ptrauth_insn_mask.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_put_unwind_info.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_reg_offset.c create mode 100644 vendor/libunwind/src/ptrace/_UPT_resume.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 76b2377197..466bf5f35b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -670,6 +670,10 @@ endif() if(SENTRY_WITH_LIBUNWIND) if(LINUX) + # Build remote unwinding support for the native backend's crash daemon + if(SENTRY_BACKEND_NATIVE) + set(LIBUNWIND_BUILD_REMOTE TRUE) + endif() # Use vendored libunwind add_subdirectory(vendor/libunwind) target_link_libraries(sentry PRIVATE unwind) @@ -835,6 +839,10 @@ elseif(SENTRY_BACKEND_NATIVE) SENTRY_BUILD_STATIC ) + if(SENTRY_WITH_LIBUNWIND AND LINUX) + target_compile_definitions(sentry-crash PRIVATE SENTRY_WITH_REMOTE_UNWIND) + endif() + # Copy include directories from sentry target target_include_directories(sentry-crash PRIVATE ${PROJECT_SOURCE_DIR}/include @@ -874,7 +882,9 @@ elseif(SENTRY_BACKEND_NATIVE) endif() if(SENTRY_WITH_LIBUNWIND AND LINUX) - target_link_libraries(sentry-crash PRIVATE unwind) + # Use unwind_remote for the daemon (includes ptrace accessors + # for remote DWARF unwinding of the crashed process) + target_link_libraries(sentry-crash PRIVATE unwind_remote) endif() # Make sentry library depend on crash daemon so it's always built together diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6086dbaafb..c9d4044ace 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -171,6 +171,13 @@ elseif(SENTRY_BACKEND_NATIVE) backends/native/minidump/sentry_minidump_writer.h ) + # Remote unwinding (Linux only — uses libunwind ptrace accessors) + if(LINUX) + sentry_target_sources_cwd(sentry + backends/native/sentry_remote_unwind.c + ) + endif() + # Platform-specific minidump writers if(LINUX OR ANDROID) sentry_target_sources_cwd(sentry diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index b440aa1d29..b8a774fde5 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -47,6 +47,9 @@ # include # include # endif +# if defined(SENTRY_PLATFORM_LINUX) +# include "sentry_remote_unwind.h" +# endif #elif defined(SENTRY_PLATFORM_WINDOWS) # include # include @@ -900,10 +903,71 @@ build_stacktrace_for_thread( sentry_value_t temp_frames[MAX_STACK_FRAMES]; int frame_count = 0; +#if defined(SENTRY_PLATFORM_LINUX) + // Remote DWARF unwinding via libunwind ptrace accessors. + // Works for all threads (including crashing) and resolves symbol names. + { + pid_t tid = 0; + if (thread_idx == SIZE_MAX || thread_idx == 0) { + tid = ctx->crashed_tid; + } else if (thread_idx < ctx->platform.num_threads) { + tid = ctx->platform.threads[thread_idx].tid; + } + + if (tid > 0) { + sentry_remote_frame_t remote_frames[MAX_STACK_FRAMES]; + size_t remote_count = sentry__remote_unwind_thread( + tid, remote_frames, MAX_STACK_FRAMES); + + if (remote_count > 0) { + SENTRY_DEBUGF("Remote unwound %zu frames for thread %d", + remote_count, tid); + + for (size_t i = 0; + i < remote_count && frame_count < MAX_STACK_FRAMES; i++) { + if (remote_frames[i].ip == 0 + || !is_valid_code_addr(remote_frames[i].ip)) { + continue; + } + temp_frames[frame_count] = sentry_value_new_object(); + sentry_value_set_by_key(temp_frames[frame_count], + "instruction_addr", + sentry__value_new_addr(remote_frames[i].ip)); + sentry_value_set_by_key(temp_frames[frame_count], "trust", + sentry_value_new_string(i == 0 ? "context" : "cfi")); + enrich_frame_with_module_info( + ctx, temp_frames[frame_count], remote_frames[i].ip); + if (remote_frames[i].symbol[0]) { + sentry_value_set_by_key(temp_frames[frame_count], + "function", + sentry_value_new_string(remote_frames[i].symbol)); + } + frame_count++; + } + + if (stack_buf) { + sentry_free(stack_buf); + } + + if (frame_count > 0) { + for (int i = frame_count - 1; i >= 0; i--) { + sentry_value_append(frames, temp_frames[i]); + } + sentry_value_set_by_key(stacktrace, "frames", frames); + sentry_value_set_by_key(stacktrace, "registers", + build_registers_from_ctx(ctx, thread_idx)); + return stacktrace; + } + } + } + } + // Fall through to pre-captured backtrace or FP-walking if remote + // unwinding failed +#endif + #if defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID) - // Use pre-captured libunwind backtrace if available (DWARF-based, works - // without frame pointers). This is preferred over FP-based walking for - // the crashed thread. + // Fallback: use pre-captured libunwind backtrace if available + // (DWARF-based, works without frame pointers). if (ctx->platform.backtrace_count > 0 && (thread_idx == SIZE_MAX || thread_idx == 0)) { SENTRY_DEBUGF("Using pre-captured libunwind backtrace (%zu frames)", diff --git a/src/backends/native/sentry_remote_unwind.c b/src/backends/native/sentry_remote_unwind.c new file mode 100644 index 0000000000..3d2addb6c4 --- /dev/null +++ b/src/backends/native/sentry_remote_unwind.c @@ -0,0 +1,111 @@ +// Remote stack unwinding via libunwind ptrace accessors. +// This file must NOT define UNW_LOCAL_ONLY so that unw_init_remote() +// and other generic (_U prefix) symbols are used. +// +// Only compiled into sentry-crash daemon (SENTRY_WITH_REMOTE_UNWIND). +// The sentry library compiles this file too (shared sources) but the +// function body is empty without the define. + +#include "sentry_remote_unwind.h" + +#ifdef SENTRY_WITH_REMOTE_UNWIND + +# include "sentry_logger.h" + +# include +# include +# include +# include + +# include +# include + +size_t +sentry__remote_unwind_thread( + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +{ + if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) != 0) { + SENTRY_WARNF("remote_unwind: ptrace attach failed for %d: %s", tid, + strerror(errno)); + return 0; + } + + int status; + if (waitpid(tid, &status, __WALL) < 0) { + SENTRY_WARNF( + "remote_unwind: waitpid failed for %d: %s", tid, strerror(errno)); + ptrace(PTRACE_DETACH, tid, NULL, NULL); + return 0; + } + + size_t n = 0; + + unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0); + if (!as) { + SENTRY_WARN("remote_unwind: unw_create_addr_space failed"); + goto detach; + } + + void *upt = _UPT_create(tid); + if (!upt) { + SENTRY_WARN("remote_unwind: _UPT_create failed"); + unw_destroy_addr_space(as); + goto detach; + } + + unw_cursor_t cursor; + int ret = unw_init_remote(&cursor, as, upt); + if (ret < 0) { + SENTRY_WARNF("remote_unwind: unw_init_remote failed: %d", ret); + _UPT_destroy(upt); + unw_destroy_addr_space(as); + goto detach; + } + + while (n < max_frames) { + unw_word_t ip = 0; + if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0 || ip == 0) { + break; + } + + frames[n].ip = (uint64_t)ip; + frames[n].symbol[0] = '\0'; + frames[n].symbol_offset = 0; + + unw_word_t off = 0; + if (unw_get_proc_name( + &cursor, frames[n].symbol, sizeof(frames[n].symbol), &off) + == 0) { + frames[n].symbol_offset = (uint64_t)off; + } + + n++; + + if (unw_step(&cursor) <= 0) { + break; + } + } + + _UPT_destroy(upt); + unw_destroy_addr_space(as); + +detach: + ptrace(PTRACE_DETACH, tid, NULL, NULL); + + SENTRY_DEBUGF("Remote unwound %zu frames for thread %d", n, tid); + return n; +} + +#else /* !SENTRY_WITH_REMOTE_UNWIND */ + +size_t +sentry__remote_unwind_thread( + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +{ + (void)tid; + (void)frames; + (void)max_frames; + return 0; +} + +#endif /* SENTRY_WITH_REMOTE_UNWIND */ diff --git a/src/backends/native/sentry_remote_unwind.h b/src/backends/native/sentry_remote_unwind.h new file mode 100644 index 0000000000..998d2cf034 --- /dev/null +++ b/src/backends/native/sentry_remote_unwind.h @@ -0,0 +1,28 @@ +#ifndef SENTRY_REMOTE_UNWIND_H_INCLUDED +#define SENTRY_REMOTE_UNWIND_H_INCLUDED + +#include +#include +#include + +#define SENTRY_REMOTE_UNWIND_MAX_SYMBOL 256 + +typedef struct { + uint64_t ip; + char symbol[SENTRY_REMOTE_UNWIND_MAX_SYMBOL]; + uint64_t symbol_offset; +} sentry_remote_frame_t; + +/** + * Remotely unwind a thread's stack using libunwind ptrace accessors. + * Handles ptrace attach/detach internally. + * + * @param tid Thread ID to unwind + * @param frames Output array of frames + * @param max_frames Maximum number of frames to capture + * @return Number of frames captured, or 0 on failure + */ +size_t sentry__remote_unwind_thread( + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames); + +#endif diff --git a/vendor/libunwind/CMakeLists.txt b/vendor/libunwind/CMakeLists.txt index 6a684f0c95..7d76c3ff61 100644 --- a/vendor/libunwind/CMakeLists.txt +++ b/vendor/libunwind/CMakeLists.txt @@ -1,5 +1,7 @@ # CMakeLists.txt for vendored libunwind (Linux only; x86_64, aarch64, x86, arm) -# This builds only the local unwinding library (libunwind.a equivalent) +# Builds the local unwinding library (libunwind.a equivalent). +# When LIBUNWIND_BUILD_REMOTE is set, also builds unwind_remote with +# generic (G-prefix) sources and ptrace accessors for remote unwinding. # Vendored libunwind - built as a subdirectory of the main project. # Enable ASM for the .S sources without a nested project() call. @@ -289,3 +291,166 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") endif() target_link_libraries(unwind PRIVATE ${CMAKE_DL_LIBS} pthread) + +# --- Remote unwinding support (optional, for native backend daemon) --- +if(LIBUNWIND_BUILD_REMOTE) + +# Generic (G-prefix) sources — compiled WITHOUT UNW_LOCAL_ONLY. +# Produce _U_ symbols that coexist with the _UL_ local symbols. +set(UNWIND_GENERIC_MI_SOURCES + ${LIBUNWIND_SRC}/mi/Gaddress_validator.c + ${LIBUNWIND_SRC}/mi/Gdestroy_addr_space.c + ${LIBUNWIND_SRC}/mi/Gdyn-extract.c + ${LIBUNWIND_SRC}/mi/Gdyn-remote.c + ${LIBUNWIND_SRC}/mi/Gfind_dynamic_proc_info.c + ${LIBUNWIND_SRC}/mi/Gget_accessors.c + ${LIBUNWIND_SRC}/mi/Gget_elf_filename.c + ${LIBUNWIND_SRC}/mi/Gget_fpreg.c + ${LIBUNWIND_SRC}/mi/Gget_proc_info_by_ip.c + ${LIBUNWIND_SRC}/mi/Gget_proc_name.c + ${LIBUNWIND_SRC}/mi/Gget_reg.c + ${LIBUNWIND_SRC}/mi/Gis_plt_entry.c + ${LIBUNWIND_SRC}/mi/Gput_dynamic_unwind_info.c + ${LIBUNWIND_SRC}/mi/Gset_cache_size.c + ${LIBUNWIND_SRC}/mi/Gset_caching_policy.c + ${LIBUNWIND_SRC}/mi/Gset_fpreg.c + ${LIBUNWIND_SRC}/mi/Gset_iterate_phdr_function.c + ${LIBUNWIND_SRC}/mi/Gset_reg.c +) + +set(UNWIND_GENERIC_DWARF_SOURCES + ${LIBUNWIND_SRC}/dwarf/Gexpr.c + ${LIBUNWIND_SRC}/dwarf/Gfde.c + ${LIBUNWIND_SRC}/dwarf/Gfind_proc_info-lsb.c + ${LIBUNWIND_SRC}/dwarf/Gfind_unwind_table.c + ${LIBUNWIND_SRC}/dwarf/Gget_proc_info_in_range.c + ${LIBUNWIND_SRC}/dwarf/Gparser.c + ${LIBUNWIND_SRC}/dwarf/Gpe.c +) + +if(UNWIND_ARCH STREQUAL "x86_64") + set(UNWIND_GENERIC_ARCH_SOURCES + ${LIBUNWIND_SRC}/x86_64/Gos-linux.c + ${LIBUNWIND_SRC}/x86_64/Gapply_reg_state.c + ${LIBUNWIND_SRC}/x86_64/Gcreate_addr_space.c + ${LIBUNWIND_SRC}/x86_64/Gget_proc_info.c + ${LIBUNWIND_SRC}/x86_64/Gget_save_loc.c + ${LIBUNWIND_SRC}/x86_64/Gglobal.c + ${LIBUNWIND_SRC}/x86_64/Ginit.c + ${LIBUNWIND_SRC}/x86_64/Ginit_local.c + ${LIBUNWIND_SRC}/x86_64/Ginit_remote.c + ${LIBUNWIND_SRC}/x86_64/Gregs.c + ${LIBUNWIND_SRC}/x86_64/Greg_states_iterate.c + ${LIBUNWIND_SRC}/x86_64/Gresume.c + ${LIBUNWIND_SRC}/x86_64/Gstash_frame.c + ${LIBUNWIND_SRC}/x86_64/Gstep.c + ${LIBUNWIND_SRC}/x86_64/Gtrace.c + ) +elseif(UNWIND_ARCH STREQUAL "aarch64") + set(UNWIND_GENERIC_ARCH_SOURCES + ${LIBUNWIND_SRC}/aarch64/Gos-linux.c + ${LIBUNWIND_SRC}/aarch64/Gapply_reg_state.c + ${LIBUNWIND_SRC}/aarch64/Gcreate_addr_space.c + ${LIBUNWIND_SRC}/aarch64/Gget_proc_info.c + ${LIBUNWIND_SRC}/aarch64/Gget_save_loc.c + ${LIBUNWIND_SRC}/aarch64/Gglobal.c + ${LIBUNWIND_SRC}/aarch64/Ginit.c + ${LIBUNWIND_SRC}/aarch64/Ginit_local.c + ${LIBUNWIND_SRC}/aarch64/Ginit_remote.c + ${LIBUNWIND_SRC}/aarch64/Gis_signal_frame.c + ${LIBUNWIND_SRC}/aarch64/Gregs.c + ${LIBUNWIND_SRC}/aarch64/Greg_states_iterate.c + ${LIBUNWIND_SRC}/aarch64/Gresume.c + ${LIBUNWIND_SRC}/aarch64/Gstash_frame.c + ${LIBUNWIND_SRC}/aarch64/Gstep.c + ${LIBUNWIND_SRC}/aarch64/Gtrace.c + ${LIBUNWIND_SRC}/aarch64/Gstrip_ptrauth_insn_mask.c + ) +elseif(UNWIND_ARCH STREQUAL "x86") + set(UNWIND_GENERIC_ARCH_SOURCES + ${LIBUNWIND_SRC}/x86/Gos-linux.c + ${LIBUNWIND_SRC}/x86/Gapply_reg_state.c + ${LIBUNWIND_SRC}/x86/Gcreate_addr_space.c + ${LIBUNWIND_SRC}/x86/Gget_proc_info.c + ${LIBUNWIND_SRC}/x86/Gget_save_loc.c + ${LIBUNWIND_SRC}/x86/Gglobal.c + ${LIBUNWIND_SRC}/x86/Ginit.c + ${LIBUNWIND_SRC}/x86/Ginit_local.c + ${LIBUNWIND_SRC}/x86/Ginit_remote.c + ${LIBUNWIND_SRC}/x86/Gregs.c + ${LIBUNWIND_SRC}/x86/Greg_states_iterate.c + ${LIBUNWIND_SRC}/x86/Gresume.c + ${LIBUNWIND_SRC}/x86/Gstep.c + ) +endif() + +# Ptrace accessor library (_UPT_* functions for remote unwinding via ptrace) +set(UNWIND_PTRACE_SOURCES + ${LIBUNWIND_SRC}/ptrace/_UPT_accessors.c + ${LIBUNWIND_SRC}/ptrace/_UPT_access_fpreg.c + ${LIBUNWIND_SRC}/ptrace/_UPT_access_mem.c + ${LIBUNWIND_SRC}/ptrace/_UPT_access_reg.c + ${LIBUNWIND_SRC}/ptrace/_UPT_create.c + ${LIBUNWIND_SRC}/ptrace/_UPT_destroy.c + ${LIBUNWIND_SRC}/ptrace/_UPT_elf.c + ${LIBUNWIND_SRC}/ptrace/_UPT_find_proc_info.c + ${LIBUNWIND_SRC}/ptrace/_UPT_get_dyn_info_list_addr.c + ${LIBUNWIND_SRC}/ptrace/_UPT_get_elf_filename.c + ${LIBUNWIND_SRC}/ptrace/_UPT_get_proc_name.c + ${LIBUNWIND_SRC}/ptrace/_UPT_ptrauth_insn_mask.c + ${LIBUNWIND_SRC}/ptrace/_UPT_put_unwind_info.c + ${LIBUNWIND_SRC}/ptrace/_UPT_reg_offset.c + ${LIBUNWIND_SRC}/ptrace/_UPT_resume.c +) + +# unwind_remote: superset of unwind (local + generic + ptrace) +add_library(unwind_remote STATIC + ${UNWIND_COMMON_SOURCES} + ${UNWIND_LOCAL_SOURCES} + ${UNWIND_DWARF_LOCAL_SOURCES} + ${UNWIND_ELF_SOURCES} + ${UNWIND_ARCH_SOURCES} + ${UNWIND_GENERIC_MI_SOURCES} + ${UNWIND_GENERIC_DWARF_SOURCES} + ${UNWIND_GENERIC_ARCH_SOURCES} + ${UNWIND_PTRACE_SOURCES} +) + +target_include_directories(unwind_remote + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/include + ${LIBUNWIND_INC} + ${LIBUNWIND_SRC} + PUBLIC + $ + $ +) + +if(UNWIND_ARCH STREQUAL "x86_64") + target_include_directories(unwind_remote PRIVATE ${LIBUNWIND_INC}/tdep-x86_64) + target_compile_definitions(unwind_remote PRIVATE UNW_TARGET_X86_64=1) +elseif(UNWIND_ARCH STREQUAL "aarch64") + target_include_directories(unwind_remote PRIVATE ${LIBUNWIND_INC}/tdep-aarch64) + target_compile_definitions(unwind_remote PRIVATE UNW_TARGET_AARCH64=1) +elseif(UNWIND_ARCH STREQUAL "x86") + target_include_directories(unwind_remote PRIVATE ${LIBUNWIND_INC}/tdep-x86) + target_compile_definitions(unwind_remote PRIVATE UNW_TARGET_X86=1) +endif() + +target_compile_definitions(unwind_remote PRIVATE + HAVE_CONFIG_H + _GNU_SOURCE +) + +set_target_properties(unwind_remote PROPERTIES + C_STANDARD 99 + POSITION_INDEPENDENT_CODE ON +) + +if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(unwind_remote PRIVATE -w) +endif() + +target_link_libraries(unwind_remote PRIVATE ${CMAKE_DL_LIBS} pthread) + +endif() # LIBUNWIND_BUILD_REMOTE diff --git a/vendor/libunwind/VENDORING.md b/vendor/libunwind/VENDORING.md index e54786ce63..541ec60e69 100644 --- a/vendor/libunwind/VENDORING.md +++ b/vendor/libunwind/VENDORING.md @@ -9,8 +9,18 @@ ## Purpose libunwind is vendored so the sentry-native SDK can perform stack unwinding on -Linux without requiring users to install any external packages. Only the -**local** unwinding functionality is needed. +Linux without requiring users to install any external packages. + +Two CMake targets are provided: + +- **`unwind`** — local unwinding only (`L`-prefix sources, `_UL*` symbols). + Used by the main `sentry` library and the inproc backend. +- **`unwind_remote`** — local + remote unwinding (`L`-prefix + `G`-prefix + sources + `src/ptrace/` accessors, `_UL*` + `_U*` + `_UPT_*` symbols). + Only built when `LIBUNWIND_BUILD_REMOTE` is set (i.e., native backend on + Linux). Used by the `sentry-crash` daemon for out-of-process DWARF + unwinding and symbol name resolution via `unw_init_remote()` / + `unw_get_proc_name()`. ## Supported Architectures (built by CMake) @@ -66,15 +76,14 @@ Source and include directories for architectures sentry-native does not target: ### 4. Unused feature modules These are separate `libunwind` "accessor" libraries for non-local unwinding use -cases. sentry-native only uses local unwinding (unwinding the current process -in-process), so none of these are needed: +cases: -| Directory | Purpose | Why removed | -|-----------------|-------------------------------------|-----------------------------------| -| `src/coredump/` | Unwinding from a coredump file | Not a live-process use case | -| `src/nto/` | QNX Neutrino ptrace-based unwinding | QNX is not a sentry-native target | -| `src/ptrace/` | Remote unwinding via `ptrace()` | Only local unwinding is needed | -| `src/setjmp/` | `setjmp`/`longjmp` wrappers | Not relevant for crash reporting | +| Directory | Purpose | Status | +|-----------------|-------------------------------------|---------------------------------------------------------| +| `src/ptrace/` | Remote unwinding via `ptrace()` | **Re-added** — used by the native backend's crash daemon | +| `src/coredump/` | Unwinding from a coredump file | Removed — not a live-process use case | +| `src/nto/` | QNX Neutrino ptrace-based unwinding | Removed — QNX is not a sentry-native target | +| `src/setjmp/` | `setjmp`/`longjmp` wrappers | Removed — not relevant for crash reporting | ### What is kept but NOT built @@ -107,7 +116,7 @@ never calls into the C++ exception ABI. | File | Purpose | |-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| -| `CMakeLists.txt` | Custom CMake build that replaces the upstream autotools + upstream CMake build. Builds a static `unwind` target for x86, x86_64, and aarch64 only | +| `CMakeLists.txt` | Custom CMake build that replaces the upstream autotools + upstream CMake build. Builds `unwind` (local) and optionally `unwind_remote` (local + remote + ptrace) | | `cmake/config.h.cmake.in` | CMake template for `config.h` (replaces autotools `configure`-generated header) | | `cmake/libunwind-common.h.cmake.in` | CMake template for `libunwind-common.h` | | `VENDORING.md` | This file | @@ -140,8 +149,8 @@ both GCC and Clang. 3. Delete and re-copy these directories from the new tarball, **excluding** the removed architecture dirs listed above: - - `src/` — keep only: `aarch64/`, `arm/`, `dwarf/`, `mi/`, `riscv/`, - `unwind/`, `x86/`, `x86_64/`, and top-level `.c` / `.h` files + - `src/` — keep only: `aarch64/`, `arm/`, `dwarf/`, `mi/`, `ptrace/`, + `riscv/`, `unwind/`, `x86/`, `x86_64/`, and top-level `.c` / `.h` files (`src/unwind/` is kept for reference but **not compiled** — do not add it to `CMakeLists.txt`) - `include/` — keep only: `tdep/`, `tdep-aarch64/`, `tdep-arm/`, diff --git a/vendor/libunwind/src/ptrace/_UPT_access_fpreg.c b/vendor/libunwind/src/ptrace/_UPT_access_fpreg.c new file mode 100644 index 0000000000..7d8eee83d8 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_access_fpreg.c @@ -0,0 +1,146 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if HAVE_DECL_PTRACE_POKEUSER || defined(HAVE_TTRACE) +int +_UPT_access_fpreg (unw_addr_space_t as UNUSED, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + unw_word_t *wp = (unw_word_t *) val; + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + int i; + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + return -UNW_EBADREG; + + errno = 0; + if (write) + for (i = 0; i < (int) (sizeof (*val) / sizeof (wp[i])); ++i) + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg] + i * sizeof(wp[i]), + wp[i]); +#endif + if (errno) + return -UNW_EBADREG; + } + else + for (i = 0; i < (int) (sizeof (*val) / sizeof (wp[i])); ++i) + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + wp[i] = ptrace (PTRACE_PEEKUSER, pid, + _UPT_reg_offset[reg] + i * sizeof(wp[i]), 0); +#endif + if (errno) + return -UNW_EBADREG; + } + return 0; +} +#elif HAVE_DECL_PT_GETFPREGS +int +_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + fpregset_t fpreg; + +#if defined(__amd64__) + if (1) /* XXXKIB */ + return -UNW_EBADREG; +#elif defined(__i386__) + if ((unsigned) reg < UNW_X86_ST0 || (unsigned) reg > UNW_X86_ST7) + return -UNW_EBADREG; +#elif defined(__arm__) + if ((unsigned) reg < UNW_ARM_F0 || (unsigned) reg > UNW_ARM_F7) + return -UNW_EBADREG; +#elif defined(__aarch64__) + if ((unsigned) reg < UNW_AARCH64_V0 || (unsigned) reg > UNW_AARCH64_V31) + return -UNW_EBADREG; +#elif defined(__powerpc64__) + if ((unsigned) reg < UNW_PPC64_F0 || (unsigned) reg > UNW_PPC64_F31) + return -UNW_EBADREG; +#elif defined(__powerpc__) + if ((unsigned) reg < UNW_PPC32_F0 || (unsigned) reg > UNW_PPC32_F31) + return -UNW_EBADREG; +#else +#error Fix me +#endif + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + return -UNW_EBADREG; + + if (ptrace(PT_GETFPREGS, pid, (caddr_t)&fpreg, 0) == -1) + return -UNW_EBADREG; + if (write) { +#if defined(__amd64__) + memcpy(&fpreg.fpr_xacc[reg], val, sizeof(unw_fpreg_t)); +#elif defined(__i386__) + memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t)); +#elif defined(__arm__) +# if __FreeBSD_version >= 1400079 + memcpy(&fpreg.fpr_r[reg], val, sizeof(unw_fpreg_t)); +# else + memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t)); +# endif +#elif defined(__aarch64__) + memcpy(&fpreg.fp_q[reg], val, sizeof(unw_fpreg_t)); +#elif defined(__powerpc__) + memcpy(&fpreg.fpreg[reg], val, sizeof(unw_fpreg_t)); +#else +#error Fix me +#endif + if (ptrace(PT_SETFPREGS, pid, (caddr_t)&fpreg, 0) == -1) + return -UNW_EBADREG; + } else +#if defined(__amd64__) + memcpy(val, &fpreg.fpr_xacc[reg], sizeof(unw_fpreg_t)); +#elif defined(__i386__) + memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t)); +#elif defined(__arm__) +# if __FreeBSD_version >= 1400079 + memcpy(&fpreg.fpr_r[reg], val, sizeof(unw_fpreg_t)); +# else + memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t)); +# endif +#elif defined(__aarch64__) + memcpy(val, &fpreg.fp_q[reg], sizeof(unw_fpreg_t)); +#elif defined(__powerpc__) + memcpy(val, &fpreg.fpreg[reg], sizeof(unw_fpreg_t)); +#else +#error Fix me +#endif + return 0; +} +#else +#error Fix me +#endif diff --git a/vendor/libunwind/src/ptrace/_UPT_access_mem.c b/vendor/libunwind/src/ptrace/_UPT_access_mem.c new file mode 100644 index 0000000000..5892982cd7 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_access_mem.c @@ -0,0 +1,123 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if HAVE_DECL_PTRACE_POKEDATA || defined(HAVE_TTRACE) +int +_UPT_access_mem (unw_addr_space_t as UNUSED, unw_word_t addr, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + int i, end; + unw_word_t tmp_val; + + if (!ui) + return -UNW_EINVAL; + + pid_t pid = ui->pid; + + // Some 32-bit archs have to define a 64-bit unw_word_t. + // Callers of this function therefore expect a 64-bit + // return value, but ptrace only returns a 32-bit value + // in such cases. + if (sizeof(long) == 4 && sizeof(unw_word_t) == 8) + end = 2; + else + end = 1; + + for (i = 0; i < end; i++) + { + unw_word_t tmp_addr = i == 0 ? addr : addr + 4; + + errno = 0; + if (write) + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + tmp_val = i == 0 ? *val : *val >> 32; +#else + tmp_val = i == 0 && end == 2 ? *val >> 32 : *val; +#endif + + Debug (16, "mem[%lx] <- %lx\n", (long) tmp_addr, (long) tmp_val); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + ptrace (PTRACE_POKEDATA, pid, tmp_addr, tmp_val); + if (errno) + return -UNW_EINVAL; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + tmp_val = (unsigned long) ptrace (PTRACE_PEEKDATA, pid, tmp_addr, 0); + + if (i == 0) + *val = 0; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *val |= tmp_val << (i * 32); +#else + *val |= i == 0 && end == 2 ? tmp_val << 32 : tmp_val; +#endif + + if (errno) + return -UNW_EINVAL; +#endif + Debug (16, "mem[%lx] -> %lx\n", (long) tmp_addr, (long) tmp_val); + } + } + return 0; +} +#elif HAVE_DECL_PT_IO +int +_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + if (!ui) + return -UNW_EINVAL; + pid_t pid = ui->pid; + struct ptrace_io_desc iod; + + iod.piod_offs = (void *)addr; + iod.piod_addr = val; + iod.piod_len = sizeof(*val); + iod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D; + if (write) + Debug (16, "mem[%lx] <- %lx\n", (long) addr, (long) *val); + if (ptrace(PT_IO, pid, (caddr_t)&iod, 0) == -1) + return -UNW_EINVAL; + if (!write) + Debug (16, "mem[%lx] -> %lx\n", (long) addr, (long) *val); + return 0; +} +#else +#error Fix me +#endif diff --git a/vendor/libunwind/src/ptrace/_UPT_access_reg.c b/vendor/libunwind/src/ptrace/_UPT_access_reg.c new file mode 100644 index 0000000000..316ad19b8a --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_access_reg.c @@ -0,0 +1,402 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if UNW_TARGET_IA64 +# include +# ifdef HAVE_ASM_PTRACE_OFFSETS_H +# include +# endif +# include "tdep-ia64/rse.h" +#endif + +#if HAVE_DECL_PTRACE_SETREGSET && (defined(__linux__) && !defined(UNW_TARGET_X86)) +#include +int +_UPT_access_reg (unw_addr_space_t as UNUSED, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + gregset_t regs; + char *r; + struct iovec loc; + +#if UNW_DEBUG + Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n", + unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { + errno = EINVAL; + goto badreg; + } + + loc.iov_base = ®s; + loc.iov_len = sizeof(regs); + + r = (char *)®s + _UPT_reg_offset[reg]; + if (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &loc) == -1) + goto badreg; + if (write) { + memcpy(r, val, sizeof(unw_word_t)); + if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &loc) == -1) + goto badreg; + } else + memcpy(val, r, sizeof(unw_word_t)); + return 0; + +badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} +#elif (HAVE_DECL_PTRACE_POKEUSER || defined(HAVE_TTRACE)) && (defined(__linux__) && !defined(UNW_TARGET_X86)) +int +_UPT_access_reg (UNUSED unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + +#if UNW_DEBUG + Debug(16, "using pokeuser: reg: %s [%u], val: %lx, write: %d\n", unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val); +#endif + +#if UNW_TARGET_IA64 + if ((unsigned) reg - UNW_IA64_NAT < 32) + { + unsigned long nat_bits, mask; + + /* The Linux ptrace represents the statc NaT bits as a single word. */ + mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT); + errno = 0; +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + nat_bits = ptrace (PTRACE_PEEKUSER, pid, PT_NAT_BITS, 0); + if (errno) + goto badreg; +#endif + + if (write) + { + if (*val) + nat_bits |= mask; + else + nat_bits &= ~mask; +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_NAT_BITS, nat_bits); + if (errno) + goto badreg; +#endif + } + goto out; + } + else + switch (reg) + { + case UNW_IA64_GR + 0: + if (write) + goto badreg; + *val = 0; + return 0; + + case UNW_REG_IP: + { + unsigned long ip, psr; + + /* distribute bundle-addr. & slot-number across PT_IIP & PT_IPSR. */ +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + psr = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IPSR, 0); + if (errno) + goto badreg; +#endif + if (write) + { + ip = *val & ~0xfUL; + psr = (psr & ~0x3UL << 41) | (*val & 0x3); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_CR_IIP, ip); + ptrace (PTRACE_POKEUSER, pid, PT_CR_IPSR, psr); + if (errno) + goto badreg; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ip = ptrace (PTRACE_PEEKUSER, pid, PT_CR_IIP, 0); + if (errno) + goto badreg; +#endif + *val = ip + ((psr >> 41) & 0x3); + } + goto out; + } + + case UNW_IA64_AR_BSPSTORE: + reg = UNW_IA64_AR_BSP; + break; + + case UNW_IA64_AR_BSP: + case UNW_IA64_BSP: + { + unsigned long sof, cfm, bsp; + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + /* Account for the fact that ptrace() expects bsp to point + _after_ the current register frame. */ + errno = 0; + cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); + if (errno) + goto badreg; +#endif + sof = (cfm & 0x7f); + + if (write) + { + bsp = rse_skip_regs (*val, sof); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, bsp); + if (errno) + goto badreg; +#endif + } + else + { +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); + if (errno) + goto badreg; +#endif + *val = rse_skip_regs (bsp, -sof); + } + goto out; + } + + case UNW_IA64_CFM: + /* If we change CFM, we need to adjust ptrace's notion of bsp + accordingly, so that the real bsp remains unchanged. */ + if (write) + { + unsigned long new_sof, old_sof, cfm, bsp; + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + bsp = ptrace (PTRACE_PEEKUSER, pid, PT_AR_BSP, 0); + cfm = ptrace (PTRACE_PEEKUSER, pid, PT_CFM, 0); +#endif + if (errno) + goto badreg; + old_sof = (cfm & 0x7f); + new_sof = (*val & 0x7f); + if (old_sof != new_sof) + { + bsp = rse_skip_regs (bsp, -old_sof + new_sof); +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_AR_BSP, 0); + if (errno) + goto badreg; +#endif + } +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + ptrace (PTRACE_POKEUSER, pid, PT_CFM, *val); + if (errno) + goto badreg; +#endif + goto out; + } + break; + } +#endif /* End of IA64 */ + +#if UNW_TARGET_RISCV + if (reg == UNW_RISCV_X0) { + if (write) + goto badreg; + + *val = 0; + return 0; + } +#endif /* End of RISCV */ + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { +#if UNW_DEBUG + Debug(2, "register out of range: >= %zu / %zu\n", sizeof(_UPT_reg_offset), sizeof(_UPT_reg_offset[0])); +#endif + errno = EINVAL; + goto badreg; + } + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#else + errno = 0; + if (write) + ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val); + else { +#if UNW_DEBUG + Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg, + (unsigned long)_UPT_reg_offset[reg]); +#endif + *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0); + } + if (errno) { +#if UNW_DEBUG + Debug(2, "ptrace failure\n"); +#endif + goto badreg; + } +#endif + +#ifdef UNW_TARGET_IA64 + out: +#endif +#if UNW_DEBUG + if (!write) + Debug (16, "%s[%u] -> %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + return 0; + + badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} +#elif defined(HAVE_DECL_PT_GETREGS) && defined(__linux__) +# include + +int +_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + struct user_regs_struct regs; + char *r; + +#if UNW_DEBUG + Debug(16, "using getregs: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { + errno = EINVAL; + goto badreg; + } + r = (char *)®s + _UPT_reg_offset[reg]; + if (ptrace(PT_GETREGS, pid, NULL, ®s) == -1) + goto badreg; + if (write) { + memcpy(r, val, sizeof(unw_word_t)); + if (ptrace(PT_SETREGS, pid, NULL, ®s) == -1) + goto badreg; + } else + memcpy(val, r, sizeof(unw_word_t)); + return 0; + + badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} + +#elif defined(HAVE_DECL_PT_GETREGS) && defined(__FreeBSD__) +int +_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, + int write, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + gregset_t regs; + char *r; + +#if UNW_DEBUG + Debug(16, "using getregs: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); + + if (write) + Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); +#endif + + if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset)) + { + errno = EINVAL; + goto badreg; + } + r = (char *)®s + _UPT_reg_offset[reg]; + if (ptrace(PT_GETREGS, pid, (caddr_t)®s, 0) == -1) + goto badreg; + if (write) { + memcpy(r, val, sizeof(unw_word_t)); + if (ptrace(PT_SETREGS, pid, (caddr_t)®s, 0) == -1) + goto badreg; + } else + memcpy(val, r, sizeof(unw_word_t)); + return 0; + + badreg: + Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); + return -UNW_EBADREG; +} +#else +#error Port me +#endif diff --git a/vendor/libunwind/src/ptrace/_UPT_accessors.c b/vendor/libunwind/src/ptrace/_UPT_accessors.c new file mode 100644 index 0000000000..d01d8a8dcc --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_accessors.c @@ -0,0 +1,40 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +unw_accessors_t _UPT_accessors = + { + .find_proc_info = _UPT_find_proc_info, + .put_unwind_info = _UPT_put_unwind_info, + .get_dyn_info_list_addr = _UPT_get_dyn_info_list_addr, + .access_mem = _UPT_access_mem, + .access_reg = _UPT_access_reg, + .access_fpreg = _UPT_access_fpreg, + .resume = _UPT_resume, + .get_proc_name = _UPT_get_proc_name, + .get_elf_filename = _UPT_get_elf_filename, + .ptrauth_insn_mask = _UPT_ptrauth_insn_mask + }; diff --git a/vendor/libunwind/src/ptrace/_UPT_create.c b/vendor/libunwind/src/ptrace/_UPT_create.c new file mode 100644 index 0000000000..1536c27e9e --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_create.c @@ -0,0 +1,48 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include + +#include "_UPT_internal.h" + +void * +_UPT_create (pid_t pid) +{ + struct UPT_info *ui = malloc (sizeof (struct UPT_info)); + + mi_init (); + + if (!ui) + return NULL; + + memset (ui, 0, sizeof (*ui)); + ui->pid = pid; + ui->edi.di_cache.format = -1; + ui->edi.di_debug.format = -1; +#if UNW_TARGET_IA64 + ui->edi.ktab.format = -1; +#endif + return ui; +} diff --git a/vendor/libunwind/src/ptrace/_UPT_destroy.c b/vendor/libunwind/src/ptrace/_UPT_destroy.c new file mode 100644 index 0000000000..edb664ce12 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_destroy.c @@ -0,0 +1,34 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +void +_UPT_destroy (void *ptr) +{ + struct UPT_info *ui = (struct UPT_info *) ptr; + invalidate_edi (&ui->edi); + free (ptr); +} diff --git a/vendor/libunwind/src/ptrace/_UPT_elf.c b/vendor/libunwind/src/ptrace/_UPT_elf.c new file mode 100644 index 0000000000..efc43b578b --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_elf.c @@ -0,0 +1,5 @@ +/* We need to get a separate copy of the ELF-code into + libunwind-ptrace since it cannot (and must not) have any ELF + dependencies on libunwind. */ +#include "libunwind_i.h" /* get ELFCLASS defined */ +#include "../elfxx.c" diff --git a/vendor/libunwind/src/ptrace/_UPT_find_proc_info.c b/vendor/libunwind/src/ptrace/_UPT_find_proc_info.c new file mode 100644 index 0000000000..0450b0847b --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_find_proc_info.c @@ -0,0 +1,145 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include +#include +#include + +#include + +#include "_UPT_internal.h" + +static int +get_unwind_info (struct elf_dyn_info *edi, pid_t pid, unw_addr_space_t as, unw_word_t ip) +{ + unsigned long segbase, mapoff; + char path[PATH_MAX]; + +#if UNW_TARGET_IA64 && defined(__linux__) + if (!edi->ktab.start_ip && _Uia64_get_kernel_table (&edi->ktab) < 0) + return -UNW_ENOINFO; + + if (edi->ktab.format != -1 && ip >= edi->ktab.start_ip && ip < edi->ktab.end_ip) + return 0; +#endif + + if ((edi->di_cache.format != -1 + && ip >= edi->di_cache.start_ip && ip < edi->di_cache.end_ip) +#if UNW_TARGET_ARM + || (edi->di_debug.format != -1 + && ip >= edi->di_arm.start_ip && ip < edi->di_arm.end_ip) +#endif + || (edi->di_debug.format != -1 + && ip >= edi->di_debug.start_ip && ip < edi->di_debug.end_ip)) + return 0; + + invalidate_edi(edi); + + if (tdep_get_elf_image (&edi->ei, pid, ip, &segbase, &mapoff, path, + sizeof(path)) < 0) + return -UNW_ENOINFO; + + /* Here, SEGBASE is the starting-address of the (mmap'ped) segment + which covers the IP we're looking for. */ + if (tdep_find_unwind_table (edi, as, path, segbase, mapoff, ip) < 0) + return -UNW_ENOINFO; + + /* This can happen in corner cases where dynamically generated + code falls into the same page that contains the data-segment + and the page-offset of the code is within the first page of + the executable. */ + if (edi->di_cache.format != -1 + && (ip < edi->di_cache.start_ip || ip >= edi->di_cache.end_ip)) + edi->di_cache.format = -1; + + if (edi->di_debug.format != -1 + && (ip < edi->di_debug.start_ip || ip >= edi->di_debug.end_ip)) + edi->di_debug.format = -1; + + if (edi->di_cache.format == -1 +#if UNW_TARGET_ARM + && edi->di_arm.format == -1 +#endif + && edi->di_debug.format == -1) + return -UNW_ENOINFO; + + return 0; +} + +int +_UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + struct UPT_info *ui = arg; + int ret = -UNW_ENOINFO; + + if (get_unwind_info (&ui->edi, ui->pid, as, ip) < 0) + return -UNW_ENOINFO; + +#if UNW_TARGET_IA64 + if (ui->edi.ktab.format != -1) + { + /* The kernel unwind table resides in local memory, so we have + to use the local address space to search it. Since + _UPT_put_unwind_info() has no easy way of detecting this + case, we simply make a copy of the unwind-info, so + _UPT_put_unwind_info() can always free() the unwind-info + without ill effects. */ + ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->edi.ktab, pi, + need_unwind_info, arg); + if (ret >= 0) + { + if (!need_unwind_info) + pi->unwind_info = NULL; + else + { + void *mem = malloc (pi->unwind_info_size); + + if (!mem) + return -UNW_ENOMEM; + memcpy (mem, pi->unwind_info, pi->unwind_info_size); + pi->unwind_info = mem; + } + } + } +#endif + + if (ret == -UNW_ENOINFO && ui->edi.di_cache.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache, + pi, need_unwind_info, arg); + + if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi, + need_unwind_info, arg); + +#if UNW_TARGET_ARM + if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1) + ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi, + need_unwind_info, arg); +#endif + + return ret; +} diff --git a/vendor/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c b/vendor/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c new file mode 100644 index 0000000000..3156acfdaf --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_get_dyn_info_list_addr.c @@ -0,0 +1,112 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#if UNW_TARGET_IA64 && defined(__linux__) +# include "elf64.h" +# include "os-linux.h" + +static inline int +get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg, + int *countp) +{ + unsigned long lo, hi, off; + struct UPT_info *ui = arg; + struct map_iterator mi; + char path[PATH_MAX]; + unw_word_t res; + int count = 0; + + maps_init (&mi, ui->pid); + while (maps_next (&mi, &lo, &hi, &off, NULL)) + { + if (off) + continue; + + invalidate_edi(&ui->edi); + + if (elf_map_image (&ui->edi.ei, path) < 0) + /* ignore unmappable stuff like "/SYSV00001b58 (deleted)" */ + continue; + + Debug (16, "checking object %s\n", path); + + if (tdep_find_unwind_table (&ui->edi, as, path, lo, off, 0) > 0) + { + res = _Uia64_find_dyn_list (as, &ui->edi.di_cache, arg); + if (res && count++ == 0) + { + Debug (12, "dyn_info_list_addr = 0x%lx\n", (long) res); + *dil_addr = res; + } + } + } + maps_close (&mi); + *countp = count; + return 0; +} + +#else + +/* XXX fix me: there is currently no way to locate the dyn-info list + by a remote unwinder. On ia64, this is done via a special + unwind-table entry. Perhaps something similar can be done with + DWARF2 unwind info. */ + +static inline int +get_list_addr (unw_addr_space_t as UNUSED, + unw_word_t *dil_addr UNUSED, + void *arg UNUSED, + int *countp) +{ +# warning Implement get_list_addr(), please. + *countp = 0; + return 0; +} + +#endif + +int +_UPT_get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, + void *arg) +{ + int count, ret; + + Debug (12, "looking for dyn_info list\n"); + + if ((ret = get_list_addr (as, dil_addr, arg, &count)) < 0) + return ret; + + /* If multiple dynamic-info list addresses are found, we would have + to determine which was is the one actually in use (since the + dynamic name resolution algorithm will pick one "winner"). + Perhaps we'd have to track them all until we find one that's + non-empty. Hopefully, this case simply will never arise, since + only libunwind defines the dynamic info list head. */ + assert (count <= 1); + + return (count > 0) ? 0 : -UNW_ENOINFO; +} diff --git a/vendor/libunwind/src/ptrace/_UPT_get_elf_filename.c b/vendor/libunwind/src/ptrace/_UPT_get_elf_filename.c new file mode 100644 index 0000000000..401de3d181 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_get_elf_filename.c @@ -0,0 +1,38 @@ +/* + * This file is part of libunwind. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "_UPT_internal.h" + +int +_UPT_get_elf_filename (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, void *arg) +{ + struct UPT_info *ui = arg; + +#if UNW_ELF_CLASS == UNW_ELFCLASS64 + return _Uelf64_get_elf_filename (as, ui->pid, ip, buf, buf_len, offp); +#elif UNW_ELF_CLASS == UNW_ELFCLASS32 + return _Uelf32_get_elf_filename (as, ui->pid, ip, buf, buf_len, offp); +#else + return -UNW_ENOINFO; +#endif +} diff --git a/vendor/libunwind/src/ptrace/_UPT_get_proc_name.c b/vendor/libunwind/src/ptrace/_UPT_get_proc_name.c new file mode 100644 index 0000000000..4fc93e7477 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_get_proc_name.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Copyright (C) 2007 David Mosberger-Tang + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +int +_UPT_get_proc_name (unw_addr_space_t as, unw_word_t ip, + char *buf, size_t buf_len, unw_word_t *offp, void *arg) +{ + struct UPT_info *ui = arg; + +#if UNW_ELF_CLASS == UNW_ELFCLASS64 + return _Uelf64_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); +#elif UNW_ELF_CLASS == UNW_ELFCLASS32 + return _Uelf32_get_proc_name (as, ui->pid, ip, buf, buf_len, offp); +#else + return -UNW_ENOINFO; +#endif +} diff --git a/vendor/libunwind/src/ptrace/_UPT_internal.h b/vendor/libunwind/src/ptrace/_UPT_internal.h new file mode 100644 index 0000000000..5cef2573ee --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_internal.h @@ -0,0 +1,59 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003, 2005 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#ifndef _UPT_internal_h +#define _UPT_internal_h + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_PTRACE_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "libunwind_i.h" + +struct UPT_info + { + pid_t pid; /* the process-id of the child we're unwinding */ + struct elf_dyn_info edi; + }; + +extern const int _UPT_reg_offset[UNW_REG_LAST + 1]; + +#endif /* _UPT_internal_h */ diff --git a/vendor/libunwind/src/ptrace/_UPT_ptrauth_insn_mask.c b/vendor/libunwind/src/ptrace/_UPT_ptrauth_insn_mask.c new file mode 100644 index 0000000000..f402cb5553 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_ptrauth_insn_mask.c @@ -0,0 +1,58 @@ +/* +* This file is part of libunwind. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "_UPT_internal.h" + +#if defined(UNW_TARGET_AARCH64) && defined(NT_ARM_PAC_MASK) + +unw_word_t _UPT_ptrauth_insn_mask (UNUSED unw_addr_space_t as, void *arg) +{ + struct UPT_info *ui = arg; + pid_t pid = ui->pid; + int ret; + struct iovec iovec; + uint64_t regset[2] = {0, 0}; + + iovec.iov_base = ®set; + iovec.iov_len = sizeof (regset); + + ret = ptrace (PTRACE_GETREGSET, pid, NT_ARM_PAC_MASK, &iovec); + if (ret != 0) + { + Debug (12, "Failed to fetch ptrauth instruction mask"); + return 0; + } + + // regset[0] => data_mask + // regset[1] => insn_mask + return regset[1]; +} + +#else + +unw_word_t _UPT_ptrauth_insn_mask (UNUSED unw_addr_space_t as, UNUSED void *arg) +{ + return 0; +} + +#endif + diff --git a/vendor/libunwind/src/ptrace/_UPT_put_unwind_info.c b/vendor/libunwind/src/ptrace/_UPT_put_unwind_info.c new file mode 100644 index 0000000000..54989a769a --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_put_unwind_info.c @@ -0,0 +1,35 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +void +_UPT_put_unwind_info (unw_addr_space_t as UNUSED, unw_proc_info_t *pi, void *arg UNUSED) +{ + if (!pi->unwind_info) + return; + free (pi->unwind_info); + pi->unwind_info = NULL; +} diff --git a/vendor/libunwind/src/ptrace/_UPT_reg_offset.c b/vendor/libunwind/src/ptrace/_UPT_reg_offset.c new file mode 100644 index 0000000000..02e0ec6d89 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_reg_offset.c @@ -0,0 +1,740 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003-2004 Hewlett-Packard Co + Contributed by David Mosberger-Tang + Copyright (C) 2013 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +#include + +#ifdef HAVE_ASM_PTRACE_H +# include +#endif + +#ifdef HAVE_ASM_PTRACE_OFFSETS_H +# include +#endif + +#if defined(__powerpc__) && defined(__FreeBSD__) +#define PT_R0 0 +#define PT_R1 1 +#define PT_R2 2 +#define PT_R3 3 +#define PT_R4 4 +#define PT_R5 5 +#define PT_R6 6 +#define PT_R7 7 +#define PT_R8 8 +#define PT_R9 9 +#define PT_R10 10 +#define PT_R11 11 +#define PT_R12 12 +#define PT_R13 13 +#define PT_R14 14 +#define PT_R15 15 +#define PT_R16 16 +#define PT_R17 17 +#define PT_R18 18 +#define PT_R19 19 +#define PT_R20 20 +#define PT_R21 21 +#define PT_R22 22 +#define PT_R23 23 +#define PT_R24 24 +#define PT_R25 25 +#define PT_R26 26 +#define PT_R27 27 +#define PT_R28 28 +#define PT_R29 29 +#define PT_R30 30 +#define PT_R31 31 +#define PT_NIP 32 +#define PT_CCR 33 +#define PT_CTR 35 +#define PT_LNK 36 +#define PT_XER 37 +#define PT_FPR0 48 +#define PT_FPSCR (PT_FPR0 + 2*32 + 1) +#define PT_VR0 82 +#define PT_VSCR (PT_VR0 + 32*2 + 1) +#define PT_VRSAVE (PT_VR0 + 33*2) +#endif + +const int _UPT_reg_offset[UNW_REG_LAST + 1] = + { +#ifdef HAVE_ASM_PTRACE_OFFSETS_H +# ifndef PT_AR_CSD +# define PT_AR_CSD -1 /* this was introduced with rev 2.1 of ia64 */ +# endif + + [UNW_IA64_GR + 0] = -1, [UNW_IA64_GR + 1] = PT_R1, + [UNW_IA64_GR + 2] = PT_R2, [UNW_IA64_GR + 3] = PT_R3, + [UNW_IA64_GR + 4] = PT_R4, [UNW_IA64_GR + 5] = PT_R5, + [UNW_IA64_GR + 6] = PT_R6, [UNW_IA64_GR + 7] = PT_R7, + [UNW_IA64_GR + 8] = PT_R8, [UNW_IA64_GR + 9] = PT_R9, + [UNW_IA64_GR + 10] = PT_R10, [UNW_IA64_GR + 11] = PT_R11, + [UNW_IA64_GR + 12] = PT_R12, [UNW_IA64_GR + 13] = PT_R13, + [UNW_IA64_GR + 14] = PT_R14, [UNW_IA64_GR + 15] = PT_R15, + [UNW_IA64_GR + 16] = PT_R16, [UNW_IA64_GR + 17] = PT_R17, + [UNW_IA64_GR + 18] = PT_R18, [UNW_IA64_GR + 19] = PT_R19, + [UNW_IA64_GR + 20] = PT_R20, [UNW_IA64_GR + 21] = PT_R21, + [UNW_IA64_GR + 22] = PT_R22, [UNW_IA64_GR + 23] = PT_R23, + [UNW_IA64_GR + 24] = PT_R24, [UNW_IA64_GR + 25] = PT_R25, + [UNW_IA64_GR + 26] = PT_R26, [UNW_IA64_GR + 27] = PT_R27, + [UNW_IA64_GR + 28] = PT_R28, [UNW_IA64_GR + 29] = PT_R29, + [UNW_IA64_GR + 30] = PT_R30, [UNW_IA64_GR + 31] = PT_R31, + + [UNW_IA64_NAT+ 0] = -1, [UNW_IA64_NAT+ 1] = PT_NAT_BITS, + [UNW_IA64_NAT+ 2] = PT_NAT_BITS, [UNW_IA64_NAT+ 3] = PT_NAT_BITS, + [UNW_IA64_NAT+ 4] = PT_NAT_BITS, [UNW_IA64_NAT+ 5] = PT_NAT_BITS, + [UNW_IA64_NAT+ 6] = PT_NAT_BITS, [UNW_IA64_NAT+ 7] = PT_NAT_BITS, + [UNW_IA64_NAT+ 8] = PT_NAT_BITS, [UNW_IA64_NAT+ 9] = PT_NAT_BITS, + [UNW_IA64_NAT+ 10] = PT_NAT_BITS, [UNW_IA64_NAT+ 11] = PT_NAT_BITS, + [UNW_IA64_NAT+ 12] = PT_NAT_BITS, [UNW_IA64_NAT+ 13] = PT_NAT_BITS, + [UNW_IA64_NAT+ 14] = PT_NAT_BITS, [UNW_IA64_NAT+ 15] = PT_NAT_BITS, + [UNW_IA64_NAT+ 16] = PT_NAT_BITS, [UNW_IA64_NAT+ 17] = PT_NAT_BITS, + [UNW_IA64_NAT+ 18] = PT_NAT_BITS, [UNW_IA64_NAT+ 19] = PT_NAT_BITS, + [UNW_IA64_NAT+ 20] = PT_NAT_BITS, [UNW_IA64_NAT+ 21] = PT_NAT_BITS, + [UNW_IA64_NAT+ 22] = PT_NAT_BITS, [UNW_IA64_NAT+ 23] = PT_NAT_BITS, + [UNW_IA64_NAT+ 24] = PT_NAT_BITS, [UNW_IA64_NAT+ 25] = PT_NAT_BITS, + [UNW_IA64_NAT+ 26] = PT_NAT_BITS, [UNW_IA64_NAT+ 27] = PT_NAT_BITS, + [UNW_IA64_NAT+ 28] = PT_NAT_BITS, [UNW_IA64_NAT+ 29] = PT_NAT_BITS, + [UNW_IA64_NAT+ 30] = PT_NAT_BITS, [UNW_IA64_NAT+ 31] = PT_NAT_BITS, + + [UNW_IA64_FR + 0] = -1, [UNW_IA64_FR + 1] = -1, + [UNW_IA64_FR + 2] = PT_F2, [UNW_IA64_FR + 3] = PT_F3, + [UNW_IA64_FR + 4] = PT_F4, [UNW_IA64_FR + 5] = PT_F5, + [UNW_IA64_FR + 6] = PT_F6, [UNW_IA64_FR + 7] = PT_F7, + [UNW_IA64_FR + 8] = PT_F8, [UNW_IA64_FR + 9] = PT_F9, + [UNW_IA64_FR + 10] = PT_F10, [UNW_IA64_FR + 11] = PT_F11, + [UNW_IA64_FR + 12] = PT_F12, [UNW_IA64_FR + 13] = PT_F13, + [UNW_IA64_FR + 14] = PT_F14, [UNW_IA64_FR + 15] = PT_F15, + [UNW_IA64_FR + 16] = PT_F16, [UNW_IA64_FR + 17] = PT_F17, + [UNW_IA64_FR + 18] = PT_F18, [UNW_IA64_FR + 19] = PT_F19, + [UNW_IA64_FR + 20] = PT_F20, [UNW_IA64_FR + 21] = PT_F21, + [UNW_IA64_FR + 22] = PT_F22, [UNW_IA64_FR + 23] = PT_F23, + [UNW_IA64_FR + 24] = PT_F24, [UNW_IA64_FR + 25] = PT_F25, + [UNW_IA64_FR + 26] = PT_F26, [UNW_IA64_FR + 27] = PT_F27, + [UNW_IA64_FR + 28] = PT_F28, [UNW_IA64_FR + 29] = PT_F29, + [UNW_IA64_FR + 30] = PT_F30, [UNW_IA64_FR + 31] = PT_F31, + [UNW_IA64_FR + 32] = PT_F32, [UNW_IA64_FR + 33] = PT_F33, + [UNW_IA64_FR + 34] = PT_F34, [UNW_IA64_FR + 35] = PT_F35, + [UNW_IA64_FR + 36] = PT_F36, [UNW_IA64_FR + 37] = PT_F37, + [UNW_IA64_FR + 38] = PT_F38, [UNW_IA64_FR + 39] = PT_F39, + [UNW_IA64_FR + 40] = PT_F40, [UNW_IA64_FR + 41] = PT_F41, + [UNW_IA64_FR + 42] = PT_F42, [UNW_IA64_FR + 43] = PT_F43, + [UNW_IA64_FR + 44] = PT_F44, [UNW_IA64_FR + 45] = PT_F45, + [UNW_IA64_FR + 46] = PT_F46, [UNW_IA64_FR + 47] = PT_F47, + [UNW_IA64_FR + 48] = PT_F48, [UNW_IA64_FR + 49] = PT_F49, + [UNW_IA64_FR + 50] = PT_F50, [UNW_IA64_FR + 51] = PT_F51, + [UNW_IA64_FR + 52] = PT_F52, [UNW_IA64_FR + 53] = PT_F53, + [UNW_IA64_FR + 54] = PT_F54, [UNW_IA64_FR + 55] = PT_F55, + [UNW_IA64_FR + 56] = PT_F56, [UNW_IA64_FR + 57] = PT_F57, + [UNW_IA64_FR + 58] = PT_F58, [UNW_IA64_FR + 59] = PT_F59, + [UNW_IA64_FR + 60] = PT_F60, [UNW_IA64_FR + 61] = PT_F61, + [UNW_IA64_FR + 62] = PT_F62, [UNW_IA64_FR + 63] = PT_F63, + [UNW_IA64_FR + 64] = PT_F64, [UNW_IA64_FR + 65] = PT_F65, + [UNW_IA64_FR + 66] = PT_F66, [UNW_IA64_FR + 67] = PT_F67, + [UNW_IA64_FR + 68] = PT_F68, [UNW_IA64_FR + 69] = PT_F69, + [UNW_IA64_FR + 70] = PT_F70, [UNW_IA64_FR + 71] = PT_F71, + [UNW_IA64_FR + 72] = PT_F72, [UNW_IA64_FR + 73] = PT_F73, + [UNW_IA64_FR + 74] = PT_F74, [UNW_IA64_FR + 75] = PT_F75, + [UNW_IA64_FR + 76] = PT_F76, [UNW_IA64_FR + 77] = PT_F77, + [UNW_IA64_FR + 78] = PT_F78, [UNW_IA64_FR + 79] = PT_F79, + [UNW_IA64_FR + 80] = PT_F80, [UNW_IA64_FR + 81] = PT_F81, + [UNW_IA64_FR + 82] = PT_F82, [UNW_IA64_FR + 83] = PT_F83, + [UNW_IA64_FR + 84] = PT_F84, [UNW_IA64_FR + 85] = PT_F85, + [UNW_IA64_FR + 86] = PT_F86, [UNW_IA64_FR + 87] = PT_F87, + [UNW_IA64_FR + 88] = PT_F88, [UNW_IA64_FR + 89] = PT_F89, + [UNW_IA64_FR + 90] = PT_F90, [UNW_IA64_FR + 91] = PT_F91, + [UNW_IA64_FR + 92] = PT_F92, [UNW_IA64_FR + 93] = PT_F93, + [UNW_IA64_FR + 94] = PT_F94, [UNW_IA64_FR + 95] = PT_F95, + [UNW_IA64_FR + 96] = PT_F96, [UNW_IA64_FR + 97] = PT_F97, + [UNW_IA64_FR + 98] = PT_F98, [UNW_IA64_FR + 99] = PT_F99, + [UNW_IA64_FR +100] = PT_F100, [UNW_IA64_FR +101] = PT_F101, + [UNW_IA64_FR +102] = PT_F102, [UNW_IA64_FR +103] = PT_F103, + [UNW_IA64_FR +104] = PT_F104, [UNW_IA64_FR +105] = PT_F105, + [UNW_IA64_FR +106] = PT_F106, [UNW_IA64_FR +107] = PT_F107, + [UNW_IA64_FR +108] = PT_F108, [UNW_IA64_FR +109] = PT_F109, + [UNW_IA64_FR +110] = PT_F110, [UNW_IA64_FR +111] = PT_F111, + [UNW_IA64_FR +112] = PT_F112, [UNW_IA64_FR +113] = PT_F113, + [UNW_IA64_FR +114] = PT_F114, [UNW_IA64_FR +115] = PT_F115, + [UNW_IA64_FR +116] = PT_F116, [UNW_IA64_FR +117] = PT_F117, + [UNW_IA64_FR +118] = PT_F118, [UNW_IA64_FR +119] = PT_F119, + [UNW_IA64_FR +120] = PT_F120, [UNW_IA64_FR +121] = PT_F121, + [UNW_IA64_FR +122] = PT_F122, [UNW_IA64_FR +123] = PT_F123, + [UNW_IA64_FR +124] = PT_F124, [UNW_IA64_FR +125] = PT_F125, + [UNW_IA64_FR +126] = PT_F126, [UNW_IA64_FR +127] = PT_F127, + + [UNW_IA64_AR + 0] = -1, [UNW_IA64_AR + 1] = -1, + [UNW_IA64_AR + 2] = -1, [UNW_IA64_AR + 3] = -1, + [UNW_IA64_AR + 4] = -1, [UNW_IA64_AR + 5] = -1, + [UNW_IA64_AR + 6] = -1, [UNW_IA64_AR + 7] = -1, + [UNW_IA64_AR + 8] = -1, [UNW_IA64_AR + 9] = -1, + [UNW_IA64_AR + 10] = -1, [UNW_IA64_AR + 11] = -1, + [UNW_IA64_AR + 12] = -1, [UNW_IA64_AR + 13] = -1, + [UNW_IA64_AR + 14] = -1, [UNW_IA64_AR + 15] = -1, + [UNW_IA64_AR + 16] = PT_AR_RSC, [UNW_IA64_AR + 17] = PT_AR_BSP, + [UNW_IA64_AR + 18] = PT_AR_BSPSTORE,[UNW_IA64_AR + 19] = PT_AR_RNAT, + [UNW_IA64_AR + 20] = -1, [UNW_IA64_AR + 21] = -1, + [UNW_IA64_AR + 22] = -1, [UNW_IA64_AR + 23] = -1, + [UNW_IA64_AR + 24] = -1, [UNW_IA64_AR + 25] = PT_AR_CSD, + [UNW_IA64_AR + 26] = -1, [UNW_IA64_AR + 27] = -1, + [UNW_IA64_AR + 28] = -1, [UNW_IA64_AR + 29] = -1, + [UNW_IA64_AR + 30] = -1, [UNW_IA64_AR + 31] = -1, + [UNW_IA64_AR + 32] = PT_AR_CCV, [UNW_IA64_AR + 33] = -1, + [UNW_IA64_AR + 34] = -1, [UNW_IA64_AR + 35] = -1, + [UNW_IA64_AR + 36] = PT_AR_UNAT, [UNW_IA64_AR + 37] = -1, + [UNW_IA64_AR + 38] = -1, [UNW_IA64_AR + 39] = -1, + [UNW_IA64_AR + 40] = PT_AR_FPSR, [UNW_IA64_AR + 41] = -1, + [UNW_IA64_AR + 42] = -1, [UNW_IA64_AR + 43] = -1, + [UNW_IA64_AR + 44] = -1, [UNW_IA64_AR + 45] = -1, + [UNW_IA64_AR + 46] = -1, [UNW_IA64_AR + 47] = -1, + [UNW_IA64_AR + 48] = -1, [UNW_IA64_AR + 49] = -1, + [UNW_IA64_AR + 50] = -1, [UNW_IA64_AR + 51] = -1, + [UNW_IA64_AR + 52] = -1, [UNW_IA64_AR + 53] = -1, + [UNW_IA64_AR + 54] = -1, [UNW_IA64_AR + 55] = -1, + [UNW_IA64_AR + 56] = -1, [UNW_IA64_AR + 57] = -1, + [UNW_IA64_AR + 58] = -1, [UNW_IA64_AR + 59] = -1, + [UNW_IA64_AR + 60] = -1, [UNW_IA64_AR + 61] = -1, + [UNW_IA64_AR + 62] = -1, [UNW_IA64_AR + 63] = -1, + [UNW_IA64_AR + 64] = PT_AR_PFS, [UNW_IA64_AR + 65] = PT_AR_LC, + [UNW_IA64_AR + 66] = PT_AR_EC, [UNW_IA64_AR + 67] = -1, + [UNW_IA64_AR + 68] = -1, [UNW_IA64_AR + 69] = -1, + [UNW_IA64_AR + 70] = -1, [UNW_IA64_AR + 71] = -1, + [UNW_IA64_AR + 72] = -1, [UNW_IA64_AR + 73] = -1, + [UNW_IA64_AR + 74] = -1, [UNW_IA64_AR + 75] = -1, + [UNW_IA64_AR + 76] = -1, [UNW_IA64_AR + 77] = -1, + [UNW_IA64_AR + 78] = -1, [UNW_IA64_AR + 79] = -1, + [UNW_IA64_AR + 80] = -1, [UNW_IA64_AR + 81] = -1, + [UNW_IA64_AR + 82] = -1, [UNW_IA64_AR + 83] = -1, + [UNW_IA64_AR + 84] = -1, [UNW_IA64_AR + 85] = -1, + [UNW_IA64_AR + 86] = -1, [UNW_IA64_AR + 87] = -1, + [UNW_IA64_AR + 88] = -1, [UNW_IA64_AR + 89] = -1, + [UNW_IA64_AR + 90] = -1, [UNW_IA64_AR + 91] = -1, + [UNW_IA64_AR + 92] = -1, [UNW_IA64_AR + 93] = -1, + [UNW_IA64_AR + 94] = -1, [UNW_IA64_AR + 95] = -1, + [UNW_IA64_AR + 96] = -1, [UNW_IA64_AR + 97] = -1, + [UNW_IA64_AR + 98] = -1, [UNW_IA64_AR + 99] = -1, + [UNW_IA64_AR +100] = -1, [UNW_IA64_AR +101] = -1, + [UNW_IA64_AR +102] = -1, [UNW_IA64_AR +103] = -1, + [UNW_IA64_AR +104] = -1, [UNW_IA64_AR +105] = -1, + [UNW_IA64_AR +106] = -1, [UNW_IA64_AR +107] = -1, + [UNW_IA64_AR +108] = -1, [UNW_IA64_AR +109] = -1, + [UNW_IA64_AR +110] = -1, [UNW_IA64_AR +111] = -1, + [UNW_IA64_AR +112] = -1, [UNW_IA64_AR +113] = -1, + [UNW_IA64_AR +114] = -1, [UNW_IA64_AR +115] = -1, + [UNW_IA64_AR +116] = -1, [UNW_IA64_AR +117] = -1, + [UNW_IA64_AR +118] = -1, [UNW_IA64_AR +119] = -1, + [UNW_IA64_AR +120] = -1, [UNW_IA64_AR +121] = -1, + [UNW_IA64_AR +122] = -1, [UNW_IA64_AR +123] = -1, + [UNW_IA64_AR +124] = -1, [UNW_IA64_AR +125] = -1, + [UNW_IA64_AR +126] = -1, [UNW_IA64_AR +127] = -1, + + [UNW_IA64_BR + 0] = PT_B0, [UNW_IA64_BR + 1] = PT_B1, + [UNW_IA64_BR + 2] = PT_B2, [UNW_IA64_BR + 3] = PT_B3, + [UNW_IA64_BR + 4] = PT_B4, [UNW_IA64_BR + 5] = PT_B5, + [UNW_IA64_BR + 6] = PT_B6, [UNW_IA64_BR + 7] = PT_B7, + + [UNW_IA64_PR] = PT_PR, + [UNW_IA64_CFM] = PT_CFM, + [UNW_IA64_IP] = PT_CR_IIP +#elif defined(HAVE_TTRACE) +# warning No support for ttrace() yet. +#elif defined(UNW_TARGET_HPPA) + [UNW_HPPA_GR + 0] = 0x000, [UNW_HPPA_GR + 1] = 0x004, + [UNW_HPPA_GR + 2] = 0x008, [UNW_HPPA_GR + 3] = 0x00c, + [UNW_HPPA_GR + 4] = 0x010, [UNW_HPPA_GR + 5] = 0x014, + [UNW_HPPA_GR + 6] = 0x018, [UNW_HPPA_GR + 7] = 0x01c, + [UNW_HPPA_GR + 8] = 0x020, [UNW_HPPA_GR + 9] = 0x024, + [UNW_HPPA_GR + 10] = 0x028, [UNW_HPPA_GR + 11] = 0x02c, + [UNW_HPPA_GR + 12] = 0x030, [UNW_HPPA_GR + 13] = 0x034, + [UNW_HPPA_GR + 14] = 0x038, [UNW_HPPA_GR + 15] = 0x03c, + [UNW_HPPA_GR + 16] = 0x040, [UNW_HPPA_GR + 17] = 0x044, + [UNW_HPPA_GR + 18] = 0x048, [UNW_HPPA_GR + 19] = 0x04c, + [UNW_HPPA_GR + 20] = 0x050, [UNW_HPPA_GR + 21] = 0x054, + [UNW_HPPA_GR + 22] = 0x058, [UNW_HPPA_GR + 23] = 0x05c, + [UNW_HPPA_GR + 24] = 0x060, [UNW_HPPA_GR + 25] = 0x064, + [UNW_HPPA_GR + 26] = 0x068, [UNW_HPPA_GR + 27] = 0x06c, + [UNW_HPPA_GR + 28] = 0x070, [UNW_HPPA_GR + 29] = 0x074, + [UNW_HPPA_GR + 30] = 0x078, [UNW_HPPA_GR + 31] = 0x07c, + + [UNW_HPPA_FR + 0] = 0x080, [UNW_HPPA_FR + 1] = 0x088, + [UNW_HPPA_FR + 2] = 0x090, [UNW_HPPA_FR + 3] = 0x098, + [UNW_HPPA_FR + 4] = 0x0a0, [UNW_HPPA_FR + 5] = 0x0a8, + [UNW_HPPA_FR + 6] = 0x0b0, [UNW_HPPA_FR + 7] = 0x0b8, + [UNW_HPPA_FR + 8] = 0x0c0, [UNW_HPPA_FR + 9] = 0x0c8, + [UNW_HPPA_FR + 10] = 0x0d0, [UNW_HPPA_FR + 11] = 0x0d8, + [UNW_HPPA_FR + 12] = 0x0e0, [UNW_HPPA_FR + 13] = 0x0e8, + [UNW_HPPA_FR + 14] = 0x0f0, [UNW_HPPA_FR + 15] = 0x0f8, + [UNW_HPPA_FR + 16] = 0x100, [UNW_HPPA_FR + 17] = 0x108, + [UNW_HPPA_FR + 18] = 0x110, [UNW_HPPA_FR + 19] = 0x118, + [UNW_HPPA_FR + 20] = 0x120, [UNW_HPPA_FR + 21] = 0x128, + [UNW_HPPA_FR + 22] = 0x130, [UNW_HPPA_FR + 23] = 0x138, + [UNW_HPPA_FR + 24] = 0x140, [UNW_HPPA_FR + 25] = 0x148, + [UNW_HPPA_FR + 26] = 0x150, [UNW_HPPA_FR + 27] = 0x158, + [UNW_HPPA_FR + 28] = 0x160, [UNW_HPPA_FR + 29] = 0x168, + [UNW_HPPA_FR + 30] = 0x170, [UNW_HPPA_FR + 31] = 0x178, + + [UNW_HPPA_IP] = 0x1a8 /* IAOQ[0] */ +#elif defined(UNW_TARGET_X86) +#if defined __FreeBSD__ +#define UNW_R_OFF(R, r) \ + [UNW_X86_##R] = offsetof(gregset_t, r_##r), + UNW_R_OFF(EAX, eax) + UNW_R_OFF(EDX, edx) + UNW_R_OFF(ECX, ecx) + UNW_R_OFF(EBX, ebx) + UNW_R_OFF(ESI, esi) + UNW_R_OFF(EDI, edi) + UNW_R_OFF(EBP, ebp) + UNW_R_OFF(ESP, esp) + UNW_R_OFF(EIP, eip) +// UNW_R_OFF(CS, cs) +// UNW_R_OFF(EFLAGS, eflags) +// UNW_R_OFF(SS, ss) +#elif defined __linux__ + [UNW_X86_EAX] = 0x18, + [UNW_X86_EBX] = 0x00, + [UNW_X86_ECX] = 0x04, + [UNW_X86_EDX] = 0x08, + [UNW_X86_ESI] = 0x0c, + [UNW_X86_EDI] = 0x10, + [UNW_X86_EBP] = 0x14, + [UNW_X86_EIP] = 0x30, + [UNW_X86_ESP] = 0x3c +/* CS = 0x34, */ +/* DS = 0x1c, */ +/* ES = 0x20, */ +/* FS = 0x24, */ +/* GS = 0x28, */ +/* ORIG_EAX = 0x2c, */ +/* EFLAGS = 0x38, */ +/* SS = 0x40 */ +#else +#error Port me +#endif +#elif defined(UNW_TARGET_X86_64) +#if defined __FreeBSD__ +#define UNW_R_OFF(R, r) \ + [UNW_X86_64_##R] = offsetof(gregset_t, r_##r), + UNW_R_OFF(RAX, rax) + UNW_R_OFF(RDX, rdx) + UNW_R_OFF(RCX, rcx) + UNW_R_OFF(RBX, rbx) + UNW_R_OFF(RSI, rsi) + UNW_R_OFF(RDI, rdi) + UNW_R_OFF(RBP, rbp) + UNW_R_OFF(RSP, rsp) + UNW_R_OFF(R8, r8) + UNW_R_OFF(R9, r9) + UNW_R_OFF(R10, r10) + UNW_R_OFF(R11, r11) + UNW_R_OFF(R12, r12) + UNW_R_OFF(R13, r13) + UNW_R_OFF(R14, r14) + UNW_R_OFF(R15, r15) + UNW_R_OFF(RIP, rip) +// UNW_R_OFF(CS, cs) +// UNW_R_OFF(EFLAGS, rflags) +// UNW_R_OFF(SS, ss) +#undef UNW_R_OFF +#elif defined __linux__ + [UNW_X86_64_RAX] = 0x50, + [UNW_X86_64_RDX] = 0x60, + [UNW_X86_64_RCX] = 0x58, + [UNW_X86_64_RBX] = 0x28, + [UNW_X86_64_RSI] = 0x68, + [UNW_X86_64_RDI] = 0x70, + [UNW_X86_64_RBP] = 0x20, + [UNW_X86_64_RSP] = 0x98, + [UNW_X86_64_R8] = 0x48, + [UNW_X86_64_R9] = 0x40, + [UNW_X86_64_R10] = 0x38, + [UNW_X86_64_R11] = 0x30, + [UNW_X86_64_R12] = 0x18, + [UNW_X86_64_R13] = 0x10, + [UNW_X86_64_R14] = 0x08, + [UNW_X86_64_R15] = 0x00, + [UNW_X86_64_RIP] = 0x80 +// [UNW_X86_64_CS] = 0x88, +// [UNW_X86_64_EFLAGS] = 0x90, +// [UNW_X86_64_RSP] = 0x98, +// [UNW_X86_64_SS] = 0xa0 +#else +#error Port me +#endif +#elif defined(UNW_TARGET_PPC32) || defined(UNW_TARGET_PPC64) + +#define UNW_REG_SLOT_SIZE sizeof(unsigned long) +#define UNW_PPC_R(v) ((v) * UNW_REG_SLOT_SIZE) +#define UNW_PPC_PT(p) UNW_PPC_R(PT_##p) + +#define UNW_FP_OFF(b, i) \ + [UNW_PPC##b##_F##i] = UNW_PPC_R(PT_FPR0 + i * 8/UNW_REG_SLOT_SIZE) + +#define UNW_R_OFF(b, i) \ + [UNW_PPC##b##_R##i] = UNW_PPC_R(PT_R##i) + +#define UNW_PPC_REGS(b) \ + UNW_R_OFF(b, 0), \ + UNW_R_OFF(b, 1), \ + UNW_R_OFF(b, 2), \ + UNW_R_OFF(b, 3), \ + UNW_R_OFF(b, 4), \ + UNW_R_OFF(b, 5), \ + UNW_R_OFF(b, 6), \ + UNW_R_OFF(b, 7), \ + UNW_R_OFF(b, 8), \ + UNW_R_OFF(b, 9), \ + UNW_R_OFF(b, 10), \ + UNW_R_OFF(b, 11), \ + UNW_R_OFF(b, 12), \ + UNW_R_OFF(b, 13), \ + UNW_R_OFF(b, 14), \ + UNW_R_OFF(b, 15), \ + UNW_R_OFF(b, 16), \ + UNW_R_OFF(b, 17), \ + UNW_R_OFF(b, 18), \ + UNW_R_OFF(b, 19), \ + UNW_R_OFF(b, 20), \ + UNW_R_OFF(b, 21), \ + UNW_R_OFF(b, 22), \ + UNW_R_OFF(b, 23), \ + UNW_R_OFF(b, 24), \ + UNW_R_OFF(b, 25), \ + UNW_R_OFF(b, 26), \ + UNW_R_OFF(b, 27), \ + UNW_R_OFF(b, 28), \ + UNW_R_OFF(b, 29), \ + UNW_R_OFF(b, 30), \ + UNW_R_OFF(b, 31), \ + \ + [UNW_PPC##b##_CTR] = UNW_PPC_PT(CTR), \ + [UNW_PPC##b##_XER] = UNW_PPC_PT(XER), \ + [UNW_PPC##b##_LR] = UNW_PPC_PT(LNK), \ + \ + UNW_FP_OFF(b, 0), \ + UNW_FP_OFF(b, 1), \ + UNW_FP_OFF(b, 2), \ + UNW_FP_OFF(b, 3), \ + UNW_FP_OFF(b, 4), \ + UNW_FP_OFF(b, 5), \ + UNW_FP_OFF(b, 6), \ + UNW_FP_OFF(b, 7), \ + UNW_FP_OFF(b, 8), \ + UNW_FP_OFF(b, 9), \ + UNW_FP_OFF(b, 10), \ + UNW_FP_OFF(b, 11), \ + UNW_FP_OFF(b, 12), \ + UNW_FP_OFF(b, 13), \ + UNW_FP_OFF(b, 14), \ + UNW_FP_OFF(b, 15), \ + UNW_FP_OFF(b, 16), \ + UNW_FP_OFF(b, 17), \ + UNW_FP_OFF(b, 18), \ + UNW_FP_OFF(b, 19), \ + UNW_FP_OFF(b, 20), \ + UNW_FP_OFF(b, 21), \ + UNW_FP_OFF(b, 22), \ + UNW_FP_OFF(b, 23), \ + UNW_FP_OFF(b, 24), \ + UNW_FP_OFF(b, 25), \ + UNW_FP_OFF(b, 26), \ + UNW_FP_OFF(b, 27), \ + UNW_FP_OFF(b, 28), \ + UNW_FP_OFF(b, 29), \ + UNW_FP_OFF(b, 30), \ + UNW_FP_OFF(b, 31) + +#define UNW_PPC32_REGS \ + [UNW_PPC32_FPSCR] = UNW_PPC_PT(FPSCR), \ + [UNW_PPC32_CCR] = UNW_PPC_PT(CCR) + +#define UNW_VR_OFF(i) \ + [UNW_PPC64_V##i] = UNW_PPC_R(PT_VR0 + i * 2) + +#define UNW_PPC64_REGS \ + [UNW_PPC64_NIP] = UNW_PPC_PT(NIP), \ + [UNW_PPC64_FRAME_POINTER] = -1, \ + [UNW_PPC64_ARG_POINTER] = -1, \ + [UNW_PPC64_CR0] = -1, \ + [UNW_PPC64_CR1] = -1, \ + [UNW_PPC64_CR2] = -1, \ + [UNW_PPC64_CR3] = -1, \ + [UNW_PPC64_CR4] = -1, \ + [UNW_PPC64_CR5] = -1, \ + [UNW_PPC64_CR6] = -1, \ + [UNW_PPC64_CR7] = -1, \ + [UNW_PPC64_VRSAVE] = UNW_PPC_PT(VRSAVE), \ + [UNW_PPC64_VSCR] = UNW_PPC_PT(VSCR), \ + [UNW_PPC64_SPE_ACC] = -1, \ + [UNW_PPC64_SPEFSCR] = -1, \ + UNW_VR_OFF(0), \ + UNW_VR_OFF(1), \ + UNW_VR_OFF(2), \ + UNW_VR_OFF(3), \ + UNW_VR_OFF(4), \ + UNW_VR_OFF(5), \ + UNW_VR_OFF(6), \ + UNW_VR_OFF(7), \ + UNW_VR_OFF(8), \ + UNW_VR_OFF(9), \ + UNW_VR_OFF(10), \ + UNW_VR_OFF(11), \ + UNW_VR_OFF(12), \ + UNW_VR_OFF(13), \ + UNW_VR_OFF(14), \ + UNW_VR_OFF(15), \ + UNW_VR_OFF(16), \ + UNW_VR_OFF(17), \ + UNW_VR_OFF(18), \ + UNW_VR_OFF(19), \ + UNW_VR_OFF(20), \ + UNW_VR_OFF(21), \ + UNW_VR_OFF(22), \ + UNW_VR_OFF(23), \ + UNW_VR_OFF(24), \ + UNW_VR_OFF(25), \ + UNW_VR_OFF(26), \ + UNW_VR_OFF(27), \ + UNW_VR_OFF(28), \ + UNW_VR_OFF(29), \ + UNW_VR_OFF(30), \ + UNW_VR_OFF(31) + +#if defined(UNW_TARGET_PPC32) + UNW_PPC_REGS(32), + UNW_PPC32_REGS, +#else + UNW_PPC_REGS(64), + UNW_PPC64_REGS, +#endif + +#elif defined(UNW_TARGET_ARM) +#if defined(__linux__) || defined(__FreeBSD__) + [UNW_ARM_R0] = 0x00, + [UNW_ARM_R1] = 0x04, + [UNW_ARM_R2] = 0x08, + [UNW_ARM_R3] = 0x0c, + [UNW_ARM_R4] = 0x10, + [UNW_ARM_R5] = 0x14, + [UNW_ARM_R6] = 0x18, + [UNW_ARM_R7] = 0x1c, + [UNW_ARM_R8] = 0x20, + [UNW_ARM_R9] = 0x24, + [UNW_ARM_R10] = 0x28, + [UNW_ARM_R11] = 0x2c, + [UNW_ARM_R12] = 0x30, + [UNW_ARM_R13] = 0x34, + [UNW_ARM_R14] = 0x38, + [UNW_ARM_R15] = 0x3c, +#else +#error Fix me +#endif +#elif defined(UNW_TARGET_MIPS) + [UNW_MIPS_R0] = 0, + [UNW_MIPS_R1] = 1, + [UNW_MIPS_R2] = 2, + [UNW_MIPS_R3] = 3, + [UNW_MIPS_R4] = 4, + [UNW_MIPS_R5] = 5, + [UNW_MIPS_R6] = 6, + [UNW_MIPS_R7] = 7, + [UNW_MIPS_R8] = 8, + [UNW_MIPS_R9] = 9, + [UNW_MIPS_R10] = 10, + [UNW_MIPS_R11] = 11, + [UNW_MIPS_R12] = 12, + [UNW_MIPS_R13] = 13, + [UNW_MIPS_R14] = 14, + [UNW_MIPS_R15] = 15, + [UNW_MIPS_R16] = 16, + [UNW_MIPS_R17] = 17, + [UNW_MIPS_R18] = 18, + [UNW_MIPS_R19] = 19, + [UNW_MIPS_R20] = 20, + [UNW_MIPS_R21] = 21, + [UNW_MIPS_R22] = 22, + [UNW_MIPS_R23] = 23, + [UNW_MIPS_R24] = 24, + [UNW_MIPS_R25] = 25, + [UNW_MIPS_R26] = 26, + [UNW_MIPS_R27] = 27, + [UNW_MIPS_R28] = 28, + [UNW_MIPS_R29] = 29, + [UNW_MIPS_R30] = 30, + [UNW_MIPS_R31] = 31, + [UNW_MIPS_PC] = 64, +#elif defined(UNW_TARGET_SH) +#elif defined(UNW_TARGET_AARCH64) + [UNW_AARCH64_X0] = 0x00, + [UNW_AARCH64_X1] = 0x08, + [UNW_AARCH64_X2] = 0x10, + [UNW_AARCH64_X3] = 0x18, + [UNW_AARCH64_X4] = 0x20, + [UNW_AARCH64_X5] = 0x28, + [UNW_AARCH64_X6] = 0x30, + [UNW_AARCH64_X7] = 0x38, + [UNW_AARCH64_X8] = 0x40, + [UNW_AARCH64_X9] = 0x48, + [UNW_AARCH64_X10] = 0x50, + [UNW_AARCH64_X11] = 0x58, + [UNW_AARCH64_X12] = 0x60, + [UNW_AARCH64_X13] = 0x68, + [UNW_AARCH64_X14] = 0x70, + [UNW_AARCH64_X15] = 0x78, + [UNW_AARCH64_X16] = 0x80, + [UNW_AARCH64_X17] = 0x88, + [UNW_AARCH64_X18] = 0x90, + [UNW_AARCH64_X19] = 0x98, + [UNW_AARCH64_X20] = 0xa0, + [UNW_AARCH64_X21] = 0xa8, + [UNW_AARCH64_X22] = 0xb0, + [UNW_AARCH64_X23] = 0xb8, + [UNW_AARCH64_X24] = 0xc0, + [UNW_AARCH64_X25] = 0xc8, + [UNW_AARCH64_X26] = 0xd0, + [UNW_AARCH64_X27] = 0xd8, + [UNW_AARCH64_X28] = 0xe0, + [UNW_AARCH64_X29] = 0xe8, + [UNW_AARCH64_X30] = 0xf0, + [UNW_AARCH64_SP] = 0xf8, + [UNW_AARCH64_PC] = 0x100, + [UNW_AARCH64_PSTATE] = 0x108 +#elif defined(UNW_TARGET_S390X) + [UNW_S390X_R0] = 0x10, + [UNW_S390X_R1] = 0x18, + [UNW_S390X_R2] = 0x20, + [UNW_S390X_R3] = 0x28, + [UNW_S390X_R4] = 0x30, + [UNW_S390X_R5] = 0x38, + [UNW_S390X_R6] = 0x40, + [UNW_S390X_R7] = 0x48, + [UNW_S390X_R8] = 0x50, + [UNW_S390X_R9] = 0x58, + [UNW_S390X_R10] = 0x60, + [UNW_S390X_R11] = 0x68, + [UNW_S390X_R12] = 0x70, + [UNW_S390X_R13] = 0x78, + [UNW_S390X_R14] = 0x80, + [UNW_S390X_R15] = 0x88, + [UNW_S390X_F0] = 0xe0, + [UNW_S390X_F1] = 0xe8, + [UNW_S390X_F2] = 0xf0, + [UNW_S390X_F3] = 0xf8, + [UNW_S390X_F4] = 0x100, + [UNW_S390X_F5] = 0x108, + [UNW_S390X_F6] = 0x110, + [UNW_S390X_F7] = 0x118, + [UNW_S390X_F8] = 0x120, + [UNW_S390X_F9] = 0x128, + [UNW_S390X_F10] = 0x130, + [UNW_S390X_F11] = 0x138, + [UNW_S390X_F12] = 0x140, + [UNW_S390X_F13] = 0x148, + [UNW_S390X_F14] = 0x150, + [UNW_S390X_F15] = 0x150, + [UNW_S390X_IP] = 0x08 +#elif defined(UNW_TARGET_RISCV) + +#if __riscv_xlen == 64 +# define RISCV_REG_OFFSET(x) (8*x) +#elif __riscv_xlen == 32 +# define RISCV_REG_OFFSET(x) (4*x) +#else +# error "Unsupported address size" +#endif + [UNW_RISCV_PC] = RISCV_REG_OFFSET(0), + [UNW_RISCV_X1] = RISCV_REG_OFFSET(1), + [UNW_RISCV_X2] = RISCV_REG_OFFSET(2), + [UNW_RISCV_X3] = RISCV_REG_OFFSET(3), + [UNW_RISCV_X4] = RISCV_REG_OFFSET(4), + [UNW_RISCV_X5] = RISCV_REG_OFFSET(5), + [UNW_RISCV_X6] = RISCV_REG_OFFSET(6), + [UNW_RISCV_X7] = RISCV_REG_OFFSET(7), + [UNW_RISCV_X8] = RISCV_REG_OFFSET(8), + [UNW_RISCV_X9] = RISCV_REG_OFFSET(9), + [UNW_RISCV_X10] = RISCV_REG_OFFSET(10), + [UNW_RISCV_X11] = RISCV_REG_OFFSET(11), + [UNW_RISCV_X12] = RISCV_REG_OFFSET(12), + [UNW_RISCV_X13] = RISCV_REG_OFFSET(13), + [UNW_RISCV_X14] = RISCV_REG_OFFSET(14), + [UNW_RISCV_X15] = RISCV_REG_OFFSET(15), + [UNW_RISCV_X16] = RISCV_REG_OFFSET(16), + [UNW_RISCV_X17] = RISCV_REG_OFFSET(17), + [UNW_RISCV_X18] = RISCV_REG_OFFSET(18), + [UNW_RISCV_X19] = RISCV_REG_OFFSET(19), + [UNW_RISCV_X20] = RISCV_REG_OFFSET(20), + [UNW_RISCV_X21] = RISCV_REG_OFFSET(21), + [UNW_RISCV_X22] = RISCV_REG_OFFSET(22), + [UNW_RISCV_X23] = RISCV_REG_OFFSET(23), + [UNW_RISCV_X24] = RISCV_REG_OFFSET(24), + [UNW_RISCV_X25] = RISCV_REG_OFFSET(25), + [UNW_RISCV_X26] = RISCV_REG_OFFSET(26), + [UNW_RISCV_X27] = RISCV_REG_OFFSET(27), + [UNW_RISCV_X28] = RISCV_REG_OFFSET(28), + [UNW_RISCV_X29] = RISCV_REG_OFFSET(29), + [UNW_RISCV_X30] = RISCV_REG_OFFSET(30), + [UNW_RISCV_X31] = RISCV_REG_OFFSET(31), +#elif defined(UNW_TARGET_LOONGARCH64) +# include + + [UNW_LOONGARCH64_R0] = LOONGARCH_EF_R0, + [UNW_LOONGARCH64_R1] = LOONGARCH_EF_R1, + [UNW_LOONGARCH64_R2] = LOONGARCH_EF_R2, + [UNW_LOONGARCH64_R3] = LOONGARCH_EF_R3, + [UNW_LOONGARCH64_R4] = LOONGARCH_EF_R4, + [UNW_LOONGARCH64_R5] = LOONGARCH_EF_R5, + [UNW_LOONGARCH64_R6] = LOONGARCH_EF_R6, + [UNW_LOONGARCH64_R7] = LOONGARCH_EF_R7, + [UNW_LOONGARCH64_R8] = LOONGARCH_EF_R8, + [UNW_LOONGARCH64_R9] = LOONGARCH_EF_R9, + [UNW_LOONGARCH64_R10] = LOONGARCH_EF_R10, + [UNW_LOONGARCH64_R11] = LOONGARCH_EF_R11, + [UNW_LOONGARCH64_R12] = LOONGARCH_EF_R12, + [UNW_LOONGARCH64_R13] = LOONGARCH_EF_R13, + [UNW_LOONGARCH64_R14] = LOONGARCH_EF_R14, + [UNW_LOONGARCH64_R15] = LOONGARCH_EF_R15, + [UNW_LOONGARCH64_R16] = LOONGARCH_EF_R16, + [UNW_LOONGARCH64_R17] = LOONGARCH_EF_R17, + [UNW_LOONGARCH64_R18] = LOONGARCH_EF_R18, + [UNW_LOONGARCH64_R19] = LOONGARCH_EF_R19, + [UNW_LOONGARCH64_R20] = LOONGARCH_EF_R20, + [UNW_LOONGARCH64_R21] = LOONGARCH_EF_R21, + [UNW_LOONGARCH64_R22] = LOONGARCH_EF_R22, + [UNW_LOONGARCH64_R23] = LOONGARCH_EF_R23, + [UNW_LOONGARCH64_R24] = LOONGARCH_EF_R24, + [UNW_LOONGARCH64_R25] = LOONGARCH_EF_R25, + [UNW_LOONGARCH64_R26] = LOONGARCH_EF_R26, + [UNW_LOONGARCH64_R27] = LOONGARCH_EF_R27, + [UNW_LOONGARCH64_R28] = LOONGARCH_EF_R28, + [UNW_LOONGARCH64_R29] = LOONGARCH_EF_R29, + [UNW_LOONGARCH64_R30] = LOONGARCH_EF_R30, + [UNW_LOONGARCH64_R31] = LOONGARCH_EF_R31, + [UNW_LOONGARCH64_PC] = LOONGARCH_EF_CSR_ERA +#else +# error Fix me. +#endif + }; diff --git a/vendor/libunwind/src/ptrace/_UPT_resume.c b/vendor/libunwind/src/ptrace/_UPT_resume.c new file mode 100644 index 0000000000..9ca5224cd8 --- /dev/null +++ b/vendor/libunwind/src/ptrace/_UPT_resume.c @@ -0,0 +1,42 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "_UPT_internal.h" + +int +_UPT_resume (unw_addr_space_t as UNUSED, unw_cursor_t *c UNUSED, void *arg) +{ + struct UPT_info *ui = arg; + + mi_init (); + +#ifdef HAVE_TTRACE +# warning No support for ttrace() yet. +#elif HAVE_DECL_PTRACE_CONT + return ptrace (PTRACE_CONT, ui->pid, 0, 0); +#elif HAVE_DECL_PT_CONTINUE + return ptrace(PT_CONTINUE, ui->pid, (caddr_t)1, 0); +#endif +} From d1818f5de0339702e4286bdd6c930ccb9ea3c0e9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 09:34:44 +0200 Subject: [PATCH 02/14] fix(native): keep crash stack buffer for unwind fallback Only free the captured stack buffer once a remote-unwind stacktrace is actually returned. If remote unwinding yields frames but all are filtered, the fallback stacktrace paths still need to own and clean up the buffer. --- src/backends/native/sentry_crash_daemon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index b8a774fde5..9b15439f70 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -945,11 +945,11 @@ build_stacktrace_for_thread( frame_count++; } - if (stack_buf) { - sentry_free(stack_buf); - } - if (frame_count > 0) { + if (stack_buf) { + sentry_free(stack_buf); + } + for (int i = frame_count - 1; i >= 0; i--) { sentry_value_append(frames, temp_frames[i]); } From d23877aa7e28b0e3007099b409dbb8cc4940f4f2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 10:49:54 +0200 Subject: [PATCH 03/14] fix(native): heap allocate remote unwind frames Avoid reserving the remote unwind frame buffer on the daemon stack. If the allocation fails, remote unwinding is skipped and the existing fallback stacktrace paths continue to run. --- src/backends/native/sentry_crash_daemon.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 9b15439f70..8065df970c 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -915,9 +915,12 @@ build_stacktrace_for_thread( } if (tid > 0) { - sentry_remote_frame_t remote_frames[MAX_STACK_FRAMES]; - size_t remote_count = sentry__remote_unwind_thread( - tid, remote_frames, MAX_STACK_FRAMES); + sentry_remote_frame_t *remote_frames + = sentry_malloc(sizeof(*remote_frames) * MAX_STACK_FRAMES); + size_t remote_count = remote_frames + ? sentry__remote_unwind_thread( + tid, remote_frames, MAX_STACK_FRAMES) + : 0; if (remote_count > 0) { SENTRY_DEBUGF("Remote unwound %zu frames for thread %d", @@ -956,9 +959,14 @@ build_stacktrace_for_thread( sentry_value_set_by_key(stacktrace, "frames", frames); sentry_value_set_by_key(stacktrace, "registers", build_registers_from_ctx(ctx, thread_idx)); + sentry_free(remote_frames); return stacktrace; } } + + if (remote_frames) { + sentry_free(remote_frames); + } } } // Fall through to pre-captured backtrace or FP-walking if remote From 6a4bb99d897dc1c45b52319bfe07a9af89d0f339 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 10:58:14 +0200 Subject: [PATCH 04/14] Update VENDORING.md --- vendor/libunwind/VENDORING.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/vendor/libunwind/VENDORING.md b/vendor/libunwind/VENDORING.md index 541ec60e69..4b1960eb9e 100644 --- a/vendor/libunwind/VENDORING.md +++ b/vendor/libunwind/VENDORING.md @@ -75,15 +75,14 @@ Source and include directories for architectures sentry-native does not target: ### 4. Unused feature modules -These are separate `libunwind` "accessor" libraries for non-local unwinding use -cases: +These are separate `libunwind` "accessor" libraries that are not needed by +sentry-native: -| Directory | Purpose | Status | -|-----------------|-------------------------------------|---------------------------------------------------------| -| `src/ptrace/` | Remote unwinding via `ptrace()` | **Re-added** — used by the native backend's crash daemon | -| `src/coredump/` | Unwinding from a coredump file | Removed — not a live-process use case | -| `src/nto/` | QNX Neutrino ptrace-based unwinding | Removed — QNX is not a sentry-native target | -| `src/setjmp/` | `setjmp`/`longjmp` wrappers | Removed — not relevant for crash reporting | +| Directory | Purpose | Why removed | +|-----------------|-------------------------------------|-----------------------------------| +| `src/coredump/` | Unwinding from a coredump file | Not a live-process use case | +| `src/nto/` | QNX Neutrino ptrace-based unwinding | QNX is not a sentry-native target | +| `src/setjmp/` | `setjmp`/`longjmp` wrappers | Not relevant for crash reporting | ### What is kept but NOT built @@ -116,7 +115,7 @@ never calls into the C++ exception ABI. | File | Purpose | |-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| -| `CMakeLists.txt` | Custom CMake build that replaces the upstream autotools + upstream CMake build. Builds `unwind` (local) and optionally `unwind_remote` (local + remote + ptrace) | +| `CMakeLists.txt` | Custom CMake build that replaces the upstream autotools + upstream CMake build. Builds a static `unwind` target for x86, x86_64, and aarch64 only | | `cmake/config.h.cmake.in` | CMake template for `config.h` (replaces autotools `configure`-generated header) | | `cmake/libunwind-common.h.cmake.in` | CMake template for `libunwind-common.h` | | `VENDORING.md` | This file | From 0602eda4e3b89d28ea95abd9ed5491f419c0d62c Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 11:46:45 +0200 Subject: [PATCH 05/14] ref(native): align remote unwinder with unwinder dispatch Move the Linux remote libunwind implementation under src/unwinder and route it through sentry_unwinder.c, matching the existing local unwinder backend selection pattern. Expose a backend-neutral sentry__unwind_stack_from_thread() entry point for the daemon while keeping the libunwind-specific implementation private to the backend file. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- src/backends/native/sentry_crash_daemon.c | 4 +-- src/backends/native/sentry_remote_unwind.h | 28 ----------------- src/unwinder/sentry_unwinder.c | 30 +++++++++++++++++++ src/unwinder/sentry_unwinder.h | 19 ++++++++++++ .../sentry_unwinder_libunwind_remote.c} | 16 +++++----- 7 files changed, 62 insertions(+), 39 deletions(-) delete mode 100644 src/backends/native/sentry_remote_unwind.h rename src/{backends/native/sentry_remote_unwind.c => unwinder/sentry_unwinder_libunwind_remote.c} (86%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 466bf5f35b..42e5f4d684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -840,7 +840,7 @@ elseif(SENTRY_BACKEND_NATIVE) ) if(SENTRY_WITH_LIBUNWIND AND LINUX) - target_compile_definitions(sentry-crash PRIVATE SENTRY_WITH_REMOTE_UNWIND) + target_compile_definitions(sentry-crash PRIVATE SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE) endif() # Copy include directories from sentry target diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9d4044ace..317f7b3ea9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,7 +174,7 @@ elseif(SENTRY_BACKEND_NATIVE) # Remote unwinding (Linux only — uses libunwind ptrace accessors) if(LINUX) sentry_target_sources_cwd(sentry - backends/native/sentry_remote_unwind.c + unwinder/sentry_unwinder_libunwind_remote.c ) endif() diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 8065df970c..3c53c2c41a 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -48,7 +48,7 @@ # include # endif # if defined(SENTRY_PLATFORM_LINUX) -# include "sentry_remote_unwind.h" +# include "unwinder/sentry_unwinder.h" # endif #elif defined(SENTRY_PLATFORM_WINDOWS) # include @@ -918,7 +918,7 @@ build_stacktrace_for_thread( sentry_remote_frame_t *remote_frames = sentry_malloc(sizeof(*remote_frames) * MAX_STACK_FRAMES); size_t remote_count = remote_frames - ? sentry__remote_unwind_thread( + ? sentry__unwind_stack_from_thread( tid, remote_frames, MAX_STACK_FRAMES) : 0; diff --git a/src/backends/native/sentry_remote_unwind.h b/src/backends/native/sentry_remote_unwind.h deleted file mode 100644 index 998d2cf034..0000000000 --- a/src/backends/native/sentry_remote_unwind.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SENTRY_REMOTE_UNWIND_H_INCLUDED -#define SENTRY_REMOTE_UNWIND_H_INCLUDED - -#include -#include -#include - -#define SENTRY_REMOTE_UNWIND_MAX_SYMBOL 256 - -typedef struct { - uint64_t ip; - char symbol[SENTRY_REMOTE_UNWIND_MAX_SYMBOL]; - uint64_t symbol_offset; -} sentry_remote_frame_t; - -/** - * Remotely unwind a thread's stack using libunwind ptrace accessors. - * Handles ptrace attach/detach internally. - * - * @param tid Thread ID to unwind - * @param frames Output array of frames - * @param max_frames Maximum number of frames to capture - * @return Number of frames captured, or 0 on failure - */ -size_t sentry__remote_unwind_thread( - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames); - -#endif diff --git a/src/unwinder/sentry_unwinder.c b/src/unwinder/sentry_unwinder.c index 09664d0156..efee379db8 100644 --- a/src/unwinder/sentry_unwinder.c +++ b/src/unwinder/sentry_unwinder.c @@ -1,3 +1,4 @@ +#include "sentry_unwinder.h" #include "sentry_boot.h" #define DEFINE_UNWINDER(Func) \ @@ -19,6 +20,23 @@ DEFINE_UNWINDER(libunwind); DEFINE_UNWINDER(libunwind_mac); DEFINE_UNWINDER(psunwind); +#if defined(SENTRY_PLATFORM_LINUX) +# define DEFINE_THREAD_UNWINDER(Func) \ + size_t sentry__unwind_stack_from_thread_##Func( \ + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) + +# define TRY_THREAD_UNWINDER(Func) \ + do { \ + size_t rv = sentry__unwind_stack_from_thread_##Func( \ + tid, frames, max_frames); \ + if (rv > 0) { \ + return rv; \ + } \ + } while (0) + +DEFINE_THREAD_UNWINDER(libunwind_remote); +#endif + static size_t unwind_stack( void *addr, const sentry_ucontext_t *uctx, void **ptrs, size_t max_frames) @@ -56,3 +74,15 @@ sentry_unwind_stack_from_ucontext( { return unwind_stack(NULL, uctx, stacktrace_out, max_len); } + +#if defined(SENTRY_PLATFORM_LINUX) +size_t +sentry__unwind_stack_from_thread( + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +{ +# ifdef SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE + TRY_THREAD_UNWINDER(libunwind_remote); +# endif + return 0; +} +#endif diff --git a/src/unwinder/sentry_unwinder.h b/src/unwinder/sentry_unwinder.h index 889d20ca18..2d4562f29b 100644 --- a/src/unwinder/sentry_unwinder.h +++ b/src/unwinder/sentry_unwinder.h @@ -5,4 +5,23 @@ typedef struct { uintptr_t lo, hi; } mem_range_t; +#if defined(SENTRY_PLATFORM_LINUX) + +# include +# include +# include + +# define SENTRY_REMOTE_UNWIND_MAX_SYMBOL 256 + +typedef struct { + uint64_t ip; + char symbol[SENTRY_REMOTE_UNWIND_MAX_SYMBOL]; + uint64_t symbol_offset; +} sentry_remote_frame_t; + +size_t sentry__unwind_stack_from_thread( + pid_t tid, sentry_remote_frame_t *frames, size_t max_frames); + +#endif + #endif // SENTRY_UNWINDER_H_INCLUDED diff --git a/src/backends/native/sentry_remote_unwind.c b/src/unwinder/sentry_unwinder_libunwind_remote.c similarity index 86% rename from src/backends/native/sentry_remote_unwind.c rename to src/unwinder/sentry_unwinder_libunwind_remote.c index 3d2addb6c4..69ad504e0e 100644 --- a/src/backends/native/sentry_remote_unwind.c +++ b/src/unwinder/sentry_unwinder_libunwind_remote.c @@ -2,13 +2,15 @@ // This file must NOT define UNW_LOCAL_ONLY so that unw_init_remote() // and other generic (_U prefix) symbols are used. // -// Only compiled into sentry-crash daemon (SENTRY_WITH_REMOTE_UNWIND). +// Only compiled into sentry-crash daemon +// (SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE). // The sentry library compiles this file too (shared sources) but the // function body is empty without the define. -#include "sentry_remote_unwind.h" +#include "sentry_boot.h" +#include "sentry_unwinder.h" -#ifdef SENTRY_WITH_REMOTE_UNWIND +#ifdef SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE # include "sentry_logger.h" @@ -21,7 +23,7 @@ # include size_t -sentry__remote_unwind_thread( +sentry__unwind_stack_from_thread_libunwind_remote( pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) { if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) != 0) { @@ -96,10 +98,10 @@ sentry__remote_unwind_thread( return n; } -#else /* !SENTRY_WITH_REMOTE_UNWIND */ +#else /* !SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE */ size_t -sentry__remote_unwind_thread( +sentry__unwind_stack_from_thread_libunwind_remote( pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) { (void)tid; @@ -108,4 +110,4 @@ sentry__remote_unwind_thread( return 0; } -#endif /* SENTRY_WITH_REMOTE_UNWIND */ +#endif /* SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE */ From 5e16a6e1c4bff144e1dcdc1c2d9927aaad3bf4f8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 11:51:57 +0200 Subject: [PATCH 06/14] fix(native): prefer signal backtrace for crashed thread Skip remote thread unwinding for the crashed Linux thread when the signal handler already captured a backtrace. This keeps the signal-frame-aware ucontext unwind as the primary stacktrace and avoids replacing it with a potentially partial remote unwind from the handler wait state. Make sentry_unwinder.h self-contained now that sentry_unwinder.c includes it for remote unwinder dispatch. --- src/backends/native/sentry_crash_daemon.c | 9 ++++++--- src/unwinder/sentry_unwinder.h | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 3c53c2c41a..d4644852ab 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -904,8 +904,8 @@ build_stacktrace_for_thread( int frame_count = 0; #if defined(SENTRY_PLATFORM_LINUX) - // Remote DWARF unwinding via libunwind ptrace accessors. - // Works for all threads (including crashing) and resolves symbol names. + // Remote DWARF unwinding via libunwind ptrace accessors. For the crashed + // thread, prefer the signal-handler backtrace below when available. { pid_t tid = 0; if (thread_idx == SIZE_MAX || thread_idx == 0) { @@ -914,7 +914,10 @@ build_stacktrace_for_thread( tid = ctx->platform.threads[thread_idx].tid; } - if (tid > 0) { + bool has_crashed_thread_backtrace = ctx->platform.backtrace_count > 0 + && (thread_idx == SIZE_MAX || tid == ctx->crashed_tid); + + if (tid > 0 && !has_crashed_thread_backtrace) { sentry_remote_frame_t *remote_frames = sentry_malloc(sizeof(*remote_frames) * MAX_STACK_FRAMES); size_t remote_count = remote_frames diff --git a/src/unwinder/sentry_unwinder.h b/src/unwinder/sentry_unwinder.h index 2d4562f29b..aae265005d 100644 --- a/src/unwinder/sentry_unwinder.h +++ b/src/unwinder/sentry_unwinder.h @@ -1,6 +1,10 @@ #ifndef SENTRY_UNWINDER_H_INCLUDED #define SENTRY_UNWINDER_H_INCLUDED +#include "sentry_boot.h" + +#include + typedef struct { uintptr_t lo, hi; } mem_range_t; @@ -8,7 +12,6 @@ typedef struct { #if defined(SENTRY_PLATFORM_LINUX) # include -# include # include # define SENTRY_REMOTE_UNWIND_MAX_SYMBOL 256 From 26c07d513aca803d7cec57c7950f20e101976458 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 11:56:52 +0200 Subject: [PATCH 07/14] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f379e72b..b27e5fcb3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +**Features**: + +- Native/Linux: symbolicate stack frames in the crash daemon. ([#1747](https://github.com/getsentry/sentry-native/pull/1747)) + **Fixes**: - Native/macOS: fix module `image_size` computation, which could have caused the symbolicator to misattribute every frame to the lowest-addressed image (typically `dyld` or `libsystem`). ([#1740](https://github.com/getsentry/sentry-native/pull/1740)) From dcd8ebcb3c53940fd8bc5be1a0cb62acae3688a0 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:01:13 +0200 Subject: [PATCH 08/14] docs(native): clarify stack frame trust assignment Document that frame trust tracks the unwind source rather than the emitted frame index, so filtered initial frames do not cause subsequent CFI frames to be labeled as context frames. --- src/backends/native/sentry_crash_daemon.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index d4644852ab..db2b4c4f4c 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -939,6 +939,9 @@ build_stacktrace_for_thread( sentry_value_set_by_key(temp_frames[frame_count], "instruction_addr", sentry__value_new_addr(remote_frames[i].ip)); + // Trust describes the unwind source, not the emitted + // frame index. If the initial cursor frame is filtered + // out, the next emitted frame was still reached via CFI. sentry_value_set_by_key(temp_frames[frame_count], "trust", sentry_value_new_string(i == 0 ? "context" : "cfi")); enrich_frame_with_module_info( @@ -994,6 +997,9 @@ build_stacktrace_for_thread( temp_frames[frame_count] = sentry_value_new_object(); sentry_value_set_by_key(temp_frames[frame_count], "instruction_addr", sentry__value_new_addr(frame_ip)); + // Trust describes the unwind source, not the emitted frame index. + // If the initial cursor frame is filtered out, the next emitted + // frame was still reached via CFI. sentry_value_set_by_key(temp_frames[frame_count], "trust", sentry_value_new_string(i == 0 ? "context" : "cfi")); enrich_frame_with_module_info( From 311e4c4e1a0edd5fc2baf10775a925f1c9b24f82 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:09:25 +0200 Subject: [PATCH 09/14] fix(native): avoid ptrace unwind of crashed thread Skip daemon-side ptrace unwinding for the crashed Linux thread so PTRACE_DETACH cannot resume it while crash processing is still running. The crashed thread continues to use the saved fault context and any pre-captured backtrace. --- src/backends/native/sentry_crash_daemon.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index db2b4c4f4c..8074e05bcb 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -904,8 +904,8 @@ build_stacktrace_for_thread( int frame_count = 0; #if defined(SENTRY_PLATFORM_LINUX) - // Remote DWARF unwinding via libunwind ptrace accessors. For the crashed - // thread, prefer the signal-handler backtrace below when available. + // Remote DWARF unwinding via libunwind ptrace accessors. Do not attach to + // the crashed thread from the daemon; use the saved fault context below. { pid_t tid = 0; if (thread_idx == SIZE_MAX || thread_idx == 0) { @@ -914,10 +914,10 @@ build_stacktrace_for_thread( tid = ctx->platform.threads[thread_idx].tid; } - bool has_crashed_thread_backtrace = ctx->platform.backtrace_count > 0 - && (thread_idx == SIZE_MAX || tid == ctx->crashed_tid); + bool is_crashed_thread + = thread_idx == SIZE_MAX || tid == ctx->crashed_tid; - if (tid > 0 && !has_crashed_thread_backtrace) { + if (tid > 0 && !is_crashed_thread) { sentry_remote_frame_t *remote_frames = sentry_malloc(sizeof(*remote_frames) * MAX_STACK_FRAMES); size_t remote_count = remote_frames From a50627407a2d9380ae6275cf4ba75588f2de5975 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:44:44 +0200 Subject: [PATCH 10/14] fix(native): verify ptrace stop before remote unwind After attaching to a thread, require waitpid() to report a stopped tracee before entering libunwind's remote unwinder. This avoids calling unw_init_remote() when the attach/wait race reports a non-stopped thread. --- src/unwinder/sentry_unwinder_libunwind_remote.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/unwinder/sentry_unwinder_libunwind_remote.c b/src/unwinder/sentry_unwinder_libunwind_remote.c index 69ad504e0e..81e5f5451b 100644 --- a/src/unwinder/sentry_unwinder_libunwind_remote.c +++ b/src/unwinder/sentry_unwinder_libunwind_remote.c @@ -39,6 +39,13 @@ sentry__unwind_stack_from_thread_libunwind_remote( ptrace(PTRACE_DETACH, tid, NULL, NULL); return 0; } + if (!WIFSTOPPED(status)) { + SENTRY_WARNF( + "remote_unwind: thread %d did not stop after attach: status=%d", + tid, status); + ptrace(PTRACE_DETACH, tid, NULL, NULL); + return 0; + } size_t n = 0; From af1e9b8dda5cf1eb82128151ca4b5f083643f3fd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:51:44 +0200 Subject: [PATCH 11/14] fix(native): wire arm32 remote libunwind build Add the arm32 generic libunwind sources and target definitions to the vendored unwind_remote target so daemon-side remote unwinding is built consistently with the local arm32 unwinder. --- vendor/libunwind/CMakeLists.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/vendor/libunwind/CMakeLists.txt b/vendor/libunwind/CMakeLists.txt index 7d76c3ff61..4c8b4c1d38 100644 --- a/vendor/libunwind/CMakeLists.txt +++ b/vendor/libunwind/CMakeLists.txt @@ -382,6 +382,25 @@ elseif(UNWIND_ARCH STREQUAL "x86") ${LIBUNWIND_SRC}/x86/Gresume.c ${LIBUNWIND_SRC}/x86/Gstep.c ) +elseif(UNWIND_ARCH STREQUAL "arm") + set(UNWIND_GENERIC_ARCH_SOURCES + ${LIBUNWIND_SRC}/arm/Gos-linux.c + ${LIBUNWIND_SRC}/arm/Gapply_reg_state.c + ${LIBUNWIND_SRC}/arm/Gcreate_addr_space.c + ${LIBUNWIND_SRC}/arm/Gex_tables.c + ${LIBUNWIND_SRC}/arm/Gget_proc_info.c + ${LIBUNWIND_SRC}/arm/Gget_save_loc.c + ${LIBUNWIND_SRC}/arm/Gglobal.c + ${LIBUNWIND_SRC}/arm/Ginit.c + ${LIBUNWIND_SRC}/arm/Ginit_local.c + ${LIBUNWIND_SRC}/arm/Ginit_remote.c + ${LIBUNWIND_SRC}/arm/Gregs.c + ${LIBUNWIND_SRC}/arm/Greg_states_iterate.c + ${LIBUNWIND_SRC}/arm/Gresume.c + ${LIBUNWIND_SRC}/arm/Gstash_frame.c + ${LIBUNWIND_SRC}/arm/Gstep.c + ${LIBUNWIND_SRC}/arm/Gtrace.c + ) endif() # Ptrace accessor library (_UPT_* functions for remote unwinding via ptrace) @@ -435,6 +454,9 @@ elseif(UNWIND_ARCH STREQUAL "aarch64") elseif(UNWIND_ARCH STREQUAL "x86") target_include_directories(unwind_remote PRIVATE ${LIBUNWIND_INC}/tdep-x86) target_compile_definitions(unwind_remote PRIVATE UNW_TARGET_X86=1) +elseif(UNWIND_ARCH STREQUAL "arm") + target_include_directories(unwind_remote PRIVATE ${LIBUNWIND_INC}/tdep-arm) + target_compile_definitions(unwind_remote PRIVATE UNW_TARGET_ARM=1) endif() target_compile_definitions(unwind_remote PRIVATE From 2d1abb828c49130932dac61256d1dba9c998649b Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:55:08 +0200 Subject: [PATCH 12/14] fix(native): silence remote unwinder dispatcher warnings The regular sentry target compiles the Linux thread-unwind dispatcher without the daemon-only remote unwinder backend enabled. Mark the dispatcher arguments as intentionally unused so Clang -Werror builds do not fail in that configuration. --- src/unwinder/sentry_unwinder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unwinder/sentry_unwinder.c b/src/unwinder/sentry_unwinder.c index efee379db8..a8b5ef5837 100644 --- a/src/unwinder/sentry_unwinder.c +++ b/src/unwinder/sentry_unwinder.c @@ -80,6 +80,9 @@ size_t sentry__unwind_stack_from_thread( pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) { + (void)tid; + (void)frames; + (void)max_frames; # ifdef SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE TRY_THREAD_UNWINDER(libunwind_remote); # endif From 95db64650e803dfde3a5e92fef98856d415d1b9d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 12:58:14 +0200 Subject: [PATCH 13/14] fix(native): omit bogus registers from remote stacks Non-crashed Linux threads discovered by the daemon only have a TID and a zero-filled ucontext. Do not attach a registers object to successfully remote-unwound stacktraces for those threads. --- src/backends/native/sentry_crash_daemon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 8074e05bcb..0d7f99627d 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -963,8 +963,6 @@ build_stacktrace_for_thread( sentry_value_append(frames, temp_frames[i]); } sentry_value_set_by_key(stacktrace, "frames", frames); - sentry_value_set_by_key(stacktrace, "registers", - build_registers_from_ctx(ctx, thread_idx)); sentry_free(remote_frames); return stacktrace; } From 4cf3b681064cdd6c2fcdf25fe4d46cf18ba6c6bd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 25 May 2026 14:32:45 +0200 Subject: [PATCH 14/14] fix(native): attach registers to remote unwind stacks Capture register values from the initial libunwind cursor for remote Linux stack walking and attach them to the produced stacktrace. Keep the remote thread unwinder API aligned with sentry_unwind_stack by returning the frame count directly, with registers passed as optional side metadata. --- src/backends/native/sentry_crash_daemon.c | 25 +++++++- src/unwinder/sentry_unwinder.c | 12 ++-- src/unwinder/sentry_unwinder.h | 17 ++++- .../sentry_unwinder_libunwind_remote.c | 63 +++++++++++++++++-- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 0d7f99627d..d9a42d1024 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -547,6 +547,24 @@ build_registers_from_ctx(const sentry_crash_context_t *ctx, size_t thread_idx) return registers; } +#if defined(SENTRY_PLATFORM_LINUX) +static sentry_value_t +build_registers_from_remote_registers( + const sentry_remote_registers_t *remote_registers) +{ + sentry_value_t registers = sentry_value_new_object(); + + for (size_t i = 0; i < remote_registers->count; i++) { + const sentry_remote_register_t *remote_register + = &remote_registers->values[i]; + sentry_value_set_by_key(registers, remote_register->name, + sentry__value_new_addr(remote_register->value)); + } + + return registers; +} +#endif + /** * Maximum number of frames to unwind */ @@ -918,11 +936,12 @@ build_stacktrace_for_thread( = thread_idx == SIZE_MAX || tid == ctx->crashed_tid; if (tid > 0 && !is_crashed_thread) { + sentry_remote_registers_t registers = { 0 }; sentry_remote_frame_t *remote_frames = sentry_malloc(sizeof(*remote_frames) * MAX_STACK_FRAMES); size_t remote_count = remote_frames ? sentry__unwind_stack_from_thread( - tid, remote_frames, MAX_STACK_FRAMES) + tid, remote_frames, MAX_STACK_FRAMES, ®isters) : 0; if (remote_count > 0) { @@ -963,6 +982,10 @@ build_stacktrace_for_thread( sentry_value_append(frames, temp_frames[i]); } sentry_value_set_by_key(stacktrace, "frames", frames); + if (registers.count > 0) { + sentry_value_set_by_key(stacktrace, "registers", + build_registers_from_remote_registers(®isters)); + } sentry_free(remote_frames); return stacktrace; } diff --git a/src/unwinder/sentry_unwinder.c b/src/unwinder/sentry_unwinder.c index a8b5ef5837..8424236e90 100644 --- a/src/unwinder/sentry_unwinder.c +++ b/src/unwinder/sentry_unwinder.c @@ -22,13 +22,14 @@ DEFINE_UNWINDER(psunwind); #if defined(SENTRY_PLATFORM_LINUX) # define DEFINE_THREAD_UNWINDER(Func) \ - size_t sentry__unwind_stack_from_thread_##Func( \ - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) + size_t sentry__unwind_stack_from_thread_##Func(pid_t tid, \ + sentry_remote_frame_t *frames, size_t max_frames, \ + sentry_remote_registers_t *registers) # define TRY_THREAD_UNWINDER(Func) \ do { \ size_t rv = sentry__unwind_stack_from_thread_##Func( \ - tid, frames, max_frames); \ + tid, frames, max_frames, registers); \ if (rv > 0) { \ return rv; \ } \ @@ -77,12 +78,13 @@ sentry_unwind_stack_from_ucontext( #if defined(SENTRY_PLATFORM_LINUX) size_t -sentry__unwind_stack_from_thread( - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +sentry__unwind_stack_from_thread(pid_t tid, sentry_remote_frame_t *frames, + size_t max_frames, sentry_remote_registers_t *registers) { (void)tid; (void)frames; (void)max_frames; + (void)registers; # ifdef SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE TRY_THREAD_UNWINDER(libunwind_remote); # endif diff --git a/src/unwinder/sentry_unwinder.h b/src/unwinder/sentry_unwinder.h index aae265005d..09b83b77e1 100644 --- a/src/unwinder/sentry_unwinder.h +++ b/src/unwinder/sentry_unwinder.h @@ -14,16 +14,29 @@ typedef struct { # include # include +# define SENTRY_REMOTE_UNWIND_MAX_REGISTER_NAME 16 +# define SENTRY_REMOTE_UNWIND_MAX_REGISTERS 64 # define SENTRY_REMOTE_UNWIND_MAX_SYMBOL 256 +typedef struct { + char name[SENTRY_REMOTE_UNWIND_MAX_REGISTER_NAME]; + uint64_t value; +} sentry_remote_register_t; + typedef struct { uint64_t ip; char symbol[SENTRY_REMOTE_UNWIND_MAX_SYMBOL]; uint64_t symbol_offset; } sentry_remote_frame_t; -size_t sentry__unwind_stack_from_thread( - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames); +typedef struct { + size_t count; + sentry_remote_register_t values[SENTRY_REMOTE_UNWIND_MAX_REGISTERS]; +} sentry_remote_registers_t; + +size_t sentry__unwind_stack_from_thread(pid_t tid, + sentry_remote_frame_t *frames, size_t max_frames, + sentry_remote_registers_t *registers); #endif diff --git a/src/unwinder/sentry_unwinder_libunwind_remote.c b/src/unwinder/sentry_unwinder_libunwind_remote.c index 81e5f5451b..99bb8bb854 100644 --- a/src/unwinder/sentry_unwinder_libunwind_remote.c +++ b/src/unwinder/sentry_unwinder_libunwind_remote.c @@ -8,6 +8,7 @@ // function body is empty without the define. #include "sentry_boot.h" +#include "sentry_string.h" #include "sentry_unwinder.h" #ifdef SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE @@ -22,10 +23,60 @@ # include # include +static int +format_register_name(char *dst, size_t dst_len, unw_regnum_t reg) +{ + const char *name = unw_regname(reg); + if (!name || strcmp(name, "???") == 0) { + return 0; + } + + size_t len = strlen(name); + if (len == 0 || len >= dst_len) { + return 0; + } + + memcpy(dst, name, len + 1); + sentry__string_ascii_lower(dst); + return 1; +} + +static void +capture_registers(unw_cursor_t *cursor, sentry_remote_registers_t *registers) +{ + if (!registers) { + return; + } + + for (unw_regnum_t reg = 0; reg <= UNW_REG_LAST + && registers->count < SENTRY_REMOTE_UNWIND_MAX_REGISTERS; + reg++) { + unw_word_t value = 0; + if (unw_get_reg(cursor, reg, &value) < 0) { + continue; + } + + sentry_remote_register_t *remote_register + = ®isters->values[registers->count]; + if (!format_register_name( + remote_register->name, sizeof(remote_register->name), reg)) { + continue; + } + + remote_register->value = (uint64_t)value; + registers->count++; + } +} + size_t -sentry__unwind_stack_from_thread_libunwind_remote( - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +sentry__unwind_stack_from_thread_libunwind_remote(pid_t tid, + sentry_remote_frame_t *frames, size_t max_frames, + sentry_remote_registers_t *registers) { + if (registers) { + memset(registers, 0, sizeof(*registers)); + } + if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) != 0) { SENTRY_WARNF("remote_unwind: ptrace attach failed for %d: %s", tid, strerror(errno)); @@ -71,6 +122,8 @@ sentry__unwind_stack_from_thread_libunwind_remote( goto detach; } + capture_registers(&cursor, registers); + while (n < max_frames) { unw_word_t ip = 0; if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0 || ip == 0) { @@ -108,12 +161,14 @@ sentry__unwind_stack_from_thread_libunwind_remote( #else /* !SENTRY_WITH_UNWINDER_LIBUNWIND_REMOTE */ size_t -sentry__unwind_stack_from_thread_libunwind_remote( - pid_t tid, sentry_remote_frame_t *frames, size_t max_frames) +sentry__unwind_stack_from_thread_libunwind_remote(pid_t tid, + sentry_remote_frame_t *frames, size_t max_frames, + sentry_remote_registers_t *registers) { (void)tid; (void)frames; (void)max_frames; + (void)registers; return 0; }