diff options
author | Kingwel Xie <kingwel.xie@ericsson.com> | 2018-06-15 04:56:24 -0400 |
---|---|---|
committer | Damjan Marion <dmarion@me.com> | 2018-06-26 15:02:16 +0000 |
commit | 497deaf72f98dd104d9c9999a877ddd2f04c0aa6 (patch) | |
tree | fb86987cf2cebdc4e4cf34d310cebc97541dc708 /src/vlib/unix/main.c | |
parent | 6fb0d9b269057a40b6979c741f8c1187b653d12d (diff) |
add backtrace in unix_signal_handler
crash stack backtrace will be directed to syslog
1. make use of glic backtrace in execinfo.h. the old clib_backtrace is removed
2. install SIGABRT in signal handler, but have to remove it when backtrace is
done. reason is to capture stack trace caused by SIGABRT. vPP ASSERT always
call os_exit then abort(). we definitely want to know the trace of this
situation. It is a little tricky to avoid SIGABRT infinite loop
3. always load symbols by calling clib_elf_main_init () in main(). Otherwise,
PC addresses instead of symbols will be displayed.
Change-Id: I150e15b94a4620b2ea4f08c73dc3e6ad1856de1e
Signed-off-by: Kingwel Xie <kingwel.xie@ericsson.com>
Diffstat (limited to 'src/vlib/unix/main.c')
-rwxr-xr-x[-rw-r--r--] | src/vlib/unix/main.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c index f812b080f07..947c66400e0 100644..100755 --- a/src/vlib/unix/main.c +++ b/src/vlib/unix/main.c @@ -73,17 +73,33 @@ unix_main_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (unix_main_init); +static int +unsetup_signal_handlers (int sig) +{ + struct sigaction sa; + + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + return sigaction (sig, &sa, 0); +} + + +/* allocate this buffer from mheap when setting up the signal handler. + dangerous to vec_resize it when crashing, mheap itself might have been + corruptted already */ +static u8 *syslog_msg = 0; + static void unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) { uword fatal = 0; - u8 *msg = 0; - msg = format (msg, "received signal %U, PC %U", - format_signal, signum, format_ucontext_pc, uc); + syslog_msg = format (syslog_msg, "received signal %U, PC %U", + format_signal, signum, format_ucontext_pc, uc); if (signum == SIGSEGV) - msg = format (msg, ", faulting address %p", si->si_addr); + syslog_msg = format (syslog_msg, ", faulting address %p", si->si_addr); switch (signum) { @@ -103,6 +119,7 @@ unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) case SIGSEGV: case SIGHUP: case SIGFPE: + case SIGABRT: fatal = 1; break; @@ -113,17 +130,35 @@ unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) } /* Null terminate. */ - vec_add1 (msg, 0); + vec_add1 (syslog_msg, 0); if (fatal) { - syslog (LOG_ERR | LOG_DAEMON, "%s", msg); + syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg); + + /* Address of callers: outer first, inner last. */ + uword callers[15]; + uword n_callers = clib_backtrace (callers, ARRAY_LEN (callers), 0); + int i; + for (i = 0; i < n_callers; i++) + { + vec_reset_length (syslog_msg); + + syslog_msg = + format (syslog_msg, "#%-2d 0x%016lx %U%c", i, callers[i], + format_clib_elf_symbol_with_address, callers[i], 0); + + syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg); + } + + /* have to remove SIGABRT to avoid recusive - os_exit calling abort() */ + unsetup_signal_handlers (SIGABRT); + os_exit (1); } else - clib_warning ("%s", msg); + clib_warning ("%s", syslog_msg); - vec_free (msg); } static clib_error_t * @@ -132,6 +167,9 @@ setup_signal_handlers (unix_main_t * um) uword i; struct sigaction sa; + /* give a big enough buffer for msg, most likely it can avoid vec_resize */ + vec_alloc (syslog_msg, 2048); + for (i = 1; i < 32; i++) { memset (&sa, 0, sizeof (sa)); @@ -141,7 +179,6 @@ setup_signal_handlers (unix_main_t * um) switch (i) { /* these signals take the default action */ - case SIGABRT: case SIGKILL: case SIGSTOP: case SIGUSR1: @@ -626,6 +663,9 @@ vlib_unix_main (int argc, char *argv[]) } unformat_free (&input); + /* always load symbols, for signal handler and mheap memory get/put backtrace */ + clib_elf_main_init (vm->name); + vlib_thread_stack_init (0); __os_thread_index = 0; |