[PATCH 1/4] ntdll: Use exit_frame as the initial syscall_frame prev_frame value.

Rémi Bernon rbernon at codeweavers.com
Mon Feb 7 13:05:41 CST 2022


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

Something like that seems to let pthread_exit unwinding work and call
its cleanup handlers.

Unwinding also seems to work fine when adding .cfi metadata to point to
the right PE frames, although I didn't look exactly how it handles that.
Maybe it only works in the context of builtin libraries.

As we don't want pthread to do anything with the PE code I'm keeping
track of unix address only here instead, which I'm assuming makes sure
it only unwinds syscall frames.

Somehow libunwind only cares about %rip .cfi directives, although I've
also added .cfi for %rsp here (resp. %eip, %esp on i386), I'm not
completely sure why or which option is best.

 dlls/ntdll/unix/signal_i386.c   | 5 +++--
 dlls/ntdll/unix/signal_x86_64.c | 5 +++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index 6bb5649e2b5..0e3b1daf51a 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1613,8 +1613,9 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void
 NTSTATUS WINAPI NtCallbackReturn( void *ret_ptr, ULONG ret_len, NTSTATUS status )
 {
     struct user_callback_frame *frame = (struct user_callback_frame *)x86_thread_data()->syscall_frame;
+    void *exit_frame = x86_thread_data()->exit_frame;
 
-    if (!frame->frame.prev_frame) return STATUS_NO_CALLBACK_ACTIVE;
+    if (frame->frame.prev_frame == exit_frame) return STATUS_NO_CALLBACK_ACTIVE;
 
     *frame->ret_ptr = ret_ptr;
     *frame->ret_len = ret_len;
@@ -2399,7 +2400,7 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B
     *(--stack) = 0xdeadbabe;
     frame->esp = (DWORD)stack;
     frame->eip = (DWORD)pLdrInitializeThunk;
-    frame->prev_frame    = NULL;
+    frame->prev_frame    = thread_data->exit_frame;
     frame->syscall_flags = syscall_flags;
     frame->syscall_table = KeServiceDescriptorTable;
     frame->restore_flags |= LOWORD(CONTEXT_INTEGER);
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 68855dccacf..da89b958665 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2364,8 +2364,9 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void
 NTSTATUS WINAPI NtCallbackReturn( void *ret_ptr, ULONG ret_len, NTSTATUS status )
 {
     struct user_callback_frame *frame = (struct user_callback_frame *)amd64_thread_data()->syscall_frame;
+    void *exit_frame = amd64_thread_data()->exit_frame;
 
-    if (!frame->frame.prev_frame) return STATUS_NO_CALLBACK_ACTIVE;
+    if (frame->frame.prev_frame == exit_frame) return STATUS_NO_CALLBACK_ACTIVE;
 
     *frame->ret_ptr = ret_ptr;
     *frame->ret_len = ret_len;
@@ -3072,7 +3073,7 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B
     frame->rsp = (ULONG64)ctx - 8;
     frame->rip = (ULONG64)pLdrInitializeThunk;
     frame->rcx = (ULONG64)ctx;
-    frame->prev_frame = NULL;
+    frame->prev_frame = thread_data->exit_frame;
     frame->restore_flags |= CONTEXT_INTEGER;
     frame->syscall_flags = syscall_flags;
     frame->syscall_table = KeServiceDescriptorTable;
-- 
2.34.1




More information about the wine-devel mailing list