ntdll: Initial support for dispatching exceptions to stack handlers on x86_64.

This commit is contained in:
Alexandre Julliard 2009-05-22 11:52:13 +02:00
parent 7634ce154a
commit ad7b282439
1 changed files with 103 additions and 6 deletions

View File

@ -52,6 +52,27 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh);
struct _DISPATCHER_CONTEXT;
typedef EXCEPTION_DISPOSITION (WINAPI *PEXCEPTION_ROUTINE)( EXCEPTION_RECORD *rec,
ULONG64 frame,
CONTEXT *context,
struct _DISPATCHER_CONTEXT *dispatch );
typedef struct _DISPATCHER_CONTEXT
{
ULONG64 ControlPc;
ULONG64 ImageBase;
PRUNTIME_FUNCTION FunctionEntry;
ULONG64 EstablisherFrame;
ULONG64 TargetIp;
PCONTEXT ContextRecord;
PEXCEPTION_ROUTINE LanguageHandler;
PVOID HandlerData;
PUNWIND_HISTORY_TABLE HistoryTable;
ULONG ScopeIndex;
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
/***********************************************************************
* signal context platform-specific definitions
@ -649,15 +670,92 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
*
* Call the stack handlers chain.
*/
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
{
EXCEPTION_POINTERS ptrs;
UNWIND_HISTORY_TABLE table;
ULONG64 frame;
RUNTIME_FUNCTION *dir, *info;
PEXCEPTION_ROUTINE handler;
DISPATCHER_CONTEXT dispatch;
CONTEXT context, new_context;
LDR_MODULE *module;
DWORD size;
FIXME( "not implemented on x86_64\n" );
context = *orig_context;
for (;;)
{
/* FIXME: should use the history table to make things faster */
if (LdrFindEntryForAddress( (void *)context.Rip, &module ))
{
ERR( "no module found for rip %p, can't dispatch exception\n", (void *)context.Rip );
break;
}
if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
{
ERR( "module %s doesn't contain exception data, can't dispatch exception\n",
debugstr_w(module->BaseDllName.Buffer) );
break;
}
if (!(info = find_function_info( context.Rip, module->BaseAddress, dir, size )))
{
/* leaf function */
context.Rip = *(ULONG64 *)context.Rsp;
context.Rsp += sizeof(ULONG64);
continue;
}
new_context = context;
handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)module->BaseAddress, context.Rip,
info, &new_context, &dispatch.HandlerData, &frame, NULL );
if ((frame & 7) ||
frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
{
ERR( "invalid frame %lx\n", frame );
rec->ExceptionFlags |= EH_STACK_INVALID;
break;
}
if (handler)
{
dispatch.ControlPc = context.Rip;
dispatch.ImageBase = (ULONG64)module->BaseAddress;
dispatch.FunctionEntry = info;
dispatch.EstablisherFrame = frame;
dispatch.TargetIp = 0; /* FIXME */
dispatch.ContextRecord = &context;
dispatch.LanguageHandler = handler;
dispatch.HistoryTable = &table;
dispatch.ScopeIndex = 0; /* FIXME */
TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
handler, rec, frame, &context, &dispatch );
switch( handler( rec, frame, &context, &dispatch ))
{
case ExceptionContinueExecution:
if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
*orig_context = context;
return STATUS_SUCCESS;
case ExceptionContinueSearch:
break;
case ExceptionNestedException:
break;
default:
return STATUS_INVALID_DISPOSITION;
}
}
context = new_context;
}
/* hack: call unhandled exception filter directly */
ptrs.ExceptionRecord = rec;
ptrs.ContextRecord = context;
ptrs.ContextRecord = orig_context;
unhandled_exception_filter( &ptrs );
return STATUS_UNHANDLED_EXCEPTION;
}
@ -679,7 +777,7 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f
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++)
for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
{
@ -1241,8 +1339,7 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
unsigned int i, prolog_offset;
TRACE( "type %x rip %lx rsp %lx\n", type, pc, context->Rsp );
dump_unwind_info( base, function );
if (TRACE_ON(seh)) dump_unwind_info( base, function );
frame = *frame_ret = context->Rsp;
for (;;)