diff options
Diffstat (limited to 'src/backtrace-lunw.c')
-rw-r--r-- | src/backtrace-lunw.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/backtrace-lunw.c b/src/backtrace-lunw.c new file mode 100644 index 0000000..eb29467 --- /dev/null +++ b/src/backtrace-lunw.c @@ -0,0 +1,76 @@ +#include <libunwind.h> + +#include "config.h" +#include "backtrace.h" + +#define LT_MAXMSG 300 + +int bt_dump(struct lt_config_shared *cfg, unsigned long flags) +{ + unw_cursor_t cursor; + unw_context_t uc; + int ret = 0; + + unw_getcontext(&uc); + if (unw_init_local(&cursor, &uc) < 0) { + bt_display(cfg, "unw_init_local failed"); + return -1; + } + + bt_display(cfg, "backtrace:"); + + do { + char text[LT_MAXMSG]; + struct bt_map *map; + bt_word_t rel_ip = 0, ip = 0, sp; + bt_word_t sym_offset = 0; + bt_word_t sym_size= 0; + char *map_name = NULL; + char *sym_name = NULL; + struct bt_symbol *symbol = NULL; + int size = sizeof(bt_word_t) * 2; + int symbol_found = 0; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (bt_find_map(cfg, &map, ip)) { + rel_ip = ip - map->base; + map_name = map->name; + + if (bt_find_symbol(cfg, &symbol, map, rel_ip)) { + sym_name = symbol->name; + sym_offset = rel_ip - symbol->start; + sym_size = symbol->end - symbol->start; + symbol_found = 1; + } + } + + if (symbol_found) + snprintf(text, LT_MAXMSG, + "\t<0x%0*zx> %s+0x%zx/0x%zx [%s]", + size, rel_ip, + sym_name, + sym_offset, + sym_size, + map_name); + else + snprintf(text, LT_MAXMSG, + "\t<0x%0*zx> [%s]", + size, rel_ip, + map_name); + + bt_display(cfg, text); + + ret = unw_step(&cursor); + if (ret < 0) { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + snprintf(text, LT_MAXMSG, + "unw_step failed for ip=%zx\n", + ip); + bt_display(cfg, text); + } + } while (ret > 0); + + return ret; +} |