mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-12-01 18:57:38 +01:00
During the stack unwinding process, the return address points to
the instruction after the call for a normal frame. libunwind uses IP-1 to lookup unwind information. However, this is not necessary for interrupted frames such as signal frames (or interrupt frames) in the kernel context. This patch handles both cases correctly. Based on work by Mark Wielaard <mwielaard@redhat.com>
This commit is contained in:
parent
4c553ceb2c
commit
a9dce3c06e
21 changed files with 63 additions and 24 deletions
|
@ -295,6 +295,7 @@ typedef struct dwarf_cursor
|
||||||
|
|
||||||
dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS];
|
dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS];
|
||||||
|
|
||||||
|
unsigned int use_prev_instr :1; /* use previous (= call) or current (= signal) instruction? */
|
||||||
unsigned int pi_valid :1; /* is proc_info valid? */
|
unsigned int pi_valid :1; /* is proc_info valid? */
|
||||||
unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */
|
unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */
|
||||||
unw_proc_info_t pi; /* info about current procedure */
|
unw_proc_info_t pi; /* info about current procedure */
|
||||||
|
|
|
@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
|
|
||||||
c->dwarf.as = unw_local_addr_space;
|
c->dwarf.as = unw_local_addr_space;
|
||||||
c->dwarf.as_arg = uc;
|
c->dwarf.as_arg = uc;
|
||||||
return common_init (c);
|
return common_init (c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNW_REMOTE_ONLY */
|
#endif /* !UNW_REMOTE_ONLY */
|
||||||
|
|
|
@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
|
|
||||||
c->dwarf.as = as;
|
c->dwarf.as = as;
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
return common_init (c);
|
return common_init (c, 0);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init (struct cursor *c)
|
common_init (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ common_init (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = 0;
|
c->dwarf.ret_addr_column = 0;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
|
@ -76,7 +76,10 @@ run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
|
||||||
a = unw_get_accessors (as);
|
a = unw_get_accessors (as);
|
||||||
curr_ip = c->pi.start_ip;
|
curr_ip = c->pi.start_ip;
|
||||||
|
|
||||||
while (curr_ip < ip && *addr < end_addr)
|
/* Process everything up to and including the current 'ip',
|
||||||
|
including all the DW_CFA_advance_loc instructions. See
|
||||||
|
'c->use_prev_instr' use in 'fetch_proc_info' for details. */
|
||||||
|
while (curr_ip <= ip && *addr < end_addr)
|
||||||
{
|
{
|
||||||
if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
|
if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -381,7 +384,23 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
|
||||||
{
|
{
|
||||||
int ret, dynamic = 1;
|
int ret, dynamic = 1;
|
||||||
|
|
||||||
--ip;
|
/* The 'ip' can point either to the previous or next instruction
|
||||||
|
depending on what type of frame we have: normal call or a place
|
||||||
|
to resume execution (e.g. after signal frame).
|
||||||
|
|
||||||
|
For a normal call frame we need to back up so we point within the
|
||||||
|
call itself; this is important because a) the call might be the
|
||||||
|
very last instruction of the function and the edge of the FDE,
|
||||||
|
and b) so that run_cfi_program() runs locations up to the call
|
||||||
|
but not more.
|
||||||
|
|
||||||
|
For execution resume, we need to do the exact opposite and look
|
||||||
|
up using the current 'ip' value. That is where execution will
|
||||||
|
continue, and it's important we get this right, as 'ip' could be
|
||||||
|
right at the function entry and hence FDE edge, or at instruction
|
||||||
|
that manipulates CFA (push/pop). */
|
||||||
|
if (c->use_prev_instr)
|
||||||
|
--ip;
|
||||||
|
|
||||||
if (c->pi_valid && !need_unwind_info)
|
if (c->pi_valid && !need_unwind_info)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -405,6 +424,14 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
tdep_fetch_frame (c, ip, need_unwind_info);
|
tdep_fetch_frame (c, ip, need_unwind_info);
|
||||||
|
|
||||||
|
/* Update use_prev_instr for the next frame. */
|
||||||
|
if (need_unwind_info)
|
||||||
|
{
|
||||||
|
assert(c->pi.unwind_info);
|
||||||
|
struct dwarf_cie_info *dci = c->pi.unwind_info;
|
||||||
|
c->use_prev_instr = ! dci->signal_frame;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,7 +837,10 @@ dwarf_find_save_locs (struct dwarf_cursor *c)
|
||||||
rs = rs_lookup(cache, c);
|
rs = rs_lookup(cache, c);
|
||||||
|
|
||||||
if (rs)
|
if (rs)
|
||||||
c->ret_addr_column = rs->ret_addr_column;
|
{
|
||||||
|
c->ret_addr_column = rs->ret_addr_column;
|
||||||
|
c->use_prev_instr = ! rs->signal_frame;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 ||
|
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 ||
|
||||||
|
|
|
@ -48,7 +48,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
|
|
||||||
c->dwarf.as = unw_local_addr_space;
|
c->dwarf.as = unw_local_addr_space;
|
||||||
c->dwarf.as_arg = uc;
|
c->dwarf.as_arg = uc;
|
||||||
return common_init (c);
|
return common_init (c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNW_REMOTE_ONLY */
|
#endif /* !UNW_REMOTE_ONLY */
|
||||||
|
|
|
@ -41,6 +41,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
|
|
||||||
c->dwarf.as = as;
|
c->dwarf.as = as;
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
return common_init (c);
|
return common_init (c, 0);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init (struct cursor *c)
|
common_init (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -40,5 +40,7 @@ common_init (struct cursor *c)
|
||||||
ret = hppa_get (c, HPPA_REG_LOC (c, UNW_HPPA_SP), &c->sp);
|
ret = hppa_get (c, HPPA_REG_LOC (c, UNW_HPPA_SP), &c->sp);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
|
|
||||||
c->dwarf.as = unw_local_addr_space;
|
c->dwarf.as = unw_local_addr_space;
|
||||||
c->dwarf.as_arg = uc;
|
c->dwarf.as_arg = uc;
|
||||||
return common_init (c);
|
return common_init (c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNW_REMOTE_ONLY */
|
#endif /* !UNW_REMOTE_ONLY */
|
||||||
|
|
|
@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
|
|
||||||
c->dwarf.as = as;
|
c->dwarf.as = as;
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
return common_init (c);
|
return common_init (c, 0);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init (struct cursor *c)
|
common_init (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ common_init (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = 0;
|
c->dwarf.ret_addr_column = 0;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
|
@ -56,9 +56,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
c->dwarf.as = unw_local_addr_space;
|
c->dwarf.as = unw_local_addr_space;
|
||||||
c->dwarf.as_arg = uc;
|
c->dwarf.as_arg = uc;
|
||||||
#ifdef UNW_TARGET_PPC64
|
#ifdef UNW_TARGET_PPC64
|
||||||
return common_init_ppc64 (c);
|
return common_init_ppc64 (c, 1);
|
||||||
#else
|
#else
|
||||||
return common_init_ppc32 (c);
|
return common_init_ppc32 (c, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
|
|
||||||
#ifdef UNW_TARGET_PPC64
|
#ifdef UNW_TARGET_PPC64
|
||||||
return common_init_ppc64(c);
|
return common_init_ppc64 (c, 0);
|
||||||
#elif UNW_TARGET_PPC32
|
#elif UNW_TARGET_PPC32
|
||||||
return common_init_ppc32 (c);
|
return common_init_ppc32 (c, 0);
|
||||||
#else
|
#else
|
||||||
#error init_remote :: NO VALID PPC ARCH!
|
#error init_remote :: NO VALID PPC ARCH!
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,7 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/* Here is the "common" init, for remote and local debuging" */
|
/* Here is the "common" init, for remote and local debuging" */
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init_ppc32 (struct cursor *c)
|
common_init_ppc32 (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
@ -62,6 +62,7 @@ common_init_ppc32 (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = 0;
|
c->dwarf.ret_addr_column = 0;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
|
@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init_ppc64 (struct cursor *c)
|
common_init_ppc64 (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
@ -72,6 +72,7 @@ common_init_ppc64 (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = 0;
|
c->dwarf.ret_addr_column = 0;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
|
@ -50,7 +50,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
c->dwarf.as_arg = c;
|
c->dwarf.as_arg = c;
|
||||||
c->uc = uc;
|
c->uc = uc;
|
||||||
c->validate = 0;
|
c->validate = 0;
|
||||||
return common_init (c);
|
return common_init (c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNW_REMOTE_ONLY */
|
#endif /* !UNW_REMOTE_ONLY */
|
||||||
|
|
|
@ -51,6 +51,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
c->uc = 0;
|
c->uc = 0;
|
||||||
}
|
}
|
||||||
return common_init (c);
|
return common_init (c, 0);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init (struct cursor *c)
|
common_init (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ common_init (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = 0;
|
c->dwarf.ret_addr_column = 0;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
|
@ -52,7 +52,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
|
||||||
c->dwarf.as_arg = c;
|
c->dwarf.as_arg = c;
|
||||||
c->uc = uc;
|
c->uc = uc;
|
||||||
c->validate = 0;
|
c->validate = 0;
|
||||||
return common_init (c);
|
return common_init (c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNW_REMOTE_ONLY */
|
#endif /* !UNW_REMOTE_ONLY */
|
||||||
|
|
|
@ -52,6 +52,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
||||||
c->dwarf.as_arg = as_arg;
|
c->dwarf.as_arg = as_arg;
|
||||||
c->uc = 0;
|
c->uc = 0;
|
||||||
}
|
}
|
||||||
return common_init (c);
|
return common_init (c, 0);
|
||||||
#endif /* !UNW_LOCAL_ONLY */
|
#endif /* !UNW_LOCAL_ONLY */
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "unwind_i.h"
|
#include "unwind_i.h"
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
common_init (struct cursor *c)
|
common_init (struct cursor *c, unsigned use_prev_instr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ common_init (struct cursor *c)
|
||||||
|
|
||||||
c->dwarf.args_size = 0;
|
c->dwarf.args_size = 0;
|
||||||
c->dwarf.ret_addr_column = RIP;
|
c->dwarf.ret_addr_column = RIP;
|
||||||
|
c->dwarf.use_prev_instr = use_prev_instr;
|
||||||
c->dwarf.pi_valid = 0;
|
c->dwarf.pi_valid = 0;
|
||||||
c->dwarf.pi_is_dynamic = 0;
|
c->dwarf.pi_is_dynamic = 0;
|
||||||
c->dwarf.hint = 0;
|
c->dwarf.hint = 0;
|
||||||
|
|
Loading…
Reference in a new issue