Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report signal codes on native crashes #2135

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
Loading