ntdll: Add support for calling the TEB exception chain handlers on x86_64.

oldstable
Alexandre Julliard 2009-06-17 19:39:41 +02:00
parent c152b4e7d1
commit 98b8160b73
1 changed files with 90 additions and 0 deletions

View File

@ -1446,6 +1446,40 @@ static NTSTATUS call_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatc
}
/**********************************************************************
* call_teb_handler
*
* Call a single exception handler from the TEB chain.
* FIXME: Handle nested exceptions.
*/
static NTSTATUS call_teb_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
EXCEPTION_REGISTRATION_RECORD *teb_frame, CONTEXT *orig_context )
{
EXCEPTION_REGISTRATION_RECORD *dispatcher;
DWORD res;
TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatcher=%p)\n",
teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, &dispatcher );
res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, &dispatcher );
TRACE( "handler at %p returned %u\n", teb_frame->Handler, res );
switch (res)
{
case ExceptionContinueExecution:
if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
*orig_context = *dispatch->ContextRecord;
return STATUS_SUCCESS;
case ExceptionContinueSearch:
break;
case ExceptionNestedException:
break;
default:
return STATUS_INVALID_DISPOSITION;
}
return STATUS_UNHANDLED_EXCEPTION;
}
/**********************************************************************
* call_stack_handlers
*
@ -1453,6 +1487,7 @@ static NTSTATUS call_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatc
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
{
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
UNWIND_HISTORY_TABLE table;
RUNTIME_FUNCTION *dir;
DISPATCHER_CONTEXT dispatch;
@ -1542,6 +1577,17 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
status = call_handler( rec, &dispatch, orig_context );
if (status != STATUS_UNHANDLED_EXCEPTION) return status;
}
/* hack: call wine handlers registered in the tib list */
else while ((ULONG64)teb_frame < new_context.Rsp)
{
TRACE( "found wine frame %p rsp %lx handler %p\n",
teb_frame, new_context.Rsp, teb_frame->Handler );
dispatch.EstablisherFrame = (ULONG64)teb_frame;
context = *orig_context;
status = call_teb_handler( rec, &dispatch, teb_frame, orig_context );
if (status != STATUS_UNHANDLED_EXCEPTION) return status;
teb_frame = teb_frame->Prev;
}
if (new_context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
context = new_context;
@ -2239,12 +2285,44 @@ static void call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *disp
}
/**********************************************************************
* call_teb_unwind_handler
*
* Call a single unwind handler from the TEB chain.
* FIXME: Handle nested exceptions.
*/
static void call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
EXCEPTION_REGISTRATION_RECORD *teb_frame )
{
EXCEPTION_REGISTRATION_RECORD *dispatcher;
DWORD res;
TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatcher=%p)\n",
teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, &dispatcher );
res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, &dispatcher );
TRACE( "handler at %p returned %u\n", teb_frame->Handler, res );
switch (res)
{
case ExceptionContinueSearch:
break;
case ExceptionCollidedUnwind:
FIXME( "ExceptionCollidedUnwind not supported yet\n" );
break;
default:
raise_status( STATUS_INVALID_DISPOSITION, rec );
break;
}
}
/*******************************************************************
* RtlUnwindEx (NTDLL.@)
*/
void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
ULONG64 retval, CONTEXT *orig_context, UNWIND_HISTORY_TABLE *table )
{
EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
EXCEPTION_RECORD record;
RUNTIME_FUNCTION *dir;
DISPATCHER_CONTEXT dispatch;
@ -2364,6 +2442,18 @@ void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD
}
call_unwind_handler( rec, &dispatch );
}
else /* hack: call builtin handlers registered in the tib list */
{
while ((ULONG64)teb_frame < new_context.Rsp && (ULONG64)teb_frame < end_frame)
{
TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler );
dispatch.EstablisherFrame = (ULONG64)teb_frame;
call_teb_unwind_handler( rec, &dispatch, teb_frame );
teb_frame = __wine_pop_frame( teb_frame );
}
if ((ULONG64)teb_frame == end_frame && end_frame < new_context.Rsp) break;
dispatch.EstablisherFrame = new_context.Rsp;
}
context = new_context;
}