[PATCH 0/2] MR10843: ntdll: Test unaligned access on ARM64, and fix SIGTRAP handler in some cases on Linux ARM64.
The first commit fixes 569a7553b26dc0a89fb48af5da8442b4f71c42a4 ("ntdll: Use ESR in the ARM64 signal handler when possible."), on Linux it turns out that the ESR can be non-zero but also stale/incorrect. With the unaligned access test added, I was getting failures in later breakpoint tests because the SIGTRAP handler was still using the ESR from the earlier unaligned access fault. The unaligned access test shows a case where Windows differs from Linux/macOS, Wine may need to emulate/handle this in the future. (Unlike Linux/macOS, Windows sets `SCTLR_EL1.nAA` = 1 which results in no alignment fault in some cases) @jacek -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843
From: Brendan Shanks <bshanks@codeweavers.com> --- dlls/ntdll/unix/signal_arm64.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 536834955b3..f06fc24f1fe 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1146,21 +1146,20 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *_sigcontext ) save_context( &context, sigcontext ); - if (!esr) +#ifdef linux + /* debug exceptions have a stale/incorrect ESR on Linux, so we synthesize it. */ + switch (siginfo->si_code) { - /* debug exceptions do not update ESR on Linux, so we synthesize it. */ - switch (siginfo->si_code) - { - case TRAP_TRACE: - esr = make_esr( 0x33, 0 ); - break; - case TRAP_BRKPT: - if (!(PSTATE_sig( sigcontext ) & 0x10) && /* AArch64 (not WoW) */ - !(PC_sig( sigcontext ) & 3)) - esr = make_esr( 0x3c, *(ULONG *)PC_sig( sigcontext ) >> 5 ); - break; - } + case TRAP_TRACE: + esr = make_esr( 0x33, 0 ); + break; + case TRAP_BRKPT: + if (!(PSTATE_sig( sigcontext ) & 0x10) && /* AArch64 (not WoW) */ + !(PC_sig( sigcontext ) & 3)) + esr = make_esr( 0x3c, *(ULONG *)PC_sig( sigcontext ) >> 5 ); + break; } +#endif switch ((esr >> 26) & 0x3c) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10843
From: Brendan Shanks <bshanks@codeweavers.com> --- dlls/ntdll/tests/exception.c | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 5ba23d38d34..e6feec8fac7 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -9114,6 +9114,56 @@ static void test_mrs_currentel(void) ok( result == 0, "expected 0, got %llx\n", result ); } +static BOOL got_misaligned_exception; + +static const DWORD misaligned_code[] = +{ + 0xa9bf7bfd, /* stp x29, x30, [sp, #-16]! */ + 0x910003fd, /* mov x29, sp */ + 0x91003c00, /* add x0, x0, #15 */ + 0xc89ffc12, /* stlr x18, [x0] */ + 0xa8c17bfd, /* ldp x29, x30, [sp], #16 */ + 0xd65f03c0, /* ret */ +}; + +static DWORD WINAPI misaligned_exception_handler( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatcher ) +{ + ok( rec->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT, "got: %08lx\n", rec->ExceptionCode ); + ok( rec->NumberParameters == 0, "got: %ld\n", rec->NumberParameters ); + ok( rec->ExceptionAddress == (void *)context->Pc, "got addr: %p, pc: %p\n", rec->ExceptionAddress, (void *)context->Pc ); + got_misaligned_exception = TRUE; + context->Pc += 4; + return ExceptionContinueExecution; +} + +static void test_misaligned(void) +{ + /* Windows, Linux, and macOS all set SCTLR_EL1.A = 0, so most instructions + * will not generate an alignment fault. + * When FEAT_LSE2 is not implemented, load/store-exclusive and atomic instructions + * will generate a fault on unaligned accesses. + * When FEAT_LSE2 is implemented there are fewer situations where a fault is generated, + * but one is non-atomic load-acquire/store-release instructions accessing across + * a 16-byte quantity when SCTLR_EL1.nAA is 0. + * (All Apple chips support FEAT_LSE2, as does the Snapdragon X Elite). + * + * Test that situation here: a store to memory with release semantics, where not + * all bytes of the store lie within a single 16-byte aligned block. + * + * Windows sets SCTLR_EL1.nAA to 1 so there's no fault. + * Linux and macOS set it to 0 and do fault. + */ + DWORD64 buf[4]; + got_misaligned_exception = FALSE; + run_exception_test( misaligned_exception_handler, NULL, misaligned_code, + sizeof(misaligned_code), sizeof(misaligned_code), + PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER, + buf, 0 ); + todo_wine + ok( !got_misaligned_exception, "Got misaligned data exception.\n" ); +} + #endif /* __aarch64__ */ @@ -12920,6 +12970,7 @@ START_TEST(exception) test_collided_unwind(); test_restore_context(); test_mrs_currentel(); + test_misaligned(); #elif defined(__arm__) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10843
On the contrary, I don't like the idea (from 569a7553b26dc0a89fb48af5da8442b4f71c42a4) of pretending we have an ESR on Linux when we actually do not. How about reverting 569a7553b26dc0a89fb48af5da8442b4f71c42a4 (i.e., use `si_code` field just as before), *and* synthesizing `si_code` on macOS instead? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843#note_139176
On Fri May 8 02:49:07 2026 +0000, Jinoh Kang wrote:
On the contrary, I don't like the idea (from 569a7553b26dc0a89fb48af5da8442b4f71c42a4) of pretending we have an ESR on Linux when we actually do not. How about reverting 569a7553b26dc0a89fb48af5da8442b4f71c42a4 (i.e., use `si_code` field just as before), *and* synthesizing `si_code` on macOS instead? Forget about what I just said, I see the ESR is simple enough to be synthesized accurately.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843#note_139177
Jacek Caban (@jacek) commented about dlls/ntdll/unix/signal_arm64.c:
- break; - case TRAP_BRKPT: - if (!(PSTATE_sig( sigcontext ) & 0x10) && /* AArch64 (not WoW) */ - !(PC_sig( sigcontext ) & 3)) - esr = make_esr( 0x3c, *(ULONG *)PC_sig( sigcontext ) >> 5 ); - break; - } + case TRAP_TRACE: + esr = make_esr( 0x33, 0 ); + break; + case TRAP_BRKPT: + if (!(PSTATE_sig( sigcontext ) & 0x10) && /* AArch64 (not WoW) */ + !(PC_sig( sigcontext ) & 3)) + esr = make_esr( 0x3c, *(ULONG *)PC_sig( sigcontext ) >> 5 ); + break; } This still uses leaked ESR for unhandled cases. We could ifdef `get_fault_esr` call and initialize esr to 0 on linux.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843#note_139211
On Fri May 8 12:40:27 2026 +0000, Jinoh Kang wrote:
Forget about what I just said, I see the ESR is simple enough to be synthesized accurately. Also note that, when available, ESR is better because it does not require reading the faulting instruction.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843#note_139212
participants (4)
-
Brendan Shanks -
Brendan Shanks (@bshanks) -
Jacek Caban (@jacek) -
Jinoh Kang (@iamahuman)