[PATCH 1/2] ntdll: Fix KiUserExceptionDispatcher ABI on x86_64.

Paul Gofman pgofman at codeweavers.com
Tue Jun 30 15:34:34 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49436
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/signal_x86_64.c      | 23 ++++++++++++---
 dlls/ntdll/unix/signal_arm.c    |  4 +++
 dlls/ntdll/unix/signal_arm64.c  |  5 ++++
 dlls/ntdll/unix/signal_i386.c   |  4 +++
 dlls/ntdll/unix/signal_x86_64.c | 51 ++++++++++++++++++++-------------
 dlls/ntdll/unix/thread.c        |  2 +-
 dlls/ntdll/unix/unix_private.h  |  2 ++
 7 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 89ddd87f16d..5d29b675361 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -533,10 +533,7 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
 }
 
 
-/*******************************************************************
- *		KiUserExceptionDispatcher (NTDLL.@)
- */
-NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
+NTSTATUS WINAPI impl_KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
 {
     NTSTATUS status;
     DWORD c;
@@ -583,6 +580,24 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte
     return NtRaiseException( rec, context, FALSE );
 }
 
+__ASM_GLOBAL_FUNC( KiUserExceptionDispatcher,
+                  "mov 0x98(%rsp),%rcx\n\t" /* context->Rsp */
+                  "mov 0xf8(%rsp),%rdx\n\t" /* context->Rip */
+                  "mov %rdx,-0x8(%rcx)\n\t"
+                  "mov %rbp,-0x10(%rcx)\n\t"
+                  "mov %rdi,-0x18(%rcx)\n\t"
+                  "mov %rsi,-0x20(%rcx)\n\t"
+                  "mov %rcx,%rbp\n\t"
+                  "mov %rsp,%rdx\n\t" /* context */
+                  "lea 0x4f0(%rsp),%rcx\n\t" /* rec */
+                  __ASM_CFI(".cfi_signal_frame\n\t")
+                  __ASM_CFI(".cfi_def_cfa %rbp,0\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rip,-0x8\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rbp,-0x10\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rdi,-0x18\n\t")
+                  __ASM_CFI(".cfi_rel_offset %rsi,-0x20\n\t")
+                  "call impl_KiUserExceptionDispatcher\n\t"
+                  "int3")
 
 static ULONG64 get_int_reg( CONTEXT *context, int reg )
 {
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index 265836499d5..611d1ab8197 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -531,6 +531,10 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
     return &stack->rec;
 }
 
+void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    pKiUserExceptionDispatcher( rec, context );
+}
 
 /**********************************************************************
  *		raise_segv_exception
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index 2bd6deb04f1..1d512a5ed9f 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -602,6 +602,11 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
     REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb();
 }
 
+void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    pKiUserExceptionDispatcher( rec, context );
+}
+
 /**********************************************************************
  *		segv_handler
  *
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index ea9bfbeb3b9..730d0b1cb32 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1588,6 +1588,10 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
     stack->context_ptr  = &stack->context;
 }
 
+void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    pKiUserExceptionDispatcher( rec, context );
+}
 
 /**********************************************************************
  *		get_fpu_code
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 47f3650b428..128f9dad8db 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -233,6 +233,7 @@ typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
 struct stack_layout
 {
     CONTEXT           context;
+    ULONG64           unknown[4];
     EXCEPTION_RECORD  rec;
     ULONG64           rsi;
     ULONG64           rdi;
@@ -241,6 +242,8 @@ struct stack_layout
     ULONG64           red_zone[16];
 };
 
+C_ASSERT( sizeof(struct stack_layout) == 0x630 ); /* Should match the size in call_user_exception_dispatcher(). */
+
 struct amd64_thread_data
 {
     DWORD_PTR dr0;           /* debug registers */
@@ -1843,16 +1846,10 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
 }
 
 
-extern void CDECL raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
+extern void CDECL raise_func_trampoline( raise_func func );
+
 __ASM_GLOBAL_FUNC( raise_func_trampoline,
-                   __ASM_CFI(".cfi_signal_frame\n\t")
-                   __ASM_CFI(".cfi_def_cfa %rbp,160\n\t")  /* red zone + rip + rbp + rdi + rsi */
-                   __ASM_CFI(".cfi_rel_offset %rip,24\n\t")
-                   __ASM_CFI(".cfi_rel_offset %rbp,16\n\t")
-                   __ASM_CFI(".cfi_rel_offset %rdi,8\n\t")
-                   __ASM_CFI(".cfi_rel_offset %rsi,0\n\t")
-                   "call *%r8\n\t"
-                   "int $3")
+                   "jmpq *%r8\n\t")
 
 /***********************************************************************
  *           setup_exception
@@ -1934,7 +1931,6 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
 
 static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack )
 {
-    ULONG64 *rsp_ptr;
     NTSTATUS status;
 
     if (stack->rec.ExceptionCode == EXCEPTION_SINGLE_STEP)
@@ -1962,24 +1958,39 @@ static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *
         return;
     }
 
-    /* store return address and %rbp without aligning, so that the offset is fixed */
-    rsp_ptr = (ULONG64 *)RSP_sig(sigcontext) - 16;
-    *(--rsp_ptr) = stack->context.Rip;
-    *(--rsp_ptr) = stack->context.Rbp;
-    *(--rsp_ptr) = stack->context.Rdi;
-    *(--rsp_ptr) = stack->context.Rsi;
-
     /* now modify the sigcontext to return to the raise function */
     RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline;
-    RCX_sig(sigcontext) = (ULONG_PTR)&stack->rec;
-    RDX_sig(sigcontext) = (ULONG_PTR)&stack->context;
     R8_sig(sigcontext)  = (ULONG_PTR)pKiUserExceptionDispatcher;
-    RBP_sig(sigcontext) = (ULONG_PTR)rsp_ptr;
     RSP_sig(sigcontext) = (ULONG_PTR)stack;
     /* clear single-step, direction, and align check flag */
     EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000);
 }
 
+extern void WINAPI user_exception_dispatcher_trampoline( struct stack_layout *stack,
+        void *pKiUserExceptionDispatcher );
+
+__ASM_GLOBAL_FUNC( user_exception_dispatcher_trampoline,
+                   "movq %rcx,%rsp\n\t"
+                   "movq 0x98(%rsp),%rcx\n\t" /* context->Rsp */
+                   "movq 0xa0(%rsp),%rbp\n\t"
+                   "movq 0xa8(%rsp),%rsi\n\t"
+                   "movq 0xb0(%rsp),%rdi\n\t"
+                   "jmpq *%rdx")
+
+void WINAPI do_call_user_exception_dispatcher(EXCEPTION_RECORD *rec, CONTEXT *context, struct stack_layout *stack)
+{
+    memcpy(&stack->context, context, sizeof(*context));
+    memcpy(&stack->rec, rec, sizeof(*rec));
+
+    user_exception_dispatcher_trampoline( stack, pKiUserExceptionDispatcher );
+}
+
+__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
+                   "movq 0x98(%rdx),%rsp\n\t" /* context->Rsp */
+                   "and $~0xf,%rsp\n\t"
+                   "sub $0x630,%rsp\n\t" /* sizeof(struct stack_layout) */
+                   "movq %rsp,%r8\n\t"
+                   "jmp do_call_user_exception_dispatcher\n\t")
 
 /***********************************************************************
  *           is_privileged_instr
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c
index 1bf660ed917..8bbdee50f12 100644
--- a/dlls/ntdll/unix/thread.c
+++ b/dlls/ntdll/unix/thread.c
@@ -415,7 +415,7 @@ NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL
     if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
         NtSetContextThread( GetCurrentThread(), context );
 
-    if (first_chance) pKiUserExceptionDispatcher( rec, context );
+    if (first_chance) call_user_exception_dispatcher( rec, context );
 
     if (rec->ExceptionFlags & EH_STACK_INVALID)
         ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 57c33c5027a..e68fc45271b 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -241,6 +241,8 @@ extern void init_cpu_info(void) DECLSPEC_HIDDEN;
 
 extern void dbg_init(void) DECLSPEC_HIDDEN;
 
+extern void WINAPI call_user_exception_dispatcher(EXCEPTION_RECORD *rec, CONTEXT *context) DECLSPEC_HIDDEN;
+
 #define TICKSPERSEC 10000000
 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)86400)
 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
-- 
2.26.2




More information about the wine-devel mailing list