[libunwind] [SEH] Set NonVolatileRegisters before calling a personality function (#137951)

The CRT __C_specific_handler function uses this for restoring registers
before calling the filter function.

This fixes the libunwind/libcxxabi forced unwind testcases on ARM and
AArch64.
This commit is contained in:
Martin Storsjö
2025-05-09 16:04:57 +03:00
committed by GitHub
parent fc83aaea06
commit 9c67ae861c

View File

@@ -51,6 +51,32 @@ static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
DISPATCHER_CONTEXT *disp);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
// Local redefinition of this type; mingw-w64 headers lack the
// DISPATCHER_CONTEXT_NONVOLREG_ARM64 type as of May 2025, so locally redefine
// it and use that definition, to avoid needing to test/guess whether the real
// type is available of not.
union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 {
BYTE Buffer[11 * sizeof(DWORD64) + 8 * sizeof(double)];
struct {
DWORD64 GpNvRegs[11];
double FpNvRegs[8];
};
};
// Custom data type definition; this type is not defined in WinSDK.
union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM {
BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)];
struct {
DWORD GpNvRegs[8];
double FpNvRegs[8];
};
};
#pragma clang diagnostic pop
/// Common implementation of SEH-style handler functions used by Itanium-
/// style frames. Depending on how and why it was called, it may do one of:
/// a) Delegate to the given Itanium-style personality function; or
@@ -212,6 +238,21 @@ __libunwind_seh_personality(int version, _Unwind_Action state,
ms_exc.ExceptionInformation[2] = state;
DISPATCHER_CONTEXT *disp_ctx =
__unw_seh_get_disp_ctx((unw_cursor_t *)context);
#if defined(__aarch64__)
LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 nonvol;
memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->X19,
sizeof(nonvol.GpNvRegs));
for (int i = 0; i < 8; i++)
nonvol.FpNvRegs[i] = disp_ctx->ContextRecord->V[i + 8].D[0];
disp_ctx->NonVolatileRegisters = nonvol.Buffer;
#elif defined(__arm__)
LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol;
memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->R4,
sizeof(nonvol.GpNvRegs));
memcpy(&nonvol.FpNvRegs, &disp_ctx->ContextRecord->D[8],
sizeof(nonvol.FpNvRegs));
disp_ctx->NonVolatileRegisters = nonvol.Buffer;
#endif
_LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling "
"LanguageHandler %p(%p, %p, %p, %p)",
(void *)disp_ctx->LanguageHandler, (void *)&ms_exc,