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:
parent
7b998c266e
commit
0b3db9dfa2
|
@ -656,6 +656,64 @@ __ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||||
"bx r2" )
|
"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
|
* segv_handler
|
||||||
*
|
*
|
||||||
|
@ -693,6 +751,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (handle_syscall_fault( context, &rec )) return;
|
||||||
setup_exception( context, &rec );
|
setup_exception( context, &rec );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -716,6 +716,81 @@ __ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||||
"br x2" )
|
"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
|
* 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],
|
rec.ExceptionCode = virtual_handle_fault( siginfo->si_addr, rec.ExceptionInformation[0],
|
||||||
(void *)SP_sig(context) );
|
(void *)SP_sig(context) );
|
||||||
if (!rec.ExceptionCode) return;
|
if (!rec.ExceptionCode) return;
|
||||||
|
if (handle_syscall_fault( context, &rec )) return;
|
||||||
setup_exception( context, &rec );
|
setup_exception( context, &rec );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
* segv_handler
|
||||||
*
|
*
|
||||||
|
@ -1840,6 +1900,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (handle_syscall_fault( ucontext, stack, &rec, &xcontext.c )) return;
|
||||||
setup_raise_exception( ucontext, stack, &rec, &xcontext );
|
setup_raise_exception( ucontext, stack, &rec, &xcontext );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2204,6 +2204,68 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
|
||||||
return TRUE;
|
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
|
* segv_handler
|
||||||
*
|
*
|
||||||
|
@ -2267,6 +2329,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (handle_syscall_fault( sigcontext, &rec, &context.c )) return;
|
||||||
setup_raise_exception( sigcontext, &rec, &context );
|
setup_raise_exception( sigcontext, &rec, &context );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1362,16 +1362,8 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou
|
||||||
*/
|
*/
|
||||||
NTSTATUS WINAPI NtQueryPerformanceCounter( LARGE_INTEGER *counter, LARGE_INTEGER *frequency )
|
NTSTATUS WINAPI NtQueryPerformanceCounter( LARGE_INTEGER *counter, LARGE_INTEGER *frequency )
|
||||||
{
|
{
|
||||||
__TRY
|
counter->QuadPart = monotonic_counter();
|
||||||
{
|
if (frequency) frequency->QuadPart = TICKSPERSEC;
|
||||||
counter->QuadPart = monotonic_counter();
|
|
||||||
if (frequency) frequency->QuadPart = TICKSPERSEC;
|
|
||||||
}
|
|
||||||
__EXCEPT_PAGE_FAULT
|
|
||||||
{
|
|
||||||
return STATUS_ACCESS_VIOLATION;
|
|
||||||
}
|
|
||||||
__ENDTRY
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue