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" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue