Skip to content

Commit

Permalink
Fix Unix ARM floating point registers unwinding (dotnet#58915)
Browse files Browse the repository at this point in the history
* Fix Unix ARM floating point registers unwinding

There are two problems unwinding ARM floating point registers. One is that the PAL_VirtualUnwind
is not supporting that and the second is that the libunwind we carry and use actually doesn't
have support for unwinding those.

This change updates the libunwind so that both exidx and dwarf ways of unwinding can unwind
these registers and also adds support to our PAL_VirtualUnwind to copy the callee saved
floating point registers D8..D15 between the native and windows style contexts.

I am planning to make a PR for the libunwind upstream, but given the very low amount of time
we have remaining for .NET 6 completion, I am making the change here first. Once I get them
upstream later, I'll update the whole libunwind from there.

* Enable the related test
  • Loading branch information
janvorli authored Sep 10, 2021
1 parent 8b38c19 commit 1b5719c
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 8 deletions.
24 changes: 22 additions & 2 deletions src/coreclr/pal/src/exception/seh-unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwCon
#undef ASSIGN_REG
#undef ASSIGN_FP_REG
}
#else
#else // UNWIND_CONTEXT_IS_UCONTEXT_T
static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
{
#if (defined(HOST_UNIX) && defined(HOST_ARM)) || (defined(HOST_WINDOWS) && defined(TARGET_ARM))
Expand All @@ -216,6 +216,10 @@ static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwCon
unwContext->regs[13] = winContext->Sp;
unwContext->regs[14] = winContext->Lr;
unwContext->regs[15] = winContext->Pc;
for (int i = 0; i < 16; i++)
{
unwContext->fpregs[i] = winContext->D[i];
}
#elif defined(HOST_ARM64) && !defined(TARGET_OSX)
unwContext->uc_mcontext.pc = winContext->Pc;
unwContext->uc_mcontext.sp = winContext->Sp;
Expand Down Expand Up @@ -302,7 +306,7 @@ static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
unw_set_fpreg(cursor, UNW_AARCH64_V31, *(unw_fpreg_t *)&winContext->V[31].Low);
#endif
}
#endif
#endif // UNWIND_CONTEXT_IS_UCONTEXT_T

void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
{
Expand Down Expand Up @@ -334,6 +338,14 @@ void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
unw_get_reg(cursor, UNW_ARM_R9, (unw_word_t *) &winContext->R9);
unw_get_reg(cursor, UNW_ARM_R10, (unw_word_t *) &winContext->R10);
unw_get_reg(cursor, UNW_ARM_R11, (unw_word_t *) &winContext->R11);
unw_get_fpreg(cursor, UNW_ARM_D8, (unw_fpreg_t *)&winContext->D[8]);
unw_get_fpreg(cursor, UNW_ARM_D9, (unw_fpreg_t *)&winContext->D[9]);
unw_get_fpreg(cursor, UNW_ARM_D10, (unw_fpreg_t *)&winContext->D[10]);
unw_get_fpreg(cursor, UNW_ARM_D11, (unw_fpreg_t *)&winContext->D[11]);
unw_get_fpreg(cursor, UNW_ARM_D12, (unw_fpreg_t *)&winContext->D[12]);
unw_get_fpreg(cursor, UNW_ARM_D13, (unw_fpreg_t *)&winContext->D[13]);
unw_get_fpreg(cursor, UNW_ARM_D14, (unw_fpreg_t *)&winContext->D[14]);
unw_get_fpreg(cursor, UNW_ARM_D15, (unw_fpreg_t *)&winContext->D[15]);
#elif (defined(HOST_UNIX) && defined(HOST_ARM64)) || (defined(HOST_WINDOWS) && defined(TARGET_ARM64))
unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
Expand Down Expand Up @@ -438,6 +450,14 @@ void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOL
GetContextPointer(cursor, unwContext, UNW_ARM_R9, &contextPointers->R9);
GetContextPointer(cursor, unwContext, UNW_ARM_R10, &contextPointers->R10);
GetContextPointer(cursor, unwContext, UNW_ARM_R11, &contextPointers->R11);
GetContextPointer(cursor, unwContext, UNW_ARM_D8, (SIZE_T **)&contextPointers->D8);
GetContextPointer(cursor, unwContext, UNW_ARM_D9, (SIZE_T **)&contextPointers->D9);
GetContextPointer(cursor, unwContext, UNW_ARM_D10, (SIZE_T **)&contextPointers->D10);
GetContextPointer(cursor, unwContext, UNW_ARM_D11, (SIZE_T **)&contextPointers->D11);
GetContextPointer(cursor, unwContext, UNW_ARM_D12, (SIZE_T **)&contextPointers->D12);
GetContextPointer(cursor, unwContext, UNW_ARM_D13, (SIZE_T **)&contextPointers->D13);
GetContextPointer(cursor, unwContext, UNW_ARM_D14, (SIZE_T **)&contextPointers->D14);
GetContextPointer(cursor, unwContext, UNW_ARM_D15, (SIZE_T **)&contextPointers->D15);
#elif (defined(HOST_UNIX) && defined(HOST_ARM64)) || (defined(HOST_WINDOWS) && defined(TARGET_ARM64))
GetContextPointer(cursor, unwContext, UNW_AARCH64_X19, &contextPointers->X19);
GetContextPointer(cursor, unwContext, UNW_AARCH64_X20, &contextPointers->X20);
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/pal/src/libunwind/include/libunwind-arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ unw_tdep_save_loc_t;
typedef struct unw_tdep_context
{
unsigned long regs[16];
unsigned long long fpregs[16];
}
unw_tdep_context_t;

Expand All @@ -277,6 +278,8 @@ unw_tdep_context_t;
register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \
__asm__ __volatile__ ( \
"stmia %[base], {r0-r15}" \
"adds %[base], #64" \
"vstmia %[base], {d0-d15}" \
: : [base] "r" (unw_base) : "memory"); \
}), 0)
#else /* __thumb__ */
Expand All @@ -286,6 +289,8 @@ unw_tdep_context_t;
__asm__ __volatile__ ( \
".align 2\nbx pc\nnop\n.code 32\n" \
"stmia %[base], {r0-r15}\n" \
"adds %[base], #64\n" \
"vstmia %[base], {d0-d15}\n" \
"orr %[base], pc, #1\nbx %[base]\n" \
".code 16\n" \
: [base] "+r" (unw_base) : : "memory", "cc"); \
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions src/coreclr/pal/src/libunwind/src/arm/Gget_save_loc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/pal/src/libunwind/src/arm/Ginit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
33 changes: 31 additions & 2 deletions src/coreclr/pal/src/libunwind/src/arm/Gregs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
19 changes: 18 additions & 1 deletion src/coreclr/pal/src/libunwind/src/arm/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<!-- https://github.com/dotnet/runtime/issues/57040 -->
<JitOptimizationSensitive Condition="'$(TargetArchitecture)' == 'arm' And '$(TargetOS)' != 'Windows'">true</JitOptimizationSensitive>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
Expand Down

0 comments on commit 1b5719c

Please sign in to comment.