From 17bf4d0af84466787d06f90c832dc93d3cd8843a Mon Sep 17 00:00:00 2001 From: "mostang.com!davidm" Date: Tue, 3 May 2005 09:13:17 +0000 Subject: [PATCH] (unw_step): If dwarf_step() fails and the frame doesn't look like a signal-trampoline, assume that it's a PLT stub. If non-DWARF stepping fails to change IP and CFA, declare it a bad frame. 2004/11/23 16:59:56-08:00 mostang.com!davidm (unw_step): Also print IP as part of the function-trace. 2004/11/23 16:17:37-08:00 mostang.com!davidm (unw_step): When dwarf_step() fails on a signal-frame, fill in all the known locations because dwarf_step() fails on older kernels which don't export the kernel vDSO even though every- thing else may be providing proper DWARF unwind-info. 2004/10/25 17:43:57+02:00 homeip.net!davidm Add Debug statement for return-value. (Logical change 1.290) --- src/x86_64/Gstep.c | 103 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 27fcc08e..c82e5c1a 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -1,5 +1,5 @@ /* libunwind - a platform-independent unwind library - Copyright (C) 2002-2003 Hewlett-Packard Co + Copyright (C) 2002-2004 Hewlett-Packard Co Contributed by David Mosberger-Tang Modified for x86_64 by Max Asbock @@ -35,11 +35,17 @@ unw_step (unw_cursor_t *cursor) struct cursor *c = (struct cursor *) cursor; int ret, i; + Debug (1, "(cursor=%p, ip=0x%016llx)\n", + c, (unsigned long long) c->dwarf.ip); + /* Try DWARF-based unwinding... */ ret = dwarf_step (&c->dwarf); - if (unlikely (ret == -UNW_ESTOPUNWIND)) - return ret; + if (ret < 0 && ret != -UNW_ENOINFO) + { + Debug (2, "returning %d\n", ret); + return ret; + } if (likely (ret >= 0)) { @@ -50,8 +56,19 @@ unw_step (unw_cursor_t *cursor) } else { - /* DWARF failed, let's see if we can follow the frame-chain - or skip over the signal trampoline. */ + /* DWARF failed. There isn't much of a usable frame-chain on x86-64, + but we do need to handle two special-cases: + + (i) signal trampoline: Old kernels and older libcs don't + export the vDSO needed to get proper unwind info for the + trampoline. Recognize that case by looking at the code + and filling in things by hand. + + (ii) PLT (shared-library) call-stubs: PLT stubs are invoked + via CALLQ. Try this for all non-signal trampoline + code. */ + + unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa; struct dwarf_loc rbp_loc, rsp_loc, rip_loc; Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); @@ -71,28 +88,64 @@ unw_step (unw_cursor_t *cursor) ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa); if (ret < 0) - return ret; + { + Debug (2, "returning %d\n", ret); + return ret; + } + + c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0); + c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0); + c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0); + c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0); + c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0); + c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0); + c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0); + c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); + c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); + c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); + c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0); + c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0); + c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0); + c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0); + c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0); + c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0); } else { - ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &c->dwarf.cfa); + unw_word_t rbp; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp); if (ret < 0) - return ret; + { + Debug (2, "returning %d\n", ret); + return ret; + } - Debug (13, "[RBP=0x%Lx] = 0x%Lx\n", - (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RBP]), - (unsigned long long) c->dwarf.cfa); + if (!rbp) + { + /* Looks like we may have reached the end of the call-chain. */ + rbp_loc = DWARF_NULL_LOC; + rsp_loc = DWARF_NULL_LOC; + rip_loc = DWARF_NULL_LOC; + } + else + { + Debug (1, "[RBP=0x%Lx] = 0x%Lx (cfa = 0x%Lx)\n", + (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RBP]), + (unsigned long long) rbp, + (unsigned long long) c->dwarf.cfa); - rbp_loc = DWARF_LOC (c->dwarf.cfa, 0); - rsp_loc = DWARF_NULL_LOC; - rip_loc = DWARF_LOC (c->dwarf.cfa + 8, 0); - c->dwarf.cfa += 16; + rbp_loc = c->dwarf.loc[RBP]; + rsp_loc = DWARF_NULL_LOC; + rip_loc = DWARF_LOC (c->dwarf.cfa + 8, 0); + c->dwarf.cfa += 8; + } + + /* Mark all registers unsaved */ + for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[i] = DWARF_NULL_LOC; } - /* Mark all registers unsaved */ - for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) - c->dwarf.loc[i] = DWARF_NULL_LOC; - c->dwarf.loc[RBP] = rbp_loc; c->dwarf.loc[RSP] = rsp_loc; c->dwarf.loc[RIP] = rip_loc; @@ -102,10 +155,18 @@ unw_step (unw_cursor_t *cursor) { ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); if (ret < 0) - return ret; + { + Debug (2, "returning %d\n", ret); + return ret; + } } else c->dwarf.ip = 0; + + if (c->dwarf.ip == prev_ip && c->dwarf.cfa == prev_cfa) + return -UNW_EBADFRAME; } - return (c->dwarf.ip == 0) ? 0 : 1; + ret = (c->dwarf.ip == 0) ? 0 : 1; + Debug (2, "returning %d\n", ret); + return ret; }