ntdll: Move NtGetContextThread() implementation to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ac90898f72
commit
7c32b2dd93
|
@ -62,7 +62,6 @@ extern void wait_suspend( CONTEXT *context ) DECLSPEC_HIDDEN;
|
|||
extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) DECLSPEC_HIDDEN;
|
||||
extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN;
|
||||
extern void DECLSPEC_NORETURN raise_status( NTSTATUS status, EXCEPTION_RECORD *rec ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN;
|
||||
extern LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -296,148 +296,6 @@ __ASM_GLOBAL_FUNC( set_cpu_context,
|
|||
"pop {pc}" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_ARM; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_ARM; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Sp = from->Sp;
|
||||
to->Lr = from->Lr;
|
||||
to->Pc = from->Pc;
|
||||
to->Cpsr = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->R0 = from->R0;
|
||||
to->R1 = from->R1;
|
||||
to->R2 = from->R2;
|
||||
to->R3 = from->R3;
|
||||
to->R4 = from->R4;
|
||||
to->R5 = from->R5;
|
||||
to->R6 = from->R6;
|
||||
to->R7 = from->R7;
|
||||
to->R8 = from->R8;
|
||||
to->R9 = from->R9;
|
||||
to->R10 = from->R10;
|
||||
to->R11 = from->R11;
|
||||
to->R12 = from->R12;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->Fpscr = from->Fpscr;
|
||||
memcpy( to->u.D, from->u.D, sizeof(to->u.D) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_ARM;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Sp = from->ctl.arm_regs.sp;
|
||||
to->Lr = from->ctl.arm_regs.lr;
|
||||
to->Pc = from->ctl.arm_regs.pc;
|
||||
to->Cpsr = from->ctl.arm_regs.cpsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->R0 = from->integer.arm_regs.r[0];
|
||||
to->R1 = from->integer.arm_regs.r[1];
|
||||
to->R2 = from->integer.arm_regs.r[2];
|
||||
to->R3 = from->integer.arm_regs.r[3];
|
||||
to->R4 = from->integer.arm_regs.r[4];
|
||||
to->R5 = from->integer.arm_regs.r[5];
|
||||
to->R6 = from->integer.arm_regs.r[6];
|
||||
to->R7 = from->integer.arm_regs.r[7];
|
||||
to->R8 = from->integer.arm_regs.r[8];
|
||||
to->R9 = from->integer.arm_regs.r[9];
|
||||
to->R10 = from->integer.arm_regs.r[10];
|
||||
to->R11 = from->integer.arm_regs.r[11];
|
||||
to->R12 = from->integer.arm_regs.r[12];
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
|
||||
to->Fpscr = from->fp.arm_regs.fpscr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
|
||||
__ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
|
||||
".thumb\n\t"
|
||||
|
|
|
@ -308,136 +308,6 @@ static void set_cpu_context( const CONTEXT *context )
|
|||
raise( SIGUSR2 );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_ARM64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_ARM64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->u.s.Fp = from->u.s.Fp;
|
||||
to->u.s.Lr = from->u.s.Lr;
|
||||
to->Sp = from->Sp;
|
||||
to->Pc = from->Pc;
|
||||
to->Cpsr = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
memcpy( to->u.X, from->u.X, sizeof(to->u.X) );
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
memcpy( to->V, from->V, sizeof(to->V) );
|
||||
to->Fpcr = from->Fpcr;
|
||||
to->Fpsr = from->Fpsr;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
memcpy( to->Bcr, from->Bcr, sizeof(to->Bcr) );
|
||||
memcpy( to->Bvr, from->Bvr, sizeof(to->Bvr) );
|
||||
memcpy( to->Wcr, from->Wcr, sizeof(to->Wcr) );
|
||||
memcpy( to->Wvr, from->Wvr, sizeof(to->Wvr) );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (from->cpu != CPU_ARM64) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_ARM64;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->u.s.Fp = from->integer.arm64_regs.x[29];
|
||||
to->u.s.Lr = from->integer.arm64_regs.x[30];
|
||||
to->Sp = from->ctl.arm64_regs.sp;
|
||||
to->Pc = from->ctl.arm64_regs.pc;
|
||||
to->Cpsr = from->ctl.arm64_regs.pstate;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i];
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
to->V[i].s.Low = from->fp.arm64_regs.q[i].low;
|
||||
to->V[i].s.High = from->fp.arm64_regs.q[i].high;
|
||||
}
|
||||
to->Fpcr = from->fp.arm64_regs.fpcr;
|
||||
to->Fpsr = from->fp.arm64_regs.fpsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* libunwind_virtual_unwind
|
||||
|
|
|
@ -1251,96 +1251,6 @@ void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_i386; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
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_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_i386;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Ebp = from->ctl.i386_regs.ebp;
|
||||
to->Esp = from->ctl.i386_regs.esp;
|
||||
to->Eip = from->ctl.i386_regs.eip;
|
||||
to->SegCs = from->ctl.i386_regs.cs;
|
||||
to->SegSs = from->ctl.i386_regs.ss;
|
||||
to->EFlags = from->ctl.i386_regs.eflags;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Eax = from->integer.i386_regs.eax;
|
||||
to->Ebx = from->integer.i386_regs.ebx;
|
||||
to->Ecx = from->integer.i386_regs.ecx;
|
||||
to->Edx = from->integer.i386_regs.edx;
|
||||
to->Esi = from->integer.i386_regs.esi;
|
||||
to->Edi = from->integer.i386_regs.edi;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_SEGMENTS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
to->SegDs = from->seg.i386_regs.ds;
|
||||
to->SegEs = from->seg.i386_regs.es;
|
||||
to->SegFs = from->seg.i386_regs.fs;
|
||||
to->SegGs = from->seg.i386_regs.gs;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
|
||||
to->FloatSave.StatusWord = from->fp.i386_regs.status;
|
||||
to->FloatSave.TagWord = from->fp.i386_regs.tag;
|
||||
to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
|
||||
to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
|
||||
to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
|
||||
to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
|
||||
to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
|
||||
memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
to->Dr0 = from->debug.i386_regs.dr0;
|
||||
to->Dr1 = from->debug.i386_regs.dr1;
|
||||
to->Dr2 = from->debug.i386_regs.dr2;
|
||||
to->Dr3 = from->debug.i386_regs.dr3;
|
||||
to->Dr6 = from->debug.i386_regs.dr6;
|
||||
to->Dr7 = from->debug.i386_regs.dr7;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_EXTENDED_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
|
||||
memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
|
@ -1352,82 +1262,23 @@ NTSTATUS CDECL DECLSPEC_HIDDEN __regs_NtGetContextThread( DWORD edi, DWORD esi,
|
|||
DWORD ebp, DWORD retaddr, HANDLE handle,
|
||||
CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
/* debug registers require a server call */
|
||||
if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE;
|
||||
|
||||
if (!self)
|
||||
/* preset the registers that we got from the asm wrapper */
|
||||
if (needed_flags & CONTEXT_INTEGER)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
context->Ebx = ebx;
|
||||
context->Esi = esi;
|
||||
context->Edi = edi;
|
||||
}
|
||||
|
||||
if (self)
|
||||
if (needed_flags & CONTEXT_CONTROL)
|
||||
{
|
||||
if (needed_flags & CONTEXT_INTEGER)
|
||||
{
|
||||
context->Eax = 0;
|
||||
context->Ebx = ebx;
|
||||
context->Ecx = 0;
|
||||
context->Edx = 0;
|
||||
context->Esi = esi;
|
||||
context->Edi = edi;
|
||||
context->ContextFlags |= CONTEXT_INTEGER;
|
||||
}
|
||||
if (needed_flags & CONTEXT_CONTROL)
|
||||
{
|
||||
context->Ebp = ebp;
|
||||
context->Esp = (DWORD)&retaddr;
|
||||
context->Eip = *(&edi - 1);
|
||||
context->SegCs = get_cs();
|
||||
context->SegSs = get_ds();
|
||||
context->EFlags = eflags;
|
||||
context->ContextFlags |= CONTEXT_CONTROL;
|
||||
}
|
||||
if (needed_flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
context->SegDs = get_ds();
|
||||
context->SegEs = get_ds();
|
||||
context->SegFs = get_fs();
|
||||
context->SegGs = get_gs();
|
||||
context->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
}
|
||||
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))
|
||||
{
|
||||
x86_thread_data()->dr0 = context->Dr0;
|
||||
x86_thread_data()->dr1 = context->Dr1;
|
||||
x86_thread_data()->dr2 = context->Dr2;
|
||||
x86_thread_data()->dr3 = context->Dr3;
|
||||
x86_thread_data()->dr6 = context->Dr6;
|
||||
x86_thread_data()->dr7 = context->Dr7;
|
||||
}
|
||||
context->Ebp = ebp;
|
||||
context->Esp = (DWORD)&retaddr;
|
||||
context->Eip = *(&edi - 1);
|
||||
context->EFlags = eflags;
|
||||
}
|
||||
|
||||
if (context->ContextFlags & (CONTEXT_INTEGER & ~CONTEXT_i386))
|
||||
TRACE( "%p: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n", handle,
|
||||
context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi );
|
||||
if (context->ContextFlags & (CONTEXT_CONTROL & ~CONTEXT_i386))
|
||||
TRACE( "%p: ebp=%08x esp=%08x eip=%08x cs=%04x ss=%04x flags=%08x\n", handle,
|
||||
context->Ebp, context->Esp, context->Eip, context->SegCs, context->SegSs, context->EFlags );
|
||||
if (context->ContextFlags & (CONTEXT_SEGMENTS & ~CONTEXT_i386))
|
||||
TRACE( "%p: ds=%04x es=%04x fs=%04x gs=%04x\n", handle,
|
||||
context->SegDs, context->SegEs, context->SegFs, context->SegGs );
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
|
||||
TRACE( "%p: dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n", handle,
|
||||
context->Dr0, context->Dr1, context->Dr2, context->Dr3, context->Dr6, context->Dr7 );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return unix_funcs->NtGetContextThread( handle, context );
|
||||
}
|
||||
__ASM_STDCALL_FUNC( NtGetContextThread, 8,
|
||||
"pushl %ebp\n\t"
|
||||
|
|
|
@ -260,247 +260,6 @@ void WINAPI RtlCaptureContext( CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Msr = from->Msr;
|
||||
to->Ctr = from->Ctr;
|
||||
to->Iar = from->Iar;
|
||||
to->Lr = from->Lr;
|
||||
to->Dar = from->Dar;
|
||||
to->Dsisr = from->Dsisr;
|
||||
to->Trap = from->Trap;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->Gpr0 = from->Gpr0;
|
||||
to->Gpr1 = from->Gpr1;
|
||||
to->Gpr2 = from->Gpr2;
|
||||
to->Gpr3 = from->Gpr3;
|
||||
to->Gpr4 = from->Gpr4;
|
||||
to->Gpr5 = from->Gpr5;
|
||||
to->Gpr6 = from->Gpr6;
|
||||
to->Gpr7 = from->Gpr7;
|
||||
to->Gpr8 = from->Gpr8;
|
||||
to->Gpr9 = from->Gpr9;
|
||||
to->Gpr10 = from->Gpr10;
|
||||
to->Gpr11 = from->Gpr11;
|
||||
to->Gpr12 = from->Gpr12;
|
||||
to->Gpr13 = from->Gpr13;
|
||||
to->Gpr14 = from->Gpr14;
|
||||
to->Gpr15 = from->Gpr15;
|
||||
to->Gpr16 = from->Gpr16;
|
||||
to->Gpr17 = from->Gpr17;
|
||||
to->Gpr18 = from->Gpr18;
|
||||
to->Gpr19 = from->Gpr19;
|
||||
to->Gpr20 = from->Gpr20;
|
||||
to->Gpr21 = from->Gpr21;
|
||||
to->Gpr22 = from->Gpr22;
|
||||
to->Gpr23 = from->Gpr23;
|
||||
to->Gpr24 = from->Gpr24;
|
||||
to->Gpr25 = from->Gpr25;
|
||||
to->Gpr26 = from->Gpr26;
|
||||
to->Gpr27 = from->Gpr27;
|
||||
to->Gpr28 = from->Gpr28;
|
||||
to->Gpr29 = from->Gpr29;
|
||||
to->Gpr30 = from->Gpr30;
|
||||
to->Gpr31 = from->Gpr31;
|
||||
to->Xer = from->Xer;
|
||||
to->Cr = from->Cr;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->Fpr0 = from->Fpr0;
|
||||
to->Fpr1 = from->Fpr1;
|
||||
to->Fpr2 = from->Fpr2;
|
||||
to->Fpr3 = from->Fpr3;
|
||||
to->Fpr4 = from->Fpr4;
|
||||
to->Fpr5 = from->Fpr5;
|
||||
to->Fpr6 = from->Fpr6;
|
||||
to->Fpr7 = from->Fpr7;
|
||||
to->Fpr8 = from->Fpr8;
|
||||
to->Fpr9 = from->Fpr9;
|
||||
to->Fpr10 = from->Fpr10;
|
||||
to->Fpr11 = from->Fpr11;
|
||||
to->Fpr12 = from->Fpr12;
|
||||
to->Fpr13 = from->Fpr13;
|
||||
to->Fpr14 = from->Fpr14;
|
||||
to->Fpr15 = from->Fpr15;
|
||||
to->Fpr16 = from->Fpr16;
|
||||
to->Fpr17 = from->Fpr17;
|
||||
to->Fpr18 = from->Fpr18;
|
||||
to->Fpr19 = from->Fpr19;
|
||||
to->Fpr20 = from->Fpr20;
|
||||
to->Fpr21 = from->Fpr21;
|
||||
to->Fpr22 = from->Fpr22;
|
||||
to->Fpr23 = from->Fpr23;
|
||||
to->Fpr24 = from->Fpr24;
|
||||
to->Fpr25 = from->Fpr25;
|
||||
to->Fpr26 = from->Fpr26;
|
||||
to->Fpr27 = from->Fpr27;
|
||||
to->Fpr28 = from->Fpr28;
|
||||
to->Fpr29 = from->Fpr29;
|
||||
to->Fpr30 = from->Fpr30;
|
||||
to->Fpr31 = from->Fpr31;
|
||||
to->Fpscr = from->Fpscr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_POWERPC) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = 0; /* no CPU id? */
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Msr = from->ctl.powerpc_regs.msr;
|
||||
to->Ctr = from->ctl.powerpc_regs.ctr;
|
||||
to->Iar = from->ctl.powerpc_regs.iar;
|
||||
to->Lr = from->ctl.powerpc_regs.lr;
|
||||
to->Dar = from->ctl.powerpc_regs.dar;
|
||||
to->Dsisr = from->ctl.powerpc_regs.dsisr;
|
||||
to->Trap = from->ctl.powerpc_regs.trap;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Gpr0 = from->integer.powerpc_regs.gpr[0];
|
||||
to->Gpr1 = from->integer.powerpc_regs.gpr[1];
|
||||
to->Gpr2 = from->integer.powerpc_regs.gpr[2];
|
||||
to->Gpr3 = from->integer.powerpc_regs.gpr[3];
|
||||
to->Gpr4 = from->integer.powerpc_regs.gpr[4];
|
||||
to->Gpr5 = from->integer.powerpc_regs.gpr[5];
|
||||
to->Gpr6 = from->integer.powerpc_regs.gpr[6];
|
||||
to->Gpr7 = from->integer.powerpc_regs.gpr[7];
|
||||
to->Gpr8 = from->integer.powerpc_regs.gpr[8];
|
||||
to->Gpr9 = from->integer.powerpc_regs.gpr[9];
|
||||
to->Gpr10 = from->integer.powerpc_regs.gpr[10];
|
||||
to->Gpr11 = from->integer.powerpc_regs.gpr[11];
|
||||
to->Gpr12 = from->integer.powerpc_regs.gpr[12];
|
||||
to->Gpr13 = from->integer.powerpc_regs.gpr[13];
|
||||
to->Gpr14 = from->integer.powerpc_regs.gpr[14];
|
||||
to->Gpr15 = from->integer.powerpc_regs.gpr[15];
|
||||
to->Gpr16 = from->integer.powerpc_regs.gpr[16];
|
||||
to->Gpr17 = from->integer.powerpc_regs.gpr[17];
|
||||
to->Gpr18 = from->integer.powerpc_regs.gpr[18];
|
||||
to->Gpr19 = from->integer.powerpc_regs.gpr[19];
|
||||
to->Gpr20 = from->integer.powerpc_regs.gpr[20];
|
||||
to->Gpr21 = from->integer.powerpc_regs.gpr[21];
|
||||
to->Gpr22 = from->integer.powerpc_regs.gpr[22];
|
||||
to->Gpr23 = from->integer.powerpc_regs.gpr[23];
|
||||
to->Gpr24 = from->integer.powerpc_regs.gpr[24];
|
||||
to->Gpr25 = from->integer.powerpc_regs.gpr[25];
|
||||
to->Gpr26 = from->integer.powerpc_regs.gpr[26];
|
||||
to->Gpr27 = from->integer.powerpc_regs.gpr[27];
|
||||
to->Gpr28 = from->integer.powerpc_regs.gpr[28];
|
||||
to->Gpr29 = from->integer.powerpc_regs.gpr[29];
|
||||
to->Gpr30 = from->integer.powerpc_regs.gpr[30];
|
||||
to->Gpr31 = from->integer.powerpc_regs.gpr[31];
|
||||
to->Xer = from->integer.powerpc_regs.xer;
|
||||
to->Cr = from->integer.powerpc_regs.cr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
to->Fpr0 = from->fp.powerpc_regs.fpr[0];
|
||||
to->Fpr1 = from->fp.powerpc_regs.fpr[1];
|
||||
to->Fpr2 = from->fp.powerpc_regs.fpr[2];
|
||||
to->Fpr3 = from->fp.powerpc_regs.fpr[3];
|
||||
to->Fpr4 = from->fp.powerpc_regs.fpr[4];
|
||||
to->Fpr5 = from->fp.powerpc_regs.fpr[5];
|
||||
to->Fpr6 = from->fp.powerpc_regs.fpr[6];
|
||||
to->Fpr7 = from->fp.powerpc_regs.fpr[7];
|
||||
to->Fpr8 = from->fp.powerpc_regs.fpr[8];
|
||||
to->Fpr9 = from->fp.powerpc_regs.fpr[9];
|
||||
to->Fpr10 = from->fp.powerpc_regs.fpr[10];
|
||||
to->Fpr11 = from->fp.powerpc_regs.fpr[11];
|
||||
to->Fpr12 = from->fp.powerpc_regs.fpr[12];
|
||||
to->Fpr13 = from->fp.powerpc_regs.fpr[13];
|
||||
to->Fpr14 = from->fp.powerpc_regs.fpr[14];
|
||||
to->Fpr15 = from->fp.powerpc_regs.fpr[15];
|
||||
to->Fpr16 = from->fp.powerpc_regs.fpr[16];
|
||||
to->Fpr17 = from->fp.powerpc_regs.fpr[17];
|
||||
to->Fpr18 = from->fp.powerpc_regs.fpr[18];
|
||||
to->Fpr19 = from->fp.powerpc_regs.fpr[19];
|
||||
to->Fpr20 = from->fp.powerpc_regs.fpr[20];
|
||||
to->Fpr21 = from->fp.powerpc_regs.fpr[21];
|
||||
to->Fpr22 = from->fp.powerpc_regs.fpr[22];
|
||||
to->Fpr23 = from->fp.powerpc_regs.fpr[23];
|
||||
to->Fpr24 = from->fp.powerpc_regs.fpr[24];
|
||||
to->Fpr25 = from->fp.powerpc_regs.fpr[25];
|
||||
to->Fpr26 = from->fp.powerpc_regs.fpr[26];
|
||||
to->Fpr27 = from->fp.powerpc_regs.fpr[27];
|
||||
to->Fpr28 = from->fp.powerpc_regs.fpr[28];
|
||||
to->Fpr29 = from->fp.powerpc_regs.fpr[29];
|
||||
to->Fpr30 = from->fp.powerpc_regs.fpr[30];
|
||||
to->Fpr31 = from->fp.powerpc_regs.fpr[31];
|
||||
to->Fpscr = from->fp.powerpc_regs.fpscr;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* call_stack_handlers
|
||||
*
|
||||
|
|
|
@ -1889,201 +1889,6 @@ void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Rbp = from->Rbp;
|
||||
to->Rip = from->Rip;
|
||||
to->Rsp = from->Rsp;
|
||||
to->SegCs = from->SegCs;
|
||||
to->SegSs = from->SegSs;
|
||||
to->EFlags = from->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->Rax = from->Rax;
|
||||
to->Rcx = from->Rcx;
|
||||
to->Rdx = from->Rdx;
|
||||
to->Rbx = from->Rbx;
|
||||
to->Rsi = from->Rsi;
|
||||
to->Rdi = from->Rdi;
|
||||
to->R8 = from->R8;
|
||||
to->R9 = from->R9;
|
||||
to->R10 = from->R10;
|
||||
to->R11 = from->R11;
|
||||
to->R12 = from->R12;
|
||||
to->R13 = from->R13;
|
||||
to->R14 = from->R14;
|
||||
to->R15 = from->R15;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
to->SegDs = from->SegDs;
|
||||
to->SegEs = from->SegEs;
|
||||
to->SegFs = from->SegFs;
|
||||
to->SegGs = from->SegGs;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->MxCsr = from->MxCsr;
|
||||
to->u.FltSave = from->u.FltSave;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->Dr0 = from->Dr0;
|
||||
to->Dr1 = from->Dr1;
|
||||
to->Dr2 = from->Dr2;
|
||||
to->Dr3 = from->Dr3;
|
||||
to->Dr6 = from->Dr6;
|
||||
to->Dr7 = from->Dr7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_AMD64;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Rbp = from->ctl.x86_64_regs.rbp;
|
||||
to->Rip = from->ctl.x86_64_regs.rip;
|
||||
to->Rsp = from->ctl.x86_64_regs.rsp;
|
||||
to->SegCs = from->ctl.x86_64_regs.cs;
|
||||
to->SegSs = from->ctl.x86_64_regs.ss;
|
||||
to->EFlags = from->ctl.x86_64_regs.flags;
|
||||
}
|
||||
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Rax = from->integer.x86_64_regs.rax;
|
||||
to->Rcx = from->integer.x86_64_regs.rcx;
|
||||
to->Rdx = from->integer.x86_64_regs.rdx;
|
||||
to->Rbx = from->integer.x86_64_regs.rbx;
|
||||
to->Rsi = from->integer.x86_64_regs.rsi;
|
||||
to->Rdi = from->integer.x86_64_regs.rdi;
|
||||
to->R8 = from->integer.x86_64_regs.r8;
|
||||
to->R9 = from->integer.x86_64_regs.r9;
|
||||
to->R10 = from->integer.x86_64_regs.r10;
|
||||
to->R11 = from->integer.x86_64_regs.r11;
|
||||
to->R12 = from->integer.x86_64_regs.r12;
|
||||
to->R13 = from->integer.x86_64_regs.r13;
|
||||
to->R14 = from->integer.x86_64_regs.r14;
|
||||
to->R15 = from->integer.x86_64_regs.r15;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_SEGMENTS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
to->SegDs = from->seg.x86_64_regs.ds;
|
||||
to->SegEs = from->seg.x86_64_regs.es;
|
||||
to->SegFs = from->seg.x86_64_regs.fs;
|
||||
to->SegGs = from->seg.x86_64_regs.gs;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
|
||||
to->MxCsr = to->u.FltSave.MxCsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
to->Dr0 = from->debug.x86_64_regs.dr0;
|
||||
to->Dr1 = from->debug.x86_64_regs.dr1;
|
||||
to->Dr2 = from->debug.x86_64_regs.dr2;
|
||||
to->Dr3 = from->debug.x86_64_regs.dr3;
|
||||
to->Dr6 = from->debug.x86_64_regs.dr6;
|
||||
to->Dr7 = from->debug.x86_64_regs.dr7;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!context) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
needed_flags = context->ContextFlags;
|
||||
|
||||
/* debug registers require a server call */
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)) self = FALSE;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
/* update the cached version of the debug registers */
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64))
|
||||
{
|
||||
amd64_thread_data()->dr0 = context->Dr0;
|
||||
amd64_thread_data()->dr1 = context->Dr1;
|
||||
amd64_thread_data()->dr2 = context->Dr2;
|
||||
amd64_thread_data()->dr3 = context->Dr3;
|
||||
amd64_thread_data()->dr6 = context->Dr6;
|
||||
amd64_thread_data()->dr7 = context->Dr7;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wow64_get_server_context_flags
|
||||
*/
|
||||
|
|
|
@ -777,6 +777,18 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
#ifndef __i386__
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
return unix_funcs->NtGetContextThread( handle, context );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* NtSetLdtEntries (NTDLL.@)
|
||||
* ZwSetLdtEntries (NTDLL.@)
|
||||
|
|
|
@ -986,6 +986,7 @@ static struct unix_funcs unix_funcs =
|
|||
NtClose,
|
||||
NtCurrentTeb,
|
||||
NtDuplicateObject,
|
||||
NtGetContextThread,
|
||||
NtSetContextThread,
|
||||
NtSetLdtEntries,
|
||||
get_main_args,
|
||||
|
|
|
@ -90,6 +90,63 @@ __ASM_GLOBAL_FUNC( set_cpu_context,
|
|||
"pop {pc}" )
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_ARM; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_ARM; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Sp = from->Sp;
|
||||
to->Lr = from->Lr;
|
||||
to->Pc = from->Pc;
|
||||
to->Cpsr = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->R0 = from->R0;
|
||||
to->R1 = from->R1;
|
||||
to->R2 = from->R2;
|
||||
to->R3 = from->R3;
|
||||
to->R4 = from->R4;
|
||||
to->R5 = from->R5;
|
||||
to->R6 = from->R6;
|
||||
to->R7 = from->R7;
|
||||
to->R8 = from->R8;
|
||||
to->R9 = from->R9;
|
||||
to->R10 = from->R10;
|
||||
to->R11 = from->R11;
|
||||
to->R12 = from->R12;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->Fpscr = from->Fpscr;
|
||||
memcpy( to->u.D, from->u.D, sizeof(to->u.D) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
|
@ -217,6 +274,37 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -99,6 +99,61 @@ static void set_cpu_context( const CONTEXT *context )
|
|||
raise( SIGUSR2 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_ARM64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_ARM64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->u.s.Fp = from->u.s.Fp;
|
||||
to->u.s.Lr = from->u.s.Lr;
|
||||
to->Sp = from->Sp;
|
||||
to->Pc = from->Pc;
|
||||
to->Cpsr = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
memcpy( to->u.X, from->u.X, sizeof(to->u.X) );
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
memcpy( to->V, from->V, sizeof(to->V) );
|
||||
to->Fpcr = from->Fpcr;
|
||||
to->Fpsr = from->Fpsr;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
memcpy( to->Bcr, from->Bcr, sizeof(to->Bcr) );
|
||||
memcpy( to->Bvr, from->Bvr, sizeof(to->Bvr) );
|
||||
memcpy( to->Wcr, from->Wcr, sizeof(to->Wcr) );
|
||||
memcpy( to->Wvr, from->Wvr, sizeof(to->Wvr) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
|
@ -220,6 +275,37 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -201,6 +201,53 @@ static inline int is_gdt_sel( WORD sel )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* save_fpu
|
||||
*
|
||||
* Save the thread FPU context.
|
||||
*/
|
||||
static inline void save_fpu( CONTEXT *context )
|
||||
{
|
||||
struct
|
||||
{
|
||||
DWORD ControlWord;
|
||||
DWORD StatusWord;
|
||||
DWORD TagWord;
|
||||
DWORD ErrorOffset;
|
||||
DWORD ErrorSelector;
|
||||
DWORD DataOffset;
|
||||
DWORD DataSelector;
|
||||
}
|
||||
float_status;
|
||||
|
||||
context->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
__asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
|
||||
|
||||
/* Reset unmasked exceptions status to avoid firing an exception. */
|
||||
memcpy(&float_status, &context->FloatSave, sizeof(float_status));
|
||||
float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
|
||||
|
||||
__asm__ __volatile__( "fldenv %0" : : "m" (float_status) );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* save_fpux
|
||||
*
|
||||
* Save the thread FPU extended context.
|
||||
*/
|
||||
static inline void save_fpux( CONTEXT *context )
|
||||
{
|
||||
/* we have to enforce alignment by hand */
|
||||
char buffer[sizeof(XMM_SAVE_AREA32) + 16];
|
||||
XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
|
||||
|
||||
context->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
|
||||
__asm__ __volatile__( "fxsave %0" : "=m" (*state) );
|
||||
memcpy( context->ExtendedRegisters, state, sizeof(*state) );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* restore_fpu
|
||||
*
|
||||
|
@ -329,6 +376,26 @@ void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_i386; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
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_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
|
@ -501,6 +568,89 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*
|
||||
* Note: we use a small assembly wrapper to save the necessary registers
|
||||
* in case we are fetching the context of the current thread.
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
/* debug registers require a server call */
|
||||
if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (needed_flags & CONTEXT_INTEGER)
|
||||
{
|
||||
context->Eax = 0;
|
||||
context->Ecx = 0;
|
||||
context->Edx = 0;
|
||||
/* other registers already set from asm wrapper */
|
||||
context->ContextFlags |= CONTEXT_INTEGER;
|
||||
}
|
||||
if (needed_flags & CONTEXT_CONTROL)
|
||||
{
|
||||
context->SegCs = get_cs();
|
||||
context->SegSs = get_ds();
|
||||
/* other registers already set from asm wrapper */
|
||||
context->ContextFlags |= CONTEXT_CONTROL;
|
||||
}
|
||||
if (needed_flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
context->SegDs = get_ds();
|
||||
context->SegEs = get_ds();
|
||||
context->SegFs = get_fs();
|
||||
context->SegGs = get_gs();
|
||||
context->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
}
|
||||
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))
|
||||
{
|
||||
x86_thread_data()->dr0 = context->Dr0;
|
||||
x86_thread_data()->dr1 = context->Dr1;
|
||||
x86_thread_data()->dr2 = context->Dr2;
|
||||
x86_thread_data()->dr3 = context->Dr3;
|
||||
x86_thread_data()->dr6 = context->Dr6;
|
||||
x86_thread_data()->dr7 = context->Dr7;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->ContextFlags & (CONTEXT_INTEGER & ~CONTEXT_i386))
|
||||
TRACE( "%p: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n", handle,
|
||||
context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi );
|
||||
if (context->ContextFlags & (CONTEXT_CONTROL & ~CONTEXT_i386))
|
||||
TRACE( "%p: ebp=%08x esp=%08x eip=%08x cs=%04x ss=%04x flags=%08x\n", handle,
|
||||
context->Ebp, context->Esp, context->Eip, context->SegCs, context->SegSs, context->EFlags );
|
||||
if (context->ContextFlags & (CONTEXT_SEGMENTS & ~CONTEXT_i386))
|
||||
TRACE( "%p: ds=%04x es=%04x fs=%04x gs=%04x\n", handle,
|
||||
context->SegDs, context->SegEs, context->SegFs, context->SegGs );
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
|
||||
TRACE( "%p: dr0=%08x dr1=%08x dr2=%08x dr3=%08x dr6=%08x dr7=%08x\n", handle,
|
||||
context->Dr0, context->Dr1, context->Dr2, context->Dr3, context->Dr6, context->Dr7 );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* LDT support
|
||||
*/
|
||||
|
|
|
@ -77,6 +77,116 @@ static void set_cpu_context( const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Msr = from->Msr;
|
||||
to->Ctr = from->Ctr;
|
||||
to->Iar = from->Iar;
|
||||
to->Lr = from->Lr;
|
||||
to->Dar = from->Dar;
|
||||
to->Dsisr = from->Dsisr;
|
||||
to->Trap = from->Trap;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->Gpr0 = from->Gpr0;
|
||||
to->Gpr1 = from->Gpr1;
|
||||
to->Gpr2 = from->Gpr2;
|
||||
to->Gpr3 = from->Gpr3;
|
||||
to->Gpr4 = from->Gpr4;
|
||||
to->Gpr5 = from->Gpr5;
|
||||
to->Gpr6 = from->Gpr6;
|
||||
to->Gpr7 = from->Gpr7;
|
||||
to->Gpr8 = from->Gpr8;
|
||||
to->Gpr9 = from->Gpr9;
|
||||
to->Gpr10 = from->Gpr10;
|
||||
to->Gpr11 = from->Gpr11;
|
||||
to->Gpr12 = from->Gpr12;
|
||||
to->Gpr13 = from->Gpr13;
|
||||
to->Gpr14 = from->Gpr14;
|
||||
to->Gpr15 = from->Gpr15;
|
||||
to->Gpr16 = from->Gpr16;
|
||||
to->Gpr17 = from->Gpr17;
|
||||
to->Gpr18 = from->Gpr18;
|
||||
to->Gpr19 = from->Gpr19;
|
||||
to->Gpr20 = from->Gpr20;
|
||||
to->Gpr21 = from->Gpr21;
|
||||
to->Gpr22 = from->Gpr22;
|
||||
to->Gpr23 = from->Gpr23;
|
||||
to->Gpr24 = from->Gpr24;
|
||||
to->Gpr25 = from->Gpr25;
|
||||
to->Gpr26 = from->Gpr26;
|
||||
to->Gpr27 = from->Gpr27;
|
||||
to->Gpr28 = from->Gpr28;
|
||||
to->Gpr29 = from->Gpr29;
|
||||
to->Gpr30 = from->Gpr30;
|
||||
to->Gpr31 = from->Gpr31;
|
||||
to->Xer = from->Xer;
|
||||
to->Cr = from->Cr;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->Fpr0 = from->Fpr0;
|
||||
to->Fpr1 = from->Fpr1;
|
||||
to->Fpr2 = from->Fpr2;
|
||||
to->Fpr3 = from->Fpr3;
|
||||
to->Fpr4 = from->Fpr4;
|
||||
to->Fpr5 = from->Fpr5;
|
||||
to->Fpr6 = from->Fpr6;
|
||||
to->Fpr7 = from->Fpr7;
|
||||
to->Fpr8 = from->Fpr8;
|
||||
to->Fpr9 = from->Fpr9;
|
||||
to->Fpr10 = from->Fpr10;
|
||||
to->Fpr11 = from->Fpr11;
|
||||
to->Fpr12 = from->Fpr12;
|
||||
to->Fpr13 = from->Fpr13;
|
||||
to->Fpr14 = from->Fpr14;
|
||||
to->Fpr15 = from->Fpr15;
|
||||
to->Fpr16 = from->Fpr16;
|
||||
to->Fpr17 = from->Fpr17;
|
||||
to->Fpr18 = from->Fpr18;
|
||||
to->Fpr19 = from->Fpr19;
|
||||
to->Fpr20 = from->Fpr20;
|
||||
to->Fpr21 = from->Fpr21;
|
||||
to->Fpr22 = from->Fpr22;
|
||||
to->Fpr23 = from->Fpr23;
|
||||
to->Fpr24 = from->Fpr24;
|
||||
to->Fpr25 = from->Fpr25;
|
||||
to->Fpr26 = from->Fpr26;
|
||||
to->Fpr27 = from->Fpr27;
|
||||
to->Fpr28 = from->Fpr28;
|
||||
to->Fpr29 = from->Fpr29;
|
||||
to->Fpr30 = from->Fpr30;
|
||||
to->Fpr31 = from->Fpr31;
|
||||
to->Fpscr = from->Fpscr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
|
@ -296,6 +406,37 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags = context->ContextFlags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self && needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -219,6 +219,83 @@ void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_server_context_flags
|
||||
*
|
||||
* Convert CPU-specific flags to generic server flags
|
||||
*/
|
||||
static unsigned int get_server_context_flags( DWORD flags )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
|
||||
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* copy_context
|
||||
*
|
||||
* Copy a register context according to the flags.
|
||||
*/
|
||||
static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
|
||||
{
|
||||
flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->Rbp = from->Rbp;
|
||||
to->Rip = from->Rip;
|
||||
to->Rsp = from->Rsp;
|
||||
to->SegCs = from->SegCs;
|
||||
to->SegSs = from->SegSs;
|
||||
to->EFlags = from->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->Rax = from->Rax;
|
||||
to->Rcx = from->Rcx;
|
||||
to->Rdx = from->Rdx;
|
||||
to->Rbx = from->Rbx;
|
||||
to->Rsi = from->Rsi;
|
||||
to->Rdi = from->Rdi;
|
||||
to->R8 = from->R8;
|
||||
to->R9 = from->R9;
|
||||
to->R10 = from->R10;
|
||||
to->R11 = from->R11;
|
||||
to->R12 = from->R12;
|
||||
to->R13 = from->R13;
|
||||
to->R14 = from->R14;
|
||||
to->R15 = from->R15;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
to->SegDs = from->SegDs;
|
||||
to->SegEs = from->SegEs;
|
||||
to->SegFs = from->SegFs;
|
||||
to->SegGs = from->SegGs;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->MxCsr = from->MxCsr;
|
||||
to->u.FltSave = from->u.FltSave;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->Dr0 = from->Dr0;
|
||||
to->Dr1 = from->Dr1;
|
||||
to->Dr2 = from->Dr2;
|
||||
to->Dr3 = from->Dr3;
|
||||
to->Dr6 = from->Dr6;
|
||||
to->Dr7 = from->Dr7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
|
@ -382,6 +459,57 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* NtGetContextThread (NTDLL.@)
|
||||
* ZwGetContextThread (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
DWORD needed_flags;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
|
||||
if (!context) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
needed_flags = context->ContextFlags;
|
||||
|
||||
/* debug registers require a server call */
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)) self = FALSE;
|
||||
|
||||
if (!self)
|
||||
{
|
||||
context_t server_context;
|
||||
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
|
||||
|
||||
if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
|
||||
if ((ret = context_from_server( context, &server_context ))) return ret;
|
||||
needed_flags &= ~context->ContextFlags;
|
||||
}
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (needed_flags)
|
||||
{
|
||||
CONTEXT ctx;
|
||||
RtlCaptureContext( &ctx );
|
||||
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
|
||||
context->ContextFlags |= ctx.ContextFlags & needed_flags;
|
||||
}
|
||||
/* update the cached version of the debug registers */
|
||||
if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64))
|
||||
{
|
||||
amd64_thread_data()->dr0 = context->Dr0;
|
||||
amd64_thread_data()->dr1 = context->Dr1;
|
||||
amd64_thread_data()->dr2 = context->Dr2;
|
||||
amd64_thread_data()->dr3 = context->Dr3;
|
||||
amd64_thread_data()->dr6 = context->Dr6;
|
||||
amd64_thread_data()->dr7 = context->Dr7;
|
||||
}
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -168,3 +168,43 @@ NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_thread_context
|
||||
*/
|
||||
NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
|
||||
SERVER_START_REQ( get_thread_context )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
req->flags = flags;
|
||||
wine_server_set_reply( req, context, sizeof(*context) );
|
||||
ret = wine_server_call( req );
|
||||
*self = reply->self;
|
||||
handle = wine_server_ptr_handle( reply->handle );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret == STATUS_PENDING)
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
timeout.QuadPart = -1000000;
|
||||
if (NtWaitForSingleObject( handle, FALSE, &timeout ))
|
||||
{
|
||||
NtClose( handle );
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
SERVER_START_REQ( get_thread_context )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
req->flags = flags;
|
||||
wine_server_set_reply( req, context, sizeof(*context) );
|
||||
ret = wine_server_call( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ extern void start_server( BOOL debug ) DECLSPEC_HIDDEN;
|
|||
extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
struct ldt_copy;
|
||||
|
||||
/* increment this when you change the function table */
|
||||
#define NTDLL_UNIXLIB_VERSION 14
|
||||
#define NTDLL_UNIXLIB_VERSION 15
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
|
@ -37,6 +37,7 @@ struct unix_funcs
|
|||
NTSTATUS (WINAPI *NtDuplicateObject)( HANDLE source_process, HANDLE source,
|
||||
HANDLE dest_process, HANDLE *dest,
|
||||
ACCESS_MASK access, ULONG attributes, ULONG options );
|
||||
NTSTATUS (WINAPI *NtGetContextThread)( HANDLE handle, CONTEXT *context );
|
||||
NTSTATUS (WINAPI *NtSetContextThread)( HANDLE handle, const CONTEXT *context );
|
||||
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue