Commit ac90898f authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Move NtSetContextThread() implementation to the Unix library.

parent b4310a19
......@@ -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_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;
......
......@@ -354,61 +354,6 @@ static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
*/
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
{
DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_ARM;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->ctl.arm_regs.sp = from->Sp;
to->ctl.arm_regs.lr = from->Lr;
to->ctl.arm_regs.pc = from->Pc;
to->ctl.arm_regs.cpsr = from->Cpsr;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
to->integer.arm_regs.r[0] = from->R0;
to->integer.arm_regs.r[1] = from->R1;
to->integer.arm_regs.r[2] = from->R2;
to->integer.arm_regs.r[3] = from->R3;
to->integer.arm_regs.r[4] = from->R4;
to->integer.arm_regs.r[5] = from->R5;
to->integer.arm_regs.r[6] = from->R6;
to->integer.arm_regs.r[7] = from->R7;
to->integer.arm_regs.r[8] = from->R8;
to->integer.arm_regs.r[9] = from->R9;
to->integer.arm_regs.r[10] = from->R10;
to->integer.arm_regs.r[11] = from->R11;
to->integer.arm_regs.r[12] = from->R12;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->flags |= SERVER_CTX_FLOATING_POINT;
for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
to->fp.arm_regs.fpscr = from->Fpscr;
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
}
return STATUS_SUCCESS;
}
/***********************************************************************
* context_from_server
*
* Convert a register context from the server format.
......@@ -463,23 +408,6 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret;
BOOL self;
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*/
......
......@@ -361,55 +361,6 @@ static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
}
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
*/
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
{
DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM64; /* get rid of CPU id */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_ARM64;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->integer.arm64_regs.x[29] = from->u.s.Fp;
to->integer.arm64_regs.x[30] = from->u.s.Lr;
to->ctl.arm64_regs.sp = from->Sp;
to->ctl.arm64_regs.pc = from->Pc;
to->ctl.arm64_regs.pstate = from->Cpsr;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i];
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->flags |= SERVER_CTX_FLOATING_POINT;
for (i = 0; i < 32; i++)
{
to->fp.arm64_regs.q[i].low = from->V[i].s.Low;
to->fp.arm64_regs.q[i].high = from->V[i].s.High;
}
to->fp.arm64_regs.fpcr = from->Fpcr;
to->fp.arm64_regs.fpsr = from->Fpsr;
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
}
return STATUS_SUCCESS;
}
/***********************************************************************
* context_from_server
*
* Convert a register context from the server format.
......@@ -458,29 +409,6 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_ARM64)))
self = FALSE;
if (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*/
......
......@@ -1272,78 +1272,6 @@ static unsigned int get_server_context_flags( DWORD flags )
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
*/
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
{
DWORD flags = from->ContextFlags & ~CONTEXT_i386; /* get rid of CPU id */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_x86;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->ctl.i386_regs.ebp = from->Ebp;
to->ctl.i386_regs.esp = from->Esp;
to->ctl.i386_regs.eip = from->Eip;
to->ctl.i386_regs.cs = from->SegCs;
to->ctl.i386_regs.ss = from->SegSs;
to->ctl.i386_regs.eflags = from->EFlags;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
to->integer.i386_regs.eax = from->Eax;
to->integer.i386_regs.ebx = from->Ebx;
to->integer.i386_regs.ecx = from->Ecx;
to->integer.i386_regs.edx = from->Edx;
to->integer.i386_regs.esi = from->Esi;
to->integer.i386_regs.edi = from->Edi;
}
if (flags & CONTEXT_SEGMENTS)
{
to->flags |= SERVER_CTX_SEGMENTS;
to->seg.i386_regs.ds = from->SegDs;
to->seg.i386_regs.es = from->SegEs;
to->seg.i386_regs.fs = from->SegFs;
to->seg.i386_regs.gs = from->SegGs;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->flags |= SERVER_CTX_FLOATING_POINT;
to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
to->fp.i386_regs.status = from->FloatSave.StatusWord;
to->fp.i386_regs.tag = from->FloatSave.TagWord;
to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
to->debug.i386_regs.dr0 = from->Dr0;
to->debug.i386_regs.dr1 = from->Dr1;
to->debug.i386_regs.dr2 = from->Dr2;
to->debug.i386_regs.dr3 = from->Dr3;
to->debug.i386_regs.dr6 = from->Dr6;
to->debug.i386_regs.dr7 = from->Dr7;
}
if (flags & CONTEXT_EXTENDED_REGISTERS)
{
to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
}
return STATUS_SUCCESS;
}
/***********************************************************************
* context_from_server
*
* Convert a register context from the server format.
......@@ -1414,36 +1342,6 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
/* debug registers require a server call */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
self = (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 (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*
......
......@@ -261,17 +261,6 @@ void WINAPI RtlCaptureContext( CONTEXT *context )
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
static void set_cpu_context( const CONTEXT *context )
{
FIXME("not implemented\n");
}
/***********************************************************************
* get_server_context_flags
*
* Convert CPU-specific flags to generic server flags
......@@ -382,108 +371,6 @@ static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
*/
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
{
DWORD flags = from->ContextFlags; /* no CPU id? */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_POWERPC;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->ctl.powerpc_regs.iar = from->Iar;
to->ctl.powerpc_regs.msr = from->Msr;
to->ctl.powerpc_regs.ctr = from->Ctr;
to->ctl.powerpc_regs.lr = from->Lr;
to->ctl.powerpc_regs.dar = from->Dar;
to->ctl.powerpc_regs.dsisr = from->Dsisr;
to->ctl.powerpc_regs.trap = from->Trap;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
to->integer.powerpc_regs.gpr[0] = from->Gpr0;
to->integer.powerpc_regs.gpr[1] = from->Gpr1;
to->integer.powerpc_regs.gpr[2] = from->Gpr2;
to->integer.powerpc_regs.gpr[3] = from->Gpr3;
to->integer.powerpc_regs.gpr[4] = from->Gpr4;
to->integer.powerpc_regs.gpr[5] = from->Gpr5;
to->integer.powerpc_regs.gpr[6] = from->Gpr6;
to->integer.powerpc_regs.gpr[7] = from->Gpr7;
to->integer.powerpc_regs.gpr[8] = from->Gpr8;
to->integer.powerpc_regs.gpr[9] = from->Gpr9;
to->integer.powerpc_regs.gpr[10] = from->Gpr10;
to->integer.powerpc_regs.gpr[11] = from->Gpr11;
to->integer.powerpc_regs.gpr[12] = from->Gpr12;
to->integer.powerpc_regs.gpr[13] = from->Gpr13;
to->integer.powerpc_regs.gpr[14] = from->Gpr14;
to->integer.powerpc_regs.gpr[15] = from->Gpr15;
to->integer.powerpc_regs.gpr[16] = from->Gpr16;
to->integer.powerpc_regs.gpr[17] = from->Gpr17;
to->integer.powerpc_regs.gpr[18] = from->Gpr18;
to->integer.powerpc_regs.gpr[19] = from->Gpr19;
to->integer.powerpc_regs.gpr[20] = from->Gpr20;
to->integer.powerpc_regs.gpr[21] = from->Gpr21;
to->integer.powerpc_regs.gpr[22] = from->Gpr22;
to->integer.powerpc_regs.gpr[23] = from->Gpr23;
to->integer.powerpc_regs.gpr[24] = from->Gpr24;
to->integer.powerpc_regs.gpr[25] = from->Gpr25;
to->integer.powerpc_regs.gpr[26] = from->Gpr26;
to->integer.powerpc_regs.gpr[27] = from->Gpr27;
to->integer.powerpc_regs.gpr[28] = from->Gpr28;
to->integer.powerpc_regs.gpr[29] = from->Gpr29;
to->integer.powerpc_regs.gpr[30] = from->Gpr30;
to->integer.powerpc_regs.gpr[31] = from->Gpr31;
to->integer.powerpc_regs.xer = from->Xer;
to->integer.powerpc_regs.cr = from->Cr;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->flags |= SERVER_CTX_FLOATING_POINT;
to->fp.powerpc_regs.fpr[0] = from->Fpr0;
to->fp.powerpc_regs.fpr[1] = from->Fpr1;
to->fp.powerpc_regs.fpr[2] = from->Fpr2;
to->fp.powerpc_regs.fpr[3] = from->Fpr3;
to->fp.powerpc_regs.fpr[4] = from->Fpr4;
to->fp.powerpc_regs.fpr[5] = from->Fpr5;
to->fp.powerpc_regs.fpr[6] = from->Fpr6;
to->fp.powerpc_regs.fpr[7] = from->Fpr7;
to->fp.powerpc_regs.fpr[8] = from->Fpr8;
to->fp.powerpc_regs.fpr[9] = from->Fpr9;
to->fp.powerpc_regs.fpr[10] = from->Fpr10;
to->fp.powerpc_regs.fpr[11] = from->Fpr11;
to->fp.powerpc_regs.fpr[12] = from->Fpr12;
to->fp.powerpc_regs.fpr[13] = from->Fpr13;
to->fp.powerpc_regs.fpr[14] = from->Fpr14;
to->fp.powerpc_regs.fpr[15] = from->Fpr15;
to->fp.powerpc_regs.fpr[16] = from->Fpr16;
to->fp.powerpc_regs.fpr[17] = from->Fpr17;
to->fp.powerpc_regs.fpr[18] = from->Fpr18;
to->fp.powerpc_regs.fpr[19] = from->Fpr19;
to->fp.powerpc_regs.fpr[20] = from->Fpr20;
to->fp.powerpc_regs.fpr[21] = from->Fpr21;
to->fp.powerpc_regs.fpr[22] = from->Fpr22;
to->fp.powerpc_regs.fpr[23] = from->Fpr23;
to->fp.powerpc_regs.fpr[24] = from->Fpr24;
to->fp.powerpc_regs.fpr[25] = from->Fpr25;
to->fp.powerpc_regs.fpr[26] = from->Fpr26;
to->fp.powerpc_regs.fpr[27] = from->Fpr27;
to->fp.powerpc_regs.fpr[28] = from->Fpr28;
to->fp.powerpc_regs.fpr[29] = from->Fpr29;
to->fp.powerpc_regs.fpr[30] = from->Fpr30;
to->fp.powerpc_regs.fpr[31] = from->Fpr31;
to->fp.powerpc_regs.fpscr = from->Fpscr;
}
return STATUS_SUCCESS;
}
/***********************************************************************
* context_from_server
*
* Convert a register context from the server format.
......@@ -584,23 +471,6 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret;
BOOL self;
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*/
......
......@@ -1967,73 +1967,6 @@ static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
*/
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
{
DWORD flags = from->ContextFlags & ~CONTEXT_AMD64; /* get rid of CPU id */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_x86_64;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->ctl.x86_64_regs.rbp = from->Rbp;
to->ctl.x86_64_regs.rip = from->Rip;
to->ctl.x86_64_regs.rsp = from->Rsp;
to->ctl.x86_64_regs.cs = from->SegCs;
to->ctl.x86_64_regs.ss = from->SegSs;
to->ctl.x86_64_regs.flags = from->EFlags;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
to->integer.x86_64_regs.rax = from->Rax;
to->integer.x86_64_regs.rcx = from->Rcx;
to->integer.x86_64_regs.rdx = from->Rdx;
to->integer.x86_64_regs.rbx = from->Rbx;
to->integer.x86_64_regs.rsi = from->Rsi;
to->integer.x86_64_regs.rdi = from->Rdi;
to->integer.x86_64_regs.r8 = from->R8;
to->integer.x86_64_regs.r9 = from->R9;
to->integer.x86_64_regs.r10 = from->R10;
to->integer.x86_64_regs.r11 = from->R11;
to->integer.x86_64_regs.r12 = from->R12;
to->integer.x86_64_regs.r13 = from->R13;
to->integer.x86_64_regs.r14 = from->R14;
to->integer.x86_64_regs.r15 = from->R15;
}
if (flags & CONTEXT_SEGMENTS)
{
to->flags |= SERVER_CTX_SEGMENTS;
to->seg.x86_64_regs.ds = from->SegDs;
to->seg.x86_64_regs.es = from->SegEs;
to->seg.x86_64_regs.fs = from->SegFs;
to->seg.x86_64_regs.gs = from->SegGs;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->flags |= SERVER_CTX_FLOATING_POINT;
memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
to->debug.x86_64_regs.dr0 = from->Dr0;
to->debug.x86_64_regs.dr1 = from->Dr1;
to->debug.x86_64_regs.dr2 = from->Dr2;
to->debug.x86_64_regs.dr3 = from->Dr3;
to->debug.x86_64_regs.dr6 = from->Dr6;
to->debug.x86_64_regs.dr7 = from->Dr7;
}
return STATUS_SUCCESS;
}
/***********************************************************************
* context_from_server
*
* Convert a register context from the server format.
......@@ -2101,35 +2034,6 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
/* debug registers require a server call */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)))
self = (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);
if (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*/
......
......@@ -767,6 +767,16 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
return unix_funcs->NtSetContextThread( handle, context );
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
......
......@@ -986,6 +986,7 @@ static struct unix_funcs unix_funcs =
NtClose,
NtCurrentTeb,
NtDuplicateObject,
NtSetContextThread,
NtSetLdtEntries,
get_main_args,
get_paths,
......
......@@ -70,6 +70,27 @@ static pthread_key_t teb_key;
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context );
__ASM_GLOBAL_FUNC( set_cpu_context,
".arm\n\t"
"ldr r2, [r0, #0x44]\n\t" /* context->Cpsr */
"tst r2, #0x20\n\t" /* thumb? */
"ldr r1, [r0, #0x40]\n\t" /* context->Pc */
"orrne r1, r1, #1\n\t" /* Adjust PC according to thumb */
"biceq r1, r1, #1\n\t" /* Adjust PC according to arm */
"msr CPSR_f, r2\n\t"
"ldr lr, [r0, #0x3c]\n\t" /* context->Lr */
"ldr sp, [r0, #0x38]\n\t" /* context->Sp */
"push {r1}\n\t"
"ldmib r0, {r0-r12}\n\t" /* context->R0..R12 */
"pop {pc}" )
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
......@@ -179,6 +200,23 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret;
BOOL self;
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/**********************************************************************
* get_thread_ldt_entry
*/
......
......@@ -73,6 +73,31 @@ static pthread_key_t teb_key;
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
struct arm64_thread_data
{
void *exit_frame; /* exit frame pointer */
CONTEXT *context; /* context to set with SIGUSR2 */
};
C_ASSERT( sizeof(struct arm64_thread_data) <= sizeof(((TEB *)0)->SystemReserved2) );
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct arm64_thread_data, exit_frame ) == 0x300 );
static inline struct arm64_thread_data *arm64_thread_data(void)
{
return (struct arm64_thread_data *)NtCurrentTeb()->SystemReserved2;
}
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
static void set_cpu_context( const CONTEXT *context )
{
InterlockedExchangePointer( (void **)&arm64_thread_data()->context, (void *)context );
raise( SIGUSR2 );
}
/***********************************************************************
* context_to_server
......@@ -172,6 +197,29 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_ARM64)))
self = FALSE;
if (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/**********************************************************************
* get_thread_ldt_entry
*/
......
......@@ -61,6 +61,34 @@
#include "unix_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(seh);
/* not defined for x86, so copy the x86_64 definition */
typedef struct DECLSPEC_ALIGN(16) _M128A
{
ULONGLONG Low;
LONGLONG High;
} M128A;
typedef struct
{
WORD ControlWord;
WORD StatusWord;
BYTE TagWord;
BYTE Reserved1;
WORD ErrorOpcode;
DWORD ErrorOffset;
WORD ErrorSelector;
WORD Reserved2;
DWORD DataOffset;
WORD DataSelector;
WORD Reserved3;
DWORD MxCsr;
DWORD MxCsr_Mask;
M128A FloatRegisters[8];
M128A XmmRegisters[16];
BYTE Reserved4[96];
} XMM_SAVE_AREA32;
/***********************************************************************
* signal context platform-specific definitions
......@@ -152,6 +180,11 @@ struct x86_thread_data
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, gs ) == 0x1d8 );
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 );
static inline struct x86_thread_data *x86_thread_data(void)
{
return (struct x86_thread_data *)NtCurrentTeb()->SystemReserved2;
}
static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; }
static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; }
static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; }
......@@ -169,6 +202,134 @@ static inline int is_gdt_sel( WORD sel )
/***********************************************************************
* restore_fpu
*
* Restore the FPU context to a sigcontext.
*/
static inline void restore_fpu( const CONTEXT *context )
{
FLOATING_SAVE_AREA float_status = context->FloatSave;
/* reset the current interrupt status */
float_status.StatusWord &= float_status.ControlWord | 0xffffff80;
__asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) );
}
/***********************************************************************
* restore_fpux
*
* Restore the FPU extended context to a sigcontext.
*/
static inline void restore_fpux( const 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);
memcpy( state, context->ExtendedRegisters, sizeof(*state) );
/* reset the current interrupt status */
state->StatusWord &= state->ControlWord | 0xff80;
__asm__ __volatile__( "fxrstor %0" : : "m" (*state) );
}
/***********************************************************************
* set_full_cpu_context
*
* Set the new CPU context.
*/
extern void set_full_cpu_context( const CONTEXT *context );
__ASM_GLOBAL_FUNC( set_full_cpu_context,
"movl 4(%esp),%ecx\n\t"
"movw 0x8c(%ecx),%gs\n\t" /* SegGs */
"movw 0x90(%ecx),%fs\n\t" /* SegFs */
"movw 0x94(%ecx),%es\n\t" /* SegEs */
"movl 0x9c(%ecx),%edi\n\t" /* Edi */
"movl 0xa0(%ecx),%esi\n\t" /* Esi */
"movl 0xa4(%ecx),%ebx\n\t" /* Ebx */
"movl 0xb4(%ecx),%ebp\n\t" /* Ebp */
"movw %ss,%ax\n\t"
"cmpw 0xc8(%ecx),%ax\n\t" /* SegSs */
"jne 1f\n\t"
/* As soon as we have switched stacks the context structure could
* be invalid (when signal handlers are executed for example). Copy
* values on the target stack before changing ESP. */
"movl 0xc4(%ecx),%eax\n\t" /* Esp */
"leal -4*4(%eax),%eax\n\t"
"movl 0xc0(%ecx),%edx\n\t" /* EFlags */
"movl %edx,3*4(%eax)\n\t"
"movl 0xbc(%ecx),%edx\n\t" /* SegCs */
"movl %edx,2*4(%eax)\n\t"
"movl 0xb8(%ecx),%edx\n\t" /* Eip */
"movl %edx,1*4(%eax)\n\t"
"movl 0xb0(%ecx),%edx\n\t" /* Eax */
"movl %edx,0*4(%eax)\n\t"
"pushl 0x98(%ecx)\n\t" /* SegDs */
"movl 0xa8(%ecx),%edx\n\t" /* Edx */
"movl 0xac(%ecx),%ecx\n\t" /* Ecx */
"popl %ds\n\t"
"movl %eax,%esp\n\t"
"popl %eax\n\t"
"iret\n"
/* Restore the context when the stack segment changes. We can't use
* the same code as above because we do not know if the stack segment
* is 16 or 32 bit, and 'movl' will throw an exception when we try to
* access memory above the limit. */
"1:\n\t"
"movl 0xa8(%ecx),%edx\n\t" /* Edx */
"movl 0xb0(%ecx),%eax\n\t" /* Eax */
"movw 0xc8(%ecx),%ss\n\t" /* SegSs */
"movl 0xc4(%ecx),%esp\n\t" /* Esp */
"pushl 0xc0(%ecx)\n\t" /* EFlags */
"pushl 0xbc(%ecx)\n\t" /* SegCs */
"pushl 0xb8(%ecx)\n\t" /* Eip */
"pushl 0x98(%ecx)\n\t" /* SegDs */
"movl 0xac(%ecx),%ecx\n\t" /* Ecx */
"popl %ds\n\t"
"iret" )
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context. Used by NtSetContextThread.
*/
void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
{
DWORD flags = context->ContextFlags & ~CONTEXT_i386;
if (flags & CONTEXT_EXTENDED_REGISTERS) restore_fpux( context );
else if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
if (flags & CONTEXT_DEBUG_REGISTERS)
{
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 (flags & CONTEXT_FULL)
{
if (!(flags & CONTEXT_CONTROL))
FIXME( "setting partial context (%x) not supported\n", flags );
else if (flags & CONTEXT_SEGMENTS)
set_full_cpu_context( context );
else
{
CONTEXT newcontext = *context;
newcontext.SegDs = get_ds();
newcontext.SegEs = get_ds();
newcontext.SegFs = get_fs();
newcontext.SegGs = get_gs();
set_full_cpu_context( &newcontext );
}
}
}
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
......@@ -311,6 +472,36 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
/* debug registers require a server call */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
self = (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 (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/***********************************************************************
* LDT support
*/
......
......@@ -67,6 +67,17 @@ static pthread_key_t teb_key;
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context.
*/
static void set_cpu_context( const CONTEXT *context )
{
FIXME("not implemented\n");
}
/***********************************************************************
* context_to_server
*
* Convert a register context to the server format.
......@@ -268,6 +279,23 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret;
BOOL self;
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/**********************************************************************
* get_thread_ldt_entry
*/
......
......@@ -76,6 +76,8 @@
#include "unix_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(seh);
/***********************************************************************
* signal context platform-specific definitions
*/
......@@ -112,6 +114,110 @@ enum i386_trap_code
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
struct amd64_thread_data
{
DWORD_PTR dr0; /* debug registers */
DWORD_PTR dr1;
DWORD_PTR dr2;
DWORD_PTR dr3;
DWORD_PTR dr6;
DWORD_PTR dr7;
void *exit_frame; /* exit frame pointer */
};
C_ASSERT( sizeof(struct amd64_thread_data) <= sizeof(((TEB *)0)->SystemReserved2) );
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct amd64_thread_data, exit_frame ) == 0x330 );
static inline struct amd64_thread_data *amd64_thread_data(void)
{
return (struct amd64_thread_data *)NtCurrentTeb()->SystemReserved2;
}
/***********************************************************************
* set_full_cpu_context
*
* Set the new CPU context.
*/
extern void set_full_cpu_context( const CONTEXT *context );
__ASM_GLOBAL_FUNC( set_full_cpu_context,
"subq $40,%rsp\n\t"
__ASM_SEH(".seh_stackalloc 0x40\n\t")
__ASM_SEH(".seh_endprologue\n\t")
__ASM_CFI(".cfi_adjust_cfa_offset 40\n\t")
"ldmxcsr 0x34(%rdi)\n\t" /* context->MxCsr */
"movw 0x38(%rdi),%ax\n\t" /* context->SegCs */
"movq %rax,8(%rsp)\n\t"
"movw 0x42(%rdi),%ax\n\t" /* context->SegSs */
"movq %rax,32(%rsp)\n\t"
"movq 0x44(%rdi),%rax\n\t" /* context->Eflags */
"movq %rax,16(%rsp)\n\t"
"movq 0x80(%rdi),%rcx\n\t" /* context->Rcx */
"movq 0x88(%rdi),%rdx\n\t" /* context->Rdx */
"movq 0x90(%rdi),%rbx\n\t" /* context->Rbx */
"movq 0x98(%rdi),%rax\n\t" /* context->Rsp */
"movq %rax,24(%rsp)\n\t"
"movq 0xa0(%rdi),%rbp\n\t" /* context->Rbp */
"movq 0xa8(%rdi),%rsi\n\t" /* context->Rsi */
"movq 0xb8(%rdi),%r8\n\t" /* context->R8 */
"movq 0xc0(%rdi),%r9\n\t" /* context->R9 */
"movq 0xc8(%rdi),%r10\n\t" /* context->R10 */
"movq 0xd0(%rdi),%r11\n\t" /* context->R11 */
"movq 0xd8(%rdi),%r12\n\t" /* context->R12 */
"movq 0xe0(%rdi),%r13\n\t" /* context->R13 */
"movq 0xe8(%rdi),%r14\n\t" /* context->R14 */
"movq 0xf0(%rdi),%r15\n\t" /* context->R15 */
"movq 0xf8(%rdi),%rax\n\t" /* context->Rip */
"movq %rax,(%rsp)\n\t"
"fxrstor 0x100(%rdi)\n\t" /* context->FtlSave */
"movdqa 0x1a0(%rdi),%xmm0\n\t" /* context->Xmm0 */
"movdqa 0x1b0(%rdi),%xmm1\n\t" /* context->Xmm1 */
"movdqa 0x1c0(%rdi),%xmm2\n\t" /* context->Xmm2 */
"movdqa 0x1d0(%rdi),%xmm3\n\t" /* context->Xmm3 */
"movdqa 0x1e0(%rdi),%xmm4\n\t" /* context->Xmm4 */
"movdqa 0x1f0(%rdi),%xmm5\n\t" /* context->Xmm5 */
"movdqa 0x200(%rdi),%xmm6\n\t" /* context->Xmm6 */
"movdqa 0x210(%rdi),%xmm7\n\t" /* context->Xmm7 */
"movdqa 0x220(%rdi),%xmm8\n\t" /* context->Xmm8 */
"movdqa 0x230(%rdi),%xmm9\n\t" /* context->Xmm9 */
"movdqa 0x240(%rdi),%xmm10\n\t" /* context->Xmm10 */
"movdqa 0x250(%rdi),%xmm11\n\t" /* context->Xmm11 */
"movdqa 0x260(%rdi),%xmm12\n\t" /* context->Xmm12 */
"movdqa 0x270(%rdi),%xmm13\n\t" /* context->Xmm13 */
"movdqa 0x280(%rdi),%xmm14\n\t" /* context->Xmm14 */
"movdqa 0x290(%rdi),%xmm15\n\t" /* context->Xmm15 */
"movq 0x78(%rdi),%rax\n\t" /* context->Rax */
"movq 0xb0(%rdi),%rdi\n\t" /* context->Rdi */
"iretq" );
/***********************************************************************
* set_cpu_context
*
* Set the new CPU context. Used by NtSetContextThread.
*/
void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context )
{
DWORD flags = context->ContextFlags & ~CONTEXT_AMD64;
if (flags & CONTEXT_DEBUG_REGISTERS)
{
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;
}
if (flags & CONTEXT_FULL)
{
if (!(flags & CONTEXT_CONTROL))
FIXME( "setting partial context (%x) not supported\n", flags );
else
set_full_cpu_context( context );
}
}
/***********************************************************************
* context_to_server
......@@ -247,6 +353,35 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
/* debug registers require a server call */
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)))
self = (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);
if (!self)
{
context_t server_context;
context_to_server( &server_context, context );
ret = set_thread_context( handle, &server_context, &self );
}
if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
return ret;
}
/**********************************************************************
* get_thread_ldt_entry
*/
......
......@@ -148,3 +148,23 @@ void CDECL exit_process( int status )
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_thread( get_unix_exit_code( status ), exit );
}
/***********************************************************************
* set_thread_context
*/
NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self )
{
NTSTATUS ret;
SERVER_START_REQ( set_thread_context )
{
req->handle = wine_server_obj_handle( handle );
wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req );
*self = reply->self;
}
SERVER_END_REQ;
return ret;
}
......@@ -103,6 +103,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 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 13
#define NTDLL_UNIXLIB_VERSION 14
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 *NtSetContextThread)( HANDLE handle, const CONTEXT *context );
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
/* environment functions */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment