ntdll: Fix unwinding functions that end with a branch instruction.
This happens with functions that aren't intended to return e.g. like _Unwind_Resume. In these cases, the return address is outside of the function (the first instruction in the next function). Set the flag CONTEXT_UNWOUND_TO_CALL after unwinding to a callsite, and if this flag is set, look up a RUNTIME_FUNCTION based on Control.Pc - 4. This isn't a complete (nor probably entirely correct) implementation of the flag CONTEXT_UNWOUND_TO_CALL, but it practically seems to work fine and fixes a large number of unwinding cases. Signed-off-by: Martin Storsjo <martin@martin.st> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
42a5885669
commit
babbf352b6
|
@ -527,6 +527,7 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
|
|||
*frame = context->Sp;
|
||||
context->Pc = context->u.s.Lr;
|
||||
context->Sp = context->Sp + sizeof(ULONG64);
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -577,6 +578,7 @@ static NTSTATUS libunwind_virtual_unwind( ULONG_PTR ip, ULONG_PTR *frame, CONTEX
|
|||
unw_get_reg( &cursor, UNW_AARCH64_X30, (unw_word_t *)&context->u.s.Lr );
|
||||
unw_get_reg( &cursor, UNW_AARCH64_SP, (unw_word_t *)&context->Sp );
|
||||
context->Pc = context->u.s.Lr;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
|
||||
TRACE( "next function pc=%016lx%s\n", context->Pc, rc ? "" : " (last frame)" );
|
||||
TRACE(" x0=%016lx x1=%016lx x2=%016lx x3=%016lx\n",
|
||||
|
@ -614,10 +616,17 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
|
|||
dispatch->ScopeIndex = 0;
|
||||
dispatch->EstablisherFrame = 0;
|
||||
dispatch->ControlPc = context->Pc;
|
||||
/*
|
||||
* TODO: CONTEXT_UNWOUND_TO_CALL should be cleared if unwound past a
|
||||
* signal frame.
|
||||
*/
|
||||
dispatch->ControlPcIsUnwound = (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0;
|
||||
|
||||
/* first look for PE exception information */
|
||||
|
||||
if ((dispatch->FunctionEntry = lookup_function_info( context->Pc, &dispatch->ImageBase, &module )))
|
||||
if ((dispatch->FunctionEntry = lookup_function_info(
|
||||
context->Pc - (dispatch->ControlPcIsUnwound ? 4 : 0),
|
||||
&dispatch->ImageBase, &module )))
|
||||
{
|
||||
dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Pc,
|
||||
dispatch->FunctionEntry, context,
|
||||
|
@ -654,6 +663,7 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX
|
|||
dispatch->EstablisherFrame = context->u.s.Fp;
|
||||
dispatch->LanguageHandler = NULL;
|
||||
context->Pc = context->u.s.Lr;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1758,6 +1768,7 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc,
|
|||
|
||||
TRACE( "ret: lr=%lx sp=%lx handler=%p\n", context->u.s.Lr, context->Sp, handler );
|
||||
context->Pc = context->u.s.Lr;
|
||||
context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
|
||||
*frame_ret = context->Sp;
|
||||
return handler;
|
||||
}
|
||||
|
|
|
@ -1863,6 +1863,8 @@ NTSYSAPI PVOID WINAPI RtlVirtualUnwind(DWORD,DWORD,DWORD,RUNTIME_FUNCTION*,CONTE
|
|||
#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x00000004)
|
||||
#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | 0x00000008)
|
||||
|
||||
#define CONTEXT_UNWOUND_TO_CALL 0x20000000
|
||||
|
||||
#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER)
|
||||
#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
|
||||
|
||||
|
|
Loading…
Reference in New Issue