summaryrefslogtreecommitdiffstats
path: root/src/backtrace-lunw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backtrace-lunw.c')
-rw-r--r--src/backtrace-lunw.c76
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;
+}