diff --git a/CHANGELOG.md b/CHANGELOG.md index 34b5378c56..cb109ac4f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## TBD + +### Bug fixes + +* [NDK] Fix regression in 4.9.0 which truncated stacktraces on 64-bit devices to + a single frame + [#383](https://github.com/bugsnag/bugsnag-android/pull/383) + ## 4.9.1 (2018-11-01) ### Bug fixes diff --git a/ndk/src/main/CMakeLists.txt b/ndk/src/main/CMakeLists.txt index 3f43a24bb1..4547bab85c 100644 --- a/ndk/src/main/CMakeLists.txt +++ b/ndk/src/main/CMakeLists.txt @@ -24,6 +24,7 @@ add_library( # Specifies the name of the library. include_directories( jni/ jni/deps + jni/external/libunwind/include ) target_include_directories(bugsnag-ndk PRIVATE ${BUGSNAG_DIR}/assets/include) @@ -47,3 +48,9 @@ set_target_properties(bugsnag-ndk COMPILE_OPTIONS -Werror -Wall -pedantic) +if(${ANDROID_ABI} STREQUAL "armeabi" OR ${ANDROID_ABI} STREQUAL "armeabi-v7a") + add_library(libunwind STATIC IMPORTED) + set_target_properties(libunwind PROPERTIES IMPORTED_LOCATION + ${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libunwind.a) + target_link_libraries(bugsnag-ndk libunwind) +endif() diff --git a/ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java b/ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java index 2ecc505092..aeeebb43bc 100644 --- a/ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java +++ b/ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java @@ -32,7 +32,8 @@ public class NativeBridge implements Observer { private static final Lock lock = new ReentrantLock(); private static final AtomicBoolean installed = new AtomicBoolean(false); - public static native void install(String reportingDirectory, boolean autoNotify, int apiLevel); + public static native void install(String reportingDirectory, boolean autoNotify, int apiLevel, + boolean is32bit); public static native void deliverReportAtPath(String filePath); @@ -216,7 +217,15 @@ private void handleInstallMessage(Object arg) { return; } String reportPath = reportDirectory + UUID.randomUUID().toString() + ".crash"; - install(reportPath, true, Build.VERSION.SDK_INT); + String[] abis = (String[])NativeInterface.getDeviceData().get("cpuAbi"); + boolean is32bit = true; + for (String abi : abis) { + if (abi.contains("64")) { + is32bit = false; + break; + } + } + install(reportPath, true, Build.VERSION.SDK_INT, is32bit); installed.set(true); } finally { lock.unlock(); diff --git a/ndk/src/main/jni/bugsnag_ndk.c b/ndk/src/main/jni/bugsnag_ndk.c index 04781decbc..d418f0e947 100644 --- a/ndk/src/main/jni/bugsnag_ndk.c +++ b/ndk/src/main/jni/bugsnag_ndk.c @@ -43,9 +43,9 @@ bsg_unwinder bsg_configured_unwind_style() { JNIEXPORT void JNICALL Java_com_bugsnag_android_ndk_NativeBridge_install( JNIEnv *env, jobject _this, jstring _report_path, jboolean auto_notify, - jint _api_level) { + jint _api_level, jboolean is32bit) { bsg_environment *bugsnag_env = calloc(1, sizeof(bsg_environment)); - bugsnag_env->unwind_style = bsg_get_unwind_type((int)_api_level); + bugsnag_env->unwind_style = bsg_get_unwind_type((int)_api_level, (bool)is32bit); bugsnag_env->report_header.big_endian = htonl(47) == 47; // potentially too clever, see man 3 htonl bugsnag_env->report_header.version = BUGSNAG_REPORT_VERSION; diff --git a/ndk/src/main/jni/external/libunwind/include/__libunwind_config.h b/ndk/src/main/jni/external/libunwind/include/__libunwind_config.h new file mode 100644 index 0000000000..bc4e696c0c --- /dev/null +++ b/ndk/src/main/jni/external/libunwind/include/__libunwind_config.h @@ -0,0 +1,55 @@ +//===------------------------- __libunwind_config.h -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef ____LIBUNWIND_CONFIG_H__ +#define ____LIBUNWIND_CONFIG_H__ +#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ + !defined(__ARM_DWARF_EH__) +#define _LIBUNWIND_ARM_EHABI 1 +#else +#define _LIBUNWIND_ARM_EHABI 0 +#endif +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) +# if defined(__i386__) +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_CONTEXT_SIZE 8 +# define _LIBUNWIND_CURSOR_SIZE 19 +# elif defined(__x86_64__) +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_CONTEXT_SIZE 21 +# define _LIBUNWIND_CURSOR_SIZE 33 +# elif defined(__ppc__) +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_CONTEXT_SIZE 117 +# define _LIBUNWIND_CURSOR_SIZE 128 +# elif defined(__aarch64__) +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_CONTEXT_SIZE 66 +# define _LIBUNWIND_CURSOR_SIZE 78 +# elif defined(__arm__) +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_CONTEXT_SIZE 60 +# define _LIBUNWIND_CURSOR_SIZE 67 +# elif defined(__or1k__) +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 16 +# define _LIBUNWIND_CURSOR_SIZE 28 +# else +# error "Unsupported architecture." +# endif +#else // !_LIBUNWIND_IS_NATIVE_ONLY +# define _LIBUNWIND_TARGET_I386 1 +# define _LIBUNWIND_TARGET_X86_64 1 +# define _LIBUNWIND_TARGET_PPC 1 +# define _LIBUNWIND_TARGET_AARCH64 1 +# define _LIBUNWIND_TARGET_ARM 1 +# define _LIBUNWIND_TARGET_OR1K 1 +# define _LIBUNWIND_CONTEXT_SIZE 128 +# define _LIBUNWIND_CURSOR_SIZE 140 +#endif // _LIBUNWIND_IS_NATIVE_ONLY +#endif // ____LIBUNWIND_CONFIG_H__ \ No newline at end of file diff --git a/ndk/src/main/jni/external/libunwind/include/libunwind.h b/ndk/src/main/jni/external/libunwind/include/libunwind.h new file mode 100644 index 0000000000..555b1d3b15 --- /dev/null +++ b/ndk/src/main/jni/external/libunwind/include/libunwind.h @@ -0,0 +1,508 @@ +//===---------------------------- libunwind.h -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// Compatible with libuwind API documented at: +// http://www.nongnu.org/libunwind/man/libunwind(3).html +// +//===----------------------------------------------------------------------===// +#ifndef __LIBUNWIND__ +#define __LIBUNWIND__ +#include <__libunwind_config.h> +#include +#include +#ifdef __APPLE__ + #include + #ifdef __arm__ + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #else + #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #endif +#else + #define LIBUNWIND_AVAIL +#endif +/* error codes */ +enum { + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC = -6540, /* unspecified (general) error */ + UNW_ENOMEM = -6541, /* out of memory */ + UNW_EBADREG = -6542, /* bad register number */ + UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ + UNW_ESTOPUNWIND = -6544, /* stop unwinding */ + UNW_EINVALIDIP = -6545, /* invalid IP */ + UNW_EBADFRAME = -6546, /* bad frame */ + UNW_EINVAL = -6547, /* unsupported operation or bad value */ + UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ + UNW_ENOINFO = -6549 /* no unwind info found */ +}; +struct unw_context_t { + uint64_t data[_LIBUNWIND_CONTEXT_SIZE]; +}; +typedef struct unw_context_t unw_context_t; +struct unw_cursor_t { + uint64_t data[_LIBUNWIND_CURSOR_SIZE]; +}; +typedef struct unw_cursor_t unw_cursor_t; +typedef struct unw_addr_space *unw_addr_space_t; +typedef int unw_regnum_t; +#if _LIBUNWIND_ARM_EHABI +typedef uint32_t unw_word_t; +typedef uint64_t unw_fpreg_t; +#else +typedef uint64_t unw_word_t; +typedef double unw_fpreg_t; +#endif +struct unw_proc_info_t { + unw_word_t start_ip; /* start address of function */ + unw_word_t end_ip; /* address after end of function */ + unw_word_t lsda; /* address of language specific data area, */ + /* or zero if not used */ + unw_word_t handler; /* personality routine, or zero if not used */ + unw_word_t gp; /* not used */ + unw_word_t flags; /* not used */ + uint32_t format; /* compact unwind encoding, or zero if none */ + uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */ + unw_word_t unwind_info; /* address of dwarf unwind info, or zero */ + unw_word_t extra; /* mach_header of mach-o image containing func */ +}; +typedef struct unw_proc_info_t unw_proc_info_t; +#ifdef __cplusplus +extern "C" { +#endif +extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; +extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; +extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; +extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; +extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; +#ifdef __arm__ +/* Save VFP registers in FSTMX format (instead of FSTMD). */ +extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL; +#endif +extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; +extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; +//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); +extern unw_addr_space_t unw_local_addr_space; +#ifdef UNW_REMOTE +/* + * Mac OS X "remote" API for unwinding other processes on same machine + * + */ +extern unw_addr_space_t unw_create_addr_space_for_task(task_t); +extern void unw_destroy_addr_space(unw_addr_space_t); +extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *); +#endif /* UNW_REMOTE */ +/* + * traditional libuwind "remote" API + * NOT IMPLEMENTED on Mac OS X + * + * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, + * thread_t*); + * extern unw_accessors_t unw_get_accessors(unw_addr_space_t); + * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); + * extern void unw_flush_cache(unw_addr_space_t, unw_word_t, + * unw_word_t); + * extern int unw_set_caching_policy(unw_addr_space_t, + * unw_caching_policy_t); + * extern void _U_dyn_register(unw_dyn_info_t*); + * extern void _U_dyn_cancel(unw_dyn_info_t*); + */ +#ifdef __cplusplus +} +#endif +// architecture independent register numbers +enum { + UNW_REG_IP = -1, // instruction pointer + UNW_REG_SP = -2, // stack pointer +}; +// 32-bit x86 registers +enum { + UNW_X86_EAX = 0, + UNW_X86_ECX = 1, + UNW_X86_EDX = 2, + UNW_X86_EBX = 3, + UNW_X86_EBP = 4, + UNW_X86_ESP = 5, + UNW_X86_ESI = 6, + UNW_X86_EDI = 7 +}; +// 64-bit x86_64 registers +enum { + UNW_X86_64_RAX = 0, + UNW_X86_64_RDX = 1, + UNW_X86_64_RCX = 2, + UNW_X86_64_RBX = 3, + UNW_X86_64_RSI = 4, + UNW_X86_64_RDI = 5, + UNW_X86_64_RBP = 6, + UNW_X86_64_RSP = 7, + UNW_X86_64_R8 = 8, + UNW_X86_64_R9 = 9, + UNW_X86_64_R10 = 10, + UNW_X86_64_R11 = 11, + UNW_X86_64_R12 = 12, + UNW_X86_64_R13 = 13, + UNW_X86_64_R14 = 14, + UNW_X86_64_R15 = 15 +}; +// 32-bit ppc register numbers +enum { + UNW_PPC_R0 = 0, + UNW_PPC_R1 = 1, + UNW_PPC_R2 = 2, + UNW_PPC_R3 = 3, + UNW_PPC_R4 = 4, + UNW_PPC_R5 = 5, + UNW_PPC_R6 = 6, + UNW_PPC_R7 = 7, + UNW_PPC_R8 = 8, + UNW_PPC_R9 = 9, + UNW_PPC_R10 = 10, + UNW_PPC_R11 = 11, + UNW_PPC_R12 = 12, + UNW_PPC_R13 = 13, + UNW_PPC_R14 = 14, + UNW_PPC_R15 = 15, + UNW_PPC_R16 = 16, + UNW_PPC_R17 = 17, + UNW_PPC_R18 = 18, + UNW_PPC_R19 = 19, + UNW_PPC_R20 = 20, + UNW_PPC_R21 = 21, + UNW_PPC_R22 = 22, + UNW_PPC_R23 = 23, + UNW_PPC_R24 = 24, + UNW_PPC_R25 = 25, + UNW_PPC_R26 = 26, + UNW_PPC_R27 = 27, + UNW_PPC_R28 = 28, + UNW_PPC_R29 = 29, + UNW_PPC_R30 = 30, + UNW_PPC_R31 = 31, + UNW_PPC_F0 = 32, + UNW_PPC_F1 = 33, + UNW_PPC_F2 = 34, + UNW_PPC_F3 = 35, + UNW_PPC_F4 = 36, + UNW_PPC_F5 = 37, + UNW_PPC_F6 = 38, + UNW_PPC_F7 = 39, + UNW_PPC_F8 = 40, + UNW_PPC_F9 = 41, + UNW_PPC_F10 = 42, + UNW_PPC_F11 = 43, + UNW_PPC_F12 = 44, + UNW_PPC_F13 = 45, + UNW_PPC_F14 = 46, + UNW_PPC_F15 = 47, + UNW_PPC_F16 = 48, + UNW_PPC_F17 = 49, + UNW_PPC_F18 = 50, + UNW_PPC_F19 = 51, + UNW_PPC_F20 = 52, + UNW_PPC_F21 = 53, + UNW_PPC_F22 = 54, + UNW_PPC_F23 = 55, + UNW_PPC_F24 = 56, + UNW_PPC_F25 = 57, + UNW_PPC_F26 = 58, + UNW_PPC_F27 = 59, + UNW_PPC_F28 = 60, + UNW_PPC_F29 = 61, + UNW_PPC_F30 = 62, + UNW_PPC_F31 = 63, + UNW_PPC_MQ = 64, + UNW_PPC_LR = 65, + UNW_PPC_CTR = 66, + UNW_PPC_AP = 67, + UNW_PPC_CR0 = 68, + UNW_PPC_CR1 = 69, + UNW_PPC_CR2 = 70, + UNW_PPC_CR3 = 71, + UNW_PPC_CR4 = 72, + UNW_PPC_CR5 = 73, + UNW_PPC_CR6 = 74, + UNW_PPC_CR7 = 75, + UNW_PPC_XER = 76, + UNW_PPC_V0 = 77, + UNW_PPC_V1 = 78, + UNW_PPC_V2 = 79, + UNW_PPC_V3 = 80, + UNW_PPC_V4 = 81, + UNW_PPC_V5 = 82, + UNW_PPC_V6 = 83, + UNW_PPC_V7 = 84, + UNW_PPC_V8 = 85, + UNW_PPC_V9 = 86, + UNW_PPC_V10 = 87, + UNW_PPC_V11 = 88, + UNW_PPC_V12 = 89, + UNW_PPC_V13 = 90, + UNW_PPC_V14 = 91, + UNW_PPC_V15 = 92, + UNW_PPC_V16 = 93, + UNW_PPC_V17 = 94, + UNW_PPC_V18 = 95, + UNW_PPC_V19 = 96, + UNW_PPC_V20 = 97, + UNW_PPC_V21 = 98, + UNW_PPC_V22 = 99, + UNW_PPC_V23 = 100, + UNW_PPC_V24 = 101, + UNW_PPC_V25 = 102, + UNW_PPC_V26 = 103, + UNW_PPC_V27 = 104, + UNW_PPC_V28 = 105, + UNW_PPC_V29 = 106, + UNW_PPC_V30 = 107, + UNW_PPC_V31 = 108, + UNW_PPC_VRSAVE = 109, + UNW_PPC_VSCR = 110, + UNW_PPC_SPE_ACC = 111, + UNW_PPC_SPEFSCR = 112 +}; +// 64-bit ARM64 registers +enum { + UNW_ARM64_X0 = 0, + UNW_ARM64_X1 = 1, + UNW_ARM64_X2 = 2, + UNW_ARM64_X3 = 3, + UNW_ARM64_X4 = 4, + UNW_ARM64_X5 = 5, + UNW_ARM64_X6 = 6, + UNW_ARM64_X7 = 7, + UNW_ARM64_X8 = 8, + UNW_ARM64_X9 = 9, + UNW_ARM64_X10 = 10, + UNW_ARM64_X11 = 11, + UNW_ARM64_X12 = 12, + UNW_ARM64_X13 = 13, + UNW_ARM64_X14 = 14, + UNW_ARM64_X15 = 15, + UNW_ARM64_X16 = 16, + UNW_ARM64_X17 = 17, + UNW_ARM64_X18 = 18, + UNW_ARM64_X19 = 19, + UNW_ARM64_X20 = 20, + UNW_ARM64_X21 = 21, + UNW_ARM64_X22 = 22, + UNW_ARM64_X23 = 23, + UNW_ARM64_X24 = 24, + UNW_ARM64_X25 = 25, + UNW_ARM64_X26 = 26, + UNW_ARM64_X27 = 27, + UNW_ARM64_X28 = 28, + UNW_ARM64_X29 = 29, + UNW_ARM64_FP = 29, + UNW_ARM64_X30 = 30, + UNW_ARM64_LR = 30, + UNW_ARM64_X31 = 31, + UNW_ARM64_SP = 31, + // reserved block + UNW_ARM64_D0 = 64, + UNW_ARM64_D1 = 65, + UNW_ARM64_D2 = 66, + UNW_ARM64_D3 = 67, + UNW_ARM64_D4 = 68, + UNW_ARM64_D5 = 69, + UNW_ARM64_D6 = 70, + UNW_ARM64_D7 = 71, + UNW_ARM64_D8 = 72, + UNW_ARM64_D9 = 73, + UNW_ARM64_D10 = 74, + UNW_ARM64_D11 = 75, + UNW_ARM64_D12 = 76, + UNW_ARM64_D13 = 77, + UNW_ARM64_D14 = 78, + UNW_ARM64_D15 = 79, + UNW_ARM64_D16 = 80, + UNW_ARM64_D17 = 81, + UNW_ARM64_D18 = 82, + UNW_ARM64_D19 = 83, + UNW_ARM64_D20 = 84, + UNW_ARM64_D21 = 85, + UNW_ARM64_D22 = 86, + UNW_ARM64_D23 = 87, + UNW_ARM64_D24 = 88, + UNW_ARM64_D25 = 89, + UNW_ARM64_D26 = 90, + UNW_ARM64_D27 = 91, + UNW_ARM64_D28 = 92, + UNW_ARM64_D29 = 93, + UNW_ARM64_D30 = 94, + UNW_ARM64_D31 = 95, +}; +// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. +// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. +// In this scheme, even though the 64-bit floating point registers D0-D31 +// overlap physically with the 32-bit floating pointer registers S0-S31, +// they are given a non-overlapping range of register numbers. +// +// Commented out ranges are not preserved during unwinding. +enum { + UNW_ARM_R0 = 0, + UNW_ARM_R1 = 1, + UNW_ARM_R2 = 2, + UNW_ARM_R3 = 3, + UNW_ARM_R4 = 4, + UNW_ARM_R5 = 5, + UNW_ARM_R6 = 6, + UNW_ARM_R7 = 7, + UNW_ARM_R8 = 8, + UNW_ARM_R9 = 9, + UNW_ARM_R10 = 10, + UNW_ARM_R11 = 11, + UNW_ARM_R12 = 12, + UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP + UNW_ARM_R13 = 13, + UNW_ARM_LR = 14, + UNW_ARM_R14 = 14, + UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP + UNW_ARM_R15 = 15, + // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. + UNW_ARM_S0 = 64, + UNW_ARM_S1 = 65, + UNW_ARM_S2 = 66, + UNW_ARM_S3 = 67, + UNW_ARM_S4 = 68, + UNW_ARM_S5 = 69, + UNW_ARM_S6 = 70, + UNW_ARM_S7 = 71, + UNW_ARM_S8 = 72, + UNW_ARM_S9 = 73, + UNW_ARM_S10 = 74, + UNW_ARM_S11 = 75, + UNW_ARM_S12 = 76, + UNW_ARM_S13 = 77, + UNW_ARM_S14 = 78, + UNW_ARM_S15 = 79, + UNW_ARM_S16 = 80, + UNW_ARM_S17 = 81, + UNW_ARM_S18 = 82, + UNW_ARM_S19 = 83, + UNW_ARM_S20 = 84, + UNW_ARM_S21 = 85, + UNW_ARM_S22 = 86, + UNW_ARM_S23 = 87, + UNW_ARM_S24 = 88, + UNW_ARM_S25 = 89, + UNW_ARM_S26 = 90, + UNW_ARM_S27 = 91, + UNW_ARM_S28 = 92, + UNW_ARM_S29 = 93, + UNW_ARM_S30 = 94, + UNW_ARM_S31 = 95, + // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. + // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) + UNW_ARM_WR0 = 112, + UNW_ARM_WR1 = 113, + UNW_ARM_WR2 = 114, + UNW_ARM_WR3 = 115, + UNW_ARM_WR4 = 116, + UNW_ARM_WR5 = 117, + UNW_ARM_WR6 = 118, + UNW_ARM_WR7 = 119, + UNW_ARM_WR8 = 120, + UNW_ARM_WR9 = 121, + UNW_ARM_WR10 = 122, + UNW_ARM_WR11 = 123, + UNW_ARM_WR12 = 124, + UNW_ARM_WR13 = 125, + UNW_ARM_WR14 = 126, + UNW_ARM_WR15 = 127, + // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} + // 134-143 -- Reserved + // 144-150 -- R8_USR-R14_USR + // 151-157 -- R8_FIQ-R14_FIQ + // 158-159 -- R13_IRQ-R14_IRQ + // 160-161 -- R13_ABT-R14_ABT + // 162-163 -- R13_UND-R14_UND + // 164-165 -- R13_SVC-R14_SVC + // 166-191 -- Reserved + UNW_ARM_WC0 = 192, + UNW_ARM_WC1 = 193, + UNW_ARM_WC2 = 194, + UNW_ARM_WC3 = 195, + // 196-199 -- wC4-wC7 (Intel wireless MMX control) + // 200-255 -- Reserved + UNW_ARM_D0 = 256, + UNW_ARM_D1 = 257, + UNW_ARM_D2 = 258, + UNW_ARM_D3 = 259, + UNW_ARM_D4 = 260, + UNW_ARM_D5 = 261, + UNW_ARM_D6 = 262, + UNW_ARM_D7 = 263, + UNW_ARM_D8 = 264, + UNW_ARM_D9 = 265, + UNW_ARM_D10 = 266, + UNW_ARM_D11 = 267, + UNW_ARM_D12 = 268, + UNW_ARM_D13 = 269, + UNW_ARM_D14 = 270, + UNW_ARM_D15 = 271, + UNW_ARM_D16 = 272, + UNW_ARM_D17 = 273, + UNW_ARM_D18 = 274, + UNW_ARM_D19 = 275, + UNW_ARM_D20 = 276, + UNW_ARM_D21 = 277, + UNW_ARM_D22 = 278, + UNW_ARM_D23 = 279, + UNW_ARM_D24 = 280, + UNW_ARM_D25 = 281, + UNW_ARM_D26 = 282, + UNW_ARM_D27 = 283, + UNW_ARM_D28 = 284, + UNW_ARM_D29 = 285, + UNW_ARM_D30 = 286, + UNW_ARM_D31 = 287, + // 288-319 -- Reserved for VFP/Neon + // 320-8191 -- Reserved + // 8192-16383 -- Unspecified vendor co-processor register. +}; +// OpenRISC1000 register numbers +enum { + UNW_OR1K_R0 = 0, + UNW_OR1K_R1 = 1, + UNW_OR1K_R2 = 2, + UNW_OR1K_R3 = 3, + UNW_OR1K_R4 = 4, + UNW_OR1K_R5 = 5, + UNW_OR1K_R6 = 6, + UNW_OR1K_R7 = 7, + UNW_OR1K_R8 = 8, + UNW_OR1K_R9 = 9, + UNW_OR1K_R10 = 10, + UNW_OR1K_R11 = 11, + UNW_OR1K_R12 = 12, + UNW_OR1K_R13 = 13, + UNW_OR1K_R14 = 14, + UNW_OR1K_R15 = 15, + UNW_OR1K_R16 = 16, + UNW_OR1K_R17 = 17, + UNW_OR1K_R18 = 18, + UNW_OR1K_R19 = 19, + UNW_OR1K_R20 = 20, + UNW_OR1K_R21 = 21, + UNW_OR1K_R22 = 22, + UNW_OR1K_R23 = 23, + UNW_OR1K_R24 = 24, + UNW_OR1K_R25 = 25, + UNW_OR1K_R26 = 26, + UNW_OR1K_R27 = 27, + UNW_OR1K_R28 = 28, + UNW_OR1K_R29 = 29, + UNW_OR1K_R30 = 30, + UNW_OR1K_R31 = 31, +}; +#endif \ No newline at end of file diff --git a/ndk/src/main/jni/utils/stack_unwinder.c b/ndk/src/main/jni/utils/stack_unwinder.c index e3d1a849fc..b41811f604 100644 --- a/ndk/src/main/jni/utils/stack_unwinder.c +++ b/ndk/src/main/jni/utils/stack_unwinder.c @@ -12,8 +12,8 @@ #define BSG_LIBCORKSCREW_MIN_LEVEL 16 #define BSG_LIBCORKSCREW_MAX_LEVEL 19 -bsg_unwinder bsg_get_unwind_type(int apiLevel) { - if (apiLevel >= BSG_LIBUNWIND_LEVEL && bsg_configure_libunwind()) { +bsg_unwinder bsg_get_unwind_type(int apiLevel, bool is32bit) { + if (apiLevel >= BSG_LIBUNWIND_LEVEL && bsg_configure_libunwind(is32bit)) { return BSG_LIBUNWIND; } else if (apiLevel <= BSG_LIBCORKSCREW_MAX_LEVEL && apiLevel >= BSG_LIBCORKSCREW_MIN_LEVEL && diff --git a/ndk/src/main/jni/utils/stack_unwinder.h b/ndk/src/main/jni/utils/stack_unwinder.h index 9f97627e96..b4340217b5 100644 --- a/ndk/src/main/jni/utils/stack_unwinder.h +++ b/ndk/src/main/jni/utils/stack_unwinder.h @@ -23,7 +23,7 @@ typedef enum { * Everything else: custom unwinding logic * @return the preferred unwind type */ -bsg_unwinder bsg_get_unwind_type(int apiLevel); +bsg_unwinder bsg_get_unwind_type(int apiLevel, bool is32bit); /** * Unwind the stack using the preferred tool/style. If info and a user diff --git a/ndk/src/main/jni/utils/stack_unwinder_libunwind.c b/ndk/src/main/jni/utils/stack_unwinder_libunwind.c index 99ccc079c9..06eb5c7fdb 100644 --- a/ndk/src/main/jni/utils/stack_unwinder_libunwind.c +++ b/ndk/src/main/jni/utils/stack_unwinder_libunwind.c @@ -4,19 +4,21 @@ #include #include +#if defined(__arm__) +#include +#endif + typedef struct { size_t frame_count; uintptr_t frame_addresses[BUGSNAG_FRAMES_MAX]; -#if defined(__arm__) - void *signal_context; -#endif - siginfo_t *signal_info; } bsg_libunwind_state; bsg_libunwind_state *bsg_global_libunwind_state; +bool bsg_libunwind_global_is32bit = false; -bool bsg_configure_libunwind(void) { +bool bsg_configure_libunwind(bool is32bit) { bsg_global_libunwind_state = calloc(1, sizeof(bsg_libunwind_state)); + bsg_libunwind_global_is32bit = is32bit; return true; } @@ -24,24 +26,31 @@ static _Unwind_Reason_Code bsg_libunwind_callback(struct _Unwind_Context *context, void *arg) __asyncsafe { bsg_libunwind_state *state = (bsg_libunwind_state *)arg; -#if defined(__arm__) - if (state->frame_count == 0 && state->signal_context != NULL) { - const ucontext_t *signal_ucontext = - (const ucontext_t *)state->signal_context; - const struct sigcontext *signal_mcontext = &(signal_ucontext->uc_mcontext); + uintptr_t ip = _Unwind_GetIP(context); + + if (state->frame_count >= BUGSNAG_FRAMES_MAX) { + return _URC_END_OF_STACK; + } else if (state->frame_count > 0 && (void *)ip == NULL) { // nobody's home + return _URC_NO_REASON; + } + state->frame_addresses[state->frame_count] = ip; + state->frame_count++; - // Include program counter as the first frame - state->frame_addresses[state->frame_count] = signal_mcontext->arm_pc; - state->frame_count++; + return _URC_NO_REASON; +} - // Avoid unwinding in cases where there is a risk of segfault - bool single_frame_mode = state->signal_info != NULL && - (state->signal_info->si_code == SI_TKILL || - state->signal_info->si_code == SEGV_MAPERR); - if (single_frame_mode) { - return _URC_END_OF_STACK; - } +#if defined(__arm__) +ssize_t +bsg_unwind_stack_libunwind_arm32(bsg_stackframe stacktrace[BUGSNAG_FRAMES_MAX], + siginfo_t *info, void *user_context) __asyncsafe { + unw_cursor_t cursor; + unw_context_t uc; + int index = 0; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + // Initialize cursor state with register data, if any + if (user_context != NULL) { /** * Set the registers and initial frame to the values from the signal * handler user context. @@ -51,46 +60,49 @@ bsg_libunwind_callback(struct _Unwind_Context *context, void *arg) __asyncsafe { * state before unwinding the first frame (using the program counter as the * first frame). Then the stack can be unwound normally. */ - _Unwind_SetGR(context, REG_R0, signal_mcontext->arm_r0); - _Unwind_SetGR(context, REG_R1, signal_mcontext->arm_r1); - _Unwind_SetGR(context, REG_R2, signal_mcontext->arm_r2); - _Unwind_SetGR(context, REG_R3, signal_mcontext->arm_r3); - _Unwind_SetGR(context, REG_R4, signal_mcontext->arm_r4); - _Unwind_SetGR(context, REG_R5, signal_mcontext->arm_r5); - _Unwind_SetGR(context, REG_R6, signal_mcontext->arm_r6); - _Unwind_SetGR(context, REG_R7, signal_mcontext->arm_r7); - _Unwind_SetGR(context, REG_R8, signal_mcontext->arm_r8); - _Unwind_SetGR(context, REG_R9, signal_mcontext->arm_r9); - _Unwind_SetGR(context, REG_R10, signal_mcontext->arm_r10); - _Unwind_SetGR(context, REG_R11, signal_mcontext->arm_fp); - _Unwind_SetGR(context, REG_R12, signal_mcontext->arm_ip); - _Unwind_SetGR(context, REG_R13, signal_mcontext->arm_sp); - _Unwind_SetGR(context, REG_R14, signal_mcontext->arm_lr); - _Unwind_SetGR(context, REG_R15, signal_mcontext->arm_pc); - return _URC_NO_REASON; + const ucontext_t *signal_ucontext = (const ucontext_t *)user_context; + const struct sigcontext *signal_mcontext = &(signal_ucontext->uc_mcontext); + unw_set_reg(&cursor, UNW_ARM_R0, signal_mcontext->arm_r0); + unw_set_reg(&cursor, UNW_ARM_R1, signal_mcontext->arm_r1); + unw_set_reg(&cursor, UNW_ARM_R2, signal_mcontext->arm_r2); + unw_set_reg(&cursor, UNW_ARM_R3, signal_mcontext->arm_r3); + unw_set_reg(&cursor, UNW_ARM_R4, signal_mcontext->arm_r4); + unw_set_reg(&cursor, UNW_ARM_R5, signal_mcontext->arm_r5); + unw_set_reg(&cursor, UNW_ARM_R6, signal_mcontext->arm_r6); + unw_set_reg(&cursor, UNW_ARM_R7, signal_mcontext->arm_r7); + unw_set_reg(&cursor, UNW_ARM_R8, signal_mcontext->arm_r8); + unw_set_reg(&cursor, UNW_ARM_R9, signal_mcontext->arm_r9); + unw_set_reg(&cursor, UNW_ARM_R10, signal_mcontext->arm_r10); + unw_set_reg(&cursor, UNW_ARM_R11, signal_mcontext->arm_fp); + unw_set_reg(&cursor, UNW_ARM_R12, signal_mcontext->arm_ip); + unw_set_reg(&cursor, UNW_ARM_R13, signal_mcontext->arm_sp); + unw_set_reg(&cursor, UNW_ARM_R14, signal_mcontext->arm_lr); + unw_set_reg(&cursor, UNW_ARM_R15, signal_mcontext->arm_pc); + unw_set_reg(&cursor, UNW_REG_IP, signal_mcontext->arm_pc); + unw_set_reg(&cursor, UNW_REG_SP, signal_mcontext->arm_sp); + // Manually insert first frame to avoid being skipped in step() + stacktrace[index++].frame_address = signal_mcontext->arm_pc; } -#endif - uintptr_t ip = _Unwind_GetIP(context); - if (state->frame_count >= BUGSNAG_FRAMES_MAX) { - return _URC_END_OF_STACK; - } else if (state->frame_count > 0 && (void *)ip == NULL) { // nobody's home - return _URC_NO_REASON; + while (unw_step(&cursor) > 0 && index < BUGSNAG_FRAMES_MAX) { + unw_word_t ip = 0; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + stacktrace[index++].frame_address = ip; } - state->frame_addresses[state->frame_count] = ip; - state->frame_count++; - return _URC_NO_REASON; + return index; } - +#endif ssize_t bsg_unwind_stack_libunwind(bsg_stackframe stacktrace[BUGSNAG_FRAMES_MAX], siginfo_t *info, void *user_context) { - bsg_global_libunwind_state->frame_count = 0; #if defined(__arm__) - bsg_global_libunwind_state->signal_context = user_context; + if (bsg_libunwind_global_is32bit) { // avoid this code path if a 64-bit device + // is running 32-bit + return bsg_unwind_stack_libunwind_arm32(stacktrace, info, user_context); + } #endif - bsg_global_libunwind_state->signal_info = info; + bsg_global_libunwind_state->frame_count = 0; // The return value of _Unwind_Backtrace sits on a throne of lies _Unwind_Backtrace(bsg_libunwind_callback, bsg_global_libunwind_state); for (int i = 0; i < bsg_global_libunwind_state->frame_count; ++i) { diff --git a/ndk/src/main/jni/utils/stack_unwinder_libunwind.h b/ndk/src/main/jni/utils/stack_unwinder_libunwind.h index be197384bd..91d22e394f 100644 --- a/ndk/src/main/jni/utils/stack_unwinder_libunwind.h +++ b/ndk/src/main/jni/utils/stack_unwinder_libunwind.h @@ -4,7 +4,7 @@ #include "../report.h" #include -bool bsg_configure_libunwind(void); +bool bsg_configure_libunwind(bool is32bit); ssize_t bsg_unwind_stack_libunwind(bsg_stackframe stacktrace[BUGSNAG_FRAMES_MAX],