summaryrefslogtreecommitdiff
path: root/source3/lib/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/util.c')
-rw-r--r--source3/lib/util.c113
1 files changed, 88 insertions, 25 deletions
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