Skip to content

Commit 9c67ae8

Browse files
authored
[libunwind] [SEH] Set NonVolatileRegisters before calling a personality function (llvm#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.
1 parent fc83aae commit 9c67ae8

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

libunwind/src/Unwind-seh.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,32 @@ static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
5151
static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
5252
DISPATCHER_CONTEXT *disp);
5353

54+
#pragma clang diagnostic push
55+
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
56+
// Local redefinition of this type; mingw-w64 headers lack the
57+
// DISPATCHER_CONTEXT_NONVOLREG_ARM64 type as of May 2025, so locally redefine
58+
// it and use that definition, to avoid needing to test/guess whether the real
59+
// type is available of not.
60+
union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 {
61+
BYTE Buffer[11 * sizeof(DWORD64) + 8 * sizeof(double)];
62+
63+
struct {
64+
DWORD64 GpNvRegs[11];
65+
double FpNvRegs[8];
66+
};
67+
};
68+
69+
// Custom data type definition; this type is not defined in WinSDK.
70+
union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM {
71+
BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)];
72+
73+
struct {
74+
DWORD GpNvRegs[8];
75+
double FpNvRegs[8];
76+
};
77+
};
78+
#pragma clang diagnostic pop
79+
5480
/// Common implementation of SEH-style handler functions used by Itanium-
5581
/// style frames. Depending on how and why it was called, it may do one of:
5682
/// a) Delegate to the given Itanium-style personality function; or
@@ -212,6 +238,21 @@ __libunwind_seh_personality(int version, _Unwind_Action state,
212238
ms_exc.ExceptionInformation[2] = state;
213239
DISPATCHER_CONTEXT *disp_ctx =
214240
__unw_seh_get_disp_ctx((unw_cursor_t *)context);
241+
#if defined(__aarch64__)
242+
LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 nonvol;
243+
memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->X19,
244+
sizeof(nonvol.GpNvRegs));
245+
for (int i = 0; i < 8; i++)
246+
nonvol.FpNvRegs[i] = disp_ctx->ContextRecord->V[i + 8].D[0];
247+
disp_ctx->NonVolatileRegisters = nonvol.Buffer;
248+
#elif defined(__arm__)
249+
LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol;
250+
memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->R4,
251+
sizeof(nonvol.GpNvRegs));
252+
memcpy(&nonvol.FpNvRegs, &disp_ctx->ContextRecord->D[8],
253+
sizeof(nonvol.FpNvRegs));
254+
disp_ctx->NonVolatileRegisters = nonvol.Buffer;
255+
#endif
215256
_LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling "
216257
"LanguageHandler %p(%p, %p, %p, %p)",
217258
(void *)disp_ctx->LanguageHandler, (void *)&ms_exc,

0 commit comments

Comments
 (0)