Commit f704b80a authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Use a .seh handler for the unwind exception handler.

parent 658a0665
...@@ -205,58 +205,81 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX ...@@ -205,58 +205,81 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
} }
struct unwind_exception_frame
{
EXCEPTION_REGISTRATION_RECORD frame;
DISPATCHER_CONTEXT *dispatch;
};
/********************************************************************** /**********************************************************************
* unwind_exception_handler * unwind_exception_handler
* *
* Handler for exceptions happening while calling an unwind handler. * Handler for exceptions happening while calling an unwind handler.
*/ */
static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, EXCEPTION_DISPOSITION WINAPI unwind_exception_handler( EXCEPTION_RECORD *record, void *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
{ {
struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame; DISPATCHER_CONTEXT *orig_dispatch = ((DISPATCHER_CONTEXT **)frame)[-2];
DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher;
/* copy the original dispatcher into the current one, except for the TargetIp */ /* copy the original dispatcher into the current one, except for the TargetIp */
dispatch->ControlPc = unwind_frame->dispatch->ControlPc; dispatch->ControlPc = orig_dispatch->ControlPc;
dispatch->ImageBase = unwind_frame->dispatch->ImageBase; dispatch->ImageBase = orig_dispatch->ImageBase;
dispatch->FunctionEntry = unwind_frame->dispatch->FunctionEntry; dispatch->FunctionEntry = orig_dispatch->FunctionEntry;
dispatch->EstablisherFrame = unwind_frame->dispatch->EstablisherFrame; dispatch->EstablisherFrame = orig_dispatch->EstablisherFrame;
dispatch->ContextRecord = unwind_frame->dispatch->ContextRecord; dispatch->ContextRecord = orig_dispatch->ContextRecord;
dispatch->LanguageHandler = unwind_frame->dispatch->LanguageHandler; dispatch->LanguageHandler = orig_dispatch->LanguageHandler;
dispatch->HandlerData = unwind_frame->dispatch->HandlerData; dispatch->HandlerData = orig_dispatch->HandlerData;
dispatch->HistoryTable = unwind_frame->dispatch->HistoryTable; dispatch->HistoryTable = orig_dispatch->HistoryTable;
dispatch->ScopeIndex = unwind_frame->dispatch->ScopeIndex; dispatch->ScopeIndex = orig_dispatch->ScopeIndex;
TRACE( "detected collided unwind\n" ); TRACE( "detected collided unwind\n" );
return ExceptionCollidedUnwind; return ExceptionCollidedUnwind;
} }
/********************************************************************** /**********************************************************************
* unwind_handler_wrapper
*/
#ifdef __WINE_PE_BUILD
extern DWORD WINAPI unwind_handler_wrapper( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch );
__ASM_GLOBAL_FUNC( unwind_handler_wrapper,
"push {r1,lr}\n\t"
".seh_save_regs {r1,lr}\n\t"
".seh_endprologue\n\t"
".seh_handler " __ASM_NAME("unwind_exception_handler") ", %except, %unwind\n\t"
"mov r3, r1\n\t" /* dispatch */
"ldr r1, [r3, #0x0c]\n\t" /* dispatch->EstablisherFrame */
"ldr r2, [r3, #0x14]\n\t" /* dispatch->ContextRecord */
"ldr ip, [r3, #0x18]\n\t" /* dispatch->LanguageHandler */
"blx ip\n\t"
"pop {r1,pc}\n\t" )
#else
static DWORD unwind_handler_wrapper( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
{
struct
{
DISPATCHER_CONTEXT *dispatch;
ULONG lr;
EXCEPTION_REGISTRATION_RECORD frame;
} frame;
DWORD res;
frame.frame.Handler = (PEXCEPTION_HANDLER)unwind_exception_handler;
frame.dispatch = dispatch;
__wine_push_frame( &frame.frame );
res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
__wine_pop_frame( &frame.frame );
return res;
}
#endif
/**********************************************************************
* call_unwind_handler * call_unwind_handler
* *
* Call a single unwind handler. * Call a single unwind handler.
*/ */
static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
{ {
struct unwind_exception_frame frame;
DWORD res; DWORD res;
frame.frame.Handler = unwind_exception_handler;
frame.dispatch = dispatch;
__wine_push_frame( &frame.frame );
TRACE( "calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)\n", TRACE( "calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)\n",
dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); res = unwind_handler_wrapper( rec, dispatch );
TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res ); TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res );
__wine_pop_frame( &frame.frame );
switch (res) switch (res)
{ {
case ExceptionContinueSearch: case ExceptionContinueSearch:
......
...@@ -206,58 +206,64 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX ...@@ -206,58 +206,64 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
} }
struct unwind_exception_frame
{
EXCEPTION_REGISTRATION_RECORD frame;
DISPATCHER_CONTEXT *dispatch;
};
/********************************************************************** /**********************************************************************
* unwind_exception_handler * unwind_exception_handler
* *
* Handler for exceptions happening while calling an unwind handler. * Handler for exceptions happening while calling an unwind handler.
*/ */
static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, EXCEPTION_DISPOSITION WINAPI unwind_exception_handler( EXCEPTION_RECORD *record, void *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
{ {
struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame; DISPATCHER_CONTEXT *orig_dispatch = ((DISPATCHER_CONTEXT **)frame)[-2];
DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher;
/* copy the original dispatcher into the current one, except for the TargetPc */
/* copy the original dispatcher into the current one, except for the TargetIp */ dispatch->ControlPc = orig_dispatch->ControlPc;
dispatch->ControlPc = unwind_frame->dispatch->ControlPc; dispatch->ImageBase = orig_dispatch->ImageBase;
dispatch->ImageBase = unwind_frame->dispatch->ImageBase; dispatch->FunctionEntry = orig_dispatch->FunctionEntry;
dispatch->FunctionEntry = unwind_frame->dispatch->FunctionEntry; dispatch->EstablisherFrame = orig_dispatch->EstablisherFrame;
dispatch->EstablisherFrame = unwind_frame->dispatch->EstablisherFrame; dispatch->ContextRecord = orig_dispatch->ContextRecord;
dispatch->ContextRecord = unwind_frame->dispatch->ContextRecord; dispatch->LanguageHandler = orig_dispatch->LanguageHandler;
dispatch->LanguageHandler = unwind_frame->dispatch->LanguageHandler; dispatch->HandlerData = orig_dispatch->HandlerData;
dispatch->HandlerData = unwind_frame->dispatch->HandlerData; dispatch->HistoryTable = orig_dispatch->HistoryTable;
dispatch->HistoryTable = unwind_frame->dispatch->HistoryTable; dispatch->ScopeIndex = orig_dispatch->ScopeIndex;
dispatch->ScopeIndex = unwind_frame->dispatch->ScopeIndex;
TRACE( "detected collided unwind\n" ); TRACE( "detected collided unwind\n" );
return ExceptionCollidedUnwind; return ExceptionCollidedUnwind;
} }
/********************************************************************** /**********************************************************************
* unwind_handler_wrapper
*/
extern DWORD WINAPI unwind_handler_wrapper( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch );
__ASM_GLOBAL_FUNC( unwind_handler_wrapper,
"stp x29, x30, [sp, #-32]!\n\t"
".seh_save_fplr_x 32\n\t"
"mov x29, sp\n\t"
".seh_set_fp\n\t"
".seh_endprologue\n\t"
".seh_handler " __ASM_NAME("unwind_exception_handler") ", @except, @unwind\n\t"
"str x1, [sp, #16]\n\t" /* frame[-2] = dispatch */
"mov x3, x1\n\t"
"ldr x1, [x3, #0x18]\n\t" /* dispatch->EstablisherFrame */
"ldr x2, [x3, #0x28]\n\t" /* dispatch->ContextRecord */
"ldr x15, [x3, #0x30]\n\t" /* dispatch->LanguageHandler */
"blr x15\n\t"
"ldp x29, x30, [sp], #32\n\t"
"ret" )
/**********************************************************************
* call_unwind_handler * call_unwind_handler
* *
* Call a single unwind handler. * Call a single unwind handler.
*/ */
static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
{ {
struct unwind_exception_frame frame;
DWORD res; DWORD res;
frame.frame.Handler = unwind_exception_handler;
frame.dispatch = dispatch;
__wine_push_frame( &frame.frame );
TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n", TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n",
dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); res = unwind_handler_wrapper( rec, dispatch );
TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res ); TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res );
__wine_pop_frame( &frame.frame );
switch (res) switch (res)
{ {
case ExceptionContinueSearch: case ExceptionContinueSearch:
......
...@@ -367,9 +367,9 @@ DWORD WINAPI exception_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, ...@@ -367,9 +367,9 @@ DWORD WINAPI exception_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame,
C_ASSERT( offsetof(DISPATCHER_CONTEXT, LanguageHandler) == 0x30 ); C_ASSERT( offsetof(DISPATCHER_CONTEXT, LanguageHandler) == 0x30 );
__ASM_GLOBAL_FUNC( exception_handler_call_wrapper, __ASM_GLOBAL_FUNC( exception_handler_call_wrapper,
".seh_endprologue\n\t"
"subq $0x28, %rsp\n\t" "subq $0x28, %rsp\n\t"
".seh_stackalloc 0x28\n\t" ".seh_stackalloc 0x28\n\t"
".seh_endprologue\n\t"
"callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */
"nop\n\t" /* avoid epilogue so handler is called */ "nop\n\t" /* avoid epilogue so handler is called */
"addq $0x28, %rsp\n\t" "addq $0x28, %rsp\n\t"
...@@ -1076,9 +1076,9 @@ C_ASSERT( offsetof(struct unwind_exception_frame, dispatch) == 0x20 ); ...@@ -1076,9 +1076,9 @@ C_ASSERT( offsetof(struct unwind_exception_frame, dispatch) == 0x20 );
C_ASSERT( offsetof(DISPATCHER_CONTEXT, LanguageHandler) == 0x30 ); C_ASSERT( offsetof(DISPATCHER_CONTEXT, LanguageHandler) == 0x30 );
__ASM_GLOBAL_FUNC( unwind_handler_call_wrapper, __ASM_GLOBAL_FUNC( unwind_handler_call_wrapper,
".seh_endprologue\n\t"
"subq $0x28,%rsp\n\t" "subq $0x28,%rsp\n\t"
".seh_stackalloc 0x28\n\t" ".seh_stackalloc 0x28\n\t"
".seh_endprologue\n\t"
"movq %r9,0x20(%rsp)\n\t" /* unwind_exception_frame->dispatch */ "movq %r9,0x20(%rsp)\n\t" /* unwind_exception_frame->dispatch */
"callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */
"nop\n\t" /* avoid epilogue so handler is called */ "nop\n\t" /* avoid epilogue so handler is called */
......
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