1
0
Fork 0
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:
Lassi Tuura 2010-04-24 19:16:09 -07:00 committed by Arun Sharma
parent 4c553ceb2c
commit a9dce3c06e
21 changed files with 63 additions and 24 deletions

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */
} }

View file

@ -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;

View file

@ -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 ||

View file

@ -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 */

View file

@ -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 */
} }

View file

@ -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;
} }

View file

@ -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 */

View file

@ -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 */
} }

View file

@ -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;

View file

@ -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
} }

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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 */
} }

View file

@ -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;

View file

@ -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 */

View file

@ -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 */
} }

View file

@ -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;