Commit c5a57e7d authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Move NtRaiseException and RtlUnwind implementations to the CPU-specific files.

parent 53169b98
......@@ -41,7 +41,8 @@ struct drive_info
/* exceptions */
extern void wait_suspend( CONTEXT *context );
extern NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance );
extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context );
extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context );
extern void raise_status( NTSTATUS status, EXCEPTION_RECORD *rec ) DECLSPEC_NORETURN;
extern void set_cpu_context( const CONTEXT *context );
extern void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags );
......
......@@ -465,6 +465,16 @@ enum i386_trap_code
#endif
};
/* Exception record for handling exceptions happening inside exception handlers */
typedef struct
{
EXCEPTION_REGISTRATION_RECORD frame;
EXCEPTION_REGISTRATION_RECORD *prevFrame;
} EXC_NESTED_FRAME;
extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher,
PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler );
/***********************************************************************
* dispatch_signal
......@@ -528,6 +538,164 @@ static inline TEB *get_current_teb(void)
}
/*******************************************************************
* raise_handler
*
* Handler for exceptions happening inside a handler.
*/
static DWORD raise_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
{
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
return ExceptionContinueSearch;
/* We shouldn't get here so we store faulty frame in dispatcher */
*dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
return ExceptionNestedException;
}
/*******************************************************************
* unwind_handler
*
* Handler for exceptions happening inside an unwind handler.
*/
static DWORD unwind_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
{
if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
return ExceptionContinueSearch;
/* We shouldn't get here so we store faulty frame in dispatcher */
*dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
return ExceptionCollidedUnwind;
}
/**********************************************************************
* call_stack_handlers
*
* Call the stack handlers chain.
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
{
EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
DWORD res;
frame = NtCurrentTeb()->Tib.ExceptionList;
nested_frame = NULL;
while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
{
/* Check frame address */
if (((void*)frame < NtCurrentTeb()->Tib.StackLimit) ||
((void*)(frame+1) > NtCurrentTeb()->Tib.StackBase) ||
(ULONG_PTR)frame & 3)
{
rec->ExceptionFlags |= EH_STACK_INVALID;
break;
}
/* Call handler */
TRACE( "calling handler at %p code=%x flags=%x\n",
frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, raise_handler );
TRACE( "handler at %p returned %x\n", frame->Handler, res );
if (frame == nested_frame)
{
/* no longer nested */
nested_frame = NULL;
rec->ExceptionFlags &= ~EH_NESTED_CALL;
}
switch(res)
{
case ExceptionContinueExecution:
if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
return STATUS_NONCONTINUABLE_EXCEPTION;
case ExceptionContinueSearch:
break;
case ExceptionNestedException:
if (nested_frame < dispatch) nested_frame = dispatch;
rec->ExceptionFlags |= EH_NESTED_CALL;
break;
default:
return STATUS_INVALID_DISPOSITION;
}
frame = frame->Prev;
}
return STATUS_UNHANDLED_EXCEPTION;
}
/*******************************************************************
* raise_exception
*
* Implementation of NtRaiseException.
*/
static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status;
if (first_chance)
{
DWORD c;
TRACE( "code=%x flags=%x addr=%p ip=%08x tid=%04x\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
context->Eip, GetCurrentThreadId() );
for (c = 0; c < rec->NumberParameters; c++)
TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
{
if (rec->ExceptionInformation[1] >> 16)
MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
else
MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
}
else
{
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 );
}
status = send_debug_event( rec, TRUE, context );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
return STATUS_SUCCESS;
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
return STATUS_SUCCESS;
if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
return status;
}
/* last chance exception */
status = send_debug_event( rec, FALSE, context );
if (status != DBG_CONTINUE)
{
if (rec->ExceptionFlags & EH_STACK_INVALID)
WINE_ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
WINE_ERR("Process attempted to continue execution after noncontinuable exception.\n");
else
WINE_ERR("Unhandled exception code %x flags %x addr %p\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
NtTerminateProcess( NtCurrentProcess(), 1 );
}
return STATUS_SUCCESS;
}
#ifdef __HAVE_VM86
/***********************************************************************
* save_vm86_context
......@@ -2008,6 +2176,80 @@ void __wine_enter_vm86( CONTEXT *context )
#endif /* __HAVE_VM86 */
/*******************************************************************
* RtlUnwind (NTDLL.@)
*/
void WINAPI __regs_RtlUnwind( EXCEPTION_REGISTRATION_RECORD* pEndFrame, PVOID targetIp,
PEXCEPTION_RECORD pRecord, PVOID retval, CONTEXT *context )
{
EXCEPTION_RECORD record;
EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
DWORD res;
context->Eax = (DWORD)retval;
/* build an exception record, if we do not have one */
if (!pRecord)
{
record.ExceptionCode = STATUS_UNWIND;
record.ExceptionFlags = 0;
record.ExceptionRecord = NULL;
record.ExceptionAddress = (void *)context->Eip;
record.NumberParameters = 0;
pRecord = &record;
}
pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
TRACE( "code=%x flags=%x\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );
/* get chain of exception frames */
frame = NtCurrentTeb()->Tib.ExceptionList;
while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != pEndFrame))
{
/* Check frame address */
if (pEndFrame && (frame > pEndFrame))
raise_status( STATUS_INVALID_UNWIND_TARGET, pRecord );
if (((void*)frame < NtCurrentTeb()->Tib.StackLimit) ||
((void*)(frame+1) > NtCurrentTeb()->Tib.StackBase) ||
(UINT_PTR)frame & 3)
raise_status( STATUS_BAD_STACK, pRecord );
/* Call handler */
TRACE( "calling handler at %p code=%x flags=%x\n",
frame->Handler, pRecord->ExceptionCode, pRecord->ExceptionFlags );
res = EXC_CallHandler( pRecord, frame, context, &dispatch, frame->Handler, unwind_handler );
TRACE( "handler at %p returned %x\n", frame->Handler, res );
switch(res)
{
case ExceptionContinueSearch:
break;
case ExceptionCollidedUnwind:
frame = dispatch;
break;
default:
raise_status( STATUS_INVALID_DISPOSITION, pRecord );
break;
}
frame = __wine_pop_frame( frame );
}
}
DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
/*******************************************************************
* NtRaiseException (NTDLL.@)
*/
NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status = raise_exception( rec, context, first_chance );
if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
return status;
}
/***********************************************************************
* RtlRaiseException (NTDLL.@)
*/
......
......@@ -610,6 +610,89 @@ static inline DWORD get_fpu_code( const CONTEXT *context )
return EXCEPTION_FLT_INVALID_OPERATION; /* generic error */
}
/**********************************************************************
* call_stack_handlers
*
* Call the stack handlers chain.
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
{
EXCEPTION_POINTERS ptrs;
FIXME( "not implemented on PowerPC\n" );
/* hack: call unhandled exception filter directly */
ptrs.ExceptionRecord = rec;
ptrs.ContextRecord = context;
unhandled_exception_filter( &ptrs );
return STATUS_UNHANDLED_EXCEPTION;
}
/*******************************************************************
* raise_exception
*
* Implementation of NtRaiseException.
*/
static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status;
if (first_chance)
{
DWORD c;
TRACE( "code=%x flags=%x addr=%p ip=%x tid=%04x\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
context->Iar, GetCurrentThreadId() );
for (c = 0; c < rec->NumberParameters; c++)
TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
{
if (rec->ExceptionInformation[1] >> 16)
MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
else
MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
}
else
{
/* FIXME: dump context */
}
status = send_debug_event( rec, TRUE, context );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
return STATUS_SUCCESS;
if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
return STATUS_SUCCESS;
if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
return status;
}
/* last chance exception */
status = send_debug_event( rec, FALSE, context );
if (status != DBG_CONTINUE)
{
if (rec->ExceptionFlags & EH_STACK_INVALID)
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
ERR("Process attempted to continue execution after noncontinuable exception.\n");
else
ERR("Unhandled exception code %x flags %x addr %p\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
NtTerminateProcess( NtCurrentProcess(), 1 );
}
return STATUS_SUCCESS;
}
/**********************************************************************
* do_segv
*
......@@ -1002,6 +1085,24 @@ void __wine_enter_vm86( CONTEXT *context )
}
/***********************************************************************
* RtlUnwind (NTDLL.@)
*/
void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
{
FIXME( "Not implemented on PowerPC\n" );
}
/*******************************************************************
* NtRaiseException (NTDLL.@)
*/
NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status = raise_exception( rec, context, first_chance );
if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
return status;
}
/***********************************************************************
* RtlRaiseException (NTDLL.@)
*/
void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
......
......@@ -152,6 +152,88 @@ static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
}
/**********************************************************************
* call_stack_handlers
*
* Call the stack handlers chain.
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
{
EXCEPTION_POINTERS ptrs;
FIXME( "not implemented on Sparc\n" );
/* hack: call unhandled exception filter directly */
ptrs.ExceptionRecord = rec;
ptrs.ContextRecord = context;
unhandled_exception_filter( &ptrs );
return STATUS_UNHANDLED_EXCEPTION;
}
/*******************************************************************
* raise_exception
*
* Implementation of NtRaiseException.
*/
static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status;
if (first_chance)
{
DWORD c;
TRACE( "code=%x flags=%x addr=%p ip=%x tid=%04x\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
context->pc, GetCurrentThreadId() );
for (c = 0; c < rec->NumberParameters; c++)
TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
{
if (rec->ExceptionInformation[1] >> 16)
MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
else
MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
}
else
{
/* FIXME: dump context */
}
status = send_debug_event( rec, TRUE, context );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
return STATUS_SUCCESS;
if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
return STATUS_SUCCESS;
if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
return status;
}
/* last chance exception */
status = send_debug_event( rec, FALSE, context );
if (status != DBG_CONTINUE)
{
if (rec->ExceptionFlags & EH_STACK_INVALID)
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
ERR("Process attempted to continue execution after noncontinuable exception.\n");
else
ERR("Unhandled exception code %x flags %x addr %p\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
NtTerminateProcess( NtCurrentProcess(), 1 );
}
return STATUS_SUCCESS;
}
/***********************************************************************
* RtlCaptureContext (NTDLL.@)
*/
......@@ -716,6 +798,24 @@ void __wine_enter_vm86( CONTEXT *context )
}
/***********************************************************************
* RtlUnwind (NTDLL.@)
*/
void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
{
FIXME( "Not implemented on Sparc\n" );
}
/*******************************************************************
* NtRaiseException (NTDLL.@)
*/
NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status = raise_exception( rec, context, first_chance );
if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
return status;
}
/***********************************************************************
* RtlRaiseException (NTDLL.@)
*/
void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
......
......@@ -470,6 +470,94 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
/**********************************************************************
* call_stack_handlers
*
* Call the stack handlers chain.
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
{
EXCEPTION_POINTERS ptrs;
FIXME( "not implemented on x86_64\n" );
/* hack: call unhandled exception filter directly */
ptrs.ExceptionRecord = rec;
ptrs.ContextRecord = context;
unhandled_exception_filter( &ptrs );
return STATUS_UNHANDLED_EXCEPTION;
}
/*******************************************************************
* raise_exception
*
* Implementation of NtRaiseException.
*/
static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status;
if (first_chance)
{
DWORD c;
TRACE( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
context->Rip, GetCurrentThreadId() );
for (c = 0; c < rec->NumberParameters; c++)
TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
{
if (rec->ExceptionInformation[1] >> 16)
MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
else
MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
rec->ExceptionAddress,
(char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
}
else
{
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 );
}
status = send_debug_event( rec, TRUE, context );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
return STATUS_SUCCESS;
if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
return STATUS_SUCCESS;
if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
return status;
}
/* last chance exception */
status = send_debug_event( rec, FALSE, context );
if (status != DBG_CONTINUE)
{
if (rec->ExceptionFlags & EH_STACK_INVALID)
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
ERR("Process attempted to continue execution after noncontinuable exception.\n");
else
ERR("Unhandled exception code %x flags %x addr %p\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
}
return STATUS_SUCCESS;
}
/**********************************************************************
* segv_handler
*
* Handler for SIGSEGV and related errors.
......@@ -804,6 +892,45 @@ PVOID WINAPI RtlVirtualUnwind ( ULONG type, ULONG64 base, ULONG64 pc,
}
/*******************************************************************
* RtlUnwind (NTDLL.@)
*/
void WINAPI __regs_RtlUnwind( EXCEPTION_REGISTRATION_RECORD* pEndFrame, PVOID targetIp,
PEXCEPTION_RECORD pRecord, PVOID retval, CONTEXT *context )
{
EXCEPTION_RECORD record;
/* build an exception record, if we do not have one */
if (!pRecord)
{
record.ExceptionCode = STATUS_UNWIND;
record.ExceptionFlags = 0;
record.ExceptionRecord = NULL;
record.ExceptionAddress = (void *)context->Rip;
record.NumberParameters = 0;
pRecord = &record;
}
pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
FIXME( "code=%x flags=%x not implemented on x86_64\n",
pRecord->ExceptionCode, pRecord->ExceptionFlags );
NtTerminateProcess( GetCurrentProcess(), 1 );
}
DEFINE_REGS_ENTRYPOINT( RtlUnwind, 4 )
/*******************************************************************
* NtRaiseException (NTDLL.@)
*/
NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
{
NTSTATUS status = raise_exception( rec, context, first_chance );
if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
return status;
}
/***********************************************************************
* RtlRaiseException (NTDLL.@)
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment