From e09164e88c9bd934d17f476ba56be0334ff28699 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 8 Jul 2022 23:51:21 +0300 Subject: Add support for arm fp registers unwind --- include/libunwind-arm.h | 58 +++++++++++++++++++++++++------------------------ src/arm/Gex_tables.c | 4 +++- src/arm/Gget_save_loc.c | 19 ++++++++++++++++ src/arm/Ginit.c | 2 ++ src/arm/Gregs.c | 33 ++++++++++++++++++++++++++-- src/arm/init.h | 19 +++++++++++++++- 6 files changed, 103 insertions(+), 32 deletions(-) diff --git a/include/libunwind-arm.h b/include/libunwind-arm.h index 85134b40..c4b90fdd 100644 --- a/include/libunwind-arm.h +++ b/include/libunwind-arm.h @@ -261,6 +261,7 @@ unw_tdep_save_loc_t; typedef struct unw_tdep_context { unsigned long regs[16]; + unsigned long long fpregs[16]; } unw_tdep_context_t; @@ -269,36 +270,37 @@ unw_tdep_context_t; In thumb mode, we return directly back to thumb mode on return (with bx), to avoid altering any registers after unw_resume. */ #ifndef __thumb__ -#define unw_tdep_getcontext(uc) ({ \ - unw_tdep_context_t *unw_ctx = (uc); \ - register unsigned long *r0 __asm__ ("r0"); \ - unsigned long *unw_base = unw_ctx->regs; \ - __asm__ __volatile__ ( \ - "mov r0, #0\n" \ - "stmia %[base], {r0-r15}\n" \ - "nop\n" /* align return address to value stored by stmia */ \ - : [r0] "=r" (r0) : [base] "r" (unw_base) : "memory"); \ +#define unw_tdep_getcontext(uc) ({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register unsigned long *r0 __asm__ ("r0"); \ + register unsigned long *unw_base __asm__ ("r1") = unw_ctx->regs; \ + __asm__ __volatile__ ( \ + "mov r0, #0\n" \ + "stmia %[base]!, {r0-r15}\n" \ + "vstmia %[base], {d0-d15}\n" /* this also aligns return address to value stored by stmia */ \ + : [r0] "=r" (r0) : [base] "r" (unw_base) : "memory"); \ (int)r0; }) #else /* __thumb__ */ -#define unw_tdep_getcontext(uc) ({ \ - unw_tdep_context_t *unw_ctx = (uc); \ - register unsigned long *r0 __asm__ ("r0"); \ - unsigned long *unw_base = unw_ctx->regs; \ - __asm__ __volatile__ ( \ - ".align 2\n" \ - "bx pc\n" \ - "nop\n" \ - ".code 32\n" \ - "mov r0, #0\n" \ - "stmia %[base], {r0-r14}\n" \ - "adr r0, ret%=+1\n" \ - "str r0, [%[base], #60]\n" \ - "orr r0, pc, #1\n" \ - "bx r0\n" \ - ".code 16\n" \ - "mov r0, #0\n" \ - "ret%=:\n" \ - : [r0] "=r" (r0) : [base] "r" (unw_base) : "memory", "cc"); \ +#define unw_tdep_getcontext(uc) ({ \ + unw_tdep_context_t *unw_ctx = (uc); \ + register unsigned long *r0 __asm__ ("r0"); \ + register unsigned long *unw_base __asm__ ("r1") = unw_ctx->regs; \ + __asm__ __volatile__ ( \ + ".align 2\n" \ + "bx pc\n" \ + "nop\n" \ + ".code 32\n" \ + "mov r0, #0\n" \ + "stmia %[base], {r0-r14}\n" \ + "adr r0, ret%=+1\n" \ + "stmia %[base]!, {r0}\n" \ + "vstmia %[base], {d0-d15}\n" \ + "orr r0, pc, #1\n" \ + "bx r0\n" \ + ".code 16\n" \ + "mov r0, #0\n" \ + "ret%=:\n" \ + : [r0] "=r" (r0), [base] "+r" (unw_base) : : "memory", "cc"); \ (int)r0; }) #endif diff --git a/src/arm/Gex_tables.c b/src/arm/Gex_tables.c index 083d2b2f..40cd1534 100644 --- a/src/arm/Gex_tables.c +++ b/src/arm/Gex_tables.c @@ -119,10 +119,12 @@ arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c) dwarf_get (c, c->loc[UNW_ARM_R13], &c->cfa); break; case ARM_EXIDX_CMD_VFP_POP: - /* Skip VFP registers, but be sure to adjust stack */ for (i = ARM_EXBUF_START (edata->data); i <= ARM_EXBUF_END (edata->data); i++) + { + c->loc[UNW_ARM_S0 + i] = DWARF_LOC (c->cfa, 0); c->cfa += 8; + } if (!(edata->data & ARM_EXIDX_VFP_DOUBLE)) c->cfa += 4; break; diff --git a/src/arm/Gget_save_loc.c b/src/arm/Gget_save_loc.c index 9fb07048..906c5b18 100644 --- a/src/arm/Gget_save_loc.c +++ b/src/arm/Gget_save_loc.c @@ -53,6 +53,25 @@ unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc) loc = c->dwarf.loc[reg - UNW_ARM_R0]; break; + case UNW_ARM_D0: + case UNW_ARM_D1: + case UNW_ARM_D2: + case UNW_ARM_D3: + case UNW_ARM_D4: + case UNW_ARM_D5: + case UNW_ARM_D6: + case UNW_ARM_D7: + case UNW_ARM_D8: + case UNW_ARM_D9: + case UNW_ARM_D10: + case UNW_ARM_D11: + case UNW_ARM_D12: + case UNW_ARM_D13: + case UNW_ARM_D14: + case UNW_ARM_D15: + loc = c->dwarf.loc[UNW_ARM_S0 + (reg - UNW_ARM_D0)]; + break; + default: break; } diff --git a/src/arm/Ginit.c b/src/arm/Ginit.c index bce52dc3..680b2d47 100644 --- a/src/arm/Ginit.c +++ b/src/arm/Ginit.c @@ -43,6 +43,8 @@ uc_addr (unw_tdep_context_t *uc, int reg) { if (reg >= UNW_ARM_R0 && reg < UNW_ARM_R0 + 16) return &uc->regs[reg - UNW_ARM_R0]; + else if (reg >= UNW_ARM_D0 && reg <= UNW_ARM_D15) + return &uc->fpregs[reg - UNW_ARM_D0]; else return NULL; } diff --git a/src/arm/Gregs.c b/src/arm/Gregs.c index 0d52f0b2..30720631 100644 --- a/src/arm/Gregs.c +++ b/src/arm/Gregs.c @@ -78,6 +78,35 @@ HIDDEN int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp, int write) { - Debug (1, "bad register number %u\n", reg); - return -UNW_EBADREG; + dwarf_loc_t loc = DWARF_NULL_LOC; + switch (reg) + { + case UNW_ARM_D0: + case UNW_ARM_D1: + case UNW_ARM_D2: + case UNW_ARM_D3: + case UNW_ARM_D4: + case UNW_ARM_D5: + case UNW_ARM_D6: + case UNW_ARM_D7: + case UNW_ARM_D8: + case UNW_ARM_D9: + case UNW_ARM_D10: + case UNW_ARM_D11: + case UNW_ARM_D12: + case UNW_ARM_D13: + case UNW_ARM_D14: + case UNW_ARM_D15: + loc = c->dwarf.loc[UNW_ARM_S0 + (reg - UNW_ARM_D0)]; + break; + + default: + Debug (1, "bad register number %u\n", reg); + return -UNW_EBADREG; + } + + if (write) + return dwarf_putfp (&c->dwarf, loc, *valp); + else + return dwarf_getfp (&c->dwarf, loc, valp); } diff --git a/src/arm/init.h b/src/arm/init.h index 7d765ecf..44cf7c22 100644 --- a/src/arm/init.h +++ b/src/arm/init.h @@ -45,7 +45,24 @@ common_init (struct cursor *c, unsigned use_prev_instr) c->dwarf.loc[UNW_ARM_R13] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R13); c->dwarf.loc[UNW_ARM_R14] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R14); c->dwarf.loc[UNW_ARM_R15] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R15); - for (i = UNW_ARM_R15 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i) + c->dwarf.loc[UNW_ARM_S0] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S0); + c->dwarf.loc[UNW_ARM_S1] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S1); + c->dwarf.loc[UNW_ARM_S2] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S2); + c->dwarf.loc[UNW_ARM_S3] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S3); + c->dwarf.loc[UNW_ARM_S4] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S4); + c->dwarf.loc[UNW_ARM_S5] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S5); + c->dwarf.loc[UNW_ARM_S6] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S6); + c->dwarf.loc[UNW_ARM_S7] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S7); + c->dwarf.loc[UNW_ARM_S8] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S8); + c->dwarf.loc[UNW_ARM_S9] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S9); + c->dwarf.loc[UNW_ARM_S10] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S10); + c->dwarf.loc[UNW_ARM_S11] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S11); + c->dwarf.loc[UNW_ARM_S12] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S12); + c->dwarf.loc[UNW_ARM_S13] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S13); + c->dwarf.loc[UNW_ARM_S14] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S14); + c->dwarf.loc[UNW_ARM_S15] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_S15); + + for (i = UNW_ARM_S15 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i) c->dwarf.loc[i] = DWARF_NULL_LOC; ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip); -- cgit v1.2.1