Paul Gofman : ntdll: Save unwind information in KiUserApcDispatcher() on x64.

Alexandre Julliard julliard at winehq.org
Thu Dec 17 15:50:26 CST 2020


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

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Thu Dec 17 02:05:05 2020 +0300

ntdll: Save unwind information in KiUserApcDispatcher() on x64.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/signal_arm.c         | 11 +++++++++
 dlls/ntdll/signal_arm64.c       | 12 ++++++++++
 dlls/ntdll/signal_i386.c        | 12 ++++++++++
 dlls/ntdll/signal_x86_64.c      | 30 +++++++++++++++++++++++
 dlls/ntdll/tests/exception.c    | 53 +++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/thread.c             | 11 ---------
 dlls/ntdll/unix/signal_x86_64.c | 23 ++++++++++++++++--
 7 files changed, 139 insertions(+), 13 deletions(-)

diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index 0e80a35b0c0..512462b7066 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -175,6 +175,17 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
 }
 
 
+/*******************************************************************
+ *		KiUserApcDispatcher (NTDLL.@)
+ */
+void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+                                 PNTAPCFUNC func )
+{
+    func( ctx, arg1, arg2 );
+    NtContinue( context, TRUE );
+}
+
+
 /***********************************************************************
  *            RtlUnwind  (NTDLL.@)
  */
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index c31eb510382..4c4694959f0 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -523,6 +523,18 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
     return NtRaiseException( rec, context, FALSE );
 }
 
+
+/*******************************************************************
+ *		KiUserApcDispatcher (NTDLL.@)
+ */
+void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+                                 PNTAPCFUNC func )
+{
+    func( ctx, arg1, arg2 );
+    NtContinue( context, TRUE );
+}
+
+
 /***********************************************************************
  * Definitions for Win32 unwind tables
  */
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index ddc2bf6adbd..93e03ae5b8b 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -218,6 +218,18 @@ __ASM_STDCALL_FUNC( KiUserExceptionDispatcher, 8,
                     "call " __ASM_STDCALL("dispatch_exception", 8) "\n\t"
                     "int3" )
 
+
+/*******************************************************************
+ *		KiUserApcDispatcher (NTDLL.@)
+ */
+void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+                                 PNTAPCFUNC func )
+{
+    func( ctx, arg1, arg2 );
+    NtContinue( context, TRUE );
+}
+
+
 /***********************************************************************
  *           save_fpu
  *
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index a3dba815c1f..7e39991ad1a 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -590,6 +590,36 @@ __ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
                    "call " __ASM_NAME("dispatch_exception") "\n\t"
                   "int3")
 
+
+/*******************************************************************
+ *		KiUserApcDispatcher (NTDLL.@)
+ */
+void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+                          PNTAPCFUNC func )
+{
+    func( ctx, arg1, arg2 );
+    NtContinue( context, TRUE );
+}
+
+__ASM_GLOBAL_FUNC( KiUserApcDispatcher,
+                  "addq $0x8,%rsp\n\t"
+                  "mov 0x98(%rcx),%r10\n\t" /* context->Rsp */
+                  "mov 0xf8(%rcx),%r11\n\t" /* context->Rip */
+                  "mov %r11,-0x8(%r10)\n\t"
+                  "mov %rbp,-0x10(%r10)\n\t"
+                  "lea -0x10(%r10),%rbp\n\t"
+                  __ASM_SEH(".seh_pushreg %rbp\n\t")
+                  __ASM_SEH(".seh_setframe %rbp,0\n\t")
+                  __ASM_SEH(".seh_endprologue\n\t")
+                  __ASM_CFI(".cfi_signal_frame\n\t")
+                  __ASM_CFI(".cfi_adjust_cfa_offset 0x10\n\t")
+                  __ASM_CFI(".cfi_def_cfa %rbp,0x10\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rip,0x8\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
+                   "call " __ASM_NAME("dispatch_apc") "\n\t"
+                   "int3")
+
+
 static ULONG64 get_int_reg( CONTEXT *context, int reg )
 {
     return *(&context->Rax + reg);
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 5686e39ab9e..3a0a5ac049c 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -37,6 +37,8 @@ static void *code_mem;
 
 static NTSTATUS  (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
 static NTSTATUS  (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
+static NTSTATUS  (WINAPI *pNtQueueApcThread)(HANDLE handle, PNTAPCFUNC func,
+        ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3);
 static NTSTATUS  (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
 static PVOID     (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
 static VOID      (WINAPI *pRtlCaptureContext)(CONTEXT*);
@@ -4061,6 +4063,55 @@ static void test_nested_exception(void)
     ok(got_prev_frame_exception, "Did not get nested exception in the previous frame.\n");
 }
 
+static CONTEXT test_unwind_apc_context;
+static BOOL test_unwind_apc_called;
+
+static void CALLBACK test_unwind_apc(ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3)
+{
+    EXCEPTION_RECORD rec;
+
+    test_unwind_apc_called = TRUE;
+    memset(&rec, 0, sizeof(rec));
+    pRtlUnwind((void *)test_unwind_apc_context.Rsp, (void *)test_unwind_apc_context.Rip, &rec, (void *)0xdeadbeef);
+    ok(0, "Should not get here.\n");
+}
+
+static void test_unwind_from_apc(void)
+{
+    NTSTATUS status;
+    int pass;
+
+    if (!pNtQueueApcThread)
+    {
+        win_skip("NtQueueApcThread is not available.\n");
+        return;
+    }
+
+    pass = 0;
+    InterlockedIncrement(&pass);
+    RtlCaptureContext(&test_unwind_apc_context);
+    InterlockedIncrement(&pass);
+
+    if (pass == 2)
+    {
+        test_unwind_apc_called = FALSE;
+        status = pNtQueueApcThread(GetCurrentThread(), test_unwind_apc, 0, 0, 0);
+        ok(!status, "Got unexpected status %#x.\n", status);
+        SleepEx(0, TRUE);
+        ok(0, "Should not get here.\n");
+    }
+    if (pass == 3)
+    {
+        ok(test_unwind_apc_called, "Test user APC was not called.\n");
+        test_unwind_apc_called = FALSE;
+        status = pNtQueueApcThread(GetCurrentThread(), test_unwind_apc, 0, 0, 0);
+        ok(!status, "Got unexpected status %#x.\n", status);
+        NtContinue(&test_unwind_apc_context, TRUE );
+        ok(0, "Should not get here.\n");
+    }
+    ok(pass == 4, "Got unexpected pass %d.\n", pass);
+    ok(test_unwind_apc_called, "Test user APC was not called.\n");
+}
 #elif defined(__arm__)
 
 static void test_thread_context(void)
@@ -8073,6 +8124,7 @@ START_TEST(exception)
 #define X(f) p##f = (void*)GetProcAddress(hntdll, #f)
     X(NtGetContextThread);
     X(NtSetContextThread);
+    X(NtQueueApcThread);
     X(NtReadVirtualMemory);
     X(NtClose);
     X(RtlUnwind);
@@ -8241,6 +8293,7 @@ START_TEST(exception)
       skip( "Dynamic unwind functions not found\n" );
     test_extended_context();
     test_copy_context();
+    test_unwind_from_apc();
 
 #elif defined(__aarch64__)
 
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 578c7a5436c..3dd1c9a5c26 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -75,17 +75,6 @@ int __cdecl __wine_dbg_output( const char *str )
 }
 
 
-/*******************************************************************
- *		KiUserApcDispatcher (NTDLL.@)
- */
-void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
-                                 PNTAPCFUNC func )
-{
-    func( ctx, arg1, arg2 );
-    NtContinue( context, TRUE );
-}
-
-
 /***********************************************************************
  *           RtlExitUserThread  (NTDLL.@)
  */
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 3ae3b4c141e..837cd9ed654 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2073,9 +2073,28 @@ __ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
                    "movq %r14,%r9\n"                /* arg2 */
                    "movq $0,0x328(%rbx)\n\t"        /* amd64_thread_data()->syscall_frame */
                    "movq %rsi,0x20(%rsp)\n\t"       /* func */
-                   "movq 0xa0(%rcx),%rbp\n\t"       /* context.Rbp */
+                   "movq %rdi,%r10\n\t"
+                   /* Set nonvolatile regs from context. */
+                   "movq 0xa0(%rcx),%rbp\n\t"
+                   "movq 0x90(%rcx),%rbx\n\t"
+                   "movq 0xa8(%rcx),%rsi\n\t"
+                   "movq 0xb0(%rcx),%rdi\n\t"
+                   "movq 0xd8(%rcx),%r12\n\t"
+                   "movq 0xe0(%rcx),%r13\n\t"
+                   "movq 0xe8(%rcx),%r14\n\t"
+                   "movq 0xf0(%rcx),%r15\n\t"
+                   "movdqa 0x200(%rcx),%xmm6\n\t"
+                   "movdqa 0x210(%rcx),%xmm7\n\t"
+                   "movdqa 0x220(%rcx),%xmm8\n\t"
+                   "movdqa 0x230(%rcx),%xmm9\n\t"
+                   "movdqa 0x240(%rcx),%xmm10\n\t"
+                   "movdqa 0x250(%rcx),%xmm11\n\t"
+                   "movdqa 0x260(%rcx),%xmm12\n\t"
+                   "movdqa 0x270(%rcx),%xmm13\n\t"
+                   "movdqa 0x280(%rcx),%xmm14\n\t"
+                   "movdqa 0x290(%rcx),%xmm15\n\t"
                    "pushq 0xf8(%rcx)\n\t"           /* context.Rip */
-                   "jmp *%rdi" )
+                   "jmp *%r10" )
 
 
 /***********************************************************************




More information about the wine-cvs mailing list