Commit 5316dd01 authored by Alexandre Julliard's avatar Alexandre Julliard

server: Define a generic context structure instead of using the platform-specific version.

parent 53929f19
...@@ -149,14 +149,16 @@ void wait_suspend( CONTEXT *context ) ...@@ -149,14 +149,16 @@ void wait_suspend( CONTEXT *context )
{ {
LARGE_INTEGER timeout; LARGE_INTEGER timeout;
int saved_errno = errno; int saved_errno = errno;
context_t server_context;
context_to_server( &server_context, context );
/* store the context we got at suspend time */ /* store the context we got at suspend time */
SERVER_START_REQ( set_thread_context ) SERVER_START_REQ( set_thread_context )
{ {
req->handle = wine_server_obj_handle( GetCurrentThread() ); req->handle = wine_server_obj_handle( GetCurrentThread() );
req->flags = CONTEXT_FULL;
req->suspend = 1; req->suspend = 1;
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, &server_context, sizeof(server_context) );
wine_server_call( req ); wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -169,13 +171,13 @@ void wait_suspend( CONTEXT *context ) ...@@ -169,13 +171,13 @@ void wait_suspend( CONTEXT *context )
SERVER_START_REQ( get_thread_context ) SERVER_START_REQ( get_thread_context )
{ {
req->handle = wine_server_obj_handle( GetCurrentThread() ); req->handle = wine_server_obj_handle( GetCurrentThread() );
req->flags = CONTEXT_FULL;
req->suspend = 1; req->suspend = 1;
wine_server_set_reply( req, context, sizeof(*context) ); wine_server_set_reply( req, &server_context, sizeof(server_context) );
wine_server_call( req ); wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
context_from_server( context, &server_context );
errno = saved_errno; errno = saved_errno;
} }
...@@ -187,16 +189,19 @@ void wait_suspend( CONTEXT *context ) ...@@ -187,16 +189,19 @@ void wait_suspend( CONTEXT *context )
*/ */
static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
{ {
int ret; NTSTATUS ret;
DWORD i; DWORD i;
HANDLE handle = 0; HANDLE handle = 0;
client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS]; client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
context_t server_context;
if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */ if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++) for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
params[i] = rec->ExceptionInformation[i]; params[i] = rec->ExceptionInformation[i];
context_to_server( &server_context, context );
SERVER_START_REQ( queue_exception_event ) SERVER_START_REQ( queue_exception_event )
{ {
req->first = first_chance; req->first = first_chance;
...@@ -206,7 +211,7 @@ static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTE ...@@ -206,7 +211,7 @@ static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTE
req->address = wine_server_client_ptr( rec->ExceptionAddress ); req->address = wine_server_client_ptr( rec->ExceptionAddress );
req->len = i * sizeof(params[0]); req->len = i * sizeof(params[0]);
wine_server_add_data( req, params, req->len ); wine_server_add_data( req, params, req->len );
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, &server_context, sizeof(server_context) );
if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle ); if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -217,10 +222,11 @@ static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTE ...@@ -217,10 +222,11 @@ static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTE
SERVER_START_REQ( get_exception_status ) SERVER_START_REQ( get_exception_status )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
wine_server_set_reply( req, context, sizeof(*context) ); wine_server_set_reply( req, &server_context, sizeof(server_context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
if (!ret) ret = context_from_server( context, &server_context );
return ret; return ret;
} }
......
...@@ -44,6 +44,8 @@ extern void wait_suspend( CONTEXT *context ); ...@@ -44,6 +44,8 @@ extern void wait_suspend( CONTEXT *context );
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
extern void set_cpu_context( const CONTEXT *context ); extern void set_cpu_context( const CONTEXT *context );
extern void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags ); extern void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags );
extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from );
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from );
/* debug helpers */ /* debug helpers */
extern LPCSTR debugstr_us( const UNICODE_STRING *str ); extern LPCSTR debugstr_us( const UNICODE_STRING *str );
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
# include <sys/sysctl.h> # include <sys/sysctl.h>
#endif #endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "wine/library.h" #include "wine/library.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
...@@ -1065,6 +1067,148 @@ void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags ) ...@@ -1065,6 +1067,148 @@ 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_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.
*/
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;
}
/***********************************************************************
* is_privileged_instr * is_privileged_instr
* *
* Check if the fault location is a privileged instruction. * Check if the fault location is a privileged instruction.
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <stdio.h> #include <stdio.h>
#include <sys/ucontext.h> #include <sys/ucontext.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "winnt.h" #include "winnt.h"
...@@ -230,6 +232,136 @@ void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags ) ...@@ -230,6 +232,136 @@ 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_SPARC; /* get rid of CPU id */
memset( to, 0, sizeof(*to) );
to->cpu = CPU_SPARC;
if (flags & CONTEXT_CONTROL)
{
to->flags |= SERVER_CTX_CONTROL;
to->ctl.sparc_regs.psr = from->psr;
to->ctl.sparc_regs.pc = from->pc;
to->ctl.sparc_regs.npc = from->npc;
to->ctl.sparc_regs.y = from->y;
to->ctl.sparc_regs.wim = from->wim;
to->ctl.sparc_regs.tbr = from->tbr;
}
if (flags & CONTEXT_INTEGER)
{
to->flags |= SERVER_CTX_INTEGER;
to->integer.sparc_regs.g[0] = from->g0;
to->integer.sparc_regs.g[1] = from->g1;
to->integer.sparc_regs.g[2] = from->g2;
to->integer.sparc_regs.g[3] = from->g3;
to->integer.sparc_regs.g[4] = from->g4;
to->integer.sparc_regs.g[5] = from->g5;
to->integer.sparc_regs.g[6] = from->g6;
to->integer.sparc_regs.g[7] = from->g7;
to->integer.sparc_regs.o[0] = from->o0;
to->integer.sparc_regs.o[1] = from->o1;
to->integer.sparc_regs.o[2] = from->o2;
to->integer.sparc_regs.o[3] = from->o3;
to->integer.sparc_regs.o[4] = from->o4;
to->integer.sparc_regs.o[5] = from->o5;
to->integer.sparc_regs.o[6] = from->o6;
to->integer.sparc_regs.o[7] = from->o7;
to->integer.sparc_regs.l[0] = from->l0;
to->integer.sparc_regs.l[1] = from->l1;
to->integer.sparc_regs.l[2] = from->l2;
to->integer.sparc_regs.l[3] = from->l3;
to->integer.sparc_regs.l[4] = from->l4;
to->integer.sparc_regs.l[5] = from->l5;
to->integer.sparc_regs.l[6] = from->l6;
to->integer.sparc_regs.l[7] = from->l7;
to->integer.sparc_regs.i[0] = from->i0;
to->integer.sparc_regs.i[1] = from->i1;
to->integer.sparc_regs.i[2] = from->i2;
to->integer.sparc_regs.i[3] = from->i3;
to->integer.sparc_regs.i[4] = from->i4;
to->integer.sparc_regs.i[5] = from->i5;
to->integer.sparc_regs.i[6] = from->i6;
to->integer.sparc_regs.i[7] = from->i7;
}
if (flags & CONTEXT_FLOATING_POINT)
{
/* FIXME */
}
return STATUS_SUCCESS;
}
/***********************************************************************
* 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_SPARC) return STATUS_INVALID_PARAMETER;
to->ContextFlags = CONTEXT_SPARC;
if (from->flags & SERVER_CTX_CONTROL)
{
to->ContextFlags |= CONTEXT_CONTROL;
to->psr = from->ctl.sparc_regs.psr;
to->pc = from->ctl.sparc_regs.pc;
to->npc = from->ctl.sparc_regs.npc;
to->y = from->ctl.sparc_regs.y;
to->wim = from->ctl.sparc_regs.wim;
to->tbr = from->ctl.sparc_regs.tbr;
}
if (from->flags & SERVER_CTX_INTEGER)
{
to->ContextFlags |= CONTEXT_INTEGER;
to->g0 = from->integer.sparc_regs.g[0];
to->g1 = from->integer.sparc_regs.g[1];
to->g2 = from->integer.sparc_regs.g[2];
to->g3 = from->integer.sparc_regs.g[3];
to->g4 = from->integer.sparc_regs.g[4];
to->g5 = from->integer.sparc_regs.g[5];
to->g6 = from->integer.sparc_regs.g[6];
to->g7 = from->integer.sparc_regs.g[7];
to->o0 = from->integer.sparc_regs.o[0];
to->o1 = from->integer.sparc_regs.o[1];
to->o2 = from->integer.sparc_regs.o[2];
to->o3 = from->integer.sparc_regs.o[3];
to->o4 = from->integer.sparc_regs.o[4];
to->o5 = from->integer.sparc_regs.o[5];
to->o6 = from->integer.sparc_regs.o[6];
to->o7 = from->integer.sparc_regs.o[7];
to->l0 = from->integer.sparc_regs.l[0];
to->l1 = from->integer.sparc_regs.l[1];
to->l2 = from->integer.sparc_regs.l[2];
to->l3 = from->integer.sparc_regs.l[3];
to->l4 = from->integer.sparc_regs.l[4];
to->l5 = from->integer.sparc_regs.l[5];
to->l6 = from->integer.sparc_regs.l[6];
to->l7 = from->integer.sparc_regs.l[7];
to->i0 = from->integer.sparc_regs.i[0];
to->i1 = from->integer.sparc_regs.i[1];
to->i2 = from->integer.sparc_regs.i[2];
to->i3 = from->integer.sparc_regs.i[3];
to->i4 = from->integer.sparc_regs.i[4];
to->i5 = from->integer.sparc_regs.i[5];
to->i6 = from->integer.sparc_regs.i[6];
to->i7 = from->integer.sparc_regs.i[7];
}
if (from->flags & SERVER_CTX_FLOATING_POINT)
{
/* FIXME */
}
return STATUS_SUCCESS;
}
/********************************************************************** /**********************************************************************
* segv_handler * segv_handler
* *
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#endif #endif
#define NONAMELESSUNION #define NONAMELESSUNION
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "wine/library.h" #include "wine/library.h"
...@@ -327,6 +329,141 @@ void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags ) ...@@ -327,6 +329,141 @@ 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;
to->ctl.x86_64_regs.mxcsr = from->MxCsr;
}
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.
*/
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;
to->MxCsr = from->ctl.x86_64_regs.mxcsr;
}
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) );
}
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;
}
/********************************************************************** /**********************************************************************
* segv_handler * segv_handler
* *
......
...@@ -824,12 +824,15 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) ...@@ -824,12 +824,15 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
if (!self) if (!self)
{ {
context_t server_context;
context_to_server( &server_context, context );
SERVER_START_REQ( set_thread_context ) SERVER_START_REQ( set_thread_context )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
req->suspend = 0; req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, &server_context, sizeof(server_context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
self = reply->self; self = reply->self;
} }
...@@ -844,9 +847,8 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) ...@@ -844,9 +847,8 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
SERVER_START_REQ( set_thread_context ) SERVER_START_REQ( set_thread_context )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
req->suspend = 0; req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, &server_context, sizeof(server_context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -871,6 +873,29 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) ...@@ -871,6 +873,29 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
} }
/* convert CPU-specific flags to generic server flags */
static inline unsigned int get_server_context_flags( DWORD flags )
{
unsigned int ret = 0;
flags &= ~0x3f; /* mask CPU id flags */
if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
#ifdef CONTEXT_SEGMENTS
if (flags & CONTEXT_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
#endif
#ifdef CONTEXT_FLOATING_POINT
if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
#endif
#ifdef CONTEXT_DEBUG_REGISTERS
if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
#endif
#ifdef CONTEXT_EXTENDED_REGISTERS
if (flags & CONTEXT_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
#endif
return ret;
}
/*********************************************************************** /***********************************************************************
* NtGetContextThread (NTDLL.@) * NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@) * ZwGetContextThread (NTDLL.@)
...@@ -878,7 +903,6 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) ...@@ -878,7 +903,6 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
{ {
NTSTATUS ret; NTSTATUS ret;
CONTEXT ctx;
DWORD dummy, i; DWORD dummy, i;
DWORD needed_flags = context->ContextFlags; DWORD needed_flags = context->ContextFlags;
BOOL self = (handle == GetCurrentThread()); BOOL self = (handle == GetCurrentThread());
...@@ -890,12 +914,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) ...@@ -890,12 +914,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
if (!self) if (!self)
{ {
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
context_t server_context;
SERVER_START_REQ( get_thread_context ) SERVER_START_REQ( get_thread_context )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags; req->flags = server_flags;
req->suspend = 0; req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) ); wine_server_set_reply( req, &server_context, sizeof(server_context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
self = reply->self; self = reply->self;
} }
...@@ -910,9 +937,9 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) ...@@ -910,9 +937,9 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
SERVER_START_REQ( get_thread_context ) SERVER_START_REQ( get_thread_context )
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags; req->flags = server_flags;
req->suspend = 0; req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) ); wine_server_set_reply( req, &server_context, sizeof(server_context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -928,17 +955,19 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) ...@@ -928,17 +955,19 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
} }
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
} }
if (!ret) ret = context_from_server( context, &server_context );
if (ret) return ret; if (ret) return ret;
copy_context( context, &ctx, context->ContextFlags & ctx.ContextFlags ); needed_flags &= ~context->ContextFlags;
needed_flags &= ~ctx.ContextFlags;
} }
if (self) if (self)
{ {
if (needed_flags) if (needed_flags)
{ {
CONTEXT ctx;
RtlCaptureContext( &ctx ); RtlCaptureContext( &ctx );
copy_context( context, &ctx, ctx.ContextFlags & needed_flags ); copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
context->ContextFlags |= ctx.ContextFlags & needed_flags;
} }
#ifdef __i386__ #ifdef __i386__
/* update the cached version of the debug registers */ /* update the cached version of the debug registers */
......
...@@ -135,6 +135,63 @@ enum cpu_type ...@@ -135,6 +135,63 @@ enum cpu_type
typedef int cpu_type_t; typedef int cpu_type_t;
typedef struct
{
cpu_type_t cpu;
unsigned int flags;
union
{
struct { unsigned int eip, ebp, esp, eflags, cs, ss; } i386_regs;
struct { unsigned __int64 rip, rbp, rsp;
unsigned int cs, ss, flags, mxcsr; } x86_64_regs;
struct { unsigned __int64 fir;
unsigned int psr; } alpha_regs;
struct { unsigned int iar, msr, ctr, lr, dar, dsisr, trap; } powerpc_regs;
struct { unsigned int psr, pc, npc, y, wim, tbr; } sparc_regs;
} ctl;
union
{
struct { unsigned int eax, ebx, ecx, edx, esi, edi; } i386_regs;
struct { unsigned __int64 rax,rbx, rcx, rdx, rsi, rdi,
r8, r9, r10, r11, r12, r13, r14, r15; } x86_64_regs;
struct { unsigned __int64 v0, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12,
s0, s1, s2, s3, s4, s5, s6, a0, a1, a2, a3, a4, a5, at; } alpha_regs;
struct { unsigned int gpr[32], cr, xer; } powerpc_regs;
struct { unsigned int g[8], o[8], l[8], i[8]; } sparc_regs;
} integer;
union
{
struct { unsigned int ds, es, fs, gs; } i386_regs;
struct { unsigned int ds, es, fs, gs; } x86_64_regs;
} seg;
union
{
struct { unsigned int ctrl, status, tag, err_off, err_sel, data_off, data_sel, cr0npx;
unsigned char regs[80]; } i386_regs;
struct { struct { unsigned __int64 low, high; } fpregs[32]; } x86_64_regs;
struct { unsigned __int64 f[32], fpcr, softfpcr; } alpha_regs;
struct { double fpr[32], fpscr; } powerpc_regs;
} fp;
union
{
struct { unsigned int dr0, dr1, dr2, dr3, dr6, dr7; } i386_regs;
struct { unsigned __int64 dr0, dr1, dr2, dr3, dr6, dr7; } x86_64_regs;
struct { unsigned int dr[8]; } powerpc_regs;
} debug;
union
{
unsigned char i386_regs[512];
} ext;
} context_t;
#define SERVER_CTX_CONTROL 0x01
#define SERVER_CTX_INTEGER 0x02
#define SERVER_CTX_SEGMENTS 0x04
#define SERVER_CTX_FLOATING_POINT 0x08
#define SERVER_CTX_DEBUG_REGISTERS 0x10
#define SERVER_CTX_EXTENDED_REGISTERS 0x20
struct send_fd struct send_fd
{ {
thread_id_t tid; thread_id_t tid;
...@@ -2356,7 +2413,6 @@ struct set_thread_context_request ...@@ -2356,7 +2413,6 @@ struct set_thread_context_request
{ {
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
unsigned int flags;
int suspend; int suspend;
/* VARARG(context,context); */ /* VARARG(context,context); */
}; };
...@@ -5224,6 +5280,6 @@ union generic_reply ...@@ -5224,6 +5280,6 @@ union generic_reply
struct set_window_layered_info_reply set_window_layered_info_reply; struct set_window_layered_info_reply set_window_layered_info_reply;
}; };
#define SERVER_PROTOCOL_VERSION 384 #define SERVER_PROTOCOL_VERSION 385
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -14,11 +14,6 @@ C_SRCS = \ ...@@ -14,11 +14,6 @@ C_SRCS = \
clipboard.c \ clipboard.c \
completion.c \ completion.c \
console.c \ console.c \
context_alpha.c \
context_i386.c \
context_powerpc.c \
context_sparc.c \
context_x86_64.c \
debugger.c \ debugger.c \
device.c \ device.c \
directory.c \ directory.c \
......
/*
* i386 register context support
*
* Copyright (C) 1999 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#ifdef __i386__
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include "windef.h"
#include "file.h"
#include "thread.h"
#include "request.h"
/* copy a context structure according to the flags */
void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
{
flags &= ~CONTEXT_i386; /* get rid of CPU id */
if (flags & CONTEXT_CONTROL)
{
to->Ebp = from->Ebp;
to->Eip = from->Eip;
to->Esp = from->Esp;
to->SegCs = from->SegCs;
to->SegSs = from->SegSs;
to->EFlags = from->EFlags;
}
if (flags & CONTEXT_INTEGER)
{
to->Eax = from->Eax;
to->Ebx = from->Ebx;
to->Ecx = from->Ecx;
to->Edx = from->Edx;
to->Esi = from->Esi;
to->Edi = from->Edi;
}
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->FloatSave = from->FloatSave;
}
if (flags & CONTEXT_EXTENDED_REGISTERS)
{
memcpy( to->ExtendedRegisters, from->ExtendedRegisters, sizeof(to->ExtendedRegisters) );
}
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;
}
to->ContextFlags |= flags;
}
/* retrieve the current instruction pointer of a context */
client_ptr_t get_context_ip( const CONTEXT *context )
{
return context->Eip;
}
/* return the context flag that contains the CPU id */
unsigned int get_context_cpu_flag(void)
{
return CONTEXT_i386;
}
/* return only the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
unsigned int get_context_system_regs( unsigned int flags )
{
return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386);
}
#endif /* __i386__ */
/*
* PowerPC register context support
*
* Copyright (C) 2002 Marcus Meissner, SuSE Linux AG.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#ifdef __powerpc__
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_SYS_REG_H
# include <sys/reg.h>
#endif
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_SYS_PTRACE_H
# include <sys/ptrace.h>
#endif
#include "windef.h"
#if 0 /* no longer used */
#ifndef PTRACE_PEEKUSER
# ifdef PT_READ_D
# define PTRACE_PEEKUSER PT_READ_D
# endif
#endif /* PTRACE_PEEKUSER */
#ifndef PTRACE_POKEUSER
# ifdef PT_WRITE_D
# define PTRACE_POKEUSER PT_WRITE_D
# endif
#endif /* PTRACE_POKEUSER */
#include "file.h"
#include "thread.h"
#include "request.h"
/* retrieve a thread context */
static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
{
int pid = get_ptrace_pid(thread);
if (flags & CONTEXT_INTEGER)
{
#define XREG(x,y) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
#define IREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
#undef IREG
XREG(37,Xer);
XREG(38,Cr);
context->ContextFlags |= CONTEXT_INTEGER;
}
if (flags & CONTEXT_CONTROL)
{
XREG(32,Iar);
XREG(33,Msr);
XREG(35,Ctr);
XREG(36,Lr); /* 36 is LNK ... probably Lr ? */
context->ContextFlags |= CONTEXT_CONTROL;
}
if (flags & CONTEXT_FLOATING_POINT)
{
#define FREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
FREG(0);
FREG(1);
FREG(2);
FREG(3);
FREG(4);
FREG(5);
FREG(6);
FREG(7);
FREG(8);
FREG(9);
FREG(10);
FREG(11);
FREG(12);
FREG(13);
FREG(14);
FREG(15);
FREG(16);
FREG(17);
FREG(18);
FREG(19);
FREG(20);
FREG(21);
FREG(22);
FREG(23);
FREG(24);
FREG(25);
FREG(26);
FREG(27);
FREG(28);
FREG(29);
FREG(30);
FREG(31);
XREG((48+32*2),Fpscr);
context->ContextFlags |= CONTEXT_FLOATING_POINT;
}
return;
error:
file_set_error();
}
#undef XREG
#undef IREG
#undef FREG
#define XREG(x,y) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
#define IREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
#define FREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
/* set a thread context */
static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
{
int pid = get_ptrace_pid(thread);
if (flags & CONTEXT_FULL)
{
if (flags & CONTEXT_INTEGER)
{
IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
XREG(37,Xer);
XREG(38,Cr);
}
if (flags & CONTEXT_CONTROL)
{
XREG(32,Iar);
XREG(33,Msr);
XREG(35,Ctr);
XREG(36,Lr);
}
}
if (flags & CONTEXT_FLOATING_POINT)
{
FREG(0);
FREG(1);
FREG(2);
FREG(3);
FREG(4);
FREG(5);
FREG(6);
FREG(7);
FREG(8);
FREG(9);
FREG(10);
FREG(11);
FREG(12);
FREG(13);
FREG(14);
FREG(15);
FREG(16);
FREG(17);
FREG(18);
FREG(19);
FREG(20);
FREG(21);
FREG(22);
FREG(23);
FREG(24);
FREG(25);
FREG(26);
FREG(27);
FREG(28);
FREG(29);
FREG(30);
FREG(31);
#undef FREG
XREG((48+32*2),Fpscr);
}
return;
error:
file_set_error();
}
#undef XREG
#undef IREG
#undef FREG
#endif /* 0 */
#define IREG(x) to->Gpr##x = from->Gpr##x;
#define FREG(x) to->Fpr##x = from->Fpr##x;
#define CREG(x) to->x = from->x;
/* copy a context structure according to the flags */
void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
{
if (flags & CONTEXT_CONTROL)
{
CREG(Msr);
CREG(Ctr);
CREG(Iar);
to->ContextFlags |= CONTEXT_CONTROL;
}
if (flags & CONTEXT_INTEGER)
{
IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
CREG(Xer);
CREG(Cr);
to->ContextFlags |= CONTEXT_INTEGER;
}
if (flags & CONTEXT_FLOATING_POINT)
{
FREG(0);
FREG(1);
FREG(2);
FREG(3);
FREG(4);
FREG(5);
FREG(6);
FREG(7);
FREG(8);
FREG(9);
FREG(10);
FREG(11);
FREG(12);
FREG(13);
FREG(14);
FREG(15);
FREG(16);
FREG(17);
FREG(18);
FREG(19);
FREG(20);
FREG(21);
FREG(22);
FREG(23);
FREG(24);
FREG(25);
FREG(26);
FREG(27);
FREG(28);
FREG(29);
FREG(30);
FREG(31);
CREG(Fpscr);
to->ContextFlags |= CONTEXT_FLOATING_POINT;
}
}
/* retrieve the current instruction pointer of a context */
client_ptr_t get_context_ip( const CONTEXT *context )
{
return context->Iar;
}
/* return the context flag that contains the CPU id */
unsigned int get_context_cpu_flag(void)
{
return 0;
}
/* return only the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
unsigned int get_context_system_regs( unsigned int flags )
{
return 0; /* FIXME: implement client-side handling */
}
#endif /* __powerpc__ */
/*
* Sparc register context support
*
* Copyright (C) 2000 Ulrich Weigand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#ifdef __sparc__
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_SYS_REG_H
# include <sys/reg.h>
#endif
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_SYS_PTRACE_H
# include <sys/ptrace.h>
#endif
#include "windef.h"
#include "file.h"
#include "thread.h"
#include "request.h"
#if 0 /* no longer used */
#if defined(__sun) || defined(__sun__)
/* retrieve a thread context */
static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
{
int pid = get_ptrace_pid(thread);
if (flags & CONTEXT_FULL)
{
struct regs regs;
if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
if (flags & CONTEXT_INTEGER)
{
context->g0 = 0;
context->g1 = regs.r_g1;
context->g2 = regs.r_g2;
context->g3 = regs.r_g3;
context->g4 = regs.r_g4;
context->g5 = regs.r_g5;
context->g6 = regs.r_g6;
context->g7 = regs.r_g7;
context->o0 = regs.r_o0;
context->o1 = regs.r_o1;
context->o2 = regs.r_o2;
context->o3 = regs.r_o3;
context->o4 = regs.r_o4;
context->o5 = regs.r_o5;
context->o6 = regs.r_o6;
context->o7 = regs.r_o7;
/* FIXME: local and in registers */
}
if (flags & CONTEXT_CONTROL)
{
context->psr = regs.r_psr;
context->pc = regs.r_pc;
context->npc = regs.r_npc;
context->y = regs.r_y;
context->wim = 0; /* FIXME */
context->tbr = 0; /* FIXME */
}
context |= flags & (CONTEXT_CONTROL|CONTEXT_INTEGER);
}
if (flags & CONTEXT_FLOATING_POINT)
{
/* FIXME */
}
return;
error:
file_set_error();
}
/* set a thread context */
static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
{
/* FIXME */
}
#else /* __sun__ */
#error You must implement get/set_thread_context_ptrace for your platform
#endif /* __sun__ */
#endif /* 0 */
/* copy a context structure according to the flags */
void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
{
flags &= ~CONTEXT_SPARC; /* get rid of CPU id */
if (flags & CONTEXT_CONTROL)
{
to->psr = from->psr;
to->pc = from->pc;
to->npc = from->npc;
to->y = from->y;
to->wim = from->wim;
to->tbr = from->tbr;
}
if (flags & CONTEXT_INTEGER)
{
to->g0 = from->g0;
to->g1 = from->g1;
to->g2 = from->g2;
to->g3 = from->g3;
to->g4 = from->g4;
to->g5 = from->g5;
to->g6 = from->g6;
to->g7 = from->g7;
to->o0 = from->o0;
to->o1 = from->o1;
to->o2 = from->o2;
to->o3 = from->o3;
to->o4 = from->o4;
to->o5 = from->o5;
to->o6 = from->o6;
to->o7 = from->o7;
to->l0 = from->l0;
to->l1 = from->l1;
to->l2 = from->l2;
to->l3 = from->l3;
to->l4 = from->l4;
to->l5 = from->l5;
to->l6 = from->l6;
to->l7 = from->l7;
to->i0 = from->i0;
to->i1 = from->i1;
to->i2 = from->i2;
to->i3 = from->i3;
to->i4 = from->i4;
to->i5 = from->i5;
to->i6 = from->i6;
to->i7 = from->i7;
}
if (flags & CONTEXT_FLOATING_POINT)
{
/* FIXME */
}
context |= flags & (CONTEXT_CONTROL|CONTEXT_INTEGER);
}
/* retrieve the current instruction pointer of a context */
client_ptr_t get_context_ip( const CONTEXT *context )
{
return context->pc;
}
/* return the context flag that contains the CPU id */
unsigned int get_context_cpu_flag(void)
{
return CONTEXT_SPARC;
}
/* return only the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
unsigned int get_context_system_regs( unsigned int flags )
{
return 0; /* FIXME: implement client-side handling */
}
#endif /* __sparc__ */
/*
* x86-64 register context support
*
* Copyright (C) 1999, 2005 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#ifdef __x86_64__
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "file.h"
#include "thread.h"
#include "request.h"
/* copy a context structure according to the flags */
void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int 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;
to->MxCsr = from->MxCsr;
}
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->u.FltSave = from->u.FltSave;
}
/* we don't bother copying the debug registers, since they */
/* always need to be accessed by ptrace anyway */
to->ContextFlags |= flags & ~CONTEXT_DEBUG_REGISTERS;
}
/* retrieve the current instruction pointer of a context */
client_ptr_t get_context_ip( const CONTEXT *context )
{
return context->Rip;
}
/* return the context flag that contains the CPU id */
unsigned int get_context_cpu_flag(void)
{
return CONTEXT_AMD64;
}
/* return only the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
unsigned int get_context_system_regs( unsigned int flags )
{
return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64);
}
#endif /* __x86_64__ */
...@@ -49,7 +49,7 @@ struct debug_event ...@@ -49,7 +49,7 @@ struct debug_event
enum debug_event_state state; /* event state */ enum debug_event_state state; /* event state */
int status; /* continuation status */ int status; /* continuation status */
debug_event_t data; /* event data */ debug_event_t data; /* event data */
CONTEXT context; /* register context */ context_t context; /* register context */
}; };
/* debug context */ /* debug context */
...@@ -652,11 +652,11 @@ DECL_HANDLER(queue_exception_event) ...@@ -652,11 +652,11 @@ DECL_HANDLER(queue_exception_event)
if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data ))) if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data )))
{ {
const CONTEXT *context = (const CONTEXT *)((char *)get_req_data() + req->len); const context_t *context = (const context_t *)((char *)get_req_data() + req->len);
data_size_t size = get_req_data_size() - req->len; data_size_t size = get_req_data_size() - req->len;
memset( &event->context, 0, sizeof(event->context) ); memset( &event->context, 0, sizeof(event->context) );
memcpy( &event->context, context, size ); memcpy( &event->context, context, min( sizeof(event->context), size ) );
current->context = &event->context; current->context = &event->context;
if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 ))) if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 )))
...@@ -682,7 +682,7 @@ DECL_HANDLER(get_exception_status) ...@@ -682,7 +682,7 @@ DECL_HANDLER(get_exception_status)
{ {
if (current->context == &event->context) if (current->context == &event->context)
{ {
data_size_t size = min( sizeof(CONTEXT), get_reply_max_size() ); data_size_t size = min( sizeof(context_t), get_reply_max_size() );
set_reply_data( &event->context, size ); set_reply_data( &event->context, size );
current->context = NULL; current->context = NULL;
} }
......
...@@ -160,7 +160,7 @@ void finish_process_tracing( struct process *process ) ...@@ -160,7 +160,7 @@ void finish_process_tracing( struct process *process )
} }
/* retrieve the thread x86 registers */ /* retrieve the thread x86 registers */
void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) void get_thread_context( struct thread *thread, context_t *context, unsigned int flags )
{ {
#ifdef __i386__ #ifdef __i386__
x86_debug_state32_t state; x86_debug_state32_t state;
...@@ -169,7 +169,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f ...@@ -169,7 +169,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
mach_port_t port, process_port = get_process_port( thread->process ); mach_port_t port, process_port = get_process_port( thread->process );
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (thread->unix_pid == -1 || !process_port || if (thread->unix_pid == -1 || !process_port ||
mach_port_extract_right( process_port, thread->unix_tid, mach_port_extract_right( process_port, thread->unix_tid,
...@@ -183,28 +183,28 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f ...@@ -183,28 +183,28 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
{ {
/* work around silly renaming of struct members in OS X 10.5 */ /* work around silly renaming of struct members in OS X 10.5 */
#if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32) #if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32)
context->Dr0 = state.__dr0; context->debug.i386_regs.dr0 = state.__dr0;
context->Dr1 = state.__dr1; context->debug.i386_regs.dr1 = state.__dr1;
context->Dr2 = state.__dr2; context->debug.i386_regs.dr2 = state.__dr2;
context->Dr3 = state.__dr3; context->debug.i386_regs.dr3 = state.__dr3;
context->Dr6 = state.__dr6; context->debug.i386_regs.dr6 = state.__dr6;
context->Dr7 = state.__dr7; context->debug.i386_regs.dr7 = state.__dr7;
#else #else
context->Dr0 = state.dr0; context->debug.i386_regs.dr0 = state.dr0;
context->Dr1 = state.dr1; context->debug.i386_regs.dr1 = state.dr1;
context->Dr2 = state.dr2; context->debug.i386_regs.dr2 = state.dr2;
context->Dr3 = state.dr3; context->debug.i386_regs.dr3 = state.dr3;
context->Dr6 = state.dr6; context->debug.i386_regs.dr6 = state.dr6;
context->Dr7 = state.dr7; context->debug.i386_regs.dr7 = state.dr7;
#endif #endif
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; context->flags |= SERVER_CTX_DEBUG_REGISTERS;
} }
mach_port_deallocate( mach_task_self(), port ); mach_port_deallocate( mach_task_self(), port );
#endif #endif
} }
/* set the thread x86 registers */ /* set the thread x86 registers */
void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags )
{ {
#ifdef __i386__ #ifdef __i386__
x86_debug_state32_t state; x86_debug_state32_t state;
...@@ -213,7 +213,7 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned ...@@ -213,7 +213,7 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
mach_port_t port, process_port = get_process_port( thread->process ); mach_port_t port, process_port = get_process_port( thread->process );
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (thread->unix_pid == -1 || !process_port || if (thread->unix_pid == -1 || !process_port ||
mach_port_extract_right( process_port, thread->unix_tid, mach_port_extract_right( process_port, thread->unix_tid,
...@@ -224,35 +224,28 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned ...@@ -224,35 +224,28 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
} }
#if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32) #if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32)
state.__dr0 = context->Dr0; state.__dr0 = context->debug.i386_regs.dr0;
state.__dr1 = context->Dr1; state.__dr1 = context->debug.i386_regs.dr1;
state.__dr2 = context->Dr2; state.__dr2 = context->debug.i386_regs.dr2;
state.__dr3 = context->Dr3; state.__dr3 = context->debug.i386_regs.dr3;
state.__dr4 = 0; state.__dr4 = 0;
state.__dr5 = 0; state.__dr5 = 0;
state.__dr6 = context->Dr6; state.__dr6 = context->debug.i386_regs.dr6;
state.__dr7 = context->Dr7; state.__dr7 = context->debug.i386_regs.dr7;
#else #else
state.dr0 = context->Dr0; state.dr0 = context->debug.i386_regs.dr0;
state.dr1 = context->Dr1; state.dr1 = context->debug.i386_regs.dr1;
state.dr2 = context->Dr2; state.dr2 = context->debug.i386_regs.dr2;
state.dr3 = context->Dr3; state.dr3 = context->debug.i386_regs.dr3;
state.dr4 = 0; state.dr4 = 0;
state.dr5 = 0; state.dr5 = 0;
state.dr6 = context->Dr6; state.dr6 = context->debug.i386_regs.dr6;
state.dr7 = context->Dr7; state.dr7 = context->debug.i386_regs.dr7;
#endif #endif
if (!thread_set_state( port, x86_DEBUG_STATE32, (thread_state_t)&state, count )) if (!thread_set_state( port, x86_DEBUG_STATE32, (thread_state_t)&state, count ))
{ {
if (thread->context) /* update the cached values */ if (thread->context) /* update the cached values */
{ thread->context->debug.i386_regs = context->debug.i386_regs;
thread->context->Dr0 = context->Dr0;
thread->context->Dr1 = context->Dr1;
thread->context->Dr2 = context->Dr2;
thread->context->Dr3 = context->Dr3;
thread->context->Dr6 = context->Dr6;
thread->context->Dr7 = context->Dr7;
}
} }
mach_port_deallocate( mach_task_self(), port ); mach_port_deallocate( mach_task_self(), port );
#endif #endif
......
...@@ -200,20 +200,14 @@ error: ...@@ -200,20 +200,14 @@ error:
} }
/* retrieve the thread registers */ /* retrieve the thread registers */
void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) void get_thread_context( struct thread *thread, context_t *context, unsigned int flags )
{ {
/* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
/* FIXME: get debug registers */ /* FIXME: get debug registers */
} }
/* set the thread registers */ /* set the thread registers */
void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags )
{ {
/* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS );
/* FIXME: set debug registers */ /* FIXME: set debug registers */
} }
......
...@@ -150,6 +150,63 @@ enum cpu_type ...@@ -150,6 +150,63 @@ enum cpu_type
}; };
typedef int cpu_type_t; typedef int cpu_type_t;
/* context data */
typedef struct
{
cpu_type_t cpu; /* cpu type */
unsigned int flags; /* SERVER_CTX_* flags */
union
{
struct { unsigned int eip, ebp, esp, eflags, cs, ss; } i386_regs;
struct { unsigned __int64 rip, rbp, rsp;
unsigned int cs, ss, flags, mxcsr; } x86_64_regs;
struct { unsigned __int64 fir;
unsigned int psr; } alpha_regs;
struct { unsigned int iar, msr, ctr, lr, dar, dsisr, trap; } powerpc_regs;
struct { unsigned int psr, pc, npc, y, wim, tbr; } sparc_regs;
} ctl; /* selected by SERVER_CTX_CONTROL */
union
{
struct { unsigned int eax, ebx, ecx, edx, esi, edi; } i386_regs;
struct { unsigned __int64 rax,rbx, rcx, rdx, rsi, rdi,
r8, r9, r10, r11, r12, r13, r14, r15; } x86_64_regs;
struct { unsigned __int64 v0, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12,
s0, s1, s2, s3, s4, s5, s6, a0, a1, a2, a3, a4, a5, at; } alpha_regs;
struct { unsigned int gpr[32], cr, xer; } powerpc_regs;
struct { unsigned int g[8], o[8], l[8], i[8]; } sparc_regs;
} integer; /* selected by SERVER_CTX_INTEGER */
union
{
struct { unsigned int ds, es, fs, gs; } i386_regs;
struct { unsigned int ds, es, fs, gs; } x86_64_regs;
} seg; /* selected by SERVER_CTX_SEGMENTS */
union
{
struct { unsigned int ctrl, status, tag, err_off, err_sel, data_off, data_sel, cr0npx;
unsigned char regs[80]; } i386_regs;
struct { struct { unsigned __int64 low, high; } fpregs[32]; } x86_64_regs;
struct { unsigned __int64 f[32], fpcr, softfpcr; } alpha_regs;
struct { double fpr[32], fpscr; } powerpc_regs;
} fp; /* selected by SERVER_CTX_FLOATING_POINT */
union
{
struct { unsigned int dr0, dr1, dr2, dr3, dr6, dr7; } i386_regs;
struct { unsigned __int64 dr0, dr1, dr2, dr3, dr6, dr7; } x86_64_regs;
struct { unsigned int dr[8]; } powerpc_regs;
} debug; /* selected by SERVER_CTX_DEBUG_REGISTERS */
union
{
unsigned char i386_regs[512];
} ext; /* selected by SERVER_CTX_EXTENDED_REGISTERS */
} context_t;
#define SERVER_CTX_CONTROL 0x01
#define SERVER_CTX_INTEGER 0x02
#define SERVER_CTX_SEGMENTS 0x04
#define SERVER_CTX_FLOATING_POINT 0x08
#define SERVER_CTX_DEBUG_REGISTERS 0x10
#define SERVER_CTX_EXTENDED_REGISTERS 0x20
/* structure used in sending an fd from client to server */ /* structure used in sending an fd from client to server */
struct send_fd struct send_fd
{ {
...@@ -1732,7 +1789,6 @@ enum char_info_mode ...@@ -1732,7 +1789,6 @@ enum char_info_mode
/* Set the current context of a thread */ /* Set the current context of a thread */
@REQ(set_thread_context) @REQ(set_thread_context)
obj_handle_t handle; /* thread handle */ obj_handle_t handle; /* thread handle */
unsigned int flags; /* context flags */
int suspend; /* if setting context during suspend */ int suspend; /* if setting context during suspend */
VARARG(context,context); /* thread context */ VARARG(context,context); /* thread context */
@REPLY @REPLY
......
...@@ -527,13 +527,13 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base, ...@@ -527,13 +527,13 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
#define DR_OFFSET(dr) ((((struct user *)0)->u_debugreg) + (dr)) #define DR_OFFSET(dr) ((((struct user *)0)->u_debugreg) + (dr))
/* retrieve the thread x86 registers */ /* retrieve the thread x86 registers */
void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) void get_thread_context( struct thread *thread, context_t *context, unsigned int flags )
{ {
int i, pid = get_ptrace_tid(thread); int i, pid = get_ptrace_tid(thread);
long data[8]; long data[8];
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (!suspend_for_ptrace( thread )) return; if (!suspend_for_ptrace( thread )) return;
...@@ -548,39 +548,39 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f ...@@ -548,39 +548,39 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
goto done; goto done;
} }
} }
context->Dr0 = data[0]; context->debug.i386_regs.dr0 = data[0];
context->Dr1 = data[1]; context->debug.i386_regs.dr1 = data[1];
context->Dr2 = data[2]; context->debug.i386_regs.dr2 = data[2];
context->Dr3 = data[3]; context->debug.i386_regs.dr3 = data[3];
context->Dr6 = data[6]; context->debug.i386_regs.dr6 = data[6];
context->Dr7 = data[7]; context->debug.i386_regs.dr7 = data[7];
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; context->flags |= SERVER_CTX_DEBUG_REGISTERS;
done: done:
resume_after_ptrace( thread ); resume_after_ptrace( thread );
} }
/* set the thread x86 registers */ /* set the thread x86 registers */
void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags )
{ {
int pid = get_ptrace_tid( thread ); int pid = get_ptrace_tid( thread );
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (!suspend_for_ptrace( thread )) return; if (!suspend_for_ptrace( thread )) return;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error;
if (thread->context) thread->context->Dr0 = context->Dr0; if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error;
if (thread->context) thread->context->Dr1 = context->Dr1; if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error;
if (thread->context) thread->context->Dr2 = context->Dr2; if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error;
if (thread->context) thread->context->Dr3 = context->Dr3; if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error;
if (thread->context) thread->context->Dr6 = context->Dr6; if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error;
if (thread->context) thread->context->Dr7 = context->Dr7; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7;
resume_after_ptrace( thread ); resume_after_ptrace( thread );
return; return;
error: error:
...@@ -594,13 +594,13 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned ...@@ -594,13 +594,13 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
#include <machine/reg.h> #include <machine/reg.h>
/* retrieve the thread x86 registers */ /* retrieve the thread x86 registers */
void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) void get_thread_context( struct thread *thread, context_t *context, unsigned int flags )
{ {
int pid = get_ptrace_tid(thread); int pid = get_ptrace_tid(thread);
struct dbreg dbregs; struct dbreg dbregs;
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (!suspend_for_ptrace( thread )) return; if (!suspend_for_ptrace( thread )) return;
...@@ -609,78 +609,71 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f ...@@ -609,78 +609,71 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
{ {
#ifdef DBREG_DRX #ifdef DBREG_DRX
/* needed for FreeBSD, the structure fields have changed under 5.x */ /* needed for FreeBSD, the structure fields have changed under 5.x */
context->Dr0 = DBREG_DRX((&dbregs), 0); context->debug.i386_regs.dr0 = DBREG_DRX((&dbregs), 0);
context->Dr1 = DBREG_DRX((&dbregs), 1); context->debug.i386_regs.dr1 = DBREG_DRX((&dbregs), 1);
context->Dr2 = DBREG_DRX((&dbregs), 2); context->debug.i386_regs.dr2 = DBREG_DRX((&dbregs), 2);
context->Dr3 = DBREG_DRX((&dbregs), 3); context->debug.i386_regs.dr3 = DBREG_DRX((&dbregs), 3);
context->Dr6 = DBREG_DRX((&dbregs), 6); context->debug.i386_regs.dr6 = DBREG_DRX((&dbregs), 6);
context->Dr7 = DBREG_DRX((&dbregs), 7); context->debug.i386_regs.dr7 = DBREG_DRX((&dbregs), 7);
#else #else
context->Dr0 = dbregs.dr0; context->debug.i386_regs.dr0 = dbregs.dr0;
context->Dr1 = dbregs.dr1; context->debug.i386_regs.dr1 = dbregs.dr1;
context->Dr2 = dbregs.dr2; context->debug.i386_regs.dr2 = dbregs.dr2;
context->Dr3 = dbregs.dr3; context->debug.i386_regs.dr3 = dbregs.dr3;
context->Dr6 = dbregs.dr6; context->debug.i386_regs.dr6 = dbregs.dr6;
context->Dr7 = dbregs.dr7; context->debug.i386_regs.dr7 = dbregs.dr7;
#endif #endif
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; context->flags |= SERVER_CTX_DEBUG_REGISTERS;
} }
resume_after_ptrace( thread ); resume_after_ptrace( thread );
} }
/* set the thread x86 registers */ /* set the thread x86 registers */
void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags )
{ {
int pid = get_ptrace_tid(thread); int pid = get_ptrace_tid(thread);
struct dbreg dbregs; struct dbreg dbregs;
/* all other regs are handled on the client side */ /* all other regs are handled on the client side */
assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); assert( flags == SERVER_CTX_DEBUG_REGISTERS );
if (!suspend_for_ptrace( thread )) return; if (!suspend_for_ptrace( thread )) return;
#ifdef DBREG_DRX #ifdef DBREG_DRX
/* needed for FreeBSD, the structure fields have changed under 5.x */ /* needed for FreeBSD, the structure fields have changed under 5.x */
DBREG_DRX((&dbregs), 0) = context->Dr0; DBREG_DRX((&dbregs), 0) = context->debug.i386_regs.dr0;
DBREG_DRX((&dbregs), 1) = context->Dr1; DBREG_DRX((&dbregs), 1) = context->debug.i386_regs.dr1;
DBREG_DRX((&dbregs), 2) = context->Dr2; DBREG_DRX((&dbregs), 2) = context->debug.i386_regs.dr2;
DBREG_DRX((&dbregs), 3) = context->Dr3; DBREG_DRX((&dbregs), 3) = context->debug.i386_regs.dr3;
DBREG_DRX((&dbregs), 4) = 0; DBREG_DRX((&dbregs), 4) = 0;
DBREG_DRX((&dbregs), 5) = 0; DBREG_DRX((&dbregs), 5) = 0;
DBREG_DRX((&dbregs), 6) = context->Dr6; DBREG_DRX((&dbregs), 6) = context->debug.i386_regs.dr6;
DBREG_DRX((&dbregs), 7) = context->Dr7; DBREG_DRX((&dbregs), 7) = context->debug.i386_regs.dr7;
#else #else
dbregs.dr0 = context->Dr0; dbregs.dr0 = context->debug.i386_regs.dr0;
dbregs.dr1 = context->Dr1; dbregs.dr1 = context->debug.i386_regs.dr1;
dbregs.dr2 = context->Dr2; dbregs.dr2 = context->debug.i386_regs.dr2;
dbregs.dr3 = context->Dr3; dbregs.dr3 = context->debug.i386_regs.dr3;
dbregs.dr4 = 0; dbregs.dr4 = 0;
dbregs.dr5 = 0; dbregs.dr5 = 0;
dbregs.dr6 = context->Dr6; dbregs.dr6 = context->debug.i386_regs.dr6;
dbregs.dr7 = context->Dr7; dbregs.dr7 = context->debug.i386_regs.dr7;
#endif #endif
if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error();
else if (thread->context) /* update the cached values */ else if (thread->context)
{ thread->context->debug.i386_regs = context->debug.i386_regs; /* update the cached values */
thread->context->Dr0 = context->Dr0;
thread->context->Dr1 = context->Dr1;
thread->context->Dr2 = context->Dr2;
thread->context->Dr3 = context->Dr3;
thread->context->Dr6 = context->Dr6;
thread->context->Dr7 = context->Dr7;
}
resume_after_ptrace( thread ); resume_after_ptrace( thread );
} }
#else /* linux || __FreeBSD__ */ #else /* linux || __FreeBSD__ */
/* retrieve the thread x86 registers */ /* retrieve the thread x86 registers */
void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) void get_thread_context( struct thread *thread, context_t *context, unsigned int flags )
{ {
} }
/* set the thread x86 debug registers */ /* set the thread x86 debug registers */
void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags )
{ {
} }
......
...@@ -1212,8 +1212,7 @@ C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, suspend) == 20 ); ...@@ -1212,8 +1212,7 @@ C_ASSERT( FIELD_OFFSET(struct get_thread_context_request, suspend) == 20 );
C_ASSERT( FIELD_OFFSET(struct get_thread_context_reply, self) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_thread_context_reply, self) == 8 );
C_ASSERT( sizeof(struct get_thread_context_reply) == 16 ); C_ASSERT( sizeof(struct get_thread_context_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, flags) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, suspend) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, suspend) == 20 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_reply, self) == 8 ); C_ASSERT( FIELD_OFFSET(struct set_thread_context_reply, self) == 8 );
C_ASSERT( sizeof(struct set_thread_context_reply) == 16 ); C_ASSERT( sizeof(struct set_thread_context_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_selector_entry_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_selector_entry_request, handle) == 12 );
......
...@@ -944,6 +944,34 @@ void kill_thread( struct thread *thread, int violent_death ) ...@@ -944,6 +944,34 @@ void kill_thread( struct thread *thread, int violent_death )
release_object( thread ); release_object( thread );
} }
/* copy parts of a context structure */
static void copy_context( context_t *to, const context_t *from, unsigned int flags )
{
assert( to->cpu == from->cpu );
to->flags |= flags;
if (flags & SERVER_CTX_CONTROL) to->ctl = from->ctl;
if (flags & SERVER_CTX_INTEGER) to->integer = from->integer;
if (flags & SERVER_CTX_SEGMENTS) to->seg = from->seg;
if (flags & SERVER_CTX_FLOATING_POINT) to->fp = from->fp;
if (flags & SERVER_CTX_DEBUG_REGISTERS) to->debug = from->debug;
if (flags & SERVER_CTX_EXTENDED_REGISTERS) to->ext = from->ext;
}
/* return the context flags that correspond to system regs */
/* (system regs are the ones we can't access on the client side) */
static unsigned int get_context_system_regs( enum cpu_type cpu )
{
switch (cpu)
{
case CPU_x86: return SERVER_CTX_DEBUG_REGISTERS;
case CPU_x86_64: return SERVER_CTX_DEBUG_REGISTERS;
case CPU_ALPHA: return 0;
case CPU_POWERPC: return 0;
case CPU_SPARC: return 0;
}
return 0;
}
/* trigger a breakpoint event in a given thread */ /* trigger a breakpoint event in a given thread */
void break_thread( struct thread *thread ) void break_thread( struct thread *thread )
{ {
...@@ -955,7 +983,24 @@ void break_thread( struct thread *thread ) ...@@ -955,7 +983,24 @@ void break_thread( struct thread *thread )
data.exception.first = 1; data.exception.first = 1;
data.exception.exc_code = STATUS_BREAKPOINT; data.exception.exc_code = STATUS_BREAKPOINT;
data.exception.flags = EXCEPTION_CONTINUABLE; data.exception.flags = EXCEPTION_CONTINUABLE;
data.exception.address = get_context_ip( thread->context ); switch (thread->context->cpu)
{
case CPU_x86:
data.exception.address = thread->context->ctl.i386_regs.eip;
break;
case CPU_x86_64:
data.exception.address = thread->context->ctl.x86_64_regs.rip;
break;
case CPU_ALPHA:
data.exception.address = thread->context->ctl.alpha_regs.fir;
break;
case CPU_POWERPC:
data.exception.address = thread->context->ctl.powerpc_regs.iar;
break;
case CPU_SPARC:
data.exception.address = thread->context->ctl.sparc_regs.pc;
break;
}
generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data ); generate_debug_event( thread, EXCEPTION_DEBUG_EVENT, &data );
thread->debug_break = 0; thread->debug_break = 0;
} }
...@@ -1357,9 +1402,9 @@ DECL_HANDLER(get_apc_result) ...@@ -1357,9 +1402,9 @@ DECL_HANDLER(get_apc_result)
DECL_HANDLER(get_thread_context) DECL_HANDLER(get_thread_context)
{ {
struct thread *thread; struct thread *thread;
CONTEXT *context; context_t *context;
if (get_reply_max_size() < sizeof(CONTEXT)) if (get_reply_max_size() < sizeof(context_t))
{ {
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return;
...@@ -1376,7 +1421,7 @@ DECL_HANDLER(get_thread_context) ...@@ -1376,7 +1421,7 @@ DECL_HANDLER(get_thread_context)
else else
{ {
if (thread->context == thread->suspend_context) thread->context = NULL; if (thread->context == thread->suspend_context) thread->context = NULL;
set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) ); set_reply_data_ptr( thread->suspend_context, sizeof(context_t) );
thread->suspend_context = NULL; thread->suspend_context = NULL;
} }
} }
...@@ -1386,12 +1431,12 @@ DECL_HANDLER(get_thread_context) ...@@ -1386,12 +1431,12 @@ DECL_HANDLER(get_thread_context)
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
else set_error( STATUS_PENDING ); else set_error( STATUS_PENDING );
} }
else if ((context = set_reply_data_size( sizeof(CONTEXT) ))) else if ((context = set_reply_data_size( sizeof(context_t) )))
{ {
unsigned int flags = get_context_system_regs( req->flags ); unsigned int flags = get_context_system_regs( thread->process->cpu );
memset( context, 0, sizeof(CONTEXT) ); memset( context, 0, sizeof(context_t) );
context->ContextFlags = get_context_cpu_flag(); context->cpu = thread->process->cpu;
if (thread->context) copy_context( context, thread->context, req->flags & ~flags ); if (thread->context) copy_context( context, thread->context, req->flags & ~flags );
if (flags) get_thread_context( thread, context, flags ); if (flags) get_thread_context( thread, context, flags );
} }
...@@ -1403,8 +1448,9 @@ DECL_HANDLER(get_thread_context) ...@@ -1403,8 +1448,9 @@ DECL_HANDLER(get_thread_context)
DECL_HANDLER(set_thread_context) DECL_HANDLER(set_thread_context)
{ {
struct thread *thread; struct thread *thread;
const context_t *context = get_req_data();
if (get_req_data_size() < sizeof(CONTEXT)) if (get_req_data_size() < sizeof(context_t))
{ {
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return;
...@@ -1413,14 +1459,14 @@ DECL_HANDLER(set_thread_context) ...@@ -1413,14 +1459,14 @@ DECL_HANDLER(set_thread_context)
if (req->suspend) if (req->suspend)
{ {
if (thread != current || thread->context) if (thread != current || thread->context || context->cpu != thread->process->cpu)
{ {
/* nested suspend or exception, shouldn't happen */ /* nested suspend or exception, shouldn't happen */
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
} }
else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) ))) else if ((thread->suspend_context = mem_alloc( sizeof(context_t) )))
{ {
memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) ); memcpy( thread->suspend_context, get_req_data(), sizeof(context_t) );
thread->context = thread->suspend_context; thread->context = thread->suspend_context;
if (thread->debug_break) break_thread( thread ); if (thread->debug_break) break_thread( thread );
} }
...@@ -1431,15 +1477,16 @@ DECL_HANDLER(set_thread_context) ...@@ -1431,15 +1477,16 @@ DECL_HANDLER(set_thread_context)
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
else set_error( STATUS_PENDING ); else set_error( STATUS_PENDING );
} }
else else if (context->cpu == thread->process->cpu)
{ {
const CONTEXT *context = get_req_data(); unsigned int system_flags = get_context_system_regs(context->cpu) & context->flags;
unsigned int flags = get_context_system_regs( req->flags ); unsigned int client_flags = context->flags & ~system_flags;
if (flags) set_thread_context( thread, context, flags ); if (system_flags) set_thread_context( thread, context, system_flags );
if (thread->context && !get_error()) if (thread->context && !get_error()) copy_context( thread->context, context, client_flags );
copy_context( thread->context, context, req->flags & ~flags );
} }
else set_error( STATUS_INVALID_PARAMETER );
reply->self = (thread == current); reply->self = (thread == current);
release_object( thread ); release_object( thread );
} }
......
...@@ -76,8 +76,8 @@ struct thread ...@@ -76,8 +76,8 @@ struct thread
int exit_code; /* thread exit code */ int exit_code; /* thread exit code */
int unix_pid; /* Unix pid of client */ int unix_pid; /* Unix pid of client */
int unix_tid; /* Unix tid of client */ int unix_tid; /* Unix tid of client */
CONTEXT *context; /* current context if in an exception handler */ context_t *context; /* current context if in an exception handler */
CONTEXT *suspend_context; /* current context if suspended */ context_t *suspend_context; /* current context if suspended */
client_ptr_t teb; /* TEB address (in client address space) */ client_ptr_t teb; /* TEB address (in client address space) */
affinity_t affinity; /* affinity mask */ affinity_t affinity; /* affinity mask */
int priority; /* priority level */ int priority; /* priority level */
...@@ -119,17 +119,11 @@ extern int thread_get_inflight_fd( struct thread *thread, int client ); ...@@ -119,17 +119,11 @@ extern int thread_get_inflight_fd( struct thread *thread, int client );
extern struct thread_snapshot *thread_snap( int *count ); extern struct thread_snapshot *thread_snap( int *count );
extern struct token *thread_get_impersonation_token( struct thread *thread ); extern struct token *thread_get_impersonation_token( struct thread *thread );
/* CPU context functions */
extern void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags );
extern client_ptr_t get_context_ip( const CONTEXT *context );
extern unsigned int get_context_cpu_flag(void);
extern unsigned int get_context_system_regs( unsigned int flags );
/* ptrace functions */ /* ptrace functions */
extern void sigchld_callback(void); extern void sigchld_callback(void);
extern void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ); extern void get_thread_context( struct thread *thread, context_t *context, unsigned int flags );
extern void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ); extern void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags );
extern int send_thread_signal( struct thread *thread, int sig ); extern int send_thread_signal( struct thread *thread, int sig );
extern void get_selector_entry( struct thread *thread, int entry, unsigned int *base, extern void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
unsigned int *limit, unsigned char *flags ); unsigned int *limit, unsigned char *flags );
......
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