diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 175e86168a4..be8e5e4b735 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -656,6 +656,64 @@ __ASM_GLOBAL_FUNC( call_user_exception_dispatcher, "bx r2" ) +/*********************************************************************** + * handle_syscall_fault + * + * Handle a page fault happening during a system call. + */ +static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) +{ + struct syscall_frame *frame = arm_thread_data()->syscall_frame; + __WINE_FRAME *wine_frame = (__WINE_FRAME *)NtCurrentTeb()->Tib.ExceptionList; + DWORD i; + + if (!frame) return FALSE; + + TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + (DWORD)PC_sig(context), GetCurrentThreadId() ); + for (i = 0; i < rec->NumberParameters; i++) + TRACE( " info[%d]=%08lx\n", i, rec->ExceptionInformation[i] ); + + TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n", + (DWORD)REGn_sig(0, context), (DWORD)REGn_sig(1, context), (DWORD)REGn_sig(2, context), + (DWORD)REGn_sig(3, context), (DWORD)REGn_sig(4, context), (DWORD)REGn_sig(5, context) ); + TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x r11=%08x\n", + (DWORD)REGn_sig(6, context), (DWORD)REGn_sig(7, context), (DWORD)REGn_sig(8, context), + (DWORD)REGn_sig(9, context), (DWORD)REGn_sig(10, context), (DWORD)FP_sig(context) ); + TRACE( " r12=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n", + (DWORD)IP_sig(context), (DWORD)SP_sig(context), (DWORD)LR_sig(context), + (DWORD)PC_sig(context), (DWORD)CPSR_sig(context) ); + + if ((char *)wine_frame < (char *)frame) + { + TRACE( "returning to handler\n" ); + REGn_sig(0, context) = (DWORD)&wine_frame->jmp; + REGn_sig(1, context) = 1; + PC_sig(context) = (DWORD)__wine_longjmp; + } + else + { + TRACE( "returning to user mode ip=%08x ret=%08x\n", frame->ret_addr, rec->ExceptionCode ); + REGn_sig(0, context) = rec->ExceptionCode; + REGn_sig(4, context) = frame->r4; + REGn_sig(5, context) = frame->r5; + REGn_sig(6, context) = frame->r6; + REGn_sig(7, context) = frame->r7; + REGn_sig(8, context) = frame->r8; + REGn_sig(9, context) = frame->r9; + REGn_sig(10, context) = frame->r10; + FP_sig(context) = frame->r11; + LR_sig(context) = frame->thunk_addr; + SP_sig(context) = (DWORD)&frame->r4; + PC_sig(context) = frame->thunk_addr; + CPSR_sig(context) = frame->cpsr; + arm_thread_data()->syscall_frame = frame->prev_frame; + } + return TRUE; +} + + /********************************************************************** * segv_handler * @@ -693,6 +751,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; } + if (handle_syscall_fault( context, &rec )) return; setup_exception( context, &rec ); } diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index a4454af71e9..169f50985e9 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -716,6 +716,81 @@ __ASM_GLOBAL_FUNC( call_user_exception_dispatcher, "br x2" ) +/*********************************************************************** + * handle_syscall_fault + * + * Handle a page fault happening during a system call. + */ +static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) +{ + struct syscall_frame *frame = arm64_thread_data()->syscall_frame; + __WINE_FRAME *wine_frame = (__WINE_FRAME *)NtCurrentTeb()->Tib.ExceptionList; + DWORD i; + + if (!frame) return FALSE; + + TRACE( "code=%x flags=%x addr=%p pc=%p tid=%04x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + (void *)PC_sig(context), GetCurrentThreadId() ); + for (i = 0; i < rec->NumberParameters; i++) + TRACE( " info[%d]=%016lx\n", i, rec->ExceptionInformation[i] ); + + TRACE(" x0=%016lx x1=%016lx x2=%016lx x3=%016lx\n", + (DWORD64)REGn_sig(0, context), (DWORD64)REGn_sig(1, context), + (DWORD64)REGn_sig(2, context), (DWORD64)REGn_sig(3, context) ); + TRACE(" x4=%016lx x5=%016lx x6=%016lx x7=%016lx\n", + (DWORD64)REGn_sig(4, context), (DWORD64)REGn_sig(5, context), + (DWORD64)REGn_sig(6, context), (DWORD64)REGn_sig(7, context) ); + TRACE(" x8=%016lx x9=%016lx x10=%016lx x11=%016lx\n", + (DWORD64)REGn_sig(8, context), (DWORD64)REGn_sig(9, context), + (DWORD64)REGn_sig(10, context), (DWORD64)REGn_sig(11, context) ); + TRACE(" x12=%016lx x13=%016lx x14=%016lx x15=%016lx\n", + (DWORD64)REGn_sig(12, context), (DWORD64)REGn_sig(13, context), + (DWORD64)REGn_sig(14, context), (DWORD64)REGn_sig(15, context) ); + TRACE(" x16=%016lx x17=%016lx x18=%016lx x19=%016lx\n", + (DWORD64)REGn_sig(16, context), (DWORD64)REGn_sig(17, context), + (DWORD64)REGn_sig(18, context), (DWORD64)REGn_sig(19, context) ); + TRACE(" x20=%016lx x21=%016lx x22=%016lx x23=%016lx\n", + (DWORD64)REGn_sig(20, context), (DWORD64)REGn_sig(21, context), + (DWORD64)REGn_sig(22, context), (DWORD64)REGn_sig(23, context) ); + TRACE(" x24=%016lx x25=%016lx x26=%016lx x27=%016lx\n", + (DWORD64)REGn_sig(24, context), (DWORD64)REGn_sig(25, context), + (DWORD64)REGn_sig(26, context), (DWORD64)REGn_sig(27, context) ); + TRACE(" x28=%016lx fp=%016lx lr=%016lx sp=%016lx\n", + (DWORD64)REGn_sig(28, context), (DWORD64)FP_sig(context), + (DWORD64)LR_sig(context), (DWORD64)SP_sig(context) ); + + if ((char *)wine_frame < (char *)frame) + { + TRACE( "returning to handler\n" ); + REGn_sig(0, context) = (ULONG_PTR)&wine_frame->jmp; + REGn_sig(1, context) = 1; + PC_sig(context) = (ULONG_PTR)__wine_longjmp; + } + else + { + TRACE( "returning to user mode ip=%p ret=%08x\n", (void *)frame->ret_addr, rec->ExceptionCode ); + REGn_sig(0, context) = rec->ExceptionCode; + REGn_sig(19, context) = frame->x19; + REGn_sig(20, context) = frame->x20; + REGn_sig(21, context) = frame->x21; + REGn_sig(22, context) = frame->x22; + REGn_sig(23, context) = frame->x23; + REGn_sig(24, context) = frame->x24; + REGn_sig(25, context) = frame->x25; + REGn_sig(26, context) = frame->x26; + REGn_sig(27, context) = frame->x27; + REGn_sig(28, context) = frame->x28; + FP_sig(context) = frame->x29; + LR_sig(context) = frame->ret_addr; + SP_sig(context) = (DWORD)&frame->thunk_x29; + PC_sig(context) = frame->thunk_addr; + arm64_thread_data()->syscall_frame = frame->prev_frame; + } + return TRUE; +} + + /********************************************************************** * segv_handler * @@ -732,6 +807,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = virtual_handle_fault( siginfo->si_addr, rec.ExceptionInformation[0], (void *)SP_sig(context) ); if (!rec.ExceptionCode) return; + if (handle_syscall_fault( context, &rec )) return; setup_exception( context, &rec ); } diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 6a27277bc22..bb11b50f8f7 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1755,6 +1755,66 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo } +/*********************************************************************** + * handle_syscall_fault + * + * Handle a page fault happening during a system call. + */ +static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, + EXCEPTION_RECORD *rec, CONTEXT *context ) +{ + struct syscall_frame *frame = x86_thread_data()->syscall_frame; + __WINE_FRAME *wine_frame = (__WINE_FRAME *)NtCurrentTeb()->Tib.ExceptionList; + DWORD i; + + if (!frame) return FALSE; + + TRACE( "code=%x flags=%x addr=%p ip=%08x tid=%04x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + context->Eip, GetCurrentThreadId() ); + for (i = 0; i < rec->NumberParameters; i++) + TRACE( " info[%d]=%08lx\n", i, rec->ExceptionInformation[i] ); + TRACE(" eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n", + context->Eax, context->Ebx, context->Ecx, + context->Edx, context->Esi, context->Edi ); + TRACE(" ebp=%08x esp=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n", + context->Ebp, context->Esp, context->SegCs, context->SegDs, + context->SegEs, context->SegFs, context->SegGs, context->EFlags ); + + if ((char *)wine_frame < (char *)frame) + { + /* stack frame for calling __wine_longjmp */ + struct + { + int retval; + __wine_jmp_buf *jmp; + void *retaddr; + } *stack; + + TRACE( "returning to handler\n" ); + stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec ); + stack->retval = 1; + stack->jmp = &wine_frame->jmp; + stack->retaddr = (void *)0xdeadbabe; + ESP_sig(sigcontext) = (DWORD)stack; + EIP_sig(sigcontext) = (DWORD)__wine_longjmp; + } + else + { + TRACE( "returning to user mode ip=%08x ret=%08x\n", frame->ret_addr, rec->ExceptionCode ); + EAX_sig(sigcontext) = rec->ExceptionCode; + EBX_sig(sigcontext) = frame->ebx; + ESI_sig(sigcontext) = frame->esi; + EDI_sig(sigcontext) = frame->edi; + EBP_sig(sigcontext) = frame->ebp; + ESP_sig(sigcontext) = (DWORD)&frame->ret_addr; + EIP_sig(sigcontext) = frame->thunk_addr; + x86_thread_data()->syscall_frame = frame->prev_frame; + } + return TRUE; +} + + /********************************************************************** * segv_handler * @@ -1840,6 +1900,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; } + if (handle_syscall_fault( ucontext, stack, &rec, &xcontext.c )) return; setup_raise_exception( ucontext, stack, &rec, &xcontext ); } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 7c13b4f7d20..6b57d0cdb1b 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2204,6 +2204,68 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r return TRUE; } + +/*********************************************************************** + * handle_syscall_fault + * + * Handle a page fault happening during a system call. + */ +static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context ) +{ + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + __WINE_FRAME *wine_frame = (__WINE_FRAME *)NtCurrentTeb()->Tib.ExceptionList; + DWORD i; + + if (!frame) return FALSE; + + TRACE( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + context->Rip, GetCurrentThreadId() ); + for (i = 0; i < rec->NumberParameters; i++) + TRACE( " info[%d]=%016lx\n", i, rec->ExceptionInformation[i] ); + TRACE(" rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n", + context->Rax, context->Rbx, context->Rcx, context->Rdx ); + TRACE(" rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n", + context->Rsi, context->Rdi, context->Rbp, context->Rsp ); + TRACE(" r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n", + context->R8, context->R9, context->R10, context->R11 ); + TRACE(" r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n", + context->R12, context->R13, context->R14, context->R15 ); + + if ((char *)wine_frame < (char *)frame) + { + TRACE( "returning to handler\n" ); + RCX_sig(sigcontext) = (ULONG_PTR)&wine_frame->jmp; + RDX_sig(sigcontext) = 1; + RIP_sig(sigcontext) = (ULONG_PTR)__wine_longjmp; + } + else + { + XMM_SAVE_AREA32 *fpu = FPU_sig(sigcontext); + + TRACE( "returning to user mode ip=%016lx ret=%08x\n", frame->ret_addr, rec->ExceptionCode ); + RAX_sig(sigcontext) = rec->ExceptionCode; + RBX_sig(sigcontext) = frame->rbx; + RSI_sig(sigcontext) = frame->rsi; + RDI_sig(sigcontext) = frame->rdi; + RBP_sig(sigcontext) = frame->rbp; + R12_sig(sigcontext) = frame->r12; + R13_sig(sigcontext) = frame->r13; + R14_sig(sigcontext) = frame->r14; + R15_sig(sigcontext) = frame->r15; + RSP_sig(sigcontext) = (ULONG_PTR)&frame->ret_addr; + RIP_sig(sigcontext) = frame->thunk_addr; + if (fpu) + { + fpu->MxCsr =frame->mxcsr; + memcpy( fpu->XmmRegisters + 6, frame->xmm, sizeof(frame->xmm) ); + } + amd64_thread_data()->syscall_frame = frame->prev_frame; + } + return TRUE; +} + + /********************************************************************** * segv_handler * @@ -2267,6 +2329,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; } + if (handle_syscall_fault( sigcontext, &rec, &context.c )) return; setup_raise_exception( sigcontext, &rec, &context ); } diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 18e64b02627..2d027b83f4a 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1362,16 +1362,8 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou */ NTSTATUS WINAPI NtQueryPerformanceCounter( LARGE_INTEGER *counter, LARGE_INTEGER *frequency ) { - __TRY - { - counter->QuadPart = monotonic_counter(); - if (frequency) frequency->QuadPart = TICKSPERSEC; - } - __EXCEPT_PAGE_FAULT - { - return STATUS_ACCESS_VIOLATION; - } - __ENDTRY + counter->QuadPart = monotonic_counter(); + if (frequency) frequency->QuadPart = TICKSPERSEC; return STATUS_SUCCESS; }