ntdll: Use a stack_layout structure to build exception data on x86-64.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-09-12 16:44:21 +02:00
parent 24876bf17e
commit 6e6711d773
1 changed files with 79 additions and 95 deletions

View File

@ -282,6 +282,19 @@ static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
static size_t signal_stack_size; static size_t signal_stack_size;
typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
/* stack layout when calling an exception raise function */
struct stack_layout
{
CONTEXT context;
EXCEPTION_RECORD rec;
ULONG64 rsi;
ULONG64 rdi;
ULONG64 rbp;
ULONG64 rip;
ULONG64 red_zone[16];
};
typedef int (*wine_signal_handler)(unsigned int sig); typedef int (*wine_signal_handler)(unsigned int sig);
static wine_signal_handler handlers[256]; static wine_signal_handler handlers[256];
@ -2414,17 +2427,6 @@ NTSTATUS WINAPI RtlWow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *co
} }
/***********************************************************************
* get_exception_context
*
* Get a pointer to the context built by setup_exception.
*/
static inline CONTEXT *get_exception_context( EXCEPTION_RECORD *rec )
{
return (CONTEXT *)rec - 1; /* cf. stack_layout structure */
}
static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
{ {
@ -2683,17 +2685,6 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
"call *%rdx\n\t" "call *%rdx\n\t"
"int $3") "int $3")
struct stack_layout
{
CONTEXT context;
EXCEPTION_RECORD rec;
ULONG64 rsi;
ULONG64 rdi;
ULONG64 rbp;
ULONG64 rip;
ULONG64 red_zone[16];
};
/*********************************************************************** /***********************************************************************
* setup_exception * setup_exception
* *
@ -2701,7 +2692,7 @@ struct stack_layout
* sigcontext so that the return from the signal handler will call * sigcontext so that the return from the signal handler will call
* the raise function. * the raise function.
*/ */
static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext ) static struct stack_layout *setup_exception( ucontext_t *sigcontext )
{ {
struct stack_layout *stack; struct stack_layout *stack;
DWORD exception_code = 0; DWORD exception_code = 0;
@ -2769,22 +2760,21 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext )
stack->rec.NumberParameters = 0; stack->rec.NumberParameters = 0;
save_context( &stack->context, sigcontext ); save_context( &stack->context, sigcontext );
return &stack->rec; return stack;
} }
static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec ) static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack )
{ {
struct stack_layout *stack = CONTAINING_RECORD( rec, struct stack_layout, rec );
ULONG64 *rsp_ptr; ULONG64 *rsp_ptr;
NTSTATUS status; NTSTATUS status;
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP) if (stack->rec.ExceptionCode == EXCEPTION_SINGLE_STEP)
{ {
/* when single stepping can't tell whether this is a hw bp or a /* when single stepping can't tell whether this is a hw bp or a
* single step interrupt. try to avoid as much overhead as possible * single step interrupt. try to avoid as much overhead as possible
* and only do a server call if there is any hw bp enabled. */ * and only do a server call if there is any hw bp enabled. */
if( !(stack->context.EFlags & 0x100) || (amd64_thread_data()->dr7 & 0xff) ) if (!(stack->context.EFlags & 0x100) || (stack->context.Dr7 & 0xff))
{ {
/* (possible) hardware breakpoint, fetch the debug registers */ /* (possible) hardware breakpoint, fetch the debug registers */
DWORD saved_flags = stack->context.ContextFlags; DWORD saved_flags = stack->context.ContextFlags;
@ -2796,7 +2786,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
stack->context.EFlags &= ~0x100; /* clear single-step flag */ stack->context.EFlags &= ~0x100; /* clear single-step flag */
} }
status = send_debug_event( rec, TRUE, &stack->context ); status = send_debug_event( &stack->rec, TRUE, &stack->context );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
{ {
restore_context( &stack->context, sigcontext ); restore_context( &stack->context, sigcontext );
@ -2909,15 +2899,15 @@ static inline DWORD is_privileged_instr( CONTEXT *context )
* *
* Handle an interrupt. * Handle an interrupt.
*/ */
static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context ) static inline BOOL handle_interrupt( ucontext_t *sigcontext, struct stack_layout *stack )
{ {
switch (ERROR_sig(sigcontext) >> 3) switch (ERROR_sig(sigcontext) >> 3)
{ {
case 0x2c: case 0x2c:
rec->ExceptionCode = STATUS_ASSERTION_FAILURE; stack->rec.ExceptionCode = STATUS_ASSERTION_FAILURE;
break; break;
case 0x2d: case 0x2d:
switch (context->Rax) switch (stack->context.Rax)
{ {
case 1: /* BREAKPOINT_PRINT */ case 1: /* BREAKPOINT_PRINT */
case 3: /* BREAKPOINT_LOAD_SYMBOLS */ case 3: /* BREAKPOINT_LOAD_SYMBOLS */
@ -2926,16 +2916,16 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
RIP_sig(sigcontext) += 3; RIP_sig(sigcontext) += 3;
return TRUE; return TRUE;
} }
context->Rip += 3; stack->context.Rip += 3;
rec->ExceptionCode = EXCEPTION_BREAKPOINT; stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT;
rec->ExceptionAddress = (void *)context->Rip; stack->rec.ExceptionAddress = (void *)stack->context.Rip;
rec->NumberParameters = 1; stack->rec.NumberParameters = 1;
rec->ExceptionInformation[0] = context->Rax; stack->rec.ExceptionInformation[0] = stack->context.Rax;
break; break;
default: default:
return FALSE; return FALSE;
} }
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
return TRUE; return TRUE;
} }
@ -2947,7 +2937,7 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
*/ */
static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
EXCEPTION_RECORD *rec; struct stack_layout *stack;
ucontext_t *ucontext = sigcontext; ucontext_t *ucontext = sigcontext;
/* check for page fault inside the thread stack */ /* check for page fault inside the thread stack */
@ -2958,58 +2948,52 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
case 1: /* handled */ case 1: /* handled */
return; return;
case -1: /* overflow */ case -1: /* overflow */
rec = setup_exception( sigcontext ); stack = setup_exception( sigcontext );
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
setup_raise_exception( sigcontext, rec ); goto done;
return;
} }
} }
rec = setup_exception( sigcontext ); stack = setup_exception( sigcontext );
if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done;
{
setup_raise_exception( sigcontext, rec );
return;
}
switch(TRAP_sig(ucontext)) switch(TRAP_sig(ucontext))
{ {
case TRAP_x86_OFLOW: /* Overflow exception */ case TRAP_x86_OFLOW: /* Overflow exception */
rec->ExceptionCode = EXCEPTION_INT_OVERFLOW; stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
break; break;
case TRAP_x86_BOUND: /* Bound range exception */ case TRAP_x86_BOUND: /* Bound range exception */
rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
break; break;
case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */ case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */
rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
break; break;
case TRAP_x86_STKFLT: /* Stack fault */ case TRAP_x86_STKFLT: /* Stack fault */
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
break; break;
case TRAP_x86_SEGNPFLT: /* Segment not present exception */ case TRAP_x86_SEGNPFLT: /* Segment not present exception */
case TRAP_x86_PROTFLT: /* General protection fault */ case TRAP_x86_PROTFLT: /* General protection fault */
case TRAP_x86_UNKNOWN: /* Unknown fault code */ case TRAP_x86_UNKNOWN: /* Unknown fault code */
{ {
CONTEXT *win_context = get_exception_context( rec );
WORD err = ERROR_sig(ucontext); WORD err = ERROR_sig(ucontext);
if (!err && (rec->ExceptionCode = is_privileged_instr( win_context ))) break; if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break;
if ((err & 7) == 2 && handle_interrupt( ucontext, rec, win_context )) return; if ((err & 7) == 2 && handle_interrupt( ucontext, stack )) return;
rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
rec->NumberParameters = 2; stack->rec.NumberParameters = 2;
rec->ExceptionInformation[0] = 0; stack->rec.ExceptionInformation[0] = 0;
rec->ExceptionInformation[1] = 0xffffffffffffffff; stack->rec.ExceptionInformation[1] = 0xffffffffffffffff;
} }
break; break;
case TRAP_x86_PAGEFLT: /* Page fault */ case TRAP_x86_PAGEFLT: /* Page fault */
rec->NumberParameters = 2; stack->rec.NumberParameters = 2;
rec->ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; stack->rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09;
rec->ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1], if (!(stack->rec.ExceptionCode = virtual_handle_fault((void *)stack->rec.ExceptionInformation[1],
rec->ExceptionInformation[0], FALSE ))) stack->rec.ExceptionInformation[0], FALSE )))
return; return;
break; break;
case TRAP_x86_ALIGNFLT: /* Alignment check exception */ case TRAP_x86_ALIGNFLT: /* Alignment check exception */
rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
break; break;
default: default:
ERR( "Got unexpected trap %ld\n", (ULONG_PTR)TRAP_sig(ucontext) ); ERR( "Got unexpected trap %ld\n", (ULONG_PTR)TRAP_sig(ucontext) );
@ -3020,11 +3004,11 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
case TRAP_x86_TSSFLT: /* Invalid TSS exception */ case TRAP_x86_TSSFLT: /* Invalid TSS exception */
case TRAP_x86_MCHK: /* Machine check exception */ case TRAP_x86_MCHK: /* Machine check exception */
case TRAP_x86_CACHEFLT: /* Cache flush exception */ case TRAP_x86_CACHEFLT: /* Cache flush exception */
rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
break; break;
} }
done:
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
} }
/********************************************************************** /**********************************************************************
@ -3034,34 +3018,34 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
EXCEPTION_RECORD *rec = setup_exception( sigcontext ); struct stack_layout *stack = setup_exception( sigcontext );
switch (siginfo->si_code) switch (siginfo->si_code)
{ {
case TRAP_TRACE: /* Single-step exception */ case TRAP_TRACE: /* Single-step exception */
case 4 /* TRAP_HWBKPT */: /* Hardware breakpoint exception */ case 4 /* TRAP_HWBKPT */: /* Hardware breakpoint exception */
rec->ExceptionCode = EXCEPTION_SINGLE_STEP; stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
break; break;
case TRAP_BRKPT: /* Breakpoint exception */ case TRAP_BRKPT: /* Breakpoint exception */
#ifdef SI_KERNEL #ifdef SI_KERNEL
case SI_KERNEL: case SI_KERNEL:
#endif #endif
/* Check if this is actually icebp instruction */ /* Check if this is actually icebp instruction */
if (((unsigned char *)rec->ExceptionAddress)[-1] == 0xF1) if (((unsigned char *)stack->rec.ExceptionAddress)[-1] == 0xF1)
{ {
rec->ExceptionCode = EXCEPTION_SINGLE_STEP; stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
break; break;
} }
rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1; /* back up over the int3 instruction */ stack->rec.ExceptionAddress = (char *)stack->rec.ExceptionAddress - 1; /* back up over the int3 instruction */
/* fall through */ /* fall through */
default: default:
rec->ExceptionCode = EXCEPTION_BREAKPOINT; stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT;
rec->NumberParameters = 1; stack->rec.NumberParameters = 1;
rec->ExceptionInformation[0] = 0; stack->rec.ExceptionInformation[0] = 0;
break; break;
} }
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
} }
/********************************************************************** /**********************************************************************
@ -3071,38 +3055,38 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
EXCEPTION_RECORD *rec = setup_exception( sigcontext ); struct stack_layout *stack = setup_exception( sigcontext );
switch (siginfo->si_code) switch (siginfo->si_code)
{ {
case FPE_FLTSUB: case FPE_FLTSUB:
rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
break; break;
case FPE_INTDIV: case FPE_INTDIV:
rec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
break; break;
case FPE_INTOVF: case FPE_INTOVF:
rec->ExceptionCode = EXCEPTION_INT_OVERFLOW; stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
break; break;
case FPE_FLTDIV: case FPE_FLTDIV:
rec->ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; stack->rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
break; break;
case FPE_FLTOVF: case FPE_FLTOVF:
rec->ExceptionCode = EXCEPTION_FLT_OVERFLOW; stack->rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
break; break;
case FPE_FLTUND: case FPE_FLTUND:
rec->ExceptionCode = EXCEPTION_FLT_UNDERFLOW; stack->rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
break; break;
case FPE_FLTRES: case FPE_FLTRES:
rec->ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; stack->rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
break; break;
case FPE_FLTINV: case FPE_FLTINV:
default: default:
rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
break; break;
} }
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
} }
/********************************************************************** /**********************************************************************
@ -3114,9 +3098,9 @@ static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
if (!dispatch_signal(SIGINT)) if (!dispatch_signal(SIGINT))
{ {
EXCEPTION_RECORD *rec = setup_exception( sigcontext ); struct stack_layout *stack = setup_exception( sigcontext );
rec->ExceptionCode = CONTROL_C_EXIT; stack->rec.ExceptionCode = CONTROL_C_EXIT;
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
} }
} }
@ -3128,10 +3112,10 @@ static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
EXCEPTION_RECORD *rec = setup_exception( sigcontext ); struct stack_layout *stack = setup_exception( sigcontext );
rec->ExceptionCode = EXCEPTION_WINE_ASSERTION; stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
rec->ExceptionFlags = EH_NONCONTINUABLE; stack->rec.ExceptionFlags = EH_NONCONTINUABLE;
setup_raise_exception( sigcontext, rec ); setup_raise_exception( sigcontext, stack );
} }