mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-03-10 18:30:08 +01: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:
parent
be2bed2712
commit
6058013abe
1 changed files with 43 additions and 18 deletions
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue