From 077252f13b0e1b2869ba517c57aaf5c8b34e35b2 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 1 Mar 2024 18:42:18 +0100 Subject: [PATCH] ntdll: Port the RtlRaiseException test to ARM64. --- dlls/ntdll/signal_arm64.c | 3 + dlls/ntdll/tests/exception.c | 164 +++++++++++++++++++++++++++++++---- 2 files changed, 151 insertions(+), 16 deletions(-) diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index a5d22cee020..192bcdce83d 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -905,6 +905,9 @@ __ASM_GLOBAL_FUNC( RtlRaiseException, "stp x4, x5, [x1, #0xf0]\n\t" /* context->Fp, Lr */ "str x5, [x1, #0x108]\n\t" /* context->Pc */ "str x5, [x0, #0x10]\n\t" /* rec->ExceptionAddress */ + "ldr w2, [x1]\n\t" /* context->ContextFlags */ + "orr w2, w2, #0x20000000\n\t" /* CONTEXT_UNWOUND_TO_CALL */ + "str w2, [x1]\n\t" "ldr x3, [x18, #0x60]\n\t" /* peb */ "ldrb w2, [x3, #2]\n\t" /* peb->BeingDebugged */ "cbnz w2, 1f\n\t" diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index eed151cdb1f..59a8bdf9d6a 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -6252,11 +6252,11 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { if (stage == STAGE_RTLRAISE_NOT_HANDLED) { - ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %p instead of %p\n", - (char *)ctx.Pc, (char *)code_mem_address + 0xb); + ok((char *)ctx.Pc == (char *)code_mem_address + 0xc, "Pc at %p instead of %p\n", + (char *)ctx.Pc, (char *)code_mem_address + 0xc); /* setting the context from debugger does not affect the context that the * exception handler gets, except on w2008 */ - ctx.Pc = (UINT_PTR)code_mem_address + 0xd; + ctx.Pc = (UINT_PTR)code_mem_address + 0x10; ctx.X0 = 0xf00f00f1; /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; @@ -6266,9 +6266,9 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) if (de.u.Exception.dwFirstChance) { /* debugger gets first chance exception with unmodified ctx.Pc */ - ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %p instead of %p\n", - (char *)ctx.Pc, (char *)code_mem_address + 0xb); - ctx.Pc = (UINT_PTR)code_mem_address + 0xd; + ok((char *)ctx.Pc == (char *)code_mem_address + 0xc, "Pc at %p instead of %p\n", + (char *)ctx.Pc, (char *)code_mem_address + 0xc); + ctx.Pc = (UINT_PTR)code_mem_address + 0x10; ctx.X0 = 0xf00f00f1; /* pass exception to debuggee * exception will not be handled and a second chance exception will be raised */ @@ -6280,13 +6280,13 @@ static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) /* ctx.Pc is the same value the exception handler got */ if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { - ok((char *)ctx.Pc == (char *)code_mem_address + 0xa, - "Pc at %p instead of %p\n", (char *)ctx.Pc, (char *)code_mem_address + 0xa); + ok((char *)ctx.Pc == (char *)code_mem_address + 0xc, + "Pc at %p instead of %p\n", (char *)ctx.Pc, (char *)code_mem_address + 0xc); /* need to fixup Pc for debuggee */ ctx.Pc += 4; } - else ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, - "Pc at %p instead of %p\n", (void *)ctx.Pc, (char *)code_mem_address + 0xb); + else ok((char *)ctx.Pc == (char *)code_mem_address + 0xc, + "Pc at %p instead of %p\n", (void *)ctx.Pc, (char *)code_mem_address + 0xc); /* here we handle exception */ } } @@ -6767,12 +6767,13 @@ static void test_KiUserCallbackDispatcher(void) static void run_exception_test(void *handler, const void* context, const void *code, unsigned int code_size, - unsigned int func2_offset, DWORD access, DWORD handler_flags) + unsigned int func2_offset, DWORD access, DWORD handler_flags, + void *arg1, void *arg2) { DWORD buf[14]; RUNTIME_FUNCTION runtime_func[2]; IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA unwind; - void (*func)(void) = code_mem; + void (*func)(void*,void*) = code_mem; DWORD oldaccess, oldaccess2; runtime_func[0].BeginAddress = 0; @@ -6807,7 +6808,7 @@ static void run_exception_test(void *handler, const void* context, FlushInstructionCache( GetCurrentProcess(), code_mem, 0x2000 ); pRtlAddFunctionTable(runtime_func, ARRAY_SIZE(runtime_func), (ULONG_PTR)code_mem); - func(); + func( arg1, arg2 ); pRtlDeleteFunctionTable(runtime_func); if (access) VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2); @@ -6876,7 +6877,7 @@ static void test_nested_exception(void) { got_nested_exception = got_prev_frame_exception = FALSE; run_exception_test(nested_exception_handler, NULL, nested_except_code, sizeof(nested_except_code), - 5 * sizeof(DWORD), PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER); + 5 * sizeof(DWORD), PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER, 0, 0); ok(got_nested_exception, "Did not get nested exception.\n"); ok(got_prev_frame_exception, "Did not get nested exception in the previous frame.\n"); } @@ -6944,10 +6945,140 @@ static void test_collided_unwind(void) got_nested_exception = got_prev_frame_exception = FALSE; collided_unwind_exception_count = 0; run_exception_test(collided_exception_handler, NULL, nested_except_code, sizeof(nested_except_code), - 5 * sizeof(DWORD), PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER); + 5 * sizeof(DWORD), PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER, 0, 0); ok(collided_unwind_exception_count == 6, "got %u.\n", collided_unwind_exception_count); } + +static int rtlraiseexception_unhandled_handler_called; +static int rtlraiseexception_teb_handler_called; +static int rtlraiseexception_handler_called; + +static void rtlraiseexception_handler_( EXCEPTION_RECORD *rec, void *frame, CONTEXT *context, + void *dispatcher, BOOL unhandled_handler ) +{ + void *addr = rec->ExceptionAddress; + + trace( "exception: %08lx flags:%lx addr:%p context: Pc:%p\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, (void *)context->Pc ); + + ok( addr == (char *)code_mem + 0x0c, + "ExceptionAddress at %p instead of %p\n", addr, (char *)code_mem + 0x0c ); + ok( context->ContextFlags == (CONTEXT_FULL | CONTEXT_UNWOUND_TO_CALL) || + context->ContextFlags == (CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_UNWOUND_TO_CALL), + "wrong context flags %lx\n", context->ContextFlags ); + ok( context->Pc == (UINT_PTR)addr, + "%d: Pc at %Ix instead of %Ix\n", test_stage, context->Pc, (UINT_PTR)addr ); + + ok( context->X0 == 0xf00f00f0, "context->X0 is %Ix, should have been set to 0xf00f00f0 in vectored handler\n", context->X0 ); +} + +static LONG CALLBACK rtlraiseexception_unhandled_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PCONTEXT context = ExceptionInfo->ContextRecord; + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + + rtlraiseexception_unhandled_handler_called = 1; + rtlraiseexception_handler_(rec, NULL, context, NULL, TRUE); + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return EXCEPTION_CONTINUE_SEARCH; + + return EXCEPTION_CONTINUE_EXECUTION; +} + +static DWORD WINAPI rtlraiseexception_teb_handler( EXCEPTION_RECORD *rec, + EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, + EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + rtlraiseexception_teb_handler_called = 1; + rtlraiseexception_handler_(rec, frame, context, dispatcher, FALSE); + return ExceptionContinueSearch; +} + +static DWORD WINAPI rtlraiseexception_handler( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, void *dispatcher ) +{ + rtlraiseexception_handler_called = 1; + rtlraiseexception_handler_(rec, frame, context, dispatcher, FALSE); + return ExceptionContinueSearch; +} + +static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PCONTEXT context = ExceptionInfo->ContextRecord; + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + void *addr = rec->ExceptionAddress; + + ok( addr == (char *)code_mem + 0xc, + "ExceptionAddress at %p instead of %p\n", addr, (char *)code_mem + 0xc ); + ok( context->Pc == (UINT_PTR)addr, + "%d: Pc at %Ix instead of %Ix\n", test_stage, context->Pc, (UINT_PTR)addr ); + + context->X0 = 0xf00f00f0; + + return EXCEPTION_CONTINUE_SEARCH; +} + +static const DWORD call_one_arg_code[] = +{ + 0xa9bf7bfd, /* 00: stp x29, x30, [sp, #-16]! */ + 0x910003fd, /* 04: mov x29, sp */ + 0xd63f0020, /* 08: blr x1 */ + 0xd503201f, /* 0c: nop */ + 0xa8c17bfd, /* 10: ldp x29, x30, [sp], #16 */ + 0xd65f03c0, /* 14: ret */ +}; + +static void run_rtlraiseexception_test(DWORD exceptioncode) +{ + EXCEPTION_REGISTRATION_RECORD frame; + EXCEPTION_RECORD record; + PVOID vectored_handler = NULL; + + record.ExceptionCode = exceptioncode; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = NULL; /* does not matter, copied return address */ + record.NumberParameters = 0; + + frame.Handler = rtlraiseexception_teb_handler; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList; + + NtCurrentTeb()->Tib.ExceptionList = &frame; + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, rtlraiseexception_vectored_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + if (pRtlSetUnhandledExceptionFilter) pRtlSetUnhandledExceptionFilter(rtlraiseexception_unhandled_handler); + + rtlraiseexception_handler_called = 0; + rtlraiseexception_teb_handler_called = 0; + rtlraiseexception_unhandled_handler_called = 0; + + run_exception_test( rtlraiseexception_handler, NULL, call_one_arg_code, + sizeof(call_one_arg_code), sizeof(call_one_arg_code), + PAGE_EXECUTE_READ, UNW_FLAG_EHANDLER, + &record, pRtlRaiseException); + + ok( record.ExceptionAddress == (char *)code_mem + 0x0c, + "address set to %p instead of %p\n", record.ExceptionAddress, (char *)code_mem + 0x0c ); + + todo_wine + ok( !rtlraiseexception_teb_handler_called, "Frame TEB handler called\n" ); + ok( rtlraiseexception_handler_called, "Frame handler called\n" ); + ok( rtlraiseexception_unhandled_handler_called, "UnhandledExceptionFilter wasn't called\n" ); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); + + if (pRtlSetUnhandledExceptionFilter) pRtlSetUnhandledExceptionFilter(NULL); + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; +} + +static void test_rtlraiseexception(void) +{ + run_rtlraiseexception_test(0x12345); + run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); + run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); +} + #endif /* __aarch64__ */ #if defined(__i386__) || defined(__x86_64__) @@ -10079,7 +10210,7 @@ START_TEST(exception) return; } -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) if (pRtlRaiseException) { test_stage = STAGE_RTLRAISE_NOT_HANDLED; @@ -10206,6 +10337,7 @@ START_TEST(exception) test_continue(); test_nested_exception(); test_collided_unwind(); + test_rtlraiseexception(); #elif defined(__arm__)