From d1a8ca6d84389c083e3dc1a48446ff5225d0e654 Mon Sep 17 00:00:00 2001 From: Alexander Esilevich Date: Tue, 1 Sep 2015 04:25:18 +0600 Subject: [PATCH] powerpc64 implementation --- include/tdep-ppc64/libunwind_i.h | 63 +++++++++++++++++++++++++++++--- src/ppc/Gget_proc_info.c | 11 +++++- src/ppc64/Ginit.c | 2 +- src/ppc64/Gregs.c | 57 +++++++++++++++++++++++++---- src/ppc64/Gresume.c | 38 ++++++++++++++++++- src/ppc64/Gstep.c | 14 +++++++ src/ppc64/setcontext.S | 2 +- 7 files changed, 168 insertions(+), 19 deletions(-) diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h index 41fb4335..5a5bddbc 100644 --- a/include/tdep-ppc64/libunwind_i.h +++ b/include/tdep-ppc64/libunwind_i.h @@ -88,15 +88,68 @@ struct cursor # define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0) # define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) }) # define DWARF_IS_REG_LOC(l) 0 -# define DWARF_IS_FP_LOC(l) 0 -# define DWARF_IS_V_LOC(l) 0 -# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) # define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \ tdep_uc_addr((c)->as_arg, (r)), 0)) +# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0) # define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ tdep_uc_addr((c)->as_arg, (r)), 0)) # define DWARF_VREG_LOC(c,r) (DWARF_LOC((unw_word_t) \ tdep_uc_addr((c)->as_arg, (r)), 0)) + +static inline int +dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_fpreg_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_fpreg_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + +static inline int +dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *val = *(unw_word_t *) DWARF_GET_LOC (loc); + return 0; +} + +static inline int +dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) +{ + if (!DWARF_GET_LOC (loc)) + return -1; + *(unw_word_t *) DWARF_GET_LOC (loc) = val; + return 0; +} + #else /* !UNW_LOCAL_ONLY */ # define DWARF_LOC_TYPE_FP (1 << 0) @@ -116,8 +169,6 @@ struct cursor # define DWARF_VREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \ | DWARF_LOC_TYPE_V)) -#endif /* !UNW_LOCAL_ONLY */ - static inline int dwarf_getvr (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t * val) { @@ -253,6 +304,8 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) 1, c->as_arg); } +#endif /* !UNW_LOCAL_ONLY */ + #define tdep_getcontext_trace unw_getcontext #define tdep_init_done UNW_OBJ(init_done) #define tdep_init UNW_OBJ(init) diff --git a/src/ppc/Gget_proc_info.c b/src/ppc/Gget_proc_info.c index ff08d1b8..29f1db55 100644 --- a/src/ppc/Gget_proc_info.c +++ b/src/ppc/Gget_proc_info.c @@ -29,6 +29,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ PROTECTED int unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) { - /* XXX: empty stub. */ - return -UNW_EINVAL; + struct cursor *c = (struct cursor *) cursor; + int ret; + + ret = dwarf_make_proc_info (&c->dwarf); + if (ret < 0) + return ret; + + *pi = c->dwarf.pi; + return 0; } diff --git a/src/ppc64/Ginit.c b/src/ppc64/Ginit.c index 1606c10b..07409610 100644 --- a/src/ppc64/Ginit.c +++ b/src/ppc64/Ginit.c @@ -169,7 +169,7 @@ access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, ucontext_t *uc = arg; unw_fpreg_t *addr; - if ((unsigned) (reg - UNW_PPC64_F0) < 0) + if ((reg - UNW_PPC64_F0) < 0) goto badreg; if ((unsigned) (reg - UNW_PPC64_V0) >= 32) diff --git a/src/ppc64/Gregs.c b/src/ppc64/Gregs.c index a5785613..1cb5d9dc 100644 --- a/src/ppc64/Gregs.c +++ b/src/ppc64/Gregs.c @@ -35,6 +35,54 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, switch (reg) { + case UNW_PPC64_R0: + case UNW_PPC64_R2: + case UNW_PPC64_R3: + case UNW_PPC64_R4: + case UNW_PPC64_R5: + case UNW_PPC64_R6: + case UNW_PPC64_R7: + case UNW_PPC64_R8: + case UNW_PPC64_R9: + case UNW_PPC64_R10: + case UNW_PPC64_R11: + case UNW_PPC64_R12: + case UNW_PPC64_R13: + case UNW_PPC64_R14: + case UNW_PPC64_R15: + case UNW_PPC64_R16: + case UNW_PPC64_R17: + case UNW_PPC64_R18: + case UNW_PPC64_R19: + case UNW_PPC64_R20: + case UNW_PPC64_R21: + case UNW_PPC64_R22: + case UNW_PPC64_R23: + case UNW_PPC64_R24: + case UNW_PPC64_R25: + case UNW_PPC64_R26: + case UNW_PPC64_R27: + case UNW_PPC64_R28: + case UNW_PPC64_R29: + case UNW_PPC64_R30: + case UNW_PPC64_R31: + case UNW_PPC64_LR: + case UNW_PPC64_CTR: + case UNW_PPC64_CR0: + case UNW_PPC64_CR1: + case UNW_PPC64_CR2: + case UNW_PPC64_CR3: + case UNW_PPC64_CR4: + case UNW_PPC64_CR5: + case UNW_PPC64_CR6: + case UNW_PPC64_CR7: + case UNW_PPC64_VRSAVE: + case UNW_PPC64_VSCR: + case UNW_PPC64_SPE_ACC: + case UNW_PPC64_SPEFSCR: + loc = c->dwarf.loc[reg]; + break; + case UNW_TDEP_IP: if (write) { @@ -53,18 +101,11 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, *valp = c->dwarf.cfa; return 0; - default: + return -UNW_EBADREG; break; } - /* make sure it's not an FP or VR register */ - if ((((unsigned) (reg - UNW_PPC64_F0)) <= 31) || - (((unsigned) (reg - UNW_PPC64_V0)) <= 31)) - return -UNW_EBADREG; - - loc = c->dwarf.loc[reg]; - if (write) return dwarf_put (&c->dwarf, loc, *valp); else diff --git a/src/ppc64/Gresume.c b/src/ppc64/Gresume.c index 8ff93bd2..3f850e93 100644 --- a/src/ppc64/Gresume.c +++ b/src/ppc64/Gresume.c @@ -45,7 +45,20 @@ my_rt_sigreturn (void *new_sp) HIDDEN inline int ppc64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) { - /* XXX: empty stub. */ + struct cursor *c = (struct cursor *) cursor; + ucontext_t *uc = (ucontext_t *)c->dwarf.as_arg; + + if (unlikely (c->sigcontext_format != PPC_SCF_NONE)) + { + my_rt_sigreturn(cursor); + abort(); + } + else + { + Debug (8, "resuming at ip=%llx via setcontext()\n", + (unsigned long long) c->dwarf.ip); + setcontext (uc); + } return -UNW_EINVAL; } @@ -57,7 +70,28 @@ ppc64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) static inline int establish_machine_state (struct cursor *c) { - /* XXX: empty stub. */ + unw_addr_space_t as = c->dwarf.as; + void *arg = c->dwarf.as_arg; + unw_fpreg_t fpval; + unw_word_t val; + int reg; + + Debug (8, "copying out cursor state\n"); + + for (reg = 0; reg <= UNW_REG_LAST; ++reg) + { + Debug (16, "copying %s %d\n", unw_regname (reg), reg); + if (unw_is_fpreg (reg)) + { + if (tdep_access_fpreg (c, reg, &fpval, 0) >= 0) + as->acc.access_fpreg (as, reg, &fpval, 1, arg); + } + else + { + if (tdep_access_reg (c, reg, &val, 0) >= 0) + as->acc.access_reg (as, reg, &val, 1, arg); + } + } return 0; } diff --git a/src/ppc64/Gstep.c b/src/ppc64/Gstep.c index 038510fe..6170adc5 100644 --- a/src/ppc64/Gstep.c +++ b/src/ppc64/Gstep.c @@ -432,5 +432,19 @@ unw_step (unw_cursor_t * cursor) ret = 1; } } + + // on ppc64, R2 register is used as pointer to TOC + // section which is used for symbol lookup in PIC code + // ppc64 linker generates "ld r2, 24(r1)" instruction after each + // @plt call. We need restore R2, but only for @plt calls + { + unsigned int *inst = (unw_word_t*)c->dwarf.ip; + if (*inst == (0xE8410000 + 24)) { + // @plt call, restoring R2 from CFA+24 + c->dwarf.loc[UNW_PPC64_R2] = DWARF_LOC(c->dwarf.cfa + 24, 0); + } + } + + Debug (2, "returning %d with last return statement\n", ret); return ret; } diff --git a/src/ppc64/setcontext.S b/src/ppc64/setcontext.S index b54378a9..ffc2500a 100644 --- a/src/ppc64/setcontext.S +++ b/src/ppc64/setcontext.S @@ -1,7 +1,7 @@ .global _UI_setcontext _UI_setcontext: - retq + blr #ifdef __linux__ /* We do not need executable stack. */