From a04f52279d507d2980a65003647ca545f0e83efb Mon Sep 17 00:00:00 2001 From: "hp.com!davidm" Date: Tue, 3 May 2005 09:13:17 +0000 Subject: [PATCH] Add include of "offsets.h". (unw_step): Improve debug output. Implement signal-frame fall-back code. 2004/12/02 00:40:45-08:00 mostang.com!davidm (update_frame_state): Remove. (unw_step): Implement it based on DWARF unwinder. (Logical change 1.290) --- src/hppa/Gstep.c | 160 +++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 102 deletions(-) diff --git a/src/hppa/Gstep.c b/src/hppa/Gstep.c index d49fdfcb..abff4569 100644 --- a/src/hppa/Gstep.c +++ b/src/hppa/Gstep.c @@ -24,117 +24,73 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" - -static inline int -update_frame_state (struct cursor *c) -{ -#if 0 - unw_word_t prev_ip, prev_sp, prev_bsp, ip, pr, num_regs, cfm; - int ret; - - prev_ip = c->ip; - prev_sp = c->sp; - prev_bsp = c->bsp; - - c->cfm_loc = c->pfs_loc; - - num_regs = 0; - if (c->is_signal_frame) - { - ret = ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &c->sigcontext_loc); - Debug (12, "sigcontext_loc=%lx (ret=%d)\n", c->sigcontext_loc, ret); - if (ret < 0) - return ret; - - if (c->ip_loc == c->sigcontext_loc + SIGCONTEXT_BR_OFF + 0*8) - { - /* Earlier kernels (before 2.4.19 and 2.5.10) had buggy - unwind info for sigtramp. Fix it up here. */ - c->ip_loc = (c->sigcontext_loc + SIGCONTEXT_IP_OFF); - c->cfm_loc = (c->sigcontext_loc + SIGCONTEXT_CFM_OFF); - } - - /* do what can't be described by unwind directives: */ - c->pfs_loc = (c->sigcontext_loc + SIGCONTEXT_AR_PFS_OFF); - - ret = ia64_get (c, c->cfm_loc, &cfm); - if (ret < 0) - return ret; - - num_regs = cfm & 0x7f; /* size of frame */ - } - else - { - ret = ia64_get (c, c->cfm_loc, &cfm); - if (ret < 0) - return ret; - num_regs = (cfm >> 7) & 0x7f; /* size of locals */ - } - c->bsp = ia64_rse_skip_regs (c->bsp, -num_regs); - - /* update the IP cache: */ - ret = ia64_get (c, c->ip_loc, &ip); - if (ret < 0) - return ret; - c->ip = ip; - - if ((ip & 0xc) != 0) - { - /* don't let obviously bad addresses pollute the cache */ - Debug (1, "rejecting bad ip=0x%lx\n", (long) c->ip); - return -UNW_EINVALIDIP; - } - if (ip == 0) - /* end of frame-chain reached */ - return 0; - - pr = c->pr; - c->sp = c->psp; - c->is_signal_frame = 0; - - if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp) - { - dprintf ("%s: ip, sp, and bsp unchanged; stopping here (ip=0x%lx)\n", - __FUNCTION__, (long) ip); - return -UNW_EBADFRAME; - } - - /* as we unwind, the saved ar.unat becomes the primary unat: */ - c->pri_unat_loc = c->unat_loc; - - /* restore the predicates: */ - ret = ia64_get (c, c->pr_loc, &c->pr); - if (ret < 0) - return ret; - - c->pi_valid = 0; -#endif - return 0; -} - +#include "offsets.h" PROTECTED int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; - int ret; + int ret, i; - ret = hppa_get (c, c->sp_loc, &c->sp); - if (ret < 0) - return ret; + Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip); - c->sp_loc = HPPA_LOC (c->sp, 0); - c->ip_loc = HPPA_LOC (c->sp + 4, 0); - c->sp += 8; + /* Try DWARF-based unwinding... */ + ret = dwarf_step (&c->dwarf); - if (HPPA_GET_LOC (c->sp_loc)) + if (ret < 0 && ret != -UNW_ENOINFO) { - ret = hppa_get (c, c->ip_loc, &c->ip); - if (ret < 0) - return ret; + Debug (2, "returning %d\n", ret); + return ret; } - else - c->ip = 0; - return (c->ip == 0) ? 0 : 1; + if (unlikely (ret < 0)) + { + /* DWARF failed, let's see if we can follow the frame-chain + or skip over the signal trampoline. */ + + Debug (13, "dwarf_step() failed (ret=%d), trying fallback\n", ret); + + if (unw_is_signal_frame (cursor)) + { +#ifdef __linux__ + /* Assume that the trampoline is at the beginning of the + sigframe. */ + unw_word_t ip, sc_addr = c->dwarf.ip + LINUX_RT_SIGFRAME_UC_OFF; + dwarf_loc_t iaoq_loc = DWARF_LOC (sc_addr + LINUX_SC_IAOQ_OFF, 0); + + c->sigcontext_format = HPPA_SCF_LINUX_RT_SIGFRAME; + c->sigcontext_addr = sc_addr; + c->dwarf.ret_addr_column = UNW_HPPA_RP; + + if ((ret = dwarf_get (&c->dwarf, iaoq_loc, &ip)) , 0) + { + Debug (2, "failed to read IAOQ[1] (ret=%d)\n", ret); + return ret; + } + c->dwarf.ip = ip & ~0x3; /* mask out the privilege level */ + + for (i = 0; i < 32; ++i) + { + c->dwarf.loc[UNW_HPPA_GR + i] + = DWARF_LOC (sc_addr + LINUX_SC_GR_OFF + 4*i, 0); + c->dwarf.loc[UNW_HPPA_FR + i] + = DWARF_LOC (sc_addr + LINUX_SC_FR_OFF + 4*i, 0); + } + + if ((ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_HPPA_SP], + &c->dwarf.cfa)) < 0) + { + Debug (2, "failed to read SP (ret=%d)\n", ret); + return ret; + } +#else +# error Implement me! +#endif + } + else + c->dwarf.ip = 0; + } + ret = (c->dwarf.ip == 0) ? 0 : 1; + Debug (2, "returning %d\n", ret); + return ret; }