summaryrefslogtreecommitdiff
path: root/source3/lib/util.c
diff options
context:
space:
mode:
authorJames Peach <jpeach@samba.org>2006-04-12 00:07:40 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:16:00 -0500
commit7a5ff0885d08f9e32dc9939e5fd676a987b881d9 (patch)
treede8abf7e0c7a49284d2730dd0c6cae614a8016a7 /source3/lib/util.c
parenta407405438beb1f71e186d7e5b2145b303ccfdaf (diff)
downloadsamba-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/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