summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Vorlicek <jan.vorlicek@volny.cz>2022-07-08 23:51:21 +0300
committerStephen M. Webb <stephen.webb@bregmasoft.ca>2022-07-26 22:26:14 -0400
commite09164e88c9bd934d17f476ba56be0334ff28699 (patch)
tree69887e205d49d3ebf94a0bb570f776845180312a
parentd3e137a8008f3261f0a21406212264330c519703 (diff)
downloadlibunwind-e09164e88c9bd934d17f476ba56be0334ff28699.tar.gz
Add support for arm fp registers unwind
-rw-r--r--include/libunwind-arm.h58
-rw-r--r--src/arm/Gex_tables.c4
-rw-r--r--src/arm/Gget_save_loc.c19
-rw-r--r--src/arm/Ginit.c2
-rw-r--r--src/arm/Gregs.c33
-rw-r--r--src/arm/init.h19
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);