diff --git a/CHANGELOG.md b/CHANGELOG.md index 900bce6b68..de4f2f4537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## TBD + +### Enhancements + +* Native crashes will now include their signal code (where applicable) in the error message + [#2135](https://github.com/bugsnag/bugsnag-android/pull/2135) + ## 6.11.0 (2025-01-22) ### Enhancements diff --git a/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c b/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c index 613f747af8..ca4c681b3d 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c +++ b/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c @@ -16,7 +16,7 @@ #include "../utils/string.h" #include "../utils/threads.h" #define BSG_HANDLED_SIGNAL_COUNT 6 - +#define BSG_SIGNAL_CODE_COUNT 15 /** * Function to capture signals and write reports to disk * @param signum The captured signal number @@ -48,6 +48,17 @@ struct sigaction *bsg_global_sigaction; /* the previous signal handler array */ struct sigaction *bsg_global_sigaction_previous; +#define MSG_SIGILL "Illegal instruction" +#define MSG_SIGTRAP "Trace/breakpoint trap" +#define MSG_SIGABRT "Abort program" +#define MSG_SIGBUS "Bus error (bad memory access)" +#define MSG_SIGFPE "Floating-point exception" +#define MSG_SIGSEGV "Segmentation violation (invalid memory reference)" + +#define xstr(s) str(s) +#define str(s) #s +#define SIG_CODE_MESSAGE(msg, code) (msg ", code " xstr(code) " (" #code ")") + /** * Native signals which will be captured by the Bugsnag signal handlerâ„¢ */ @@ -56,12 +67,88 @@ static const int bsg_native_signals[BSG_HANDLED_SIGNAL_COUNT + 1] = { static const char bsg_native_signal_names[BSG_HANDLED_SIGNAL_COUNT + 1][8] = { "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGSEGV"}; static const char bsg_native_signal_msgs[BSG_HANDLED_SIGNAL_COUNT + 1][60] = { - "Illegal instruction", - "Trace/breakpoint trap", - "Abort program", - "Bus error (bad memory access)", - "Floating-point exception", - "Segmentation violation (invalid memory reference)"}; + MSG_SIGILL, MSG_SIGTRAP, MSG_SIGABRT, MSG_SIGBUS, MSG_SIGFPE, MSG_SIGSEGV}; + +static const char + bsg_native_signal_code_names[BSG_HANDLED_SIGNAL_COUNT + + 1][BSG_SIGNAL_CODE_COUNT + 1][72] = { + {SIG_CODE_MESSAGE(MSG_SIGILL, ILL_ILLOPC), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_ILLOPN), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_ILLADR), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_ILLTRP), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_PRVOPC), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_PRVREG), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_COPROC), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_BADSTK), + SIG_CODE_MESSAGE(MSG_SIGILL, ILL_BADIADDR), + SIG_CODE_MESSAGE(MSG_SIGILL, __ILL_BREAK), + SIG_CODE_MESSAGE(MSG_SIGILL, __ILL_BNDMOD)}, + {SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_BRKPT), + SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_TRACE), + SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_BRANCH), + SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_HWBKPT), + SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_UNK), + SIG_CODE_MESSAGE(MSG_SIGTRAP, TRAP_PERF)}, + {0}, + {SIG_CODE_MESSAGE(MSG_SIGBUS, BUS_ADRALN), + SIG_CODE_MESSAGE(MSG_SIGBUS, BUS_ADRERR), + SIG_CODE_MESSAGE(MSG_SIGBUS, BUS_OBJERR), + SIG_CODE_MESSAGE(MSG_SIGBUS, BUS_MCEERR_AR), + SIG_CODE_MESSAGE(MSG_SIGBUS, BUS_MCEERR_AO)}, + {SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_INTDIV), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_INTOVF), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTDIV), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTOVF), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTUND), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTRES), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTINV), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTSUB), + SIG_CODE_MESSAGE(MSG_SIGFPE, __FPE_DECOVF), + SIG_CODE_MESSAGE(MSG_SIGFPE, __FPE_DECDIV), + SIG_CODE_MESSAGE(MSG_SIGFPE, __FPE_DECERR), + SIG_CODE_MESSAGE(MSG_SIGFPE, __FPE_INVASC), + SIG_CODE_MESSAGE(MSG_SIGFPE, __FPE_INVDEC), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_FLTUNK), + SIG_CODE_MESSAGE(MSG_SIGFPE, FPE_CONDTRAP)}, + {SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_MAPERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_ACCERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_BNDERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_PKUERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_ACCADI), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_ADIDERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_ADIPERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_MTEAERR), + SIG_CODE_MESSAGE(MSG_SIGSEGV, SEGV_MTESERR)}}; + +static const int bsg_native_signal_codes[BSG_HANDLED_SIGNAL_COUNT + + 1][BSG_SIGNAL_CODE_COUNT + 1] = { + {ILL_ILLOPC, ILL_ILLOPN, ILL_ILLADR, ILL_ILLTRP, ILL_PRVOPC, ILL_PRVREG, + ILL_COPROC, ILL_BADSTK, ILL_BADIADDR, __ILL_BREAK, __ILL_BNDMOD}, + {TRAP_BRKPT, TRAP_TRACE, TRAP_BRANCH, TRAP_HWBKPT, TRAP_UNK, TRAP_PERF}, + {BUS_ADRALN, BUS_ADRERR, BUS_OBJERR, BUS_MCEERR_AR, BUS_MCEERR_AO}, + {FPE_INTDIV, FPE_INTOVF, FPE_FLTDIV, FPE_FLTOVF, FPE_FLTUND, FPE_FLTRES, + FPE_FLTINV, FPE_FLTSUB, __FPE_DECOVF, __FPE_DECDIV, __FPE_DECERR, + __FPE_INVASC, __FPE_INVDEC, FPE_FLTUNK, FPE_CONDTRAP}, + {SEGV_MAPERR, SEGV_ACCERR, SEGV_BNDERR, SEGV_PKUERR, SEGV_ACCADI, + SEGV_ADIDERR, SEGV_ADIPERR, SEGV_MTEAERR, SEGV_MTESERR}}; + +static const char * +bsg_get_signal_code_description(const int signal, + const int signal_code) __asyncsafe { + for (int i = 0; i < BSG_HANDLED_SIGNAL_COUNT; i++) { + if (bsg_native_signals[i] == signal) { + for (int j = 0; j < BSG_SIGNAL_CODE_COUNT; j++) { + if (bsg_native_signal_codes[i][j] == signal_code) { + return bsg_native_signal_code_names[i][j]; + } else if (*bsg_native_signal_code_names[i][j] == 0) { + // NULL in the signal_code_name array indicates no more known codes + break; + } + } + } + } + return NULL; +} bool bsg_handler_install_signal(bsg_environment *env) { if (bsg_global_env != NULL) { @@ -195,12 +282,17 @@ void bsg_handle_signal(int signum, siginfo_t *info, for (int i = 0; i < BSG_HANDLED_SIGNAL_COUNT; i++) { const int signal = bsg_native_signals[i]; + const int signal_code = info->si_code; if (signal == signum) { bsg_strncpy(bsg_global_env->next_event.error.errorClass, (char *)bsg_native_signal_names[i], sizeof(bsg_global_env->next_event.error.errorClass)); - bsg_strncpy(bsg_global_env->next_event.error.errorMessage, - (char *)bsg_native_signal_msgs[i], + const char *error_message = + bsg_get_signal_code_description(signal, signal_code); + if (error_message == NULL || *error_message == 0) { + error_message = (char *)bsg_native_signal_msgs[i]; + } + bsg_strncpy(bsg_global_env->next_event.error.errorMessage, error_message, sizeof(bsg_global_env->next_event.error.errorMessage)); break; } diff --git a/features/full_tests/native_crash_handling.feature b/features/full_tests/native_crash_handling.feature index 69df20ae69..a9b87e899d 100644 --- a/features/full_tests/native_crash_handling.feature +++ b/features/full_tests/native_crash_handling.feature @@ -52,8 +52,11 @@ Feature: Native crash reporting | SIGILL | | SIGTRAP | And the exception "message" equals one of: - | Illegal instruction | - | Trace/breakpoint trap | + | Illegal instruction | + | Trace/breakpoint trap | + | Illegal instruction, code 4 (ILL_ILLTRP) | + | Illegal instruction, code 1 (ILL_ILLOPC) | + | Trace/breakpoint trap, code 1 (TRAP_BRKPT) | And the exception "type" equals "c" And the event "severity" equals "error" And the event "unhandled" is true @@ -132,8 +135,10 @@ Feature: Native crash reporting | SIGILL | | SIGTRAP | And the exception "message" equals one of: - | Illegal instruction | - | Trace/breakpoint trap | + | Illegal instruction | + | Trace/breakpoint trap | + | Illegal instruction, code 1 (ILL_ILLOPC) | + | Trace/breakpoint trap, code 1 (TRAP_BRKPT) | And the exception "type" equals "c" And the first significant stack frames match: | something_innocuous | libmonochrome.so | (ignore) | diff --git a/features/full_tests/native_signal_raise.feature b/features/full_tests/native_signal_raise.feature index 6b477a9f6c..725a5ce81e 100644 --- a/features/full_tests/native_signal_raise.feature +++ b/features/full_tests/native_signal_raise.feature @@ -10,8 +10,10 @@ Feature: Raising native signals And the error payload contains a completed unhandled native report And the exception "errorClass" equals "SIGILL" And the exception "message" equals one of: - | Illegal instruction | - | Trace/breakpoint trap | + | Illegal instruction | + | Trace/breakpoint trap | + | Illegal instruction, code 4 (ILL_ILLTRP) | + | Trace/breakpoint trap, code 5 (TRAP_UNK) | And the exception "type" equals "c" And the event "severity" equals "error" And the event "unhandled" is true @@ -55,7 +57,9 @@ Feature: Raising native signals And I wait to receive an error And the error payload contains a completed unhandled native report And the exception "errorClass" equals "SIGFPE" - And the exception "message" equals "Floating-point exception" + And the exception "message" equals one of: + | Floating-point exception | + | Floating-point exception, code 8 (FPE_FLTSUB) | And the exception "type" equals "c" And the event "severity" equals "error" And the event "unhandled" is true @@ -66,7 +70,9 @@ Feature: Raising native signals And I wait to receive an error And the error payload contains a completed unhandled native report And the exception "errorClass" equals "SIGTRAP" - And the exception "message" equals "Trace/breakpoint trap" + And the exception "message" equals one of: + | Trace/breakpoint trap | + | Trace/breakpoint trap, code 5 (TRAP_UNK) | And the exception "type" equals "c" And the event "severity" equals "error" And the event "unhandled" is true