ntdll: Add a helper function to push the exception data to the thread stack.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9a9fb47e24
commit
ca45eda758
|
@ -531,17 +531,12 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
|
|||
CONTEXT context;
|
||||
EXCEPTION_RECORD rec;
|
||||
} *stack;
|
||||
DWORD exception_code = 0;
|
||||
|
||||
stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
|
||||
stack--; /* push the stack_layout structure */
|
||||
|
||||
stack->rec.ExceptionRecord = NULL;
|
||||
stack->rec.ExceptionCode = exception_code;
|
||||
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
|
||||
stack->rec.NumberParameters = 0;
|
||||
EXCEPTION_RECORD rec = { 0 };
|
||||
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~3);
|
||||
|
||||
rec.ExceptionAddress = (void *)PC_sig(sigcontext);
|
||||
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
|
||||
stack->rec = rec;
|
||||
save_context( &stack->context, sigcontext );
|
||||
|
||||
/* now modify the sigcontext to return to the raise function */
|
||||
|
|
|
@ -121,8 +121,9 @@ struct stack_layout
|
|||
{
|
||||
CONTEXT context;
|
||||
EXCEPTION_RECORD rec;
|
||||
void *redzone[2];
|
||||
void *redzone[3];
|
||||
};
|
||||
C_ASSERT( !(sizeof(struct stack_layout) % 16) );
|
||||
|
||||
struct arm64_thread_data
|
||||
{
|
||||
|
@ -540,18 +541,13 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
*/
|
||||
static struct stack_layout *setup_exception( ucontext_t *sigcontext )
|
||||
{
|
||||
EXCEPTION_RECORD rec = { 0 };
|
||||
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~15);
|
||||
struct stack_layout *stack;
|
||||
DWORD exception_code = 0;
|
||||
|
||||
/* push the stack_layout structure */
|
||||
stack = (struct stack_layout *)((SP_sig(sigcontext) - sizeof(*stack)) & ~15);
|
||||
|
||||
stack->rec.ExceptionRecord = NULL;
|
||||
stack->rec.ExceptionCode = exception_code;
|
||||
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
|
||||
stack->rec.NumberParameters = 0;
|
||||
|
||||
rec.ExceptionAddress = (void *)PC_sig(sigcontext);
|
||||
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
|
||||
stack->rec = rec;
|
||||
save_context( &stack->context, sigcontext );
|
||||
save_fpu( &stack->context, sigcontext );
|
||||
return stack;
|
||||
|
|
|
@ -1460,72 +1460,12 @@ static BOOL check_atl_thunk( ucontext_t *sigcontext, struct stack_layout *stack
|
|||
*/
|
||||
static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void *stack_ptr )
|
||||
{
|
||||
struct stack_layout *stack = stack_ptr;
|
||||
DWORD exception_code = 0;
|
||||
|
||||
/* stack sanity checks */
|
||||
|
||||
if ((char *)stack >= (char *)get_signal_stack() &&
|
||||
(char *)stack < (char *)get_signal_stack() + signal_stack_size)
|
||||
{
|
||||
WINE_ERR( "nested exception on signal stack in thread %04x eip %08x esp %08x stack %p-%p\n",
|
||||
GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
|
||||
NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
|
||||
if (stack - 1 > stack || /* check for overflow in subtraction */
|
||||
(char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
|
||||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
||||
{
|
||||
WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n",
|
||||
GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
|
||||
NtCurrentTeb()->Tib.StackBase );
|
||||
}
|
||||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096)
|
||||
{
|
||||
/* stack overflow on last page, unrecoverable */
|
||||
UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1);
|
||||
WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
|
||||
diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||
{
|
||||
/* stack access below stack limit, may be recoverable */
|
||||
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||
{
|
||||
case 0: /* not handled */
|
||||
{
|
||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
||||
WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
|
||||
diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
case -1: /* overflow */
|
||||
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stack--; /* push the stack_layout structure */
|
||||
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack));
|
||||
#elif defined(VALGRIND_MAKE_WRITABLE)
|
||||
VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
|
||||
#endif
|
||||
stack->rec.ExceptionRecord = NULL;
|
||||
stack->rec.ExceptionCode = exception_code;
|
||||
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
|
||||
stack->rec.NumberParameters = 0;
|
||||
EXCEPTION_RECORD rec = { 0 };
|
||||
struct stack_layout *stack;
|
||||
|
||||
rec.ExceptionAddress = (void *)EIP_sig(sigcontext);
|
||||
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
|
||||
stack->rec = rec;
|
||||
save_context( &stack->context, sigcontext );
|
||||
return stack;
|
||||
}
|
||||
|
|
|
@ -1377,18 +1377,6 @@ static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontex
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* is_inside_signal_stack
|
||||
*
|
||||
* Check if pointer is inside the signal stack.
|
||||
*/
|
||||
static inline BOOL is_inside_signal_stack( void *ptr )
|
||||
{
|
||||
return ((char *)ptr >= (char *)get_signal_stack() &&
|
||||
(char *)ptr < (char *)get_signal_stack() + signal_stack_size);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* save_context
|
||||
*
|
||||
|
@ -1847,72 +1835,14 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
|
|||
*/
|
||||
static struct stack_layout *setup_exception( ucontext_t *sigcontext )
|
||||
{
|
||||
EXCEPTION_RECORD rec = { 0 };
|
||||
void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15);
|
||||
struct stack_layout *stack;
|
||||
DWORD exception_code = 0;
|
||||
|
||||
stack = (struct stack_layout *)(RSP_sig(sigcontext) & ~15);
|
||||
|
||||
/* stack sanity checks */
|
||||
|
||||
if (is_inside_signal_stack( stack ))
|
||||
{
|
||||
ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n",
|
||||
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
|
||||
if (stack - 1 > stack || /* check for overflow in subtraction */
|
||||
(char *)stack <= (char *)NtCurrentTeb()->DeallocationStack ||
|
||||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
||||
{
|
||||
WARN( "exception outside of stack limits in thread %04x eip %016lx esp %016lx stack %p-%p\n",
|
||||
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
}
|
||||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096)
|
||||
{
|
||||
/* stack overflow on last page, unrecoverable */
|
||||
UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1);
|
||||
ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
|
||||
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
|
||||
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||
{
|
||||
/* stack access below stack limit, may be recoverable */
|
||||
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||
{
|
||||
case 0: /* not handled */
|
||||
{
|
||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
||||
ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
|
||||
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
|
||||
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
case -1: /* overflow */
|
||||
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stack--; /* push the stack_layout structure */
|
||||
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack));
|
||||
#elif defined(VALGRIND_MAKE_WRITABLE)
|
||||
VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack));
|
||||
#endif
|
||||
stack->rec.ExceptionRecord = NULL;
|
||||
stack->rec.ExceptionCode = exception_code;
|
||||
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
stack->rec.ExceptionAddress = (void *)RIP_sig(sigcontext);
|
||||
stack->rec.NumberParameters = 0;
|
||||
rec.ExceptionAddress = (void *)RIP_sig(sigcontext);
|
||||
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), &rec );
|
||||
stack->rec = rec;
|
||||
save_context( &stack->context, sigcontext );
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
|
|||
extern ssize_t virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN;
|
||||
extern ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
|
||||
extern void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -2912,6 +2912,61 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_setup_exception
|
||||
*/
|
||||
void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec )
|
||||
{
|
||||
char *stack = stack_ptr;
|
||||
|
||||
if (is_inside_signal_stack( stack ))
|
||||
{
|
||||
ERR( "nested exception on signal stack in thread %04x addr %p stack %p (%p-%p-%p)\n",
|
||||
GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
|
||||
if (stack - size > stack || /* check for overflow in subtraction */
|
||||
stack <= (char *)NtCurrentTeb()->DeallocationStack ||
|
||||
stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
||||
{
|
||||
WARN( "exception outside of stack limits in thread %04x addr %p stack %p (%p-%p-%p)\n",
|
||||
GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
return stack - size;
|
||||
}
|
||||
|
||||
stack -= size;
|
||||
|
||||
if (stack < (char *)NtCurrentTeb()->DeallocationStack + 4096)
|
||||
{
|
||||
/* stack overflow on last page, unrecoverable */
|
||||
UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - stack;
|
||||
ERR( "stack overflow %u bytes in thread %04x addr %p stack %p (%p-%p-%p)\n",
|
||||
diff, GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
else if (stack < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||
{
|
||||
pthread_mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */
|
||||
if ((get_page_vprot( stack ) & VPROT_GUARD) && grow_thread_stack( ROUND_ADDR( stack, page_mask )))
|
||||
{
|
||||
rec->ExceptionCode = STATUS_STACK_OVERFLOW;
|
||||
rec->NumberParameters = 0;
|
||||
}
|
||||
pthread_mutex_unlock( &virtual_mutex );
|
||||
}
|
||||
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)
|
||||
VALGRIND_MAKE_MEM_UNDEFINED( stack, size );
|
||||
#elif defined(VALGRIND_MAKE_WRITABLE)
|
||||
VALGRIND_MAKE_WRITABLE( stack, size );
|
||||
#endif
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* check_write_access
|
||||
*
|
||||
|
@ -3060,30 +3115,6 @@ BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_handle_stack_fault
|
||||
*
|
||||
* Handle an access fault inside the current thread stack.
|
||||
* Return 1 if safely handled, -1 if handled into the overflow space.
|
||||
* Called from inside a signal handler.
|
||||
*/
|
||||
int virtual_handle_stack_fault( void *addr )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if ((char *)addr < (char *)NtCurrentTeb()->DeallocationStack) return 0;
|
||||
if ((char *)addr >= (char *)NtCurrentTeb()->Tib.StackBase) return 0;
|
||||
|
||||
pthread_mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */
|
||||
if (get_page_vprot( addr ) & VPROT_GUARD)
|
||||
{
|
||||
ret = grow_thread_stack( ROUND_ADDR( addr, page_mask )) ? -1 : 1;
|
||||
}
|
||||
pthread_mutex_unlock( &virtual_mutex );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* virtual_check_buffer_for_read
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue