From c176335893b5a01c1f036188aa1054e24b54eac1 Mon Sep 17 00:00:00 2001 From: James Peach Date: Wed, 12 Apr 2006 00:07:40 +0000 Subject: r15047: Add support for using libunwind to generate a backtrace. This is primarily intended for ia64 systems where libunwind knows more about the different ways of walking the stack that just about anything else. --- source/configure.in | 44 ++++++++++++++++-- source/include/includes.h | 4 -- source/lib/util.c | 113 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 129 insertions(+), 32 deletions(-) diff --git a/source/configure.in b/source/configure.in index b6a75561663..386f83172a2 100644 --- a/source/configure.in +++ b/source/configure.in @@ -827,7 +827,7 @@ AC_CHECK_HEADERS(sys/un.h) AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h) AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h) AC_CHECK_HEADERS(sys/sysmacros.h security/_pam_macros.h dlfcn.h) -AC_CHECK_HEADERS(sys/syslog.h syslog.h execinfo.h) +AC_CHECK_HEADERS(sys/syslog.h syslog.h) AC_CHECK_HEADERS(langinfo.h locale.h) AC_CHECK_HEADERS(sys/dmi.h xfs/dmapi.h sys/jfsdmapi.h sys/dmapi.h) @@ -1243,10 +1243,48 @@ AC_CHECK_FUNCS(syslog vsyslog timegm) AC_CHECK_FUNCS(setlocale nl_langinfo) AC_CHECK_FUNCS(nanosleep) # setbuffer, shmget, shm_open are needed for smbtorture -AC_CHECK_FUNCS(setbuffer shmget shm_open backtrace_symbols) -AC_CHECK_HEADERS(libexc.h) +AC_CHECK_FUNCS(setbuffer shmget shm_open) + +# Find a method of generating a stack trace +AC_CHECK_HEADERS(execinfo.h libexc.h libunwind.h) +AC_CHECK_FUNCS(backtrace_symbols) AC_CHECK_LIB(exc, trace_back_stack) +# Note that all the libunwind symbols in the API are defined to internal +# platform-specific version, so we must include libunwind.h before checking +# any of them. +AC_MSG_CHECKING([for libunwind]) +save_LIBS=$LIBS +if test x"$UNAME_P" != xunknown ; then + # This probably won't link without the platform-specific libunwind. + LIBS="$LIBS -lunwind" +else + # Add the platform-specific libunwind module. uname -p seems the most + # plausible option and works for ia64, where libunwind is most useful. + LIBS="$LIBS -lunwind -lunwind-$UNAME_P" +fi + +AC_TRY_LINK( + [ +#ifdef HAVE_LIBUNWIND_H +#include +#endif + ], + [ + unw_context_t ctx; unw_cursor_t cur; + char buf[256]; unw_word_t off; + unw_getcontext(&ctx); unw_init_local(&cur, &ctx); + unw_get_proc_name(&cur, buf, sizeof(buf), &off); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_LIBUNWIND, 1, [Whether libunwind is available]) + ], + [ + AC_MSG_RESULT(no) + LIBS=$save_LIBS + ]) + # syscall() is needed for smbwrapper. AC_CHECK_FUNCS(syscall) diff --git a/source/include/includes.h b/source/include/includes.h index c83b707887a..b96bd19fd83 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -358,10 +358,6 @@ #include #endif -#ifdef HAVE_EXECINFO_H -#include -#endif - #if defined(HAVE_RPC_RPC_H) /* * Check for AUTH_ERROR define conflict with rpc/rpc.h in prot.h. diff --git a/source/lib/util.c b/source/lib/util.c index bbc9ceddcaf..c023df0b017 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -5,7 +5,8 @@ Copyright (C) Jeremy Allison 2001-2002 Copyright (C) Simo Sorce 2001 Copyright (C) Jim McDonough 2003 - + Copyright (C) James Peach 2006 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -1616,13 +1617,76 @@ void smb_panic(const char *const why) exit shortly after calling it. ********************************************************************/ +#ifdef HAVE_LIBUNWIND_H +#include +#endif + +#ifdef HAVE_EXECINFO_H +#include +#endif + #ifdef HAVE_LIBEXC_H #include #endif void log_stack_trace(void) { -#ifdef HAVE_BACKTRACE_SYMBOLS +#ifdef HAVE_LIBUNWIND + /* Try to use libunwind before any other technique since on ia64 + * libunwind correctly walks the stack in more circumstances than + * backtrace. + */ + unw_cursor_t cursor; + unw_context_t uc; + unsigned i = 0; + + char procname[256]; + unw_word_t ip, sp, off; + + procname[sizeof(procname) - 1] = '\0'; + + if (unw_getcontext(&uc) != 0) { + goto libunwind_failed; + } + + if (unw_init_local(&cursor, &uc) != 0) { + goto libunwind_failed; + } + + DEBUG(0, ("BACKTRACE:\n")); + + do { + ip = sp = 0; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + switch (unw_get_proc_name(&cursor, + procname, sizeof(procname) - 1, &off) ) { + case 0: + /* Name found. */ + case -UNW_ENOMEM: + /* Name truncated. */ + DEBUGADD(0, (" #%u %s + %#llx [ip=%#llx] [sp=%#llx]\n", + i, procname, (long long)off, + (long long)ip, (long long) sp)); + break; + default: + /* case -UNW_ENOINFO: */ + /* case -UNW_EUNSPEC: */ + /* No symbol name found. */ + DEBUGADD(0, (" #%u %s [ip=%#llx] [sp=%#llx]\n", + i, "", + (long long)ip, (long long) sp)); + } + ++i; + } while (unw_step(&cursor) > 0); + + return; + +libunwind_failed: + DEBUG(0, ("unable to produce a stack trace with libunwind\n")); + +#elif HAVE_BACKTRACE_SYMBOLS void *backtrace_stack[BACKTRACE_STACK_SIZE]; size_t backtrace_size; char **backtrace_strings; @@ -1649,39 +1713,38 @@ void log_stack_trace(void) * libexc(3) for details. Apparantly trace_back_stack leaks memory, but * since we are about to abort anyway, it hardly matters. */ - { #define NAMESIZE 32 /* Arbitrary */ - __uint64_t addrs[BACKTRACE_STACK_SIZE]; - char * names[BACKTRACE_STACK_SIZE]; - char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE]; + __uint64_t addrs[BACKTRACE_STACK_SIZE]; + char * names[BACKTRACE_STACK_SIZE]; + char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE]; - int i; - int levels; + int i; + int levels; - ZERO_ARRAY(addrs); - ZERO_ARRAY(names); - ZERO_ARRAY(namebuf); + ZERO_ARRAY(addrs); + ZERO_ARRAY(names); + ZERO_ARRAY(namebuf); - /* We need to be root so we can open our /proc entry to walk - * our stack. It also helps when we want to dump core. - */ - become_root(); + /* We need to be root so we can open our /proc entry to walk + * our stack. It also helps when we want to dump core. + */ + become_root(); - for (i = 0; i < BACKTRACE_STACK_SIZE; i++) { - names[i] = namebuf + (i * NAMESIZE); - } + for (i = 0; i < BACKTRACE_STACK_SIZE; i++) { + names[i] = namebuf + (i * NAMESIZE); + } - levels = trace_back_stack(0, addrs, names, - BACKTRACE_STACK_SIZE, NAMESIZE - 1); + levels = trace_back_stack(0, addrs, names, + BACKTRACE_STACK_SIZE, NAMESIZE - 1); - DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels)); - for (i = 0; i < levels; i++) { - DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i])); - } - } + DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels)); + for (i = 0; i < levels; i++) { + DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i])); + } #undef NAMESIZE + #else DEBUG(0, ("unable to produce a stack trace on this platform\n")); #endif -- cgit v1.2.1