Merge branch 'norris'
authorBrian Norris <banorris@uci.edu>
Mon, 8 Oct 2012 06:25:48 +0000 (23:25 -0700)
committerBrian Norris <banorris@uci.edu>
Mon, 8 Oct 2012 06:25:48 +0000 (23:25 -0700)
common.cc
stacktrace.h [new file with mode: 0644]

index e05e094..b274989 100644 (file)
--- a/common.cc
+++ b/common.cc
@@ -4,12 +4,17 @@
 
 #include "common.h"
 #include "model.h"
+#include "stacktrace.h"
 
 #define MAX_TRACE_LEN 100
 
+#define CONFIG_STACKTRACE
 /** Print a backtrace of the current program state. */
 void print_trace(void)
 {
+#ifdef CONFIG_STACKTRACE
+       print_stacktrace(stdout);
+#else
        void *array[MAX_TRACE_LEN];
        char **strings;
        int size, i;
@@ -23,6 +28,7 @@ void print_trace(void)
                printf("\t%s\n", strings[i]);
 
        free(strings);
+#endif /* CONFIG_STACKTRACE */
 }
 
 void model_print_summary(void)
diff --git a/stacktrace.h b/stacktrace.h
new file mode 100644 (file)
index 0000000..01d31d2
--- /dev/null
@@ -0,0 +1,86 @@
+// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
+// published under the WTFPL v2.0
+
+#ifndef __STACKTRACE_H__
+#define __STACKTRACE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <execinfo.h>
+#include <cxxabi.h>
+
+/** Print a demangled stack backtrace of the caller function to FILE* out. */
+static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
+{
+       fprintf(out, "stack trace:\n");
+
+       // storage array for stack trace address data
+       void* addrlist[max_frames+1];
+
+       // retrieve current stack addresses
+       int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
+
+       if (addrlen == 0) {
+               fprintf(out, "  <empty, possibly corrupt>\n");
+               return;
+       }
+
+       // resolve addresses into strings containing "filename(function+address)",
+       // this array must be free()-ed
+       char** symbollist = backtrace_symbols(addrlist, addrlen);
+
+       // allocate string which will be filled with the demangled function name
+       size_t funcnamesize = 256;
+       char* funcname = (char*)malloc(funcnamesize);
+
+       // iterate over the returned symbol lines. skip the first, it is the
+       // address of this function.
+       for (int i = 1; i < addrlen; i++) {
+               char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
+
+               // find parentheses and +address offset surrounding the mangled name:
+               // ./module(function+0x15c) [0x8048a6d]
+               for (char *p = symbollist[i]; *p; ++p) {
+                       if (*p == '(')
+                               begin_name = p;
+                       else if (*p == '+')
+                               begin_offset = p;
+                       else if (*p == ')' && begin_offset) {
+                               end_offset = p;
+                               break;
+                       }
+               }
+
+               if (begin_name && begin_offset && end_offset && begin_name < begin_offset) {
+                       *begin_name++ = '\0';
+                       *begin_offset++ = '\0';
+                       *end_offset = '\0';
+
+                       // mangled name is now in [begin_name, begin_offset) and caller
+                       // offset in [begin_offset, end_offset). now apply
+                       // __cxa_demangle():
+
+                       int status;
+                       char* ret = abi::__cxa_demangle(begin_name,
+                                       funcname, &funcnamesize, &status);
+                       if (status == 0) {
+                               funcname = ret; // use possibly realloc()-ed string
+                               fprintf(out, "  %s : %s+%s\n",
+                                               symbollist[i], funcname, begin_offset);
+                       } else {
+                               // demangling failed. Output function name as a C function with
+                               // no arguments.
+                               fprintf(out, "  %s : %s()+%s\n",
+                                               symbollist[i], begin_name, begin_offset);
+                       }
+               } else {
+                       // couldn't parse the line? print the whole line.
+                       fprintf(out, "  %s\n", symbollist[i]);
+               }
+       }
+
+       free(funcname);
+       free(symbollist);
+}
+
+#endif // __STACKTRACE_H__