ntdll: Handle page faults happening during a syscall without dispatching the exception.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-08-24 11:46:22 +02:00
parent 7b998c266e
commit 0b3db9dfa2
5 changed files with 261 additions and 10 deletions

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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;
}