Switch back to the main process stack before calling exception
handlers.
This commit is contained in:
parent
8f1b861e27
commit
4cb001967a
|
@ -416,6 +416,7 @@ typedef int (*wine_signal_handler)(unsigned int sig);
|
|||
static wine_signal_handler handlers[256];
|
||||
|
||||
extern void WINAPI EXC_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
|
||||
extern void DECLSPEC_NORETURN __wine_call_from_32_restore_regs( CONTEXT context );
|
||||
|
||||
/* Global variable to save the thread %fs register while in 16-bit code (FIXME) */
|
||||
static unsigned int signal_fs;
|
||||
|
@ -512,6 +513,8 @@ static void restore_vm86_context( const CONTEXT *context, struct vm86plus_struct
|
|||
#endif /* __HAVE_VM86 */
|
||||
|
||||
|
||||
typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
|
||||
|
||||
/***********************************************************************
|
||||
* save_context
|
||||
*
|
||||
|
@ -737,17 +740,10 @@ inline static void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
|
|||
*
|
||||
* Restore the FPU context to a sigcontext.
|
||||
*/
|
||||
inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
|
||||
inline static void restore_fpu( CONTEXT *context )
|
||||
{
|
||||
/* reset the current interrupt status */
|
||||
context->FloatSave.StatusWord &= context->FloatSave.ControlWord | 0xffffff80;
|
||||
#ifdef FPU_sig
|
||||
if (FPU_sig(sigcontext))
|
||||
{
|
||||
*FPU_sig(sigcontext) = context->FloatSave;
|
||||
return;
|
||||
}
|
||||
#endif /* FPU_sig */
|
||||
#ifdef __GNUC__
|
||||
/* avoid nested exceptions */
|
||||
__asm__ __volatile__( "frstor %0; fwait" : : "m" (context->FloatSave) );
|
||||
|
@ -755,6 +751,158 @@ inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* setup_exception
|
||||
*
|
||||
* Setup a proper stack frame for the raise function, and modify the
|
||||
* sigcontext so that the return from the signal handler will call
|
||||
* the raise function.
|
||||
*/
|
||||
static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
|
||||
{
|
||||
struct stack_layout
|
||||
{
|
||||
void *ret_addr; /* return address from raise_func */
|
||||
EXCEPTION_RECORD *rec_ptr; /* first arg for raise_func */
|
||||
CONTEXT *context_ptr; /* second arg for raise_func */
|
||||
void *dummy; /* dummy ret addr for __wine_call_from_32_restore_regs */
|
||||
CONTEXT context;
|
||||
EXCEPTION_RECORD rec;
|
||||
DWORD ebp;
|
||||
DWORD eip;
|
||||
} *stack;
|
||||
|
||||
WORD fs, gs;
|
||||
|
||||
/* get %fs and %gs at time of the fault */
|
||||
#ifdef FS_sig
|
||||
fs = LOWORD(FS_sig(sigcontext));
|
||||
#else
|
||||
fs = wine_get_fs();
|
||||
#endif
|
||||
#ifdef GS_sig
|
||||
gs = LOWORD(GS_sig(sigcontext));
|
||||
#else
|
||||
gs = wine_get_gs();
|
||||
#endif
|
||||
|
||||
/* now restore a proper %fs for the fault handler */
|
||||
if (!IS_SELECTOR_SYSTEM(CS_sig(sigcontext)) ||
|
||||
!IS_SELECTOR_SYSTEM(SS_sig(sigcontext))) /* 16-bit mode */
|
||||
{
|
||||
/*
|
||||
* Win16 or DOS protected mode. Note that during switch
|
||||
* from 16-bit mode to linear mode, CS may be set to system
|
||||
* segment before FS is restored. Fortunately, in this case
|
||||
* SS is still non-system segment. This is why both CS and SS
|
||||
* are checked.
|
||||
*/
|
||||
wine_set_fs( signal_fs );
|
||||
wine_set_gs( NtCurrentTeb()->gs_sel );
|
||||
stack = (struct stack_layout *)NtCurrentTeb()->cur_stack;
|
||||
}
|
||||
else /* 32-bit mode */
|
||||
{
|
||||
stack = (struct stack_layout *)ESP_sig(sigcontext);
|
||||
#ifdef __HAVE_VM86
|
||||
if ((void *)EIP_sig(sigcontext) == vm86_return) /* vm86 mode */
|
||||
{
|
||||
unsigned int *int_stack = (unsigned int *)stack;
|
||||
/* fetch the saved %fs and %gs from the stack */
|
||||
wine_set_fs( int_stack[0] );
|
||||
wine_set_gs( int_stack[1] );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef FS_sig
|
||||
wine_set_fs( FS_sig(sigcontext) );
|
||||
#endif
|
||||
#ifdef GS_sig
|
||||
wine_set_gs( GS_sig(sigcontext) );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* stack sanity checks */
|
||||
|
||||
if ((char *)stack >= (char *)NtCurrentTeb()->DeallocationStack &&
|
||||
(char *)stack < (char *)NtCurrentTeb()->DeallocationStack + SIGNAL_STACK_SIZE)
|
||||
{
|
||||
ERR( "nested exception on signal stack in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
||||
GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
SYSDEPS_AbortThread(1);
|
||||
}
|
||||
|
||||
if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 ||
|
||||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
||||
{
|
||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 - (char *)stack;
|
||||
if (diff < 4096)
|
||||
ERR( "stack overflow %u bytes in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
||||
diff, GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
else
|
||||
ERR( "exception outside of stack limits in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
||||
GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
SYSDEPS_AbortThread(1);
|
||||
}
|
||||
|
||||
stack--; /* push the stack_layout structure */
|
||||
stack->ret_addr = __wine_call_from_32_restore_regs;
|
||||
stack->rec_ptr = &stack->rec;
|
||||
stack->context_ptr = &stack->context;
|
||||
|
||||
stack->rec.ExceptionRecord = NULL;
|
||||
stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
|
||||
stack->rec.NumberParameters = 0;
|
||||
|
||||
stack->context.ContextFlags = CONTEXT_FULL;
|
||||
stack->context.Eax = EAX_sig(sigcontext);
|
||||
stack->context.Ebx = EBX_sig(sigcontext);
|
||||
stack->context.Ecx = ECX_sig(sigcontext);
|
||||
stack->context.Edx = EDX_sig(sigcontext);
|
||||
stack->context.Esi = ESI_sig(sigcontext);
|
||||
stack->context.Edi = EDI_sig(sigcontext);
|
||||
stack->context.Ebp = EBP_sig(sigcontext);
|
||||
stack->context.EFlags = EFL_sig(sigcontext);
|
||||
stack->context.Eip = EIP_sig(sigcontext);
|
||||
stack->context.Esp = ESP_sig(sigcontext);
|
||||
stack->context.SegCs = LOWORD(CS_sig(sigcontext));
|
||||
stack->context.SegDs = LOWORD(DS_sig(sigcontext));
|
||||
stack->context.SegEs = LOWORD(ES_sig(sigcontext));
|
||||
stack->context.SegFs = fs;
|
||||
stack->context.SegGs = gs;
|
||||
stack->context.SegSs = LOWORD(SS_sig(sigcontext));
|
||||
|
||||
/* now modify the sigcontext to return to the raise function */
|
||||
ESP_sig(sigcontext) = (DWORD)stack;
|
||||
EIP_sig(sigcontext) = (DWORD)func;
|
||||
CS_sig(sigcontext) = wine_get_cs();
|
||||
DS_sig(sigcontext) = wine_get_ds();
|
||||
ES_sig(sigcontext) = wine_get_es();
|
||||
FS_sig(sigcontext) = wine_get_fs();
|
||||
GS_sig(sigcontext) = wine_get_gs();
|
||||
SS_sig(sigcontext) = wine_get_ss();
|
||||
|
||||
return stack->rec_ptr;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* 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 */
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_fpu_code
|
||||
*
|
||||
|
@ -781,49 +929,20 @@ static inline DWORD get_fpu_code( const CONTEXT *context )
|
|||
|
||||
|
||||
/**********************************************************************
|
||||
* do_segv
|
||||
*
|
||||
* Implementation of SIGSEGV handler.
|
||||
* raise_segv_exception
|
||||
*/
|
||||
static void do_segv( CONTEXT *context, int trap_code, void *cr2, int err_code )
|
||||
static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch(trap_code)
|
||||
switch(rec->ExceptionCode)
|
||||
{
|
||||
case T_OFLOW: /* Overflow exception */
|
||||
rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
if (rec->NumberParameters == 2)
|
||||
{
|
||||
if (!(rec->ExceptionCode = VIRTUAL_HandleFault( (void *)rec->ExceptionInformation[1] )))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case T_BOUND: /* Bound range exception */
|
||||
rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
|
||||
break;
|
||||
case T_PRIVINFLT: /* Invalid opcode exception */
|
||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
case T_STKFLT: /* Stack fault */
|
||||
rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
case T_SEGNPFLT: /* Segment not present exception */
|
||||
case T_PROTFLT: /* General protection fault */
|
||||
case T_UNKNOWN: /* Unknown fault code */
|
||||
rec.ExceptionCode = err_code ? EXCEPTION_ACCESS_VIOLATION : EXCEPTION_PRIV_INSTRUCTION;
|
||||
break;
|
||||
case T_PAGEFLT: /* Page fault */
|
||||
#ifdef FAULT_ADDRESS
|
||||
if (!(rec.ExceptionCode = VIRTUAL_HandleFault( cr2 ))) return;
|
||||
rec.NumberParameters = 2;
|
||||
rec.ExceptionInformation[0] = (err_code & 2) != 0;
|
||||
rec.ExceptionInformation[1] = (DWORD)cr2;
|
||||
#else
|
||||
rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
|
||||
#endif
|
||||
break;
|
||||
case T_ALIGNFLT: /* Alignment check exception */
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
/* FIXME: pass through exception handler first? */
|
||||
if (context->EFlags & 0x00040000)
|
||||
{
|
||||
|
@ -831,46 +950,21 @@ static void do_segv( CONTEXT *context, int trap_code, void *cr2, int err_code )
|
|||
context->EFlags &= ~0x00040000;
|
||||
return;
|
||||
}
|
||||
rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
|
||||
break;
|
||||
default:
|
||||
ERR( "Got unexpected trap %d\n", trap_code );
|
||||
/* fall through */
|
||||
case T_NMI: /* NMI interrupt */
|
||||
case T_DNA: /* Device not available exception */
|
||||
case T_DOUBLEFLT: /* Double fault exception */
|
||||
case T_TSSFLT: /* Invalid TSS exception */
|
||||
case T_RESERVED: /* Unknown exception */
|
||||
case T_MCHK: /* Machine check exception */
|
||||
#ifdef T_CACHEFLT
|
||||
case T_CACHEFLT: /* Cache flush exception */
|
||||
#endif
|
||||
rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
EXC_RtlRaiseException( rec, context );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* do_trap
|
||||
*
|
||||
* Implementation of SIGTRAP handler.
|
||||
* raise_trap_exception
|
||||
*/
|
||||
static void do_trap( CONTEXT *context, int trap_code )
|
||||
static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
DWORD dr0, dr1, dr2, dr3, dr6, dr7;
|
||||
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch(trap_code)
|
||||
if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
|
||||
{
|
||||
case T_TRCTRAP: /* Single-step exception */
|
||||
rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
|
||||
if (context->EFlags & 0x100)
|
||||
{
|
||||
context->EFlags &= ~0x100; /* clear single-step flag */
|
||||
|
@ -883,17 +977,10 @@ static void do_trap( CONTEXT *context, int trap_code )
|
|||
* if not, then someone did a kill(SIGTRAP) on us, and we
|
||||
* shall return a breakpoint, not a single step exception
|
||||
*/
|
||||
if (!(context->Dr6 & 0xf))
|
||||
rec.ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
if (!(context->Dr6 & 0xf)) rec->ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
}
|
||||
break;
|
||||
case T_BPTFLT: /* Breakpoint exception */
|
||||
rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
|
||||
/* fall through */
|
||||
default:
|
||||
rec.ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
break;
|
||||
}
|
||||
|
||||
dr0 = context->Dr0;
|
||||
dr1 = context->Dr1;
|
||||
dr2 = context->Dr2;
|
||||
|
@ -901,7 +988,7 @@ static void do_trap( CONTEXT *context, int trap_code )
|
|||
dr6 = context->Dr6;
|
||||
dr7 = context->Dr7;
|
||||
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
EXC_RtlRaiseException( rec, context );
|
||||
|
||||
if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 ||
|
||||
dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7)
|
||||
|
@ -914,36 +1001,12 @@ static void do_trap( CONTEXT *context, int trap_code )
|
|||
|
||||
|
||||
/**********************************************************************
|
||||
* do_fpe
|
||||
*
|
||||
* Implementation of SIGFPE handler
|
||||
* raise_fpu_exception
|
||||
*/
|
||||
static void do_fpe( CONTEXT *context, int trap_code )
|
||||
static void WINAPI raise_fpu_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
|
||||
switch(trap_code)
|
||||
{
|
||||
case T_DIVIDE: /* Division by zero exception */
|
||||
rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
|
||||
break;
|
||||
case T_FPOPFLT: /* Coprocessor segment overrun */
|
||||
rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
|
||||
break;
|
||||
case T_ARITHTRAP: /* Floating point exception */
|
||||
case T_UNKNOWN: /* Unknown fault code */
|
||||
rec.ExceptionCode = get_fpu_code( context );
|
||||
break;
|
||||
default:
|
||||
ERR( "Got unexpected trap %d\n", trap_code );
|
||||
rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
|
||||
break;
|
||||
}
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 0;
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
EXC_RtlRaiseException( rec, context );
|
||||
restore_fpu( context );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1031,6 +1094,7 @@ static HANDLER_DEF(usr2_handler)
|
|||
{
|
||||
CONTEXT context;
|
||||
|
||||
/* FIXME: should use setup_exception here */
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
set_vm86_pend( &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
|
@ -1045,17 +1109,54 @@ static HANDLER_DEF(usr2_handler)
|
|||
*/
|
||||
static HANDLER_DEF(segv_handler)
|
||||
{
|
||||
CONTEXT context;
|
||||
void *cr2;
|
||||
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, raise_segv_exception );
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
switch(get_trap_code(HANDLER_CONTEXT))
|
||||
{
|
||||
case T_OFLOW: /* Overflow exception */
|
||||
rec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
|
||||
break;
|
||||
case T_BOUND: /* Bound range exception */
|
||||
rec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
|
||||
break;
|
||||
case T_PRIVINFLT: /* Invalid opcode exception */
|
||||
rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
case T_STKFLT: /* Stack fault */
|
||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
case T_SEGNPFLT: /* Segment not present exception */
|
||||
case T_PROTFLT: /* General protection fault */
|
||||
case T_UNKNOWN: /* Unknown fault code */
|
||||
rec->ExceptionCode = get_error_code(HANDLER_CONTEXT) ? EXCEPTION_ACCESS_VIOLATION
|
||||
: EXCEPTION_PRIV_INSTRUCTION;
|
||||
break;
|
||||
case T_PAGEFLT: /* Page fault */
|
||||
rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
|
||||
#ifdef FAULT_ADDRESS
|
||||
cr2 = FAULT_ADDRESS;
|
||||
#else
|
||||
cr2 = NULL;
|
||||
rec->NumberParameters = 2;
|
||||
rec->ExceptionInformation[0] = (get_error_code(HANDLER_CONTEXT) & 2) != 0;
|
||||
rec->ExceptionInformation[1] = (DWORD)FAULT_ADDRESS;
|
||||
#endif
|
||||
do_segv( &context, get_trap_code(HANDLER_CONTEXT), cr2, get_error_code(HANDLER_CONTEXT) );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
break;
|
||||
case T_ALIGNFLT: /* Alignment check exception */
|
||||
rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
|
||||
break;
|
||||
default:
|
||||
ERR( "Got unexpected trap %d\n", get_trap_code(HANDLER_CONTEXT) );
|
||||
/* fall through */
|
||||
case T_NMI: /* NMI interrupt */
|
||||
case T_DNA: /* Device not available exception */
|
||||
case T_DOUBLEFLT: /* Double fault exception */
|
||||
case T_TSSFLT: /* Invalid TSS exception */
|
||||
case T_RESERVED: /* Unknown exception */
|
||||
case T_MCHK: /* Machine check exception */
|
||||
#ifdef T_CACHEFLT
|
||||
case T_CACHEFLT: /* Cache flush exception */
|
||||
#endif
|
||||
rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1066,10 +1167,21 @@ static HANDLER_DEF(segv_handler)
|
|||
*/
|
||||
static HANDLER_DEF(trap_handler)
|
||||
{
|
||||
CONTEXT context;
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
do_trap( &context, get_trap_code(HANDLER_CONTEXT) );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, raise_trap_exception );
|
||||
|
||||
switch(get_trap_code(HANDLER_CONTEXT))
|
||||
{
|
||||
case T_TRCTRAP: /* Single-step exception */
|
||||
rec->ExceptionCode = EXCEPTION_SINGLE_STEP;
|
||||
EFL_sig(HANDLER_CONTEXT) &= ~0x100; /* clear single-step flag */
|
||||
break;
|
||||
case T_BPTFLT: /* Breakpoint exception */
|
||||
rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1; /* back up over the int3 instruction */
|
||||
/* fall through */
|
||||
default:
|
||||
rec->ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1080,12 +1192,29 @@ static HANDLER_DEF(trap_handler)
|
|||
*/
|
||||
static HANDLER_DEF(fpe_handler)
|
||||
{
|
||||
CONTEXT context;
|
||||
save_fpu( &context, HANDLER_CONTEXT );
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
do_fpe( &context, get_trap_code(HANDLER_CONTEXT) );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
restore_fpu( &context, HANDLER_CONTEXT );
|
||||
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, raise_fpu_exception );
|
||||
CONTEXT *context;
|
||||
|
||||
context = get_exception_context( rec );
|
||||
save_fpu( context, HANDLER_CONTEXT );
|
||||
|
||||
switch(get_trap_code(HANDLER_CONTEXT))
|
||||
{
|
||||
case T_DIVIDE: /* Division by zero exception */
|
||||
rec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
|
||||
break;
|
||||
case T_FPOPFLT: /* Coprocessor segment overrun */
|
||||
rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
|
||||
break;
|
||||
case T_ARITHTRAP: /* Floating point exception */
|
||||
case T_UNKNOWN: /* Unknown fault code */
|
||||
rec->ExceptionCode = get_fpu_code( context );
|
||||
break;
|
||||
default:
|
||||
ERR( "Got unexpected trap %d\n", get_trap_code(HANDLER_CONTEXT) );
|
||||
rec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1099,17 +1228,8 @@ static HANDLER_DEF(int_handler)
|
|||
init_handler( HANDLER_CONTEXT );
|
||||
if (!dispatch_signal(SIGINT))
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionCode = CONTROL_C_EXIT;
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Eip;
|
||||
rec.NumberParameters = 0;
|
||||
EXC_RtlRaiseException( &rec, &context );
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, EXC_RtlRaiseException );
|
||||
rec->ExceptionCode = CONTROL_C_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1120,17 +1240,9 @@ static HANDLER_DEF(int_handler)
|
|||
*/
|
||||
static HANDLER_DEF(abrt_handler)
|
||||
{
|
||||
EXCEPTION_RECORD rec;
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, HANDLER_CONTEXT );
|
||||
rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
|
||||
rec.ExceptionFlags = EH_NONCONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context.Eip;
|
||||
rec.NumberParameters = 0;
|
||||
EXC_RtlRaiseException( &rec, &context ); /* Should never return.. */
|
||||
restore_context( &context, HANDLER_CONTEXT );
|
||||
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, EXC_RtlRaiseException );
|
||||
rec->ExceptionCode = EXCEPTION_WINE_ASSERTION;
|
||||
rec->ExceptionFlags = EH_NONCONTINUABLE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1350,14 +1462,19 @@ void __wine_enter_vm86( CONTEXT *context )
|
|||
* (avoiding sigprocmask for performance reasons) */
|
||||
teb->vm86_ptr = &vm86;
|
||||
vm86.regs.eflags |= teb->vm86_pending;
|
||||
|
||||
/* Check for VIF|VIP here, since vm86_enter doesn't */
|
||||
if ((vm86.regs.eflags & (VIF_MASK|VIP_MASK)) == (VIF_MASK|VIP_MASK)) {
|
||||
teb->vm86_ptr = NULL;
|
||||
teb->vm86_pending = 0;
|
||||
context->EFlags |= VIP_MASK;
|
||||
rec.ExceptionCode = EXCEPTION_VM86_STI;
|
||||
rec.ExceptionInformation[0] = 0;
|
||||
goto cancel_vm86;
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 0;
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
|
@ -1373,16 +1490,37 @@ void __wine_enter_vm86( CONTEXT *context )
|
|||
save_vm86_context( context, &vm86 );
|
||||
context->EFlags |= teb->vm86_pending;
|
||||
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 0;
|
||||
|
||||
switch(VM86_TYPE(res))
|
||||
{
|
||||
case VM86_UNKNOWN: /* unhandled GP fault - IO-instruction or similar */
|
||||
do_segv( context, T_PROTFLT, 0, 0 );
|
||||
rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
|
||||
raise_segv_exception( &rec, context );
|
||||
continue;
|
||||
case VM86_TRAP: /* return due to DOS-debugger request */
|
||||
do_trap( context, VM86_ARG(res) );
|
||||
switch(VM86_ARG(res))
|
||||
{
|
||||
case T_TRCTRAP: /* Single-step exception */
|
||||
rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
|
||||
context->EFlags &= ~0x100; /* clear single-step flag */
|
||||
break;
|
||||
case T_BPTFLT: /* Breakpoint exception */
|
||||
rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
|
||||
/* fall through */
|
||||
default:
|
||||
rec.ExceptionCode = EXCEPTION_BREAKPOINT;
|
||||
break;
|
||||
}
|
||||
raise_trap_exception( &rec, context );
|
||||
continue;
|
||||
case VM86_INTx: /* int3/int x instruction (ARG = x) */
|
||||
rec.ExceptionCode = EXCEPTION_VM86_INTx;
|
||||
rec.NumberParameters = 1;
|
||||
rec.ExceptionInformation[0] = VM86_ARG(res);
|
||||
break;
|
||||
case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */
|
||||
teb->vm86_pending = 0;
|
||||
|
@ -1395,12 +1533,6 @@ void __wine_enter_vm86( CONTEXT *context )
|
|||
ERR( "unhandled result from vm86 mode %x\n", res );
|
||||
continue;
|
||||
}
|
||||
rec.ExceptionInformation[0] = VM86_ARG(res);
|
||||
cancel_vm86:
|
||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||
rec.ExceptionRecord = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
rec.NumberParameters = 1;
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1006,41 +1006,40 @@ static void BuildCallFrom32Regs( FILE *outfile )
|
|||
/* Call the entry point */
|
||||
|
||||
fprintf( outfile, "\tcall *0(%%ebx)\n" );
|
||||
|
||||
/* Store %eip and %ebp onto the new stack */
|
||||
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %%eax,-4(%%edx)\n" );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Ebp) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %%eax,-8(%%edx)\n" );
|
||||
fprintf( outfile, "\tleal -%d(%%ebp),%%ecx\n", STACK_SPACE );
|
||||
|
||||
/* Restore the context structure */
|
||||
|
||||
/* Note: we don't bother to restore %cs, %ds and %ss
|
||||
* changing them in 32-bit code is a recipe for disaster anyway
|
||||
*/
|
||||
fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegEs) - STACK_SPACE );
|
||||
fprintf( outfile, "2:\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegEs) );
|
||||
fprintf( outfile, "\tpopl %%es\n" );
|
||||
fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegFs) - STACK_SPACE );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegFs) );
|
||||
fprintf( outfile, "\tpopl %%fs\n" );
|
||||
fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegGs) - STACK_SPACE );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegGs) );
|
||||
fprintf( outfile, "\tpopl %%gs\n" );
|
||||
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%edi\n", CONTEXTOFFSET(Edi) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%esi\n", CONTEXTOFFSET(Esi) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Edx) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%ecx\n", CONTEXTOFFSET(Ecx) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%ebx\n", CONTEXTOFFSET(Ebx) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%edi\n", CONTEXTOFFSET(Edi) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%esi\n", CONTEXTOFFSET(Esi) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%edx\n", CONTEXTOFFSET(Edx) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%ebx\n", CONTEXTOFFSET(Ebx) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%eax\n", CONTEXTOFFSET(Eax) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%ebp\n", CONTEXTOFFSET(Ebp) );
|
||||
|
||||
fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(EFlags) - STACK_SPACE );
|
||||
fprintf( outfile, "\tpopfl\n" );
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegSs) );
|
||||
fprintf( outfile, "\tpopl %%ss\n" );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%esp\n", CONTEXTOFFSET(Esp) );
|
||||
|
||||
fprintf( outfile, "\tmovl %d(%%ebp),%%ebp\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
|
||||
fprintf( outfile, "\tleal -8(%%ebp),%%esp\n" );
|
||||
fprintf( outfile, "\tpopl %%ebp\n" );
|
||||
fprintf( outfile, "\tret\n" );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(EFlags) );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegCs) );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(Eip) );
|
||||
fprintf( outfile, "\tpushl %d(%%ecx)\n", CONTEXTOFFSET(SegDs) );
|
||||
fprintf( outfile, "\tmovl %d(%%ecx),%%ecx\n", CONTEXTOFFSET(Ecx) );
|
||||
|
||||
fprintf( outfile, "\tpopl %%ds\n" );
|
||||
fprintf( outfile, "\tiret\n" );
|
||||
|
||||
function_header( outfile, "__wine_call_from_32_restore_regs" );
|
||||
fprintf( outfile, "\tleal 4(%%esp),%%ecx\n" );
|
||||
fprintf( outfile, "\tjmp 2b\n" );
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue