ntdll: Use a .seh handler for the unwind exception handler.
This commit is contained in:
parent
658a0665d4
commit
f704b80a26
3 changed files with 87 additions and 58 deletions
|
@ -205,37 +205,67 @@ 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
|
||||||
*
|
*
|
||||||
|
@ -243,20 +273,13 @@ static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_
|
||||||
*/
|
*/
|
||||||
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,37 +206,50 @@ 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 TargetPc */
|
||||||
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
|
||||||
|
*/
|
||||||
|
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
|
||||||
*
|
*
|
||||||
|
@ -244,20 +257,13 @@ static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
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 );
|
||||||
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 */
|
||||||
|
|
Loading…
Add table
Reference in a new issue