vlib: stack trace and signal handler improvements
- use libunwrap which seems to be industry standard
- display traceback on console if running interactive or with syslog
disabled (color output unless nocolor specified)
- print hexdump of offending code
- print library filename for each stack frame
Type: improvement
Change-Id: I61d3056251b87076be0578ccda300aa311c222ef
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c
index ee28ca8..11d0cb1 100644
--- a/src/vlib/unix/main.c
+++ b/src/vlib/unix/main.c
@@ -40,6 +40,8 @@
#include <vlib/unix/unix.h>
#include <vlib/unix/plugin.h>
#include <vppinfra/unix.h>
+#include <vppinfra/stack.h>
+#include <vppinfra/format_ansi.h>
#include <limits.h>
#include <signal.h>
@@ -97,20 +99,42 @@
uword vlib_last_faulting_address = 0;
static void
+log_one_line ()
+{
+ vec_terminate_c_string (syslog_msg);
+ if (unix_main.flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG))
+ fprintf (stderr, "%s\n", syslog_msg);
+ else
+ syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg);
+ vec_reset_length (syslog_msg);
+}
+
+static void
unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
{
uword fatal = 0;
+ int color =
+ (unix_main.flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG)) &&
+ (unix_main.flags & UNIX_FLAG_NOCOLOR) == 0;
/* These come in handy when looking at core files from optimized images */
vlib_last_signum = signum;
vlib_last_faulting_address = (uword) si->si_addr;
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_BR_RED);
+
syslog_msg = format (syslog_msg, "received signal %U, PC %U",
format_signal, signum, format_ucontext_pc, uc);
- if (signum == SIGSEGV)
+ if (signum == SIGSEGV || signum == SIGBUS)
syslog_msg = format (syslog_msg, ", faulting address %p", si->si_addr);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT);
+
+ log_one_line ();
+
switch (signum)
{
/* these (caught) signals cause the application to exit */
@@ -120,11 +144,17 @@
*/
if (unix_main.vlib_main && unix_main.vlib_main->main_loop_exit_set)
{
- syslog (LOG_ERR | LOG_DAEMON, "received SIGTERM, exiting...");
+ syslog_msg = format (
+ syslog_msg, "received SIGTERM from PID %d UID %d, exiting...",
+ si->si_pid, si->si_uid);
+ log_one_line ();
unix_main.vlib_main->main_loop_exit_now = 1;
}
else
- syslog (LOG_ERR | LOG_DAEMON, "IGNORE early SIGTERM...");
+ {
+ syslog_msg = format (syslog_msg, "IGNORE early SIGTERM...");
+ log_one_line ();
+ }
break;
/* fall through */
case SIGQUIT:
@@ -144,26 +174,75 @@
break;
}
- /* Null terminate. */
- vec_add1 (syslog_msg, 0);
if (fatal)
{
- syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg);
+ int skip = 1, index = 0;
- /* 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++)
+ foreach_clib_stack_frame (sf)
{
- vec_reset_length (syslog_msg);
+ if (sf->is_signal_frame)
+ {
+ int pipefd[2];
+ const int n_bytes = 20;
+ u8 *ip = (void *) sf->ip;
- syslog_msg =
- format (syslog_msg, "#%-2d 0x%016lx %U%c", i, callers[i],
- format_clib_elf_symbol_with_address, callers[i], 0);
+ if (pipe (pipefd) == 0)
+ {
+ /* check PC points to valid memory */
+ if (write (pipefd[1], ip, n_bytes) == n_bytes)
+ {
+ syslog_msg = format (syslog_msg, "Code: ");
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_CYAN);
+ for (int i = 0; i < n_bytes; i++)
+ syslog_msg = format (syslog_msg, " %02x", ip[i]);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT);
+ }
+ else
+ {
+ syslog_msg = format (
+ syslog_msg, "PC contains invalid memory address");
+ }
+ log_one_line ();
+ foreach_int (i, 0, 1)
+ close (pipefd[i]);
+ }
+ skip = 0;
+ }
- syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg);
+ if (skip)
+ continue;
+
+ syslog_msg = format (syslog_msg, "#%-2d ", index++);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_BLUE);
+ syslog_msg = format (syslog_msg, "0x%016lx", sf->ip);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT);
+
+ if (sf->name[0])
+ {
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_YELLOW);
+ syslog_msg =
+ format (syslog_msg, " %s + 0x%x", sf->name, sf->offset);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT);
+ }
+
+ log_one_line ();
+
+ if (sf->file_name)
+ {
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_GREEN);
+ syslog_msg = format (syslog_msg, " from %s", sf->file_name);
+ if (color)
+ syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT);
+ log_one_line ();
+ }
}
/* have to remove SIGABRT to avoid recursive - os_exit calling abort() */
@@ -175,9 +254,6 @@
else
os_exit (1);
}
- else
- clib_warning ("%s", syslog_msg);
-
}
static clib_error_t *