ntdll: Use a common wrapper to call unwind handlers on ARM64.
This commit is contained in:
parent
d6285af1fc
commit
5f890e3ce9
1 changed files with 43 additions and 81 deletions
|
@ -200,81 +200,21 @@ EXCEPTION_DISPOSITION WINAPI unwind_exception_handler( EXCEPTION_RECORD *record,
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
|
DWORD WINAPI call_unwind_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame,
|
||||||
{
|
CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler );
|
||||||
DWORD res;
|
__ASM_GLOBAL_FUNC( call_unwind_handler,
|
||||||
|
"stp x29, x30, [sp, #-32]!\n\t"
|
||||||
TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n",
|
".seh_save_fplr_x 32\n\t"
|
||||||
dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
|
".seh_endprologue\n\t"
|
||||||
res = unwind_handler_wrapper( rec, dispatch );
|
".seh_handler unwind_exception_handler, @except\n\t"
|
||||||
TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res );
|
"str x3, [sp, #16]\n\t" /* frame[-2] = dispatch */
|
||||||
|
"blr x4\n\t"
|
||||||
switch (res)
|
"ldp x29, x30, [sp], #32\n\t"
|
||||||
{
|
"ret" )
|
||||||
case ExceptionContinueSearch:
|
|
||||||
case ExceptionCollidedUnwind:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
raise_status( STATUS_INVALID_DISPOSITION, rec );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* call_teb_unwind_handler
|
|
||||||
*
|
|
||||||
* Call a single unwind handler from the TEB chain.
|
|
||||||
*/
|
|
||||||
static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
|
|
||||||
EXCEPTION_REGISTRATION_RECORD *teb_frame )
|
|
||||||
{
|
|
||||||
DWORD res;
|
|
||||||
|
|
||||||
TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
|
|
||||||
teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
|
|
||||||
res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
|
|
||||||
TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res );
|
|
||||||
|
|
||||||
switch (res)
|
|
||||||
{
|
|
||||||
case ExceptionContinueSearch:
|
|
||||||
case ExceptionCollidedUnwind:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
raise_status( STATUS_INVALID_DISPOSITION, rec );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -601,7 +541,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
||||||
CONTEXT new_context;
|
CONTEXT new_context;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
ULONG_PTR frame;
|
ULONG_PTR frame;
|
||||||
DWORD i;
|
DWORD i, res;
|
||||||
|
|
||||||
RtlCaptureContext( context );
|
RtlCaptureContext( context );
|
||||||
new_context = *context;
|
new_context = *context;
|
||||||
|
@ -654,8 +594,20 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
||||||
raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
|
raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
|
||||||
}
|
}
|
||||||
if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
|
if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
|
||||||
if (call_unwind_handler( rec, &dispatch ) == ExceptionCollidedUnwind)
|
|
||||||
|
TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n",
|
||||||
|
dispatch.LanguageHandler, rec, dispatch.EstablisherFrame,
|
||||||
|
dispatch.ContextRecord, &dispatch );
|
||||||
|
res = call_unwind_handler( rec, dispatch.EstablisherFrame, dispatch.ContextRecord,
|
||||||
|
&dispatch, dispatch.LanguageHandler );
|
||||||
|
TRACE( "handler %p returned %lx\n", dispatch.LanguageHandler, res );
|
||||||
|
|
||||||
|
switch (res)
|
||||||
{
|
{
|
||||||
|
case ExceptionContinueSearch:
|
||||||
|
rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
|
||||||
|
break;
|
||||||
|
case ExceptionCollidedUnwind:
|
||||||
new_context = *context;
|
new_context = *context;
|
||||||
RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
|
RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
|
||||||
dispatch.ControlPc, dispatch.FunctionEntry,
|
dispatch.ControlPc, dispatch.FunctionEntry,
|
||||||
|
@ -663,21 +615,30 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
||||||
NULL );
|
NULL );
|
||||||
rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
|
rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
|
||||||
goto unwind_done;
|
goto unwind_done;
|
||||||
|
default:
|
||||||
|
raise_status( STATUS_INVALID_DISPOSITION, rec );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
|
|
||||||
}
|
}
|
||||||
else /* hack: call builtin handlers registered in the tib list */
|
else /* hack: call builtin handlers registered in the tib list */
|
||||||
{
|
{
|
||||||
DWORD64 backup_frame = dispatch.EstablisherFrame;
|
|
||||||
while (is_valid_frame( (ULONG_PTR)teb_frame ) &&
|
while (is_valid_frame( (ULONG_PTR)teb_frame ) &&
|
||||||
(ULONG64)teb_frame < new_context.Sp &&
|
(ULONG64)teb_frame < new_context.Sp &&
|
||||||
(ULONG64)teb_frame < (ULONG64)end_frame)
|
(ULONG64)teb_frame < (ULONG64)end_frame)
|
||||||
{
|
{
|
||||||
TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler );
|
TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
|
||||||
dispatch.EstablisherFrame = (ULONG64)teb_frame;
|
teb_frame->Handler, rec, teb_frame, dispatch.ContextRecord, &dispatch );
|
||||||
if (call_teb_unwind_handler( rec, &dispatch, teb_frame ) == ExceptionCollidedUnwind)
|
res = call_unwind_handler( rec, (ULONG_PTR)teb_frame, dispatch.ContextRecord, &dispatch,
|
||||||
|
(PEXCEPTION_ROUTINE)teb_frame->Handler );
|
||||||
|
TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res );
|
||||||
|
teb_frame = __wine_pop_frame( teb_frame );
|
||||||
|
|
||||||
|
switch (res)
|
||||||
{
|
{
|
||||||
teb_frame = __wine_pop_frame( teb_frame );
|
case ExceptionContinueSearch:
|
||||||
|
rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND;
|
||||||
|
break;
|
||||||
|
case ExceptionCollidedUnwind:
|
||||||
new_context = *context;
|
new_context = *context;
|
||||||
RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
|
RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
|
||||||
dispatch.ControlPc, dispatch.FunctionEntry,
|
dispatch.ControlPc, dispatch.FunctionEntry,
|
||||||
|
@ -685,11 +646,12 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
|
||||||
&frame, NULL );
|
&frame, NULL );
|
||||||
rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
|
rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
|
||||||
goto unwind_done;
|
goto unwind_done;
|
||||||
|
default:
|
||||||
|
raise_status( STATUS_INVALID_DISPOSITION, rec );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
teb_frame = __wine_pop_frame( teb_frame );
|
|
||||||
}
|
}
|
||||||
if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Sp) break;
|
if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Sp) break;
|
||||||
dispatch.EstablisherFrame = backup_frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dispatch.EstablisherFrame == (ULONG64)end_frame) break;
|
if (dispatch.EstablisherFrame == (ULONG64)end_frame) break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue