[PATCH 1/3] ntdll: Support AVX registers for other thread in Nt{Get|Set}ContextThread().

Paul Gofman pgofman at codeweavers.com
Fri Oct 9 08:03:54 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/unix/server.c        |  7 +++++
 dlls/ntdll/unix/signal_i386.c   | 31 +++++++++++-------
 dlls/ntdll/unix/signal_x86_64.c | 35 ++++++++++++++-------
 dlls/ntdll/unix/thread.c        | 36 ++++++++++++++++++---
 dlls/ntdll/unix/unix_private.h  | 56 ++++++++++++++++++++++++++++-----
 include/wine/server_protocol.h  |  5 +++
 server/protocol.def             |  5 +++
 server/thread.c                 |  1 +
 server/trace.c                  |  6 ++++
 9 files changed, 148 insertions(+), 34 deletions(-)

diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 81a903ca77a..7236f0acb83 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -631,8 +631,15 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
                 if (wine_server_reply_size( reply ))
                 {
                     DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */
+                    XSTATE *xs = xstate_from_context( context );
+                    ULONG64 mask;
+
+                    if (xs)
+                        mask = xs->Mask;
                     context_from_server( context, &server_context );
                     context->ContextFlags |= context_flags;
+                    if (xs)
+                        xs->Mask |= mask;
                 }
             }
             SERVER_END_REQ;
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index e0ba27d3e94..4d8eeb2072c 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -886,14 +886,16 @@ static inline void save_context( struct xcontext *xcontext, const ucontext_t *si
     }
     if (fpux)
     {
+        XSTATE *xs;
+
         context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
         memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) );
         if (!fpu) fpux_to_fpu( &context->FloatSave, fpux );
-        xcontext->xstate = XState_sig(fpux);
-    }
-    else
-    {
-        xcontext->xstate = NULL;
+        if ((xs = XState_sig(fpux)))
+        {
+            context_init_xstate( context, xs );
+            xcontext->host_compaction_mask = xs->CompactionMask;
+        }
     }
     if (!fpu && !fpux) save_fpu( context );
 }
@@ -944,6 +946,7 @@ static inline void restore_context( const struct xcontext *xcontext, ucontext_t
         {
             memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
             dst_xs->Mask |= src_xs->Mask;
+            dst_xs->CompactionMask = xcontext->host_compaction_mask;
         }
     }
     if (!fpu && !fpux) restore_fpu( context );
@@ -1023,6 +1026,7 @@ static unsigned int get_server_context_flags( DWORD flags )
     if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
     if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
     if (flags & CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
+    if (flags & CONTEXT_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
     return ret;
 }
 
@@ -1095,6 +1099,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
         to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
         memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
     }
+    xstate_to_server( to, xstate_from_context( from ) );
     return STATUS_SUCCESS;
 }
 
@@ -1108,7 +1113,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
 {
     if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
 
-    to->ContextFlags = CONTEXT_i386;
+    to->ContextFlags = CONTEXT_i386 | (to->ContextFlags & 0x40);
     if (from->flags & SERVER_CTX_CONTROL)
     {
         to->ContextFlags |= CONTEXT_CONTROL;
@@ -1165,6 +1170,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
         to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
         memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
     }
+    xstate_from_server( xstate_from_context( to ), from );
     return STATUS_SUCCESS;
 }
 
@@ -1246,7 +1252,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
 
     /* Save xstate before any calls which can potentially change volatile ymm registers.
      * E. g., debug output will clobber ymm registers. */
-    xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS; /* FIXME: other thread. */
+    xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS;
 
     /* debug registers require a server call */
     if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE;
@@ -1293,7 +1299,6 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
         }
         if (needed_flags & CONTEXT_FLOATING_POINT) save_fpu( context );
         if (needed_flags & CONTEXT_EXTENDED_REGISTERS) save_fpux( context );
-        /* FIXME: xstate */
         /* update the cached version of the debug registers */
         if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
         {
@@ -1579,6 +1584,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr,
 {
     CONTEXT *context = &xcontext->c;
     size_t stack_size;
+    XSTATE *src_xs;
 
     struct stack_layout
     {
@@ -1606,7 +1612,7 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))
     if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
 
     stack_size = sizeof(*stack);
-    if (xcontext->xstate)
+    if ((src_xs = xstate_from_context( context )))
     {
         stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr
                 - sizeof(XSTATE)) & ~(ULONG_PTR)63);
@@ -1616,17 +1622,18 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))
     stack->rec          = *rec;
     stack->context      = *context;
 
-    if (xcontext->xstate)
+    if (src_xs)
     {
         XSTATE *dst_xs = (XSTATE *)stack->xstate;
 
         assert(!((ULONG_PTR)dst_xs & 63));
         context_init_xstate( &stack->context, stack->xstate );
+        memset( dst_xs, 0, offsetof(XSTATE, YmmContext) );
         dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0;
-        if (xcontext->xstate->Mask & 4)
+        if (src_xs->Mask & 4)
         {
             dst_xs->Mask = 4;
-            memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) );
+            memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
         }
     }
 
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index e11b2c70b59..030f8cc6feb 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -1461,14 +1461,19 @@ static void save_context( struct xcontext *xcontext, const ucontext_t *sigcontex
     context->Dr7    = amd64_thread_data()->dr7;
     if (FPU_sig(sigcontext))
     {
+        XSTATE *xs;
+
         context->ContextFlags |= CONTEXT_FLOATING_POINT;
         context->u.FltSave = *FPU_sig(sigcontext);
         context->MxCsr = context->u.FltSave.MxCsr;
-        xcontext->xstate = XState_sig(FPU_sig(sigcontext));
-    }
-    else
-    {
-        xcontext->xstate = NULL;
+        if ((xs = XState_sig(FPU_sig(sigcontext))))
+        {
+            /* xcontext and sigcontext are both on the signal stack, so we can
+             * just reference sigcontext without overflowing 32 bit XState.Offset */
+            context_init_xstate( context, xs );
+            assert( xcontext->c_ex.XState.Offset == (BYTE *)xs - (BYTE *)&xcontext->c_ex );
+            xcontext->host_compaction_mask = xs->CompactionMask;
+        }
     }
 }
 
@@ -1531,6 +1536,7 @@ static inline NTSTATUS save_xstate( CONTEXT *context )
 static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcontext )
 {
     const CONTEXT *context = &xcontext->c;
+    XSTATE *xs;
 
     amd64_thread_data()->dr0 = context->Dr0;
     amd64_thread_data()->dr1 = context->Dr1;
@@ -1540,6 +1546,8 @@ static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcon
     amd64_thread_data()->dr7 = context->Dr7;
     set_sigcontext( context, sigcontext );
     if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave;
+    if ((xs = XState_sig(FPU_sig(sigcontext))))
+        xs->CompactionMask = xcontext->host_compaction_mask;
 }
 
 
@@ -1628,6 +1636,7 @@ static unsigned int get_server_context_flags( DWORD flags )
     if (flags & CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
     if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
     if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
+    if (flags & CONTEXT_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
     return ret;
 }
 
@@ -1695,6 +1704,7 @@ NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
         to->debug.x86_64_regs.dr6 = from->Dr6;
         to->debug.x86_64_regs.dr7 = from->Dr7;
     }
+    xstate_to_server( to, xstate_from_context( from ) );
     return STATUS_SUCCESS;
 }
 
@@ -1708,7 +1718,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
 {
     if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
 
-    to->ContextFlags = CONTEXT_AMD64;
+    to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & 0x40);
     if (from->flags & SERVER_CTX_CONTROL)
     {
         to->ContextFlags |= CONTEXT_CONTROL;
@@ -1762,6 +1772,7 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
         to->Dr6 = from->debug.x86_64_regs.dr6;
         to->Dr7 = from->debug.x86_64_regs.dr7;
     }
+    xstate_from_server( xstate_from_context( to ), from );
     return STATUS_SUCCESS;
 }
 
@@ -1831,7 +1842,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
 
     /* Save xstate before any calls which can potentially change volatile ymm registers.
      * E. g., debug output will clobber ymm registers. */
-    xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS; /* FIXME: other thread. */
+    xsave_status = self ? save_xstate( context ) : STATUS_SUCCESS;
 
     needed_flags = context->ContextFlags & ~CONTEXT_AMD64;
 
@@ -1924,6 +1935,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
     struct stack_layout *stack;
     size_t stack_size;
     NTSTATUS status;
+    XSTATE *src_xs;
 
     if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
     {
@@ -1953,7 +1965,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
     if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--;
 
     stack_size = sizeof(*stack);
-    if (xcontext->xstate)
+    if ((src_xs = xstate_from_context( context )))
     {
         stack_size += (ULONG_PTR)stack_ptr - (((ULONG_PTR)stack_ptr
                 - sizeof(XSTATE)) & ~(ULONG_PTR)63);
@@ -1962,17 +1974,18 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
     stack = virtual_setup_exception( stack_ptr, stack_size, rec );
     stack->rec          = *rec;
     stack->context      = *context;
-    if (xcontext->xstate)
+    if (src_xs)
     {
         XSTATE *dst_xs = (XSTATE *)stack->xstate;
 
         assert( !((ULONG_PTR)dst_xs & 63) );
         context_init_xstate( &stack->context, stack->xstate );
+        memset( dst_xs, 0, offsetof(XSTATE, YmmContext) );
         dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? 0x8000000000000004 : 0;
-        if (xcontext->xstate->Mask & 4)
+        if (src_xs->Mask & 4)
         {
             dst_xs->Mask = 4;
-            memcpy( &dst_xs->YmmContext, &xcontext->xstate->YmmContext, sizeof(dst_xs->YmmContext) );
+            memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
         }
     }
 
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c
index ded4b33eb01..a161c5d1c90 100644
--- a/dlls/ntdll/unix/thread.c
+++ b/dlls/ntdll/unix/thread.c
@@ -344,7 +344,6 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
     DWORD i;
     obj_handle_t handle = 0;
     client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
-    CONTEXT exception_context = *context;
     select_op_t select_op;
     sigset_t old_set;
 
@@ -370,10 +369,22 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
 
     if (handle)
     {
+        struct xcontext exception_context;
+        DECLSPEC_ALIGN(64) XSTATE xs;
+        XSTATE *src_xs;
+
         select_op.wait.op = SELECT_WAIT;
         select_op.wait.handles[0] = handle;
+
+        exception_context.c = *context;
+        if ((src_xs = xstate_from_context( context )))
+        {
+            context_init_xstate( &exception_context.c, &xs );
+            memcpy( &xs, src_xs, sizeof(xs) );
+        }
+
         server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE,
-                       TIMEOUT_INFINITE, &exception_context, NULL, NULL );
+                       TIMEOUT_INFINITE, &exception_context.c, NULL, NULL );
 
         SERVER_START_REQ( get_exception_status )
         {
@@ -381,7 +392,12 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
             ret = wine_server_call( req );
         }
         SERVER_END_REQ;
-        if (ret >= 0) *context = exception_context;
+        if (ret >= 0)
+        {
+            *context = exception_context.c;
+            if (src_xs)
+                memcpy( src_xs, &xs, sizeof(xs) );
+        }
     }
 
     pthread_sigmask( SIG_SETMASK, &old_set, NULL );
@@ -632,7 +648,7 @@ static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *f
 {
     if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
 
-    to->ContextFlags = WOW64_CONTEXT_i386;
+    to->ContextFlags = WOW64_CONTEXT_i386 | (to->ContextFlags & 0x40);
     if (from->flags & SERVER_CTX_CONTROL)
     {
         to->ContextFlags |= WOW64_CONTEXT_CONTROL;
@@ -689,6 +705,12 @@ static NTSTATUS wow64_context_from_server( WOW64_CONTEXT *to, const context_t *f
         to->ContextFlags |= WOW64_CONTEXT_EXTENDED_REGISTERS;
         memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
     }
+    if ((to->ContextFlags & WOW64_CONTEXT_XSTATE) == WOW64_CONTEXT_XSTATE)
+    {
+        CONTEXT_EX *c_ex = (CONTEXT_EX *)(to + 1);
+
+        xstate_from_server( (XSTATE *)((BYTE *)c_ex + c_ex->XState.Offset), from );
+    }
     return STATUS_SUCCESS;
 }
 
@@ -758,6 +780,12 @@ static void wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from )
         to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
         memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
     }
+    if (flags & WOW64_CONTEXT_XSTATE)
+    {
+        CONTEXT_EX *c_ex = (CONTEXT_EX *)(from + 1);
+
+        xstate_to_server( to, (XSTATE *)((BYTE *)c_ex + c_ex->XState.Offset) );
+    }
 }
 
 #endif /* __x86_64__ */
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index f99c13fe2ad..c3ad0a41098 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -288,13 +288,14 @@ static inline void mutex_unlock( pthread_mutex_t *mutex )
 static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; }
 #endif
 
-#if defined(__i386__) || defined(__x86_64__)
 struct xcontext
 {
     CONTEXT c;
-    XSTATE *xstate; /* points to xstate in sigcontext */
+    CONTEXT_EX c_ex;
+    ULONG64 host_compaction_mask;
 };
 
+#if defined(__i386__) || defined(__x86_64__)
 static inline XSTATE *xstate_from_context( const CONTEXT *context )
 {
     CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1);
@@ -308,21 +309,62 @@ static inline XSTATE *xstate_from_context( const CONTEXT *context )
 static inline void context_init_xstate( CONTEXT *context, void *xstate_buffer )
 {
     CONTEXT_EX *xctx;
-    XSTATE *xs;
 
     xctx = (CONTEXT_EX *)(context + 1);
     xctx->Legacy.Length = sizeof(CONTEXT);
     xctx->Legacy.Offset = -(LONG)sizeof(CONTEXT);
 
     xctx->XState.Length = sizeof(XSTATE);
-    xctx->XState.Offset = xstate_buffer ? (((ULONG_PTR)xstate_buffer + 63) & ~63) - (ULONG_PTR)xctx
-            : (((ULONG_PTR)context + sizeof(CONTEXT) + sizeof(CONTEXT_EX) + 63) & ~63) - (ULONG_PTR)xctx;
+    xctx->XState.Offset = (BYTE *)xstate_buffer - (BYTE *)xctx;
+
     xctx->All.Length = sizeof(CONTEXT) + xctx->XState.Offset + xctx->XState.Length;
     xctx->All.Offset = -(LONG)sizeof(CONTEXT);
     context->ContextFlags |= 0x40;
+}
 
-    xs = xstate_from_context(context);
-    memset( xs, 0, offsetof(XSTATE, YmmContext) );
+static inline void xstate_to_server( context_t *to, const XSTATE *xs )
+{
+    if (!xs)
+        return;
+
+    to->flags |= SERVER_CTX_YMM_REGISTERS;
+    if (xs->Mask & 4)
+        memcpy(&to->ymm.ymm_high_regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext));
+    else
+        memset(&to->ymm.ymm_high_regs.ymm_high, 0, sizeof(xs->YmmContext));
+}
+
+static inline void xstate_from_server_( XSTATE *xs, const context_t *from, BOOL compaction_enabled)
+{
+    if (!xs)
+        return;
+
+    xs->Mask = 0;
+    xs->CompactionMask = compaction_enabled ? 0x8000000000000004 : 0;
+
+    if (from->flags & SERVER_CTX_YMM_REGISTERS)
+    {
+        unsigned long *src = (unsigned long *)&from->ymm.ymm_high_regs.ymm_high;
+        unsigned int i;
+
+        for (i = 0; i < sizeof(xs->YmmContext) / sizeof(unsigned long); ++i)
+            if (src[i])
+            {
+                memcpy( &xs->YmmContext, &from->ymm.ymm_high_regs.ymm_high, sizeof(xs->YmmContext) );
+                xs->Mask = 4;
+                break;
+            }
+    }
+}
+#define xstate_from_server( xs, from ) xstate_from_server_( xs, from, user_shared_data->XState.CompactionEnabled )
+
+#else
+static inline XSTATE *xstate_from_context( const CONTEXT *context )
+{
+    return NULL;
+}
+static inline void context_init_xstate( CONTEXT *context, void *xstate_buffer )
+{
 }
 #endif
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 751ca59ad6b..5e267195f20 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -170,6 +170,10 @@ typedef struct
     {
         unsigned char i386_regs[512];
     } ext;
+    union
+    {
+        struct { struct { unsigned __int64 low, high; } ymm_high[16]; } ymm_high_regs;
+    } ymm;
 } context_t;
 
 #define SERVER_CTX_CONTROL            0x01
@@ -178,6 +182,7 @@ typedef struct
 #define SERVER_CTX_FLOATING_POINT     0x08
 #define SERVER_CTX_DEBUG_REGISTERS    0x10
 #define SERVER_CTX_EXTENDED_REGISTERS 0x20
+#define SERVER_CTX_YMM_REGISTERS      0x40
 
 
 struct send_fd
diff --git a/server/protocol.def b/server/protocol.def
index 16c0b936743..305a1d0186f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -186,6 +186,10 @@ typedef struct
     {
         unsigned char i386_regs[512];
     } ext;                       /* selected by SERVER_CTX_EXTENDED_REGISTERS */
+    union
+    {
+        struct { struct { unsigned __int64 low, high; } ymm_high[16]; } ymm_high_regs;
+    } ymm;                       /* selected by SERVER_CTX_YMM_REGISTERS */
 } context_t;
 
 #define SERVER_CTX_CONTROL            0x01
@@ -194,6 +198,7 @@ typedef struct
 #define SERVER_CTX_FLOATING_POINT     0x08
 #define SERVER_CTX_DEBUG_REGISTERS    0x10
 #define SERVER_CTX_EXTENDED_REGISTERS 0x20
+#define SERVER_CTX_YMM_REGISTERS      0x40
 
 /* structure used in sending an fd from client to server */
 struct send_fd
diff --git a/server/thread.c b/server/thread.c
index eb138079739..942a8ff8389 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1285,6 +1285,7 @@ static void copy_context( context_t *to, const context_t *from, unsigned int fla
     if (flags & SERVER_CTX_FLOATING_POINT) to->fp = from->fp;
     if (flags & SERVER_CTX_DEBUG_REGISTERS) to->debug = from->debug;
     if (flags & SERVER_CTX_EXTENDED_REGISTERS) to->ext = from->ext;
+    if (flags & SERVER_CTX_YMM_REGISTERS) to->ymm = from->ymm;
 }
 
 /* return the context flags that correspond to system regs */
diff --git a/server/trace.c b/server/trace.c
index 17dd415b958..8ee0bc8c3e3 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -620,6 +620,9 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
         if (ctx.flags & SERVER_CTX_EXTENDED_REGISTERS)
             dump_uints( ",extended=", (const unsigned int *)ctx.ext.i386_regs,
                         sizeof(ctx.ext.i386_regs) / sizeof(int) );
+        if (ctx.flags & SERVER_CTX_YMM_REGISTERS)
+            dump_uints( ",ymm_high=", (const unsigned int *)ctx.ymm.ymm_high_regs.ymm_high,
+                        sizeof(ctx.ymm.ymm_high_regs) / sizeof(int) );
         break;
     case CPU_x86_64:
         if (ctx.flags & SERVER_CTX_CONTROL)
@@ -669,6 +672,9 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
                          (unsigned int)(ctx.fp.x86_64_regs.fpregs[i].low >> 32),
                          (unsigned int)ctx.fp.x86_64_regs.fpregs[i].low );
         }
+        if (ctx.flags & SERVER_CTX_YMM_REGISTERS)
+            dump_uints( ",ymm_high=", (const unsigned int *)ctx.ymm.ymm_high_regs.ymm_high,
+                        sizeof(ctx.ymm.ymm_high_regs) / sizeof(int) );
         break;
     case CPU_POWERPC:
         if (ctx.flags & SERVER_CTX_CONTROL)
-- 
2.26.2




More information about the wine-devel mailing list