Skip to content

Commit

Permalink
Report signal codes on native crashes (#2135)
Browse files Browse the repository at this point in the history
* feat(signal) add more detail for signal

* fix(test) fixed fail e2e tests

* feat(signal) signal code message update and add param for bsg_native_signal_code_names

* feat(signal) signal code message update and add param for bsg_native_signal_code_names

* test(ndk): added ILLOPC as a possible sig_code for the trap() test

* refactor(ndk): refactored the signal-code messages to be built with macros to reduce possible mistakes

* chore(changelog): added CHANGELOG entry for #2135

---------

Co-authored-by: jason <[email protected]>
  • Loading branch information
YYChen01988 and lemnik authored Jan 30, 2025
1 parent 0f4b1d5 commit fe862d0
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 17 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
110 changes: 101 additions & 9 deletions bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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™
*/
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
13 changes: 9 additions & 4 deletions features/full_tests/native_crash_handling.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) |
Expand Down
14 changes: 10 additions & 4 deletions features/full_tests/native_signal_raise.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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

0 comments on commit fe862d0

Please sign in to comment.