[PATCH v2 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 -- v2: ntdll/tests: Test unaligned access on ARM64. ntdll: Always synthesize ESR in SIGTRAP handler on ARM64 Linux. https://gitlab.winehq.org/wine/wine/-/merge_requests/10843
From: Brendan Shanks <bshanks@codeweavers.com> --- dlls/ntdll/unix/signal_arm64.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 536834955b3..80b078610c7 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1142,25 +1142,26 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *_sigcontext ) CONTEXT context; EXCEPTION_RECORD rec = { .ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION, .ExceptionAddress = (void *)PC_sig(sigcontext) }; - DWORD64 esr = get_fault_esr( sigcontext ); + DWORD64 esr = 0; save_context( &context, sigcontext ); - if (!esr) +#ifdef linux + /* Only SIGSEGV/SIGBUS expose ESR, synthesize it instead. */ + 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; } +#else + esr = get_fault_esr( sigcontext ); +#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 Fri May 8 20:46:30 2026 +0000, Jacek Caban wrote:
This still uses leaked ESR for unhandled cases. We could ifdef `get_fault_esr` call and initialize esr to 0 on linux. Ah true. I found the [commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...) which exported ESR, it says it's only valid for SIGSEGV and SIGBUS (and it doesn't look like this has changed since then).
(But also it seems like a bug that an invalid/stale ESR is being passed to SIGTRAP, I'll report that upstream when I get a chance) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843#note_139275
This merge request was approved by Jacek Caban. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10843
participants (3)
-
Brendan Shanks -
Brendan Shanks (@bshanks) -
Jacek Caban (@jacek)