summaryrefslogtreecommitdiff
path: root/src/x86_64/Gstep.c
diff options
context:
space:
mode:
authormostang.com!davidm <mostang.com!davidm>2005-05-03 09:13:17 +0000
committermostang.com!davidm <mostang.com!davidm>2005-05-03 09:13:17 +0000
commit17bf4d0af84466787d06f90c832dc93d3cd8843a (patch)
tree8079010cbd7b6c7a265cebaf9d3744b683650cab /src/x86_64/Gstep.c
parentfa0828ac7d77fd2c4ba3c94c42d66565f379512a (diff)
downloadlibunwind-17bf4d0af84466787d06f90c832dc93d3cd8843a.tar.gz
(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)
Diffstat (limited to 'src/x86_64/Gstep.c')
-rw-r--r--src/x86_64/Gstep.c107
1 files changed, 84 insertions, 23 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 <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.com>
@@ -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);
- if (ret < 0)
- 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);
+ unw_word_t rbp;
- 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;
+ ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
+ if (ret < 0)
+ {
+ Debug (2, "returning %d\n", ret);
+ return ret;
+ }
+
+ 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 = 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;
}