Martin Storsjo : ntdll: Fix unwinding functions that end with a branch instruction.

Alexandre Julliard julliard at winehq.org
Thu May 28 17:11:10 CDT 2020


Module: wine
Branch: master
Commit: babbf352b651dac6458335e71a980317b3b42386
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=babbf352b651dac6458335e71a980317b3b42386

Author: Martin Storsjo <martin at 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 at martin.st>
Signed-off-by: Alexandre Julliard <julliard at 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)
 




More information about the wine-cvs mailing list