Martin Storsjo : ntdll: Fix unwinding functions that end with a branch instruction.
Module: wine Branch: master Commit: babbf352b651dac6458335e71a980317b3b42386 URL: https://source.winehq.org/git/wine.git/?a=commit;h=babbf352b651dac6458335e71... Author: Martin Storsjo <martin(a)martin.st> Date: Thu May 28 11:14:42 2020 +0300 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(a)martin.st> Signed-off-by: Alexandre Julliard <julliard(a)winehq.org> --- dlls/ntdll/signal_arm64.c | 13 ++++++++++++- include/winnt.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index 4c9017b9e2..cdffda7a12 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -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; } diff --git a/include/winnt.h b/include/winnt.h index 34951766dd..aa4daaa55f 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -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)
participants (1)
-
Alexandre Julliard