Fix Unix ARM floating point registers unwinding (#58915) (#358) accepted/tizen/unified/20240112.154601
author이형주/MDE Lab(SR)/삼성전자 <leee.lee@samsung.com>
Thu, 11 Jan 2024 03:37:30 +0000 (12:37 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 11 Jan 2024 03:37:30 +0000 (12:37 +0900)
* 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

Co-authored-by: Jan Vorlicek <jan.vorlicek@volny.cz>
src/coreclr/pal/src/exception/seh-unwind.cpp
src/coreclr/pal/src/libunwind/include/libunwind-arm.h
src/coreclr/pal/src/libunwind/src/arm/Gex_tables.c
src/coreclr/pal/src/libunwind/src/arm/Gget_save_loc.c
src/coreclr/pal/src/libunwind/src/arm/Ginit.c
src/coreclr/pal/src/libunwind/src/arm/Gregs.c
src/coreclr/pal/src/libunwind/src/arm/init.h
src/tests/JIT/IL_Conformance/Convert/TestConvertFromIntegral.csproj

index a9ddb17..b79552c 100644 (file)
@@ -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))
@@ -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;
@@ -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)
 {
@@ -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);
@@ -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);
index 1a6c6b6..8e72f42 100644 (file)
@@ -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;
 
@@ -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__ */
@@ -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");                       \
index 73eac24..219ddcb 100644 (file)
@@ -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;
index 9fb0704..906c5b1 100644 (file)
@@ -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;
     }
index 0bac0d7..1932160 100644 (file)
@@ -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;
 }
index 0d52f0b..3072063 100644 (file)
@@ -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);
 }
index 7d765ec..44cf7c2 100644 (file)
@@ -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);
index 380c9ef..5d8fe22 100644 (file)
@@ -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" />