Module: wine Branch: master Commit: 5286ed3b0a40385a591ecf0daa5252d890171060 URL: https://gitlab.winehq.org/wine/wine/-/commit/5286ed3b0a40385a591ecf0daa5252d...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Mar 12 17:46:10 2024 +0100
ntdll: Add test for non-volatile regs in consolidated unwinds.
---
dlls/ntdll/signal_x86_64.c | 2 +- dlls/ntdll/tests/exception.c | 69 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index d37cd741c09..8611364b3e9 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -847,7 +847,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec }
context->Rax = (ULONG64)retval; - context->Rip = (ULONG64)target_ip; + if (rec->ExceptionCode != STATUS_UNWIND_CONSOLIDATE) context->Rip = (ULONG64)target_ip; RtlRestoreContext(context, rec); }
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 9ce0646cd47..eb8e92d8292 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -2182,12 +2182,45 @@ static void test_KiUserCallbackDispatcher(void)
#elif defined(__x86_64__)
-static int consolidate_dummy_called; +static LONG consolidate_dummy_called; static PVOID CALLBACK test_consolidate_dummy(EXCEPTION_RECORD *rec) { CONTEXT *ctx = (CONTEXT *)rec->ExceptionInformation[1]; - consolidate_dummy_called = 1; - ok(ctx->Rip == 0xdeadbeef, "test_consolidate_dummy failed for Rip, expected: 0xdeadbeef, got: %Ix\n", ctx->Rip); + + switch (InterlockedIncrement(&consolidate_dummy_called)) + { + case 1: /* RtlRestoreContext */ + ok(ctx->Rip == 0xdeadbeef, "RtlRestoreContext wrong Rip, expected: 0xdeadbeef, got: %Ix\n", ctx->Rip); + ok( rec->ExceptionInformation[10] == -1, "wrong info %Ix\n", rec->ExceptionInformation[10] ); + break; + case 2: /* RtlUnwindEx */ + ok(ctx->Rip != 0xdeadbeef, "RtlUnwindEx wrong Rip, got: %Ix\n", ctx->Rip ); + if (is_arm64ec) + { + DISPATCHER_CONTEXT_NONVOLREG_ARM64 *regs = (void *)rec->ExceptionInformation[10]; + _JUMP_BUFFER *buf = (void *)rec->ExceptionInformation[3]; + ARM64EC_NT_CONTEXT *ec_ctx = (ARM64EC_NT_CONTEXT *)ctx; + int i; + + ok( rec->ExceptionInformation[10] != -1, "wrong info %Ix\n", rec->ExceptionInformation[10] ); + ok( regs->GpNvRegs[0] == buf->R12, "wrong reg X19, %Ix / %Ix\n", regs->GpNvRegs[0], buf->R12 ); + ok( regs->GpNvRegs[1] == buf->R13, "wrong reg X20, %Ix / %Ix\n", regs->GpNvRegs[1], buf->R13 ); + ok( regs->GpNvRegs[2] == buf->R14, "wrong reg X21, %Ix / %Ix\n", regs->GpNvRegs[2], buf->R14 ); + ok( regs->GpNvRegs[3] == buf->R15, "wrong reg X22, %Ix / %Ix\n", regs->GpNvRegs[3], buf->R15 ); + ok( regs->GpNvRegs[4] == 0, "wrong reg X23, %Ix / 0\n", regs->GpNvRegs[4] ); + ok( regs->GpNvRegs[5] == 0, "wrong reg X24, %Ix / 0\n", regs->GpNvRegs[5] ); + ok( regs->GpNvRegs[6] == buf->Rsi, "wrong reg X25, %Ix / %Ix\n", regs->GpNvRegs[6], buf->Rsi ); + ok( regs->GpNvRegs[7] == buf->Rdi, "wrong reg X26, %Ix / %Ix\n", regs->GpNvRegs[7], buf->Rdi ); + ok( regs->GpNvRegs[8] == buf->Rbx, "wrong reg X27, %Ix / %Ix\n", regs->GpNvRegs[8], buf->Rbx ); + ok( regs->GpNvRegs[9] == 0, "wrong reg X28, %Ix / 0\n", regs->GpNvRegs[9] ); + ok( regs->GpNvRegs[10] == buf->Rbp,"wrong reg X29, %Ix / %Ix\n", regs->GpNvRegs[10], buf->Rbp ); + for (i = 0; i < 8; i++) + ok(regs->FpNvRegs[i] == ec_ctx->V[i + 8].D[0], "wrong reg D%u, expected: %g, got: %g\n", + i + 8, regs->FpNvRegs[i], ec_ctx->V[i + 8].D[0] ); + } + else ok( rec->ExceptionInformation[10] == -1, "wrong info %Ix\n", rec->ExceptionInformation[10] ); + break; + } return (PVOID)rec->ExceptionInformation[2]; }
@@ -2312,13 +2345,39 @@ static void test_restore_context(void) rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy; rec.ExceptionInformation[1] = (DWORD64)&ctx; rec.ExceptionInformation[2] = ctx.Rip; + rec.ExceptionInformation[10] = -1; ctx.Rip = 0xdeadbeef;
pRtlRestoreContext(&ctx, &rec); ok(0, "shouldn't be reached\n"); } else if (pass == 3) - ok(consolidate_dummy_called, "test_consolidate_dummy not called\n"); + ok(consolidate_dummy_called == 1, "test_consolidate_dummy not called\n"); + else + ok(0, "unexpected pass %ld\n", pass); + + /* test with consolidate through RtlUnwindEx */ + pass = 0; + InterlockedIncrement(&pass); + pRtlCaptureContext(&ctx); + InterlockedIncrement(&pass); + if (pass == 2) + { + rec.ExceptionCode = STATUS_UNWIND_CONSOLIDATE; + rec.NumberParameters = 4; + rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy; + rec.ExceptionInformation[1] = (DWORD64)&ctx; + rec.ExceptionInformation[2] = ctx.Rip; + rec.ExceptionInformation[3] = (DWORD64)&buf; + rec.ExceptionInformation[10] = -1; /* otherwise it doesn't get set */ + ctx.Rip = 0xdeadbeef; + /* uses consolidate callback Rip instead of bogus 0xdeadbeef */ + setjmp((_JBTYPE *)&buf); + pRtlUnwindEx((void*)buf.Frame, (void*)0xdeadbeef, &rec, NULL, &ctx, NULL); + ok(0, "shouldn't be reached\n"); + } + else if (pass == 3) + ok(consolidate_dummy_called == 2, "test_consolidate_dummy not called\n"); else ok(0, "unexpected pass %ld\n", pass); } @@ -2348,7 +2407,7 @@ static void test___C_specific_handler(void) }
memset(&rec, 0, sizeof(rec)); - rec.ExceptionFlags = 2; /* EXCEPTION_UNWINDING */ + rec.ExceptionFlags = EXCEPTION_UNWINDING; frame = 0x1234; memset(&dispatch, 0, sizeof(dispatch)); dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL);