From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/exception.c | 47 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 9 +++++-- dlls/ntdll/unix/signal_x86_64.c | 9 +++++-- 3 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index acf6946736e..c2ceef5eb7f 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -250,6 +250,51 @@ static void check_context_exception_request_( DWORD flags, BOOL hardware_excepti ok_(__FILE__, line)( (flags & exception_reporting_flags) == expected_flags, "got %#lx, expected %#lx.\n", flags, expected_flags ); } + +static BOOL test_hwbpt_in_syscall_trap; + +static LONG WINAPI test_hwbpt_in_syscall_handler( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + + test_hwbpt_in_syscall_trap = TRUE; + ok(rec->ExceptionCode == EXCEPTION_SINGLE_STEP, "got %#lx.\n", rec->ExceptionCode); + return EXCEPTION_CONTINUE_EXECUTION; +} + +static void test_hwbpt_in_syscall(void) +{ + TEB *teb = NtCurrentTeb(); + NTSTATUS status; + void *handler; + CONTEXT c; + DWORD ind; + BOOL bret; + + ind = TlsAlloc(); + ok(ind < ARRAY_SIZE(teb->TlsSlots), "got %lu.\n", ind); + handler = AddVectoredExceptionHandler(TRUE, test_hwbpt_in_syscall_handler); + memset(&c, 0, sizeof(c)); + c.ContextFlags = CONTEXT_DEBUG_REGISTERS; + c.Dr0 = (ULONG_PTR)&teb->TlsSlots[ind]; + c.Dr7 = 3 | (3 << 16) | (3 << 18); /* read / write 4 byte breakpoint. */ + bret = SetThreadContext(GetCurrentThread(), &c); + ok(bret, "got error %lu.\n", GetLastError()); + test_hwbpt_in_syscall_trap = FALSE; + teb->TlsSlots[ind] = (void *)0xdeadbeef; + ok(test_hwbpt_in_syscall_trap, "expected trap.\n"); + + test_hwbpt_in_syscall_trap = FALSE; + status = NtSetInformationThread(GetCurrentThread(), ThreadZeroTlsCell, &ind, sizeof(ind)); + ok(!status, "got %#lx.\n", status); + ok(!test_hwbpt_in_syscall_trap, "got trap.\n"); + c.Dr7 = 0; + bret = SetThreadContext(GetCurrentThread(), &c); + ok(bret, "got error %lu.\n", GetLastError()); + ok(!teb->TlsSlots[ind], "got %p.\n", teb->TlsSlots[ind]); + RemoveVectoredExceptionHandler(handler); + TlsFree(ind); +} #endif
#ifdef __i386__ @@ -11498,6 +11543,7 @@ START_TEST(exception) test_extended_context(); test_copy_context(); test_set_live_context(); + test_hwbpt_in_syscall();
#elif defined(__x86_64__)
@@ -11527,6 +11573,7 @@ START_TEST(exception) test_unwind_from_apc(); test_syscall_clobbered_regs(); test_raiseexception_regs(); + test_hwbpt_in_syscall();
#elif defined(__aarch64__)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index f55879a611e..b727a4d5d6a 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1850,7 +1850,7 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, * * Handle a trap exception during a system call. */ -static BOOL handle_syscall_trap( ucontext_t *sigcontext ) +static BOOL handle_syscall_trap( ucontext_t *sigcontext, siginfo_t *siginfo ) { struct syscall_frame *frame = x86_thread_data()->syscall_frame;
@@ -1868,6 +1868,11 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext )
EIP_sig( sigcontext ) = (ULONG)__wine_unix_call_dispatcher_prolog_end; } + else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ && is_inside_syscall( sigcontext )) + { + TRACE_(seh)( "ignoring HWBKPT in syscall eip=%p\n", (void *)EIP_sig(sigcontext) ); + return TRUE; + } else return FALSE;
TRACE( "ignoring trap in syscall eip=%08x eflags=%08x\n", EIP_sig(sigcontext), EFL_sig(sigcontext) ); @@ -1984,7 +1989,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ucontext_t *ucontext = sigcontext; void *stack = setup_exception_record( sigcontext, &rec, &xcontext );
- if (handle_syscall_trap( ucontext )) return; + if (handle_syscall_trap( ucontext, siginfo )) return;
switch (TRAP_sig(ucontext)) { diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 8ed06cc5cc1..1557d7bcb43 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1894,7 +1894,7 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, * * Handle a trap exception during a system call. */ -static BOOL handle_syscall_trap( ucontext_t *sigcontext ) +static BOOL handle_syscall_trap( ucontext_t *sigcontext, siginfo_t *siginfo ) { struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
@@ -1913,6 +1913,11 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext ) RIP_sig( sigcontext ) = (ULONG64)__wine_unix_call_dispatcher_prolog_end_ptr; R10_sig( sigcontext ) = RCX_sig( sigcontext ); } + else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ && is_inside_syscall( sigcontext )) + { + TRACE_(seh)( "ignoring HWBKPT in syscall rip=%p\n", (void *)RIP_sig(sigcontext) ); + return TRUE; + } else return FALSE;
TRACE_(seh)( "ignoring trap in syscall rip=%p eflags=%08x\n", @@ -2025,7 +2030,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) struct xcontext context; ucontext_t *ucontext = init_handler( sigcontext );
- if (handle_syscall_trap( ucontext )) return; + if (handle_syscall_trap( ucontext, siginfo )) return;
rec.ExceptionAddress = (void *)RIP_sig(ucontext); save_context( &context, ucontext );
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=148120
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000E500E8, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
Does any application rely on this behavior?
Yes, to some extent, I've got some request from devs for such an issue.
There is already handling of a bit more complicated case in the same handle_syscall_trap() so I hope its fine. Also, I've included the test which confirms the behaviour (while it looks rather apparent anyway, user mode set traps can't be affecting the kernel, even while real kernel will deal with user-mode set HW traps in a different way).