summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Peach <jpeach@samba.org>2006-04-12 00:07:40 +0000
committerJames Peach <jpeach@samba.org>2006-04-12 00:07:40 +0000
commitc176335893b5a01c1f036188aa1054e24b54eac1 (patch)
treef03a818d19dce1469d2cb6f9fc9e7ced76d47492
parentec83c50aec2921447730f4e2442b181974ce8db2 (diff)
downloadsamba-c176335893b5a01c1f036188aa1054e24b54eac1.tar.gz
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.
-rw-r--r--source/configure.in44
-rw-r--r--source/include/includes.h4
-rw-r--r--source/lib/util.c113
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 <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/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 <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/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 <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