From 91dfa021254d5ea1c607f4f514414c2130fac208 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 4 Apr 2017 09:52:57 -0400 Subject: [PATCH] gallium/util: cache symbol lookup with libunwind Signed-off-by: Rob Clark --- src/gallium/auxiliary/util/u_debug_stack.c | 117 ++++++++++++++++----- src/gallium/auxiliary/util/u_debug_stack.h | 4 +- 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 +#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 -- 2.30.2