[PATCH v3 2/2] ntdll: Save unwind information in KiUserApcDispatcher() on x64.

Paul Gofman pgofman at codeweavers.com
Tue Dec 15 03:56:40 CST 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v2:
    - fix build for other archs.

 dlls/ntdll/tests/exception.c    | 53 +++++++++++++++++++++++++++++++++
 dlls/ntdll/thread.c             | 28 ++++++++++++++++-
 dlls/ntdll/unix/signal_x86_64.c | 23 ++++++++++++--
 3 files changed, 101 insertions(+), 3 deletions(-)

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..5bf456ec040 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -78,7 +78,7 @@ int __cdecl __wine_dbg_output( const char *str )
 /*******************************************************************
  *		KiUserApcDispatcher (NTDLL.@)
  */
-void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+void WINAPI dispatch_apc( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
                                  PNTAPCFUNC func )
 {
     func( ctx, arg1, arg2 );
@@ -86,6 +86,32 @@ void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1
 }
 
 
+#ifdef __x86_64__
+__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")
+#else
+void WINAPI KiUserApcDispatcher( CONTEXT *context, ULONG_PTR ctx, ULONG_PTR arg1, ULONG_PTR arg2,
+                                 PNTAPCFUNC func )
+{
+    dispatch_apc( context, ctx, arg1, arg2, func );
+}
+#endif
+
 /***********************************************************************
  *           RtlExitUserThread  (NTDLL.@)
  */
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 0fc7ad69584..290e275a86e 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2077,9 +2077,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" )
 
 
 /***********************************************************************
-- 
2.29.2




More information about the wine-devel mailing list