From dc8162d5f0552ed1ab7c21692bcabf45b48c6467 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Thu, 27 May 2021 17:06:16 -0700 Subject: [PATCH] os: print registers in the libunwind version of xorg_backtrace() If the stack walker finds a signal frame, record the cursor at that point and then use unw_get_reg() to query the values of the architecture-specific registers at the frame that triggered the signal. Example output: (EE) Backtrace: (EE) 0: hw/xfree86/Xorg (OsSigHandler+0x25) [0x561458bb8195] (EE) 1: (EE) 2: hw/xfree86/Xorg (dix_main+0x9c) [0x561458aead6c] (EE) 3: /usr/lib/libc.so.6 (__libc_start_main+0xd5) [0x7f2d23170b25] (EE) 4: hw/xfree86/Xorg (_start+0x2e) [0x561458aad8be] (EE) (EE) Registers at frame #2: (EE) rax: 0x0 (EE) rbx: 0x561458c3ae60 (EE) rcx: 0x7f2d23328943 (EE) rdx: 0x0 (EE) rsi: 0x7ffcb6025030 (EE) rdi: 0xe (EE) rbp: 0x0 (EE) rsp: 0x7ffcb6026430 (EE) r8: 0x0 (EE) r9: 0x0 (EE) r10: 0x8 (EE) r11: 0x246 (EE) r12: 0x561458aad890 (EE) r13: 0x0 (EE) r14: 0x0 (EE) r15: 0x0 (EE) (EE) Segmentation fault at address 0x0 Signed-off-by: Aaron Plattner --- os/backtrace.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/os/backtrace.c b/os/backtrace.c index bf7ee68e2..8025bffae 100644 --- a/os/backtrace.c +++ b/os/backtrace.c @@ -40,15 +40,73 @@ #endif #include +static void +print_registers(int frame, unw_cursor_t cursor) +{ + const struct { + const char *name; + int regnum; + } regs[] = { +#if UNW_TARGET_X86_64 + { "rax", UNW_X86_64_RAX }, + { "rbx", UNW_X86_64_RBX }, + { "rcx", UNW_X86_64_RCX }, + { "rdx", UNW_X86_64_RDX }, + { "rsi", UNW_X86_64_RSI }, + { "rdi", UNW_X86_64_RDI }, + { "rbp", UNW_X86_64_RBP }, + { "rsp", UNW_X86_64_RSP }, + { " r8", UNW_X86_64_R8 }, + { " r9", UNW_X86_64_R9 }, + { "r10", UNW_X86_64_R10 }, + { "r11", UNW_X86_64_R11 }, + { "r12", UNW_X86_64_R12 }, + { "r13", UNW_X86_64_R13 }, + { "r14", UNW_X86_64_R14 }, + { "r15", UNW_X86_64_R15 }, +#endif + }; + const int num_regs = sizeof(regs) / sizeof(*regs); + int ret, i; + + if (num_regs == 0) + return; + + /* + * Advance the cursor from the signal frame to the one that triggered the + * signal. + */ + frame++; + ret = unw_step(&cursor); + if (ret < 0) { + ErrorFSigSafe("unw_step failed: %s [%d]\n", unw_strerror(ret), ret); + return; + } + + ErrorFSigSafe("\n"); + ErrorFSigSafe("Registers at frame #%d:\n", frame); + + for (i = 0; i < num_regs; i++) { + uint64_t val; + ret = unw_get_reg(&cursor, regs[i].regnum, &val); + if (ret < 0) { + ErrorFSigSafe("unw_get_reg(%s) failed: %s [%d]\n", + regs[i].name, unw_strerror(ret), ret); + } else { + ErrorFSigSafe(" %s: 0x%" PRIx64 "\n", regs[i].name, val); + } + } +} + void xorg_backtrace(void) { - unw_cursor_t cursor; + unw_cursor_t cursor, signal_cursor; unw_context_t context; unw_word_t ip; unw_word_t off; unw_proc_info_t pip; - int ret, i = 0; + int ret, i = 0, signal_frame = -1; char procname[256]; const char *filename; Dl_info dlinfo; @@ -99,6 +157,9 @@ xorg_backtrace(void) if (unw_is_signal_frame(&cursor)) { + signal_cursor = cursor; + signal_frame = i; + ErrorFSigSafe("%u: \n", i++); } else { ErrorFSigSafe("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname, @@ -110,6 +171,10 @@ xorg_backtrace(void) if (ret < 0) ErrorFSigSafe("unw_step failed: %s [%d]\n", unw_strerror(ret), ret); } + + if (signal_frame >= 0) + print_registers(signal_frame, signal_cursor); + ErrorFSigSafe("\n"); } #else /* HAVE_LIBUNWIND */