mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
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>
This commit is contained in:
parent
b9ea408385
commit
68b8a15f87
|
@ -4,6 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12
|
|||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
AM_CFLAGS = \
|
||||
$(UNWIND_CFLAGS) \
|
||||
$(SAN_FLAGS) \
|
||||
$(WERROR) \
|
||||
# end
|
||||
|
|
32
configure.ac
32
configure.ac
|
@ -958,10 +958,6 @@ case "$host_os" in
|
|||
AC_CHECK_LIB(socket, main)
|
||||
AC_CHECK_LIB(nsl, main)
|
||||
AC_CHECK_LIB(umem, main)
|
||||
AC_CHECK_FUNCS([printstack], [
|
||||
AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack])
|
||||
AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality])
|
||||
])
|
||||
CURSES=-lcurses
|
||||
SOLARIS="solaris"
|
||||
;;
|
||||
|
@ -1811,17 +1807,31 @@ dnl check for glibc 'backtrace'
|
|||
dnl ---------------------------
|
||||
if test x"${enable_backtrace}" != x"no" ; then
|
||||
backtrace_ok=no
|
||||
AC_CHECK_HEADER([execinfo.h], [
|
||||
AC_SEARCH_LIBS([backtrace], [execinfo], [
|
||||
AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace])
|
||||
AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding])
|
||||
backtrace_ok=yes
|
||||
],, [-lm])
|
||||
PKG_CHECK_MODULES([UNWIND], [libunwind], [
|
||||
AC_DEFINE(HAVE_LIBUNWIND, 1, [libunwind])
|
||||
backtrace_ok=yes
|
||||
], [
|
||||
case "$host_os" in
|
||||
sunos* | solaris2*)
|
||||
AC_CHECK_FUNCS([printstack], [
|
||||
AC_DEFINE([HAVE_PRINTSTACK], 1, [Solaris printstack])
|
||||
backtrace_ok=yes
|
||||
])
|
||||
;;
|
||||
esac
|
||||
if test "$backtrace_ok" = no; then
|
||||
AC_CHECK_HEADER([execinfo.h], [
|
||||
AC_SEARCH_LIBS([backtrace], [execinfo], [
|
||||
AC_DEFINE(HAVE_GLIBC_BACKTRACE, 1, [Glibc backtrace])
|
||||
backtrace_ok=yes
|
||||
],, [-lm])
|
||||
])
|
||||
fi
|
||||
])
|
||||
|
||||
if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then
|
||||
dnl user explicitly requested backtrace but we failed to find support
|
||||
AC_MSG_FAILURE([failed to find backtrace support])
|
||||
AC_MSG_FAILURE([failed to find backtrace or libunwind support])
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
81
lib/log.c
81
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, ...)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
lib_LTLIBRARIES += lib/libfrr.la
|
||||
lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version
|
||||
lib_libfrr_la_LIBADD = @LIBCAP@
|
||||
lib_libfrr_la_LIBADD = @LIBCAP@ $(UNWIND_LIBS)
|
||||
|
||||
lib_libfrr_la_SOURCES = \
|
||||
lib/agg_table.c \
|
||||
|
|
|
@ -32,10 +32,39 @@ struct quagga_signal_t sigs[] = {};
|
|||
|
||||
struct thread_master *master;
|
||||
|
||||
static int threadfunc(struct thread *thread)
|
||||
void func1(int *arg);
|
||||
void func3(void);
|
||||
|
||||
void func1(int *arg)
|
||||
{
|
||||
int *null = NULL;
|
||||
*null += 1;
|
||||
*arg = 1;
|
||||
}
|
||||
|
||||
static void func2(size_t depth, int *arg)
|
||||
{
|
||||
/* variable stack frame size */
|
||||
int buf[depth];
|
||||
for (size_t i = 0; i < depth; i++)
|
||||
buf[i] = arg[i] + 1;
|
||||
if (depth > 0)
|
||||
func2(depth - 1, buf);
|
||||
else
|
||||
func1(&buf[0]);
|
||||
for (size_t i = 0; i < depth; i++)
|
||||
buf[i] = arg[i] + 2;
|
||||
}
|
||||
|
||||
void func3(void)
|
||||
{
|
||||
int buf[6];
|
||||
func2(6, buf);
|
||||
}
|
||||
|
||||
static int threadfunc(struct thread *thread)
|
||||
{
|
||||
func3();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue