From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/debug.c | 47 +++++++++++++++++ dlls/ntdll/tests/exception.c | 99 ++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+)
diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 4eff7ad1cca..3c184cfa0f6 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -283,6 +283,52 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) /******************************************************************* * RaiseException (kernelbase.@) */ +#if defined(__x86_64__) +/* Some DRMs depend on RaiseException not altering non-volatile registers. */ +__ASM_GLOBAL_FUNC( RaiseException, + "raise_exception_start:\n\t" + ".byte 0x48,0x8d,0xa4,0x24,0x00,0x00,0x00,0x00\n\t" /* hotpatch prolog */ + "sub $0xc8,%rsp\n\t" + __ASM_SEH(".seh_stackalloc 0xc8\n\t") + __ASM_SEH(".seh_endprologue\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 0xc8\n\t") + "leaq 0x20(%rsp),%rax\n\t" + "movl %ecx,(%rax)\n\t" /* ExceptionCode */ + "and $1,%edx\n\t" + "movl %edx,4(%rax)\n\t" /* ExceptionFlags */ + "movq $0,8(%rax)\n\t" /* ExceptionRecord */ + "leaq raise_exception_start(%rip),%rcx\n\t" + "movq %rcx,0x10(%rax)\n\t" /* ExceptionAddress */ + "movq %rax,%rcx\n\t" + "movl $0,0x18(%rcx)\n\t" /* NumberParameters */ + "testl %r8d,%r8d\n\t" + "jz 2f\n\t" + "testq %r9,%r9\n\t" + "jz 2f\n\t" + "movl $15,%edx\n\t" + "cmp %edx,%r8d\n\t" + "cmovb %r8d,%edx\n\t" + "movl %edx,0x18(%rcx)\n\t" /* NumberParameters */ + "leaq 0x20(%rcx),%rax\n" /* ExceptionInformation */ + "1:\tmovq (%r9),%r8\n\t" + "movq %r8,(%rax)\n\t" + "decl %edx\n\t" + "jz 2f\n\t" + "addq $8,%rax\n\t" + "addq $8,%r9\n\t" + "jmp 1b\n" + "2:\tcall " __ASM_NAME("RtlRaiseException") "\n\t" + "add $0xc8,%rsp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -0xc8\n\t") + "ret" ) + +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionCode) == 0 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionFlags) == 4 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionRecord) == 8 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionAddress) == 0x10 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, NumberParameters) == 0x18 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionInformation) == 0x20 ); +#else void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) { EXCEPTION_RECORD record; @@ -301,6 +347,7 @@ void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD cou
RtlRaiseException( &record ); } +#endif __ASM_STDCALL_IMPORT(RaiseException,16)
/******************************************************************* diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 128b2adde3b..f2ba16f4bae 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5031,6 +5031,104 @@ static void test_syscall_clobbered_regs(void) ok(regs.r11 == regs.eflags, "Expected r11 (%#I64x) to equal EFLAGS (%#x).\n", regs.r11, regs.eflags);
} + +static CONTEXT test_raiseexception_regs_context; +static LONG CALLBACK test_raiseexception_regs_handle(EXCEPTION_POINTERS *exception_info) +{ + EXCEPTION_RECORD *rec = exception_info->ExceptionRecord; + unsigned int i; + + test_raiseexception_regs_context = *exception_info->ContextRecord; + ok(rec->NumberParameters == EXCEPTION_MAXIMUM_PARAMETERS, "got %lu.\n", rec->NumberParameters); + ok(rec->ExceptionCode == 0xdeadbeaf, "got %#lx.\n", rec->ExceptionCode); + ok(!rec->ExceptionRecord, "got %p.\n", rec->ExceptionRecord); + ok(!rec->ExceptionFlags, "got %#lx.\n", rec->ExceptionFlags); + for (i = 0; i < rec->NumberParameters; ++i) + ok(rec->ExceptionInformation[i] == i, "got %Iu, i %u.\n", rec->ExceptionInformation[i], i); + return EXCEPTION_CONTINUE_EXECUTION; +} + +static void test_raiseexception_regs(void) +{ + static const BYTE code[] = + { + 0xb8, 0x00, 0xb0, 0xad, 0xde, /* mov $0xdeadb000,%eax */ + 0x53, /* push %rbx */ + 0x48, 0x89, 0xc3, /* mov %rax,%rbx */ + 0x56, /* push %rsi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc6, /* mov %rax,%rsi */ + 0x57, /* push %rdi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc7, /* mov %rax,%rdi */ + 0x55, /* push %rbp */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc5, /* mov %rax,%rbp */ + 0x41, 0x54, /* push %r12 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc4, /* mov %rax,%r12 */ + 0x41, 0x55, /* push %r13 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc5, /* mov %rax,%r13 */ + 0x41, 0x56, /* push %r14 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc6, /* mov %rax,%r14 */ + 0x41, 0x57, /* push %r15 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc7, /* mov %rax,%r15 */ + + 0x50, /* push %rax */ /* align stack */ + 0x48, 0x89, 0xc8, /* mov %rcx,%rax */ + 0xb9, 0xaf, 0xbe, 0xad, 0xde, /* mov $0xdeadbeaf,%ecx */ + 0xff, 0xd0, /* call *%rax */ + 0x58, /* pop %rax */ + + 0x41, 0x5f, /* pop %r15 */ + 0x41, 0x5e, /* pop %r14 */ + 0x41, 0x5d, /* pop %r13 */ + 0x41, 0x5c, /* pop %r12 */ + 0x5d, /* pop %rbp */ + 0x5f, /* pop %rdi */ + 0x5e, /* pop %rsi */ + 0x5b, /* pop %rbx */ + 0xc3, /* ret */ + }; + void (WINAPI *pRaiseException)( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) = RaiseException; + void (WINAPI *func)(void *raise_exception, DWORD flags, DWORD count, const ULONG_PTR *args); + void *vectored_handler; + ULONG_PTR args[20]; + ULONG64 expected; + unsigned int i; + + vectored_handler = AddVectoredExceptionHandler(TRUE, test_raiseexception_regs_handle); + ok(!!vectored_handler, "failed.\n"); + + memcpy(code_mem, code, sizeof(code)); + func = code_mem; + + for (i = 0; i < ARRAY_SIZE(args); ++i) + args[i] = i; + + func(pRaiseException, 0, ARRAY_SIZE(args), args); + expected = 0xdeadb000; + ok(test_raiseexception_regs_context.Rbx == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbx); + ++expected; + ok(test_raiseexception_regs_context.Rsi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rsi); + ++expected; + ok(test_raiseexception_regs_context.Rdi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rdi); + ++expected; + ok(test_raiseexception_regs_context.Rbp == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbp); + ++expected; + ok(test_raiseexception_regs_context.R12 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R12); + ++expected; + ok(test_raiseexception_regs_context.R13 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R13); + ++expected; + ok(test_raiseexception_regs_context.R14 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R14); + ++expected; + ok(test_raiseexception_regs_context.R15 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R15); + + RemoveVectoredExceptionHandler(vectored_handler); +} #elif defined(__arm__)
#define UNW_FLAG_NHANDLER 0 @@ -10974,6 +11072,7 @@ START_TEST(exception) test_copy_context(); test_unwind_from_apc(); test_syscall_clobbered_regs(); + test_raiseexception_regs();
#elif defined(__aarch64__)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=133260
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
ntdll: exception.c:4870: Test failed: Got unexpected frame 0000000000ADFBD0.
=== debian11 (32 bit report) ===
kernel32: Unhandled exception: page fault on execute access to 0x0092fd28 in 32-bit code (0x0092fd28).