Merge pull request #3189 from opensourcerouting/libunwind

lib: add libunwind support for backtraces
This commit is contained in:
Donald Sharp 2018-10-18 10:45:32 -04:00 committed by GitHub
commit 20c11b1b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 19 deletions

View File

@ -4,6 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = \
$(UNWIND_CFLAGS) \
$(SAN_FLAGS) \
$(WERROR) \
# end

View File

@ -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
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,,[Glibc backtrace])
AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding])
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

View File

@ -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, ...)

View File

@ -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 \

View File

@ -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;
}