summaryrefslogtreecommitdiff
path: root/lib/log.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2017-08-24 16:09:48 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2018-10-18 02:51:51 +0200
commit68b8a15f87cfaf9aff1d483abb037005c237fb24 (patch)
tree771365083373b2f0824c70665011b09f2bfa5508 /lib/log.c
parentb9ea4083854503850a18950206e7285f5266d5ea (diff)
lib: add libunwind support for backtraces
libunwind provides an alternate to backtrace() for printing out the call stack of a particular location. It doesn't use the frame pointer, it goes by the DWARF debug info. In most cases the traces have exactly the same information, but there are some situations where libunwind traces are better. (On some platforms, the libc backtrace() also uses the DWARF debug info [e.g.: ARM backtraces are impossible without it] but this is not the case everywhere, especially not on BSD libexecinfo.) Signed-off-by: David Lamparter <equinox@diac24.net>
Diffstat (limited to 'lib/log.c')
-rw-r--r--lib/log.c81
1 files changed, 75 insertions, 6 deletions
diff --git a/lib/log.c b/lib/log.c
index 10cb2cd8a4..5cc303daf0 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -38,6 +38,12 @@
#include <ucontext.h>
#endif
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <dlfcn.h>
+#endif
+
DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging")
static int logfile_fd = -1; /* Used in signal handler. */
@@ -313,7 +319,9 @@ static char *num_append(char *s, int len, unsigned long x)
return str_append(s, len, t);
}
-#if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE)
+#if defined(SA_SIGINFO) \
+ || defined(HAVE_PRINTSTACK) \
+ || defined(HAVE_GLIBC_BACKTRACE)
static char *hex_append(char *s, int len, unsigned long x)
{
char buf[30];
@@ -533,7 +541,37 @@ void zlog_signal(int signo, const char *action
Needs to be enhanced to support syslog logging. */
void zlog_backtrace_sigsafe(int priority, void *program_counter)
{
-#ifdef HAVE_STACK_TRACE
+#ifdef HAVE_LIBUNWIND
+ char buf[100];
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_word_t ip, off, sp;
+ Dl_info dlinfo;
+
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ while (unw_step(&cursor) > 0) {
+ char name[128] = "?";
+
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ if (unw_is_signal_frame(&cursor))
+ dprintf(2, " ---- signal ----\n");
+
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) {
+ snprintf(name, sizeof(name), "%s+%#lx",
+ buf, (long)off);
+ }
+ dprintf(2, "%-30s %16lx %16lx", name, (long)ip, (long)sp);
+ if (dladdr((void *)ip, &dlinfo)) {
+ dprintf(2, " %s (mapped at %p)",
+ dlinfo.dli_fname, dlinfo.dli_fbase);
+ }
+ dprintf(2, "\n");
+
+ }
+#elif defined(HAVE_GLIBC_BACKTRACE) || defined(HAVE_PRINTSTACK)
static const char pclabel[] = "Program counter: ";
void *array[64];
int size;
@@ -624,9 +662,38 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
void zlog_backtrace(int priority)
{
-#ifndef HAVE_GLIBC_BACKTRACE
- zlog(priority, "No backtrace available on this platform.");
-#else
+#ifdef HAVE_LIBUNWIND
+ char buf[100];
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_word_t ip, off, sp;
+ Dl_info dlinfo;
+
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ zlog(priority, "Backtrace:");
+ while (unw_step(&cursor) > 0) {
+ char name[128] = "?";
+
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+
+ if (unw_is_signal_frame(&cursor))
+ zlog(priority, " ---- signal ----");
+
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off))
+ snprintf(name, sizeof(name), "%s+%#lx",
+ buf, (long)off);
+
+ if (dladdr((void *)ip, &dlinfo))
+ zlog(priority, "%-30s %16lx %16lx %s (mapped at %p)",
+ name, (long)ip, (long)sp,
+ dlinfo.dli_fname, dlinfo.dli_fbase);
+ else
+ zlog(priority, "%-30s %16lx %16lx",
+ name, (long)ip, (long)sp);
+ }
+#elif defined(HAVE_GLIBC_BACKTRACE)
void *array[20];
int size, i;
char **strings;
@@ -651,7 +718,9 @@ void zlog_backtrace(int priority)
zlog(priority, "[bt %d] %s", i, strings[i]);
free(strings);
}
-#endif /* HAVE_GLIBC_BACKTRACE */
+#else /* !HAVE_GLIBC_BACKTRACE && !HAVE_LIBUNWIND */
+ zlog(priority, "No backtrace available on this platform.");
+#endif
}
void zlog(int priority, const char *format, ...)