1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-09-30 02:19:31 +02:00

(unw_step): If dwarf_step() fails, fall back on using the frame-chain.

In theory, this may not be needed.  In practice, I find that
	Red Hat Enterprise Linux AS release 3, the _start() routine has
	no unwind-info, but we need to be able to unwind into this
	routine to find the end-of-frame-chain marker (RBP == 0).

(Logical change 1.253)
This commit is contained in:
homeip.net!davidm 2004-08-20 11:23:15 +00:00
parent be2bed2712
commit 6058013abe

View file

@ -35,34 +35,59 @@ unw_step (unw_cursor_t *cursor)
struct cursor *c = (struct cursor *) cursor; struct cursor *c = (struct cursor *) cursor;
int ret, i; int ret, i;
/* Only attempt DWARF based unwinding since DWARF frame info is /* Try DWARF-based unwinding... */
always expected to be there. With the exception of signal frames. */ ret = dwarf_step (&c->dwarf);
if (!unw_is_signal_frame (cursor)) if (unlikely (ret == -UNW_ESTOPUNWIND))
return ret;
if (likely (ret >= 0))
{ {
if ((ret = dwarf_step (&c->dwarf)) < 0) /* x86_64 ABI specifies that end of call-chain is marked with a
{ NULL RBP. */
Debug(1, "dwarf step failed\n"); if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
return ret; c->dwarf.ip = 0;
}
} }
else else
{ {
/* DWARF failed, let's see if we can follow the frame-chain
or skip over the signal trampoline. */
struct dwarf_loc rbp_loc, rsp_loc, rip_loc; struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
unw_word_t ucontext = c->dwarf.cfa;
Debug(1, "signal frame, skip over trampoline\n"); Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME; if (unw_is_signal_frame (cursor))
c->sigcontext_addr = c->dwarf.cfa; {
unw_word_t ucontext = c->dwarf.cfa;
rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0); Debug(1, "signal frame, skip over trampoline\n");
rbp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
rip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa); c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
if (ret < 0) c->sigcontext_addr = c->dwarf.cfa;
return ret;
rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
rbp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
rip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
if (ret < 0)
return ret;
}
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);
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;
}
/* Mark all registers unsaved */ /* Mark all registers unsaved */
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)