summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2017-04-04 09:52:57 -0400
committerRob Clark <robdclark@gmail.com>2017-04-07 08:23:02 -0400
commit91dfa021254d5ea1c607f4f514414c2130fac208 (patch)
treedd0d2b532487f7d1ac055d9ebad919a92eb3ddcc /src/gallium/auxiliary
parent7c69ea553bfa8e23feedc5d3f479a9003c139bad (diff)
gallium/util: cache symbol lookup with libunwind
Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'src/gallium/auxiliary')
-rw-r--r--src/gallium/auxiliary/util/u_debug_stack.c117
-rw-r--r--src/gallium/auxiliary/util/u_debug_stack.h4
2 files changed, 94 insertions, 27 deletions
diff --git a/src/gallium/auxiliary/util/u_debug_stack.c b/src/gallium/auxiliary/util/u_debug_stack.c
index 14d5b16c376..a5829316e40 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.c
+++ b/src/gallium/auxiliary/util/u_debug_stack.c
@@ -43,6 +43,62 @@
#endif
#include <dlfcn.h>
+#include "os/os_thread.h"
+#include "u_hash_table.h"
+
+struct util_hash_table* symbols_hash;
+static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
+
+static unsigned hash_ptr(void* p)
+{
+ return (unsigned)(uintptr_t)p;
+}
+
+static int compare_ptr(void* a, void* b)
+{
+ if(a == b)
+ return 0;
+ else if(a < b)
+ return -1;
+ else
+ return 1;
+}
+
+/* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
+ * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
+ * from build?
+ */
+static const char *
+symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
+{
+ void *addr = (void *)(uintptr_t)pip->start_ip;
+ char *name;
+
+ mtx_lock(&symbols_mutex);
+ if(!symbols_hash)
+ symbols_hash = util_hash_table_create(hash_ptr, compare_ptr);
+ name = util_hash_table_get(symbols_hash, addr);
+ if(!name)
+ {
+ char procname[256];
+ unw_word_t off;
+ int ret;
+
+ ret = unw_get_proc_name(cursor, procname, sizeof(procname), &off);
+ if (ret && ret != -UNW_ENOMEM) {
+ procname[0] = '?';
+ procname[1] = 0;
+ }
+
+ asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "");
+
+ util_hash_table_set(symbols_hash, addr, (void*)name);
+ }
+ mtx_unlock(&symbols_mutex);
+
+ return name;
+}
+
void
debug_backtrace_capture(struct debug_stack_frame *backtrace,
unsigned start_frame,
@@ -52,7 +108,6 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
unw_context_t context;
unw_proc_info_t pip;
unsigned i = 0;
- int ret;
pip.unwind_info = NULL;
@@ -63,39 +118,43 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
start_frame--;
while ((i < nr_frames) && (unw_step(&cursor) > 0)) {
- char procname[256];
- const char *filename;
- unw_word_t off;
- Dl_info dlinfo;
+ unw_word_t ip;
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_proc_info(&cursor, &pip);
- ret = unw_get_proc_name(&cursor, procname, 256, &off);
- if (ret && ret != -UNW_ENOMEM) {
- procname[0] = '?';
- procname[1] = 0;
- }
-
- if (dladdr((void *)(uintptr_t)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
- *dlinfo.dli_fname)
- filename = dlinfo.dli_fname;
- else
- filename = "?";
-
- snprintf(backtrace[i].buf, sizeof(backtrace[i].buf),
- "%u: %s (%s%s+0x%x) [%p]", i, filename, procname,
- ret == -UNW_ENOMEM ? "..." : "", (int)off,
- (void *)(uintptr_t)(pip.start_ip + off));
+ backtrace[i].start_ip = pip.start_ip;
+ backtrace[i].off = ip - pip.start_ip;
+ backtrace[i].procname = symbol_name_cached(&cursor, &pip);
i++;
}
while (i < nr_frames) {
- backtrace[i].buf[0] = '\0';
+ backtrace[i].start_ip = 0;
i++;
}
}
+static const void *
+frame_ip(const struct debug_stack_frame *frame)
+{
+ return (void *)(uintptr_t)(frame->start_ip + frame->off);
+}
+
+static const char *
+frame_filename(const struct debug_stack_frame *frame)
+{
+ Dl_info dlinfo;
+
+
+ if (dladdr(frame_ip(frame), &dlinfo) && dlinfo.dli_fname &&
+ *dlinfo.dli_fname)
+ return dlinfo.dli_fname;
+
+ return "?";
+}
+
void
debug_backtrace_dump(const struct debug_stack_frame *backtrace,
unsigned nr_frames)
@@ -103,9 +162,12 @@ debug_backtrace_dump(const struct debug_stack_frame *backtrace,
unsigned i;
for (i = 0; i < nr_frames; ++i) {
- if (backtrace[i].buf[0] == '\0')
+ if (!backtrace[i].start_ip)
break;
- debug_printf("\t%s\n", backtrace[i].buf);
+ debug_printf("\t%u: %s (%s+0x%x) [%p]\n", i,
+ frame_filename(&backtrace[i]),
+ backtrace[i].procname, backtrace[i].off,
+ frame_ip(&backtrace[i]));
}
}
@@ -117,9 +179,12 @@ debug_backtrace_print(FILE *f,
unsigned i;
for (i = 0; i < nr_frames; ++i) {
- if (backtrace[i].buf[0] == '\0')
+ if (!backtrace[i].start_ip)
break;
- fprintf(f, "\t%s\n", backtrace[i].buf);
+ fprintf(f, "\t%u: %s (%s+0x%x) [%p]\n", i,
+ frame_filename(&backtrace[i]),
+ backtrace[i].procname, backtrace[i].off,
+ frame_ip(&backtrace[i]));
}
}
diff --git a/src/gallium/auxiliary/util/u_debug_stack.h b/src/gallium/auxiliary/util/u_debug_stack.h
index 0effcbe5259..fff41a5a9ea 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.h
+++ b/src/gallium/auxiliary/util/u_debug_stack.h
@@ -60,7 +60,9 @@ extern "C" {
struct debug_stack_frame
{
#ifdef HAVE_LIBUNWIND
- char buf[128];
+ unw_word_t start_ip;
+ unsigned int off;
+ const char *procname;
#else
const void *function;
#endif