diff options
author | James Peach <jpeach@samba.org> | 2006-04-12 00:07:40 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:16:00 -0500 |
commit | 7a5ff0885d08f9e32dc9939e5fd676a987b881d9 (patch) | |
tree | de8abf7e0c7a49284d2730dd0c6cae614a8016a7 /source3 | |
parent | a407405438beb1f71e186d7e5b2145b303ccfdaf (diff) | |
download | samba-7a5ff0885d08f9e32dc9939e5fd676a987b881d9.tar.gz samba-7a5ff0885d08f9e32dc9939e5fd676a987b881d9.tar.bz2 samba-7a5ff0885d08f9e32dc9939e5fd676a987b881d9.zip |
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.
(This used to be commit 256a19d722f360dac3c8e83f5bfac453fa70db96)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/configure.in | 44 | ||||
-rw-r--r-- | source3/include/includes.h | 4 | ||||
-rw-r--r-- | source3/lib/util.c | 113 |
3 files changed, 129 insertions, 32 deletions
diff --git a/source3/configure.in b/source3/configure.in index b6a7556166..386f83172a 100644 --- a/source3/configure.in +++ b/source3/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 <libunwind.h> +#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/source3/include/includes.h b/source3/include/includes.h index c83b707887..b96bd19fd8 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -358,10 +358,6 @@ #include <poll.h> #endif -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#endif - #if defined(HAVE_RPC_RPC_H) /* * Check for AUTH_ERROR define conflict with rpc/rpc.h in prot.h. diff --git a/source3/lib/util.c b/source3/lib/util.c index bbc9ceddca..c023df0b01 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -5,7 +5,8 @@ Copyright (C) Jeremy Allison 2001-2002 Copyright (C) Simo Sorce 2001 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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 <libunwind.h> +#endif + +#ifdef HAVE_EXECINFO_H +#include <execinfo.h> +#endif + #ifdef HAVE_LIBEXC_H #include <libexc.h> #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, "<unknown symbol>", + (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 |