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 )
{
LARGE_INTEGER timeout;
int saved_errno = errno;
context_t server_context;
context_to_server( &server_context, context );
/* store the context we got at suspend time */
SERVER_START_REQ( set_thread_context )
{
req->handle = wine_server_obj_handle( GetCurrentThread() );
req->flags = CONTEXT_FULL;
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 );
}
SERVER_END_REQ;
......@@ -169,13 +171,13 @@ void wait_suspend( CONTEXT *context )
SERVER_START_REQ( get_thread_context )
{
req->handle = wine_server_obj_handle( GetCurrentThread() );
req->flags = CONTEXT_FULL;
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 );
}
SERVER_END_REQ;
context_from_server( context, &server_context );
errno = saved_errno;
}
......@@ -187,16 +189,19 @@ void wait_suspend( CONTEXT *context )
*/
static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
{
int ret;
NTSTATUS ret;
DWORD i;
HANDLE handle = 0;
client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
context_t server_context;
if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
params[i] = rec->ExceptionInformation[i];
context_to_server( &server_context, context );
SERVER_START_REQ( queue_exception_event )
{
req->first = first_chance;
......@@ -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->len = i * sizeof(params[0]);
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 );
}
SERVER_END_REQ;
......@@ -217,10 +222,11 @@ static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTE
SERVER_START_REQ( get_exception_status )
{
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 );
}
SERVER_END_REQ;
if (!ret) ret = context_from_server( context, &server_context );
return ret;
}
......
......@@ -44,6 +44,8 @@ extern void wait_suspend( CONTEXT *context );
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
extern void set_cpu_context( const CONTEXT *context );
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 */
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
......
......@@ -55,6 +55,8 @@
# include <sys/sysctl.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "wine/library.h"
#include "ntdll_misc.h"
......@@ -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
*
* Check if the fault location is a privileged instruction.
......
......@@ -51,6 +51,8 @@
# include <sys/signal.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
......@@ -301,6 +303,10 @@ void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
to->Msr = from->Msr;
to->Ctr = from->Ctr;
to->Iar = from->Iar;
to->Lr = from->Lr;
to->Dar = from->Dar;
to->Dsisr = from->Dsisr;
to->Trap = from->Trap;
}
if (flags & CONTEXT_INTEGER)
{
......@@ -378,6 +384,208 @@ 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.
*/
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
{
if (from->cpu != CPU_POWERPC) return STATUS_INVALID_PARAMETER;
to->ContextFlags = 0; /* no CPU id? */
if (from->flags & SERVER_CTX_CONTROL)
{
to->ContextFlags |= CONTEXT_CONTROL;
to->Msr = from->ctl.powerpc_regs.msr;
to->Ctr = from->ctl.powerpc_regs.ctr;
to->Iar = from->ctl.powerpc_regs.iar;
to->Lr = from->ctl.powerpc_regs.lr;
to->Dar = from->ctl.powerpc_regs.dar;
to->Dsisr = from->ctl.powerpc_regs.dsisr;
to->Trap = from->ctl.powerpc_regs.trap;
}
if (from->flags & SERVER_CTX_INTEGER)
{
to->ContextFlags |= CONTEXT_INTEGER;
to->Gpr0 = from->integer.powerpc_regs.gpr[0];
to->Gpr1 = from->integer.powerpc_regs.gpr[1];
to->Gpr2 = from->integer.powerpc_regs.gpr[2];
to->Gpr3 = from->integer.powerpc_regs.gpr[3];
to->Gpr4 = from->integer.powerpc_regs.gpr[4];
to->Gpr5 = from->integer.powerpc_regs.gpr[5];
to->Gpr6 = from->integer.powerpc_regs.gpr[6];
to->Gpr7 = from->integer.powerpc_regs.gpr[7];
to->Gpr8 = from->integer.powerpc_regs.gpr[8];
to->Gpr9 = from->integer.powerpc_regs.gpr[9];
to->Gpr10 = from->integer.powerpc_regs.gpr[10];
to->Gpr11 = from->integer.powerpc_regs.gpr[11];
to->Gpr12 = from->integer.powerpc_regs.gpr[12];
to->Gpr13 = from->integer.powerpc_regs.gpr[13];
to->Gpr14 = from->integer.powerpc_regs.gpr[14];
to->Gpr15 = from->integer.powerpc_regs.gpr[15];
to->Gpr16 = from->integer.powerpc_regs.gpr[16];
to->Gpr17 = from->integer.powerpc_regs.gpr[17];
to->Gpr18 = from->integer.powerpc_regs.gpr[18];
to->Gpr19 = from->integer.powerpc_regs.gpr[19];
to->Gpr20 = from->integer.powerpc_regs.gpr[20];
to->Gpr21 = from->integer.powerpc_regs.gpr[21];
to->Gpr22 = from->integer.powerpc_regs.gpr[22];
to->Gpr23 = from->integer.powerpc_regs.gpr[23];
to->Gpr24 = from->integer.powerpc_regs.gpr[24];
to->Gpr25 = from->integer.powerpc_regs.gpr[25];
to->Gpr26 = from->integer.powerpc_regs.gpr[26];
to->Gpr27 = from->integer.powerpc_regs.gpr[27];
to->Gpr28 = from->integer.powerpc_regs.gpr[28];
to->Gpr29 = from->integer.powerpc_regs.gpr[29];
to->Gpr30 = from->integer.powerpc_regs.gpr[30];
to->Gpr31 = from->integer.powerpc_regs.gpr[31];
to->Xer = from->integer.powerpc_regs.xer;
to->Cr = from->integer.powerpc_regs.cr;
}
if (from->flags & SERVER_CTX_FLOATING_POINT)
{
to->ContextFlags |= CONTEXT_FLOATING_POINT;
to->Fpr0 = from->fp.powerpc_regs.fpr[0];
to->Fpr1 = from->fp.powerpc_regs.fpr[1];
to->Fpr2 = from->fp.powerpc_regs.fpr[2];
to->Fpr3 = from->fp.powerpc_regs.fpr[3];
to->Fpr4 = from->fp.powerpc_regs.fpr[4];
to->Fpr5 = from->fp.powerpc_regs.fpr[5];
to->Fpr6 = from->fp.powerpc_regs.fpr[6];
to->Fpr7 = from->fp.powerpc_regs.fpr[7];
to->Fpr8 = from->fp.powerpc_regs.fpr[8];
to->Fpr9 = from->fp.powerpc_regs.fpr[9];
to->Fpr10 = from->fp.powerpc_regs.fpr[10];
to->Fpr11 = from->fp.powerpc_regs.fpr[11];
to->Fpr12 = from->fp.powerpc_regs.fpr[12];
to->Fpr13 = from->fp.powerpc_regs.fpr[13];
to->Fpr14 = from->fp.powerpc_regs.fpr[14];
to->Fpr15 = from->fp.powerpc_regs.fpr[15];
to->Fpr16 = from->fp.powerpc_regs.fpr[16];
to->Fpr17 = from->fp.powerpc_regs.fpr[17];
to->Fpr18 = from->fp.powerpc_regs.fpr[18];
to->Fpr19 = from->fp.powerpc_regs.fpr[19];
to->Fpr20 = from->fp.powerpc_regs.fpr[20];
to->Fpr21 = from->fp.powerpc_regs.fpr[21];
to->Fpr22 = from->fp.powerpc_regs.fpr[22];
to->Fpr23 = from->fp.powerpc_regs.fpr[23];
to->Fpr24 = from->fp.powerpc_regs.fpr[24];
to->Fpr25 = from->fp.powerpc_regs.fpr[25];
to->Fpr26 = from->fp.powerpc_regs.fpr[26];
to->Fpr27 = from->fp.powerpc_regs.fpr[27];
to->Fpr28 = from->fp.powerpc_regs.fpr[28];
to->Fpr29 = from->fp.powerpc_regs.fpr[29];
to->Fpr30 = from->fp.powerpc_regs.fpr[30];
to->Fpr31 = from->fp.powerpc_regs.fpr[31];
to->Fpscr = from->fp.powerpc_regs.fpscr;
}
return STATUS_SUCCESS;
}
/**********************************************************************
* get_fpu_code
*
......
......@@ -33,6 +33,8 @@
#include <stdio.h>
#include <sys/ucontext.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "winnt.h"
......@@ -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
*
......
......@@ -40,6 +40,8 @@
#endif
#define NONAMELESSUNION
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
......@@ -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
*
......
......@@ -824,12 +824,15 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
if (!self)
{
context_t server_context;
context_to_server( &server_context, context );
SERVER_START_REQ( set_thread_context )
{
req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
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 );
self = reply->self;
}
......@@ -844,9 +847,8 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
SERVER_START_REQ( set_thread_context )
{
req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
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 );
}
SERVER_END_REQ;
......@@ -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.@)
* ZwGetContextThread (NTDLL.@)
......@@ -878,7 +903,6 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
{
NTSTATUS ret;
CONTEXT ctx;
DWORD dummy, i;
DWORD needed_flags = context->ContextFlags;
BOOL self = (handle == GetCurrentThread());
......@@ -890,12 +914,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
if (!self)
{
unsigned int server_flags = get_server_context_flags( context->ContextFlags );
context_t server_context;
SERVER_START_REQ( get_thread_context )
{
req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
req->flags = server_flags;
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 );
self = reply->self;
}
......@@ -910,9 +937,9 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
SERVER_START_REQ( get_thread_context )
{
req->handle = wine_server_obj_handle( handle );
req->flags = context->ContextFlags;
req->flags = server_flags;
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 );
}
SERVER_END_REQ;
......@@ -928,17 +955,19 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
}
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
}
if (!ret) ret = context_from_server( context, &server_context );
if (ret) return ret;
copy_context( context, &ctx, context->ContextFlags & ctx.ContextFlags );
needed_flags &= ~ctx.ContextFlags;
needed_flags &= ~context->ContextFlags;
}
if (self)
{
if (needed_flags)
{
CONTEXT ctx;
RtlCaptureContext( &ctx );
copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
context->ContextFlags |= ctx.ContextFlags & needed_flags;
}
#ifdef __i386__
/* update the cached version of the debug registers */
......
......@@ -135,6 +135,63 @@ enum cpu_type
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
{
thread_id_t tid;
......@@ -2356,7 +2413,6 @@ struct set_thread_context_request
{
struct request_header __header;
obj_handle_t handle;
unsigned int flags;
int suspend;
/* VARARG(context,context); */
};
......@@ -5224,6 +5280,6 @@ union generic_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 */
......@@ -14,11 +14,6 @@ C_SRCS = \
clipboard.c \
completion.c \
console.c \
context_alpha.c \
context_i386.c \
context_powerpc.c \
context_sparc.c \
context_x86_64.c \
debugger.c \
device.c \
directory.c \
......
/*
* Alpha register context support
*
* Copyright (C) 2004 Vincent Béron
*
* 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 __ALPHA__
#include <assert.h>
#include <errno.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 "file.h"
#include "thread.h"
#include "request.h"
#if 0 /* no longer used */
#ifdef HAVE_SYS_USER_H
# include <sys/user.h>
#endif
/* user definitions from asm/user.h */
struct kernel_user_struct
{
unsigned long regs[EF_SIZE/8+32];
size_t u_tsize;
size_t u_dsize;
size_t u_ssize;
unsigned long start_code;
unsigned long start_data;
unsigned long start_stack;
long int signal;
struct regs * u_ar0;
unsigned long magic;
char u_comm[32];
};
/* get thread context */
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
{
int pid = get_ptrace_pid(thread);
if (flags & CONTEXT_FULL)
{
struct kernel_user_struct regs;
if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
if (flags & CONTEXT_INTEGER)
{
context->IntV0 = regs.regs[EF_V0];
context->IntT0 = regs.regs[EF_T0];
context->IntT1 = regs.regs[EF_T1];
context->IntT2 = regs.regs[EF_T2];
context->IntT3 = regs.regs[EF_T3];
context->IntT4 = regs.regs[EF_T4];
context->IntT5 = regs.regs[EF_T5];
context->IntT6 = regs.regs[EF_T6];
context->IntT7 = regs.regs[EF_T7];
context->IntS0 = regs.regs[EF_S0];
context->IntS1 = regs.regs[EF_S1];
context->IntS2 = regs.regs[EF_S2];
context->IntS3 = regs.regs[EF_S3];
context->IntS4 = regs.regs[EF_S4];
context->IntS5 = regs.regs[EF_S5];
context->IntFp = regs.regs[EF_S6];
context->IntA0 = regs.regs[EF_A0];
context->IntA1 = regs.regs[EF_A1];
context->IntA2 = regs.regs[EF_A2];
context->IntA3 = regs.regs[EF_A3];
context->IntA4 = regs.regs[EF_A4];
context->IntA5 = regs.regs[EF_A5];
context->IntT8 = regs.regs[EF_T8];
context->IntT9 = regs.regs[EF_T9];
context->IntT10 = regs.regs[EF_T10];
context->IntT11 = regs.regs[EF_T11];
context->IntT12 = regs.regs[EF_T12];
context->IntAt = regs.regs[EF_AT];
context->IntZero = 0;
}
if (flags & CONTEXT_CONTROL)
{
context->IntRa = regs.regs[EF_RA];
context->IntGp = regs.regs[EF_GP];
context->IntSp = regs.regs[EF_SP];
context->Fir = regs.regs[EF_PC];
context->Psr = regs.regs[EF_PS];
}
if (flags & CONTEXT_FLOATING_POINT)
{
context->FltF0 = regs.regs[EF_SIZE/8+0];
context->FltF1 = regs.regs[EF_SIZE/8+1];
context->FltF2 = regs.regs[EF_SIZE/8+2];
context->FltF3 = regs.regs[EF_SIZE/8+3];
context->FltF4 = regs.regs[EF_SIZE/8+4];
context->FltF5 = regs.regs[EF_SIZE/8+5];
context->FltF6 = regs.regs[EF_SIZE/8+6];
context->FltF7 = regs.regs[EF_SIZE/8+7];
context->FltF8 = regs.regs[EF_SIZE/8+8];
context->FltF9 = regs.regs[EF_SIZE/8+9];
context->FltF10 = regs.regs[EF_SIZE/8+10];
context->FltF11 = regs.regs[EF_SIZE/8+11];
context->FltF12 = regs.regs[EF_SIZE/8+12];
context->FltF13 = regs.regs[EF_SIZE/8+13];
context->FltF14 = regs.regs[EF_SIZE/8+14];
context->FltF15 = regs.regs[EF_SIZE/8+15];
context->FltF16 = regs.regs[EF_SIZE/8+16];
context->FltF17 = regs.regs[EF_SIZE/8+17];
context->FltF18 = regs.regs[EF_SIZE/8+18];
context->FltF19 = regs.regs[EF_SIZE/8+19];
context->FltF20 = regs.regs[EF_SIZE/8+20];
context->FltF21 = regs.regs[EF_SIZE/8+21];
context->FltF22 = regs.regs[EF_SIZE/8+22];
context->FltF23 = regs.regs[EF_SIZE/8+23];
context->FltF24 = regs.regs[EF_SIZE/8+24];
context->FltF25 = regs.regs[EF_SIZE/8+25];
context->FltF26 = regs.regs[EF_SIZE/8+26];
context->FltF27 = regs.regs[EF_SIZE/8+27];
context->FltF28 = regs.regs[EF_SIZE/8+28];
context->FltF29 = regs.regs[EF_SIZE/8+29];
context->FltF30 = regs.regs[EF_SIZE/8+30];
context->FltF31 = 0;
context->Fpcr = regs.regs[EF_SIZE/8+31];
context->SoftFpcr = 0; /* FIXME */
}
context->ContextFlags |= flags & CONTEXT_FULL;
}
return;
error:
file_set_error();
}
/* set a thread context */
static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
{
int pid = get_ptrace_pid(thread);
if (flags & CONTEXT_FULL)
{
struct kernel_user_struct regs;
if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
if (flags & CONTEXT_INTEGER)
{
regs.regs[EF_V0] = context->IntV0;
regs.regs[EF_T0] = context->IntT0;
regs.regs[EF_T1] = context->IntT1;
regs.regs[EF_T2] = context->IntT2;
regs.regs[EF_T3] = context->IntT3;
regs.regs[EF_T4] = context->IntT4;
regs.regs[EF_T5] = context->IntT5;
regs.regs[EF_T6] = context->IntT6;
regs.regs[EF_T7] = context->IntT7;
regs.regs[EF_S0] = context->IntS0;
regs.regs[EF_S1] = context->IntS1;
regs.regs[EF_S2] = context->IntS2;
regs.regs[EF_S3] = context->IntS3;
regs.regs[EF_S4] = context->IntS4;
regs.regs[EF_S5] = context->IntS5;
regs.regs[EF_S6] = context->IntFp;
regs.regs[EF_A0] = context->IntA0;
regs.regs[EF_A1] = context->IntA1;
regs.regs[EF_A2] = context->IntA2;
regs.regs[EF_A3] = context->IntA3;
regs.regs[EF_A4] = context->IntA4;
regs.regs[EF_A5] = context->IntA5;
regs.regs[EF_T8] = context->IntT8;
regs.regs[EF_T9] = context->IntT9;
regs.regs[EF_T10] = context->IntT10;
regs.regs[EF_T11] = context->IntT11;
regs.regs[EF_T12] = context->IntT12;
regs.regs[EF_AT] = context->IntAt;
}
if (flags & CONTEXT_CONTROL)
{
regs.regs[EF_RA] = context->IntRa;
regs.regs[EF_GP] = context->IntGp;
regs.regs[EF_SP] = context->IntSp;
regs.regs[EF_PC] = context->Fir;
regs.regs[EF_PS] = context->Psr;
}
if (flags & CONTEXT_FLOATING_POINT)
{
regs.regs[EF_SIZE/8+0] = context->FltF0;
regs.regs[EF_SIZE/8+1] = context->FltF1;
regs.regs[EF_SIZE/8+2] = context->FltF2;
regs.regs[EF_SIZE/8+3] = context->FltF3;
regs.regs[EF_SIZE/8+4] = context->FltF4;
regs.regs[EF_SIZE/8+5] = context->FltF5;
regs.regs[EF_SIZE/8+6] = context->FltF6;
regs.regs[EF_SIZE/8+7] = context->FltF7;
regs.regs[EF_SIZE/8+8] = context->FltF8;
regs.regs[EF_SIZE/8+9] = context->FltF9;
regs.regs[EF_SIZE/8+10] = context->FltF10;
regs.regs[EF_SIZE/8+11] = context->FltF11;
regs.regs[EF_SIZE/8+12] = context->FltF12;
regs.regs[EF_SIZE/8+13] = context->FltF13;
regs.regs[EF_SIZE/8+14] = context->FltF14;
regs.regs[EF_SIZE/8+15] = context->FltF15;
regs.regs[EF_SIZE/8+16] = context->FltF16;
regs.regs[EF_SIZE/8+17] = context->FltF17;
regs.regs[EF_SIZE/8+18] = context->FltF18;
regs.regs[EF_SIZE/8+19] = context->FltF19;
regs.regs[EF_SIZE/8+20] = context->FltF20;
regs.regs[EF_SIZE/8+21] = context->FltF21;
regs.regs[EF_SIZE/8+22] = context->FltF22;
regs.regs[EF_SIZE/8+23] = context->FltF23;
regs.regs[EF_SIZE/8+24] = context->FltF24;
regs.regs[EF_SIZE/8+25] = context->FltF25;
regs.regs[EF_SIZE/8+26] = context->FltF26;
regs.regs[EF_SIZE/8+27] = context->FltF27;
regs.regs[EF_SIZE/8+28] = context->FltF28;
regs.regs[EF_SIZE/8+29] = context->FltF29;
regs.regs[EF_SIZE/8+30] = context->FltF30;
regs.regs[EF_SIZE/8+31] = context->Fpcr;
}
if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
}
return;
error:
file_set_error();
}
#endif /* 0 */
/* copy a context structure according to the flags */
void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
{
flags &= ~CONTEXT_ALPHA; /* get rid of CPU id */
if (flags & CONTEXT_CONTROL)
{
to->IntRa = from->IntRa;
to->IntGp = from->IntGp;
to->IntSp = from->IntSp;
to->Fir = from->Fir;
to->Psr = from->Psr;
}
if (flags & CONTEXT_INTEGER)
{
to->IntV0 = from->IntV0;
to->IntT0 = from->IntT0;
to->IntT1 = from->IntT1;
to->IntT2 = from->IntT2;
to->IntT3 = from->IntT3;
to->IntT4 = from->IntT4;
to->IntT5 = from->IntT5;
to->IntT6 = from->IntT6;
to->IntT7 = from->IntT7;
to->IntS0 = from->IntS0;
to->IntS1 = from->IntS1;
to->IntS2 = from->IntS2;
to->IntS3 = from->IntS3;
to->IntS4 = from->IntS4;
to->IntS5 = from->IntS5;
to->IntFp = from->IntFp;
to->IntA0 = from->IntA0;
to->IntA1 = from->IntA1;
to->IntA2 = from->IntA2;
to->IntA3 = from->IntA3;
to->IntA4 = from->IntA4;
to->IntA5 = from->IntA5;
to->IntT8 = from->IntT8;
to->IntT9 = from->IntT9;
to->IntT10 = from->IntT10;
to->IntT11 = from->IntT11;
to->IntT12 = from->IntT12;
to->IntAt = from->IntAt;
to->IntZero = from->IntZero;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->FltF0 = from->FltF0;
to->FltF1 = from->FltF1;
to->FltF2 = from->FltF2;
to->FltF3 = from->FltF3;
to->FltF4 = from->FltF4;
to->FltF5 = from->FltF5;
to->FltF6 = from->FltF6;
to->FltF7 = from->FltF7;
to->FltF8 = from->FltF8;
to->FltF9 = from->FltF9;
to->FltF10 = from->FltF10;
to->FltF11 = from->FltF11;
to->FltF12 = from->FltF12;
to->FltF13 = from->FltF13;
to->FltF14 = from->FltF14;
to->FltF15 = from->FltF15;
to->FltF16 = from->FltF16;
to->FltF17 = from->FltF17;
to->FltF18 = from->FltF18;
to->FltF19 = from->FltF19;
to->FltF20 = from->FltF20;
to->FltF21 = from->FltF21;
to->FltF22 = from->FltF22;
to->FltF23 = from->FltF23;
to->FltF24 = from->FltF24;
to->FltF25 = from->FltF25;
to->FltF26 = from->FltF26;
to->FltF27 = from->FltF27;
to->FltF28 = from->FltF28;
to->FltF29 = from->FltF29;
to->FltF30 = from->FltF30;
to->FltF31 = from->FltF31;
to->Fpcr = from->Fpcr;
to->SoftFpcr = from->SoftFpcr;
}
to->ContextFlags |= flags;
}
/* retrieve the current instruction pointer of a context */
client_ptr_t get_context_ip( const CONTEXT *context )
{
return context->Fir;
}
/* return the context flag that contains the CPU id */
unsigned int get_context_cpu_flag(void)
{
return CONTEXT_ALPHA;
}
/* 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 /* __ALPHA__ */
/*
* 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
enum debug_event_state state; /* event state */
int status; /* continuation status */
debug_event_t data; /* event data */
CONTEXT context; /* register context */
context_t context; /* register context */
};
/* debug context */
......@@ -652,11 +652,11 @@ DECL_HANDLER(queue_exception_event)
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;
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;
if ((reply->handle = alloc_handle( current->process, event, SYNCHRONIZE, 0 )))
......@@ -682,7 +682,7 @@ DECL_HANDLER(get_exception_status)
{
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 );
current->context = NULL;
}
......
......@@ -160,7 +160,7 @@ void finish_process_tracing( struct process *process )
}
/* 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__
x86_debug_state32_t state;
......@@ -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 );
/* 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 ||
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
{
/* work around silly renaming of struct members in OS X 10.5 */
#if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32)
context->Dr0 = state.__dr0;
context->Dr1 = state.__dr1;
context->Dr2 = state.__dr2;
context->Dr3 = state.__dr3;
context->Dr6 = state.__dr6;
context->Dr7 = state.__dr7;
context->debug.i386_regs.dr0 = state.__dr0;
context->debug.i386_regs.dr1 = state.__dr1;
context->debug.i386_regs.dr2 = state.__dr2;
context->debug.i386_regs.dr3 = state.__dr3;
context->debug.i386_regs.dr6 = state.__dr6;
context->debug.i386_regs.dr7 = state.__dr7;
#else
context->Dr0 = state.dr0;
context->Dr1 = state.dr1;
context->Dr2 = state.dr2;
context->Dr3 = state.dr3;
context->Dr6 = state.dr6;
context->Dr7 = state.dr7;
context->debug.i386_regs.dr0 = state.dr0;
context->debug.i386_regs.dr1 = state.dr1;
context->debug.i386_regs.dr2 = state.dr2;
context->debug.i386_regs.dr3 = state.dr3;
context->debug.i386_regs.dr6 = state.dr6;
context->debug.i386_regs.dr7 = state.dr7;
#endif
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
context->flags |= SERVER_CTX_DEBUG_REGISTERS;
}
mach_port_deallocate( mach_task_self(), port );
#endif
}
/* 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__
x86_debug_state32_t state;
......@@ -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 );
/* 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 ||
mach_port_extract_right( process_port, thread->unix_tid,
......@@ -224,35 +224,28 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
}
#if __DARWIN_UNIX03 && defined(_STRUCT_X86_DEBUG_STATE32)
state.__dr0 = context->Dr0;
state.__dr1 = context->Dr1;
state.__dr2 = context->Dr2;
state.__dr3 = context->Dr3;
state.__dr0 = context->debug.i386_regs.dr0;
state.__dr1 = context->debug.i386_regs.dr1;
state.__dr2 = context->debug.i386_regs.dr2;
state.__dr3 = context->debug.i386_regs.dr3;
state.__dr4 = 0;
state.__dr5 = 0;
state.__dr6 = context->Dr6;
state.__dr7 = context->Dr7;
state.__dr6 = context->debug.i386_regs.dr6;
state.__dr7 = context->debug.i386_regs.dr7;
#else
state.dr0 = context->Dr0;
state.dr1 = context->Dr1;
state.dr2 = context->Dr2;
state.dr3 = context->Dr3;
state.dr0 = context->debug.i386_regs.dr0;
state.dr1 = context->debug.i386_regs.dr1;
state.dr2 = context->debug.i386_regs.dr2;
state.dr3 = context->debug.i386_regs.dr3;
state.dr4 = 0;
state.dr5 = 0;
state.dr6 = context->Dr6;
state.dr7 = context->Dr7;
state.dr6 = context->debug.i386_regs.dr6;
state.dr7 = context->debug.i386_regs.dr7;
#endif
if (!thread_set_state( port, x86_DEBUG_STATE32, (thread_state_t)&state, count ))
{
if (thread->context) /* 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;
}
thread->context->debug.i386_regs = context->debug.i386_regs;
}
mach_port_deallocate( mach_task_self(), port );
#endif
......
......@@ -200,20 +200,14 @@ error:
}
/* 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 */
}
/* 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 */
}
......
......@@ -150,6 +150,63 @@ enum cpu_type
};
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 */
struct send_fd
{
......@@ -1732,7 +1789,6 @@ enum char_info_mode
/* Set the current context of a thread */
@REQ(set_thread_context)
obj_handle_t handle; /* thread handle */
unsigned int flags; /* context flags */
int suspend; /* if setting context during suspend */
VARARG(context,context); /* thread context */
@REPLY
......
......@@ -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))
/* 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);
long data[8];
/* 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;
......@@ -548,39 +548,39 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
goto done;
}
}
context->Dr0 = data[0];
context->Dr1 = data[1];
context->Dr2 = data[2];
context->Dr3 = data[3];
context->Dr6 = data[6];
context->Dr7 = data[7];
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
context->debug.i386_regs.dr0 = data[0];
context->debug.i386_regs.dr1 = data[1];
context->debug.i386_regs.dr2 = data[2];
context->debug.i386_regs.dr3 = data[3];
context->debug.i386_regs.dr6 = data[6];
context->debug.i386_regs.dr7 = data[7];
context->flags |= SERVER_CTX_DEBUG_REGISTERS;
done:
resume_after_ptrace( thread );
}
/* 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 );
/* 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 (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
if (thread->context) thread->context->Dr0 = context->Dr0;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
if (thread->context) thread->context->Dr1 = context->Dr1;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
if (thread->context) thread->context->Dr2 = context->Dr2;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
if (thread->context) thread->context->Dr3 = context->Dr3;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
if (thread->context) thread->context->Dr6 = context->Dr6;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
if (thread->context) thread->context->Dr7 = context->Dr7;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error;
if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7;
resume_after_ptrace( thread );
return;
error:
......@@ -594,13 +594,13 @@ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned
#include <machine/reg.h>
/* 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);
struct dbreg dbregs;
/* 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;
......@@ -609,78 +609,71 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f
{
#ifdef DBREG_DRX
/* needed for FreeBSD, the structure fields have changed under 5.x */
context->Dr0 = DBREG_DRX((&dbregs), 0);
context->Dr1 = DBREG_DRX((&dbregs), 1);
context->Dr2 = DBREG_DRX((&dbregs), 2);
context->Dr3 = DBREG_DRX((&dbregs), 3);
context->Dr6 = DBREG_DRX((&dbregs), 6);
context->Dr7 = DBREG_DRX((&dbregs), 7);
context->debug.i386_regs.dr0 = DBREG_DRX((&dbregs), 0);
context->debug.i386_regs.dr1 = DBREG_DRX((&dbregs), 1);
context->debug.i386_regs.dr2 = DBREG_DRX((&dbregs), 2);
context->debug.i386_regs.dr3 = DBREG_DRX((&dbregs), 3);
context->debug.i386_regs.dr6 = DBREG_DRX((&dbregs), 6);
context->debug.i386_regs.dr7 = DBREG_DRX((&dbregs), 7);
#else
context->Dr0 = dbregs.dr0;
context->Dr1 = dbregs.dr1;
context->Dr2 = dbregs.dr2;
context->Dr3 = dbregs.dr3;
context->Dr6 = dbregs.dr6;
context->Dr7 = dbregs.dr7;
context->debug.i386_regs.dr0 = dbregs.dr0;
context->debug.i386_regs.dr1 = dbregs.dr1;
context->debug.i386_regs.dr2 = dbregs.dr2;
context->debug.i386_regs.dr3 = dbregs.dr3;
context->debug.i386_regs.dr6 = dbregs.dr6;
context->debug.i386_regs.dr7 = dbregs.dr7;
#endif
context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
context->flags |= SERVER_CTX_DEBUG_REGISTERS;
}
resume_after_ptrace( thread );
}
/* 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);
struct dbreg dbregs;
/* 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;
#ifdef DBREG_DRX
/* needed for FreeBSD, the structure fields have changed under 5.x */
DBREG_DRX((&dbregs), 0) = context->Dr0;
DBREG_DRX((&dbregs), 1) = context->Dr1;
DBREG_DRX((&dbregs), 2) = context->Dr2;
DBREG_DRX((&dbregs), 3) = context->Dr3;
DBREG_DRX((&dbregs), 0) = context->debug.i386_regs.dr0;
DBREG_DRX((&dbregs), 1) = context->debug.i386_regs.dr1;
DBREG_DRX((&dbregs), 2) = context->debug.i386_regs.dr2;
DBREG_DRX((&dbregs), 3) = context->debug.i386_regs.dr3;
DBREG_DRX((&dbregs), 4) = 0;
DBREG_DRX((&dbregs), 5) = 0;
DBREG_DRX((&dbregs), 6) = context->Dr6;
DBREG_DRX((&dbregs), 7) = context->Dr7;
DBREG_DRX((&dbregs), 6) = context->debug.i386_regs.dr6;
DBREG_DRX((&dbregs), 7) = context->debug.i386_regs.dr7;
#else
dbregs.dr0 = context->Dr0;
dbregs.dr1 = context->Dr1;
dbregs.dr2 = context->Dr2;
dbregs.dr3 = context->Dr3;
dbregs.dr0 = context->debug.i386_regs.dr0;
dbregs.dr1 = context->debug.i386_regs.dr1;
dbregs.dr2 = context->debug.i386_regs.dr2;
dbregs.dr3 = context->debug.i386_regs.dr3;
dbregs.dr4 = 0;
dbregs.dr5 = 0;
dbregs.dr6 = context->Dr6;
dbregs.dr7 = context->Dr7;
dbregs.dr6 = context->debug.i386_regs.dr6;
dbregs.dr7 = context->debug.i386_regs.dr7;
#endif
if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error();
else if (thread->context) /* 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;
}
else if (thread->context)
thread->context->debug.i386_regs = context->debug.i386_regs; /* update the cached values */
resume_after_ptrace( thread );
}
#else /* linux || __FreeBSD__ */
/* 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 */
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 );
C_ASSERT( FIELD_OFFSET(struct get_thread_context_reply, self) == 8 );
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, flags) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, suspend) == 20 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_request, suspend) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_context_reply, self) == 8 );
C_ASSERT( sizeof(struct set_thread_context_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_selector_entry_request, handle) == 12 );
......
......@@ -944,6 +944,34 @@ void kill_thread( struct thread *thread, int violent_death )
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 */
void break_thread( struct thread *thread )
{
......@@ -955,7 +983,24 @@ void break_thread( struct thread *thread )
data.exception.first = 1;
data.exception.exc_code = STATUS_BREAKPOINT;
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 );
thread->debug_break = 0;
}
......@@ -1357,9 +1402,9 @@ DECL_HANDLER(get_apc_result)
DECL_HANDLER(get_thread_context)
{
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 );
return;
......@@ -1376,7 +1421,7 @@ DECL_HANDLER(get_thread_context)
else
{
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;
}
}
......@@ -1386,12 +1431,12 @@ DECL_HANDLER(get_thread_context)
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
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) );
context->ContextFlags = get_context_cpu_flag();
memset( context, 0, sizeof(context_t) );
context->cpu = thread->process->cpu;
if (thread->context) copy_context( context, thread->context, req->flags & ~flags );
if (flags) get_thread_context( thread, context, flags );
}
......@@ -1403,8 +1448,9 @@ DECL_HANDLER(get_thread_context)
DECL_HANDLER(set_thread_context)
{
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 );
return;
......@@ -1413,14 +1459,14 @@ DECL_HANDLER(set_thread_context)
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 */
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;
if (thread->debug_break) break_thread( thread );
}
......@@ -1431,15 +1477,16 @@ DECL_HANDLER(set_thread_context)
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
else set_error( STATUS_PENDING );
}
else
else if (context->cpu == thread->process->cpu)
{
const CONTEXT *context = get_req_data();
unsigned int flags = get_context_system_regs( req->flags );
unsigned int system_flags = get_context_system_regs(context->cpu) & context->flags;
unsigned int client_flags = context->flags & ~system_flags;
if (flags) set_thread_context( thread, context, flags );
if (thread->context && !get_error())
copy_context( thread->context, context, req->flags & ~flags );
if (system_flags) set_thread_context( thread, context, system_flags );
if (thread->context && !get_error()) copy_context( thread->context, context, client_flags );
}
else set_error( STATUS_INVALID_PARAMETER );
reply->self = (thread == current);
release_object( thread );
}
......
......@@ -76,8 +76,8 @@ struct thread
int exit_code; /* thread exit code */
int unix_pid; /* Unix pid of client */
int unix_tid; /* Unix tid of client */
CONTEXT *context; /* current context if in an exception handler */
CONTEXT *suspend_context; /* current context if suspended */
context_t *context; /* current context if in an exception handler */
context_t *suspend_context; /* current context if suspended */
client_ptr_t teb; /* TEB address (in client address space) */
affinity_t affinity; /* affinity mask */
int priority; /* priority level */
......@@ -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 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 */
extern void sigchld_callback(void);
extern void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags );
extern void set_thread_context( struct thread *thread, const 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_t *context, unsigned int flags );
extern int send_thread_signal( struct thread *thread, int sig );
extern void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
unsigned int *limit, unsigned char *flags );
......
......@@ -298,33 +298,6 @@ static void dump_luid( const char *prefix, const luid_t *luid )
fprintf( stderr, "%s%d.%u", prefix, luid->high_part, luid->low_part );
}
static void dump_context( const CONTEXT *context, data_size_t size )
{
CONTEXT ctx;
memset( &ctx, 0, sizeof(ctx) );
memcpy( &ctx, context, min( size, sizeof(CONTEXT) ));
#ifdef __i386__
fprintf( stderr, "{flags=%08x,eax=%08x,ebx=%08x,ecx=%08x,edx=%08x,esi=%08x,edi=%08x,"
"ebp=%08x,eip=%08x,esp=%08x,eflags=%08x,cs=%04x,ds=%04x,es=%04x,"
"fs=%04x,gs=%04x,dr0=%08x,dr1=%08x,dr2=%08x,dr3=%08x,dr6=%08x,dr7=%08x,",
ctx.ContextFlags, ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx,
ctx.Esi, ctx.Edi, ctx.Ebp, ctx.Eip, ctx.Esp, ctx.EFlags,
ctx.SegCs, ctx.SegDs, ctx.SegEs, ctx.SegFs, ctx.SegGs,
ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr6, ctx.Dr7 );
fprintf( stderr, "float=" );
dump_uints( (const int *)&ctx.FloatSave, sizeof(ctx.FloatSave) / sizeof(int) );
if (size > FIELD_OFFSET( CONTEXT, ExtendedRegisters ))
{
fprintf( stderr, ",extended=" );
dump_uints( (const int *)&ctx.ExtendedRegisters, sizeof(ctx.ExtendedRegisters) / sizeof(int) );
}
fprintf( stderr, "}" );
#else
dump_uints( (const int *)&ctx, sizeof(ctx) / sizeof(int) );
#endif
}
static void dump_varargs_ints( const char *prefix, data_size_t size )
{
const int *data = cur_data;
......@@ -428,14 +401,190 @@ static void dump_varargs_unicode_str( const char *prefix, data_size_t size )
static void dump_varargs_context( const char *prefix, data_size_t size )
{
const context_t *context = cur_data;
context_t ctx;
unsigned int i;
if (!size)
{
fprintf( stderr, "%s{}", prefix );
return;
}
fprintf( stderr, "%s", prefix );
dump_context( cur_data, size );
remove_data( min( size, sizeof(CONTEXT) ));
size = min( size, sizeof(ctx) );
memset( &ctx, 0, sizeof(ctx) );
memcpy( &ctx, context, size );
fprintf( stderr,"%s{", prefix );
dump_cpu_type( "cpu=", &ctx.cpu );
switch (ctx.cpu)
{
case CPU_x86:
if (ctx.flags & SERVER_CTX_CONTROL)
fprintf( stderr, ",eip=%08x,esp=%08x,ebp=%08x,eflags=%08x,cs=%04x,ss=%04x",
ctx.ctl.i386_regs.eip, ctx.ctl.i386_regs.esp, ctx.ctl.i386_regs.ebp,
ctx.ctl.i386_regs.eflags, ctx.ctl.i386_regs.cs, ctx.ctl.i386_regs.ss );
if (ctx.flags & SERVER_CTX_SEGMENTS)
fprintf( stderr, ",ds=%04x,es=%04x,fs=%04x,gs=%04x",
ctx.seg.i386_regs.ds, ctx.seg.i386_regs.es,
ctx.seg.i386_regs.fs, ctx.seg.i386_regs.gs );
if (ctx.flags & SERVER_CTX_INTEGER)
fprintf( stderr, ",eax=%08x,ebx=%08x,ecx=%08x,edx=%08x,esi=%08x,edi=%08x",
ctx.integer.i386_regs.eax, ctx.integer.i386_regs.ebx, ctx.integer.i386_regs.ecx,
ctx.integer.i386_regs.edx, ctx.integer.i386_regs.esi, ctx.integer.i386_regs.edi );
if (ctx.flags & SERVER_CTX_DEBUG_REGISTERS)
fprintf( stderr, ",dr0=%08x,dr1=%08x,dr2=%08x,dr3=%08x,dr6=%08x,dr7=%08x",
ctx.debug.i386_regs.dr0, ctx.debug.i386_regs.dr1, ctx.debug.i386_regs.dr2,
ctx.debug.i386_regs.dr3, ctx.debug.i386_regs.dr6, ctx.debug.i386_regs.dr7 );
if (ctx.flags & SERVER_CTX_FLOATING_POINT)
{
fprintf( stderr, "fp.ctrl=%08x,fp.status=%08x,fp.tag=%08x,fp.err_off=%08x,fp.err_sel=%08x",
ctx.fp.i386_regs.ctrl, ctx.fp.i386_regs.status, ctx.fp.i386_regs.tag,
ctx.fp.i386_regs.err_off, ctx.fp.i386_regs.err_sel );
fprintf( stderr, ",fp.data_off=%08x,fp.data_sel=%08x,fp.cr0npx=%08x",
ctx.fp.i386_regs.data_off, ctx.fp.i386_regs.data_sel, ctx.fp.i386_regs.cr0npx );
for (i = 0; i < 8; i++)
fprintf( stderr, ",fp.reg%u=%Lg", i, *(long double *)&ctx.fp.i386_regs.regs[10*i] );
}
if (ctx.flags & SERVER_CTX_EXTENDED_REGISTERS)
{
fprintf( stderr, ",extended=" );
dump_uints( (const int *)ctx.ext.i386_regs, sizeof(ctx.ext.i386_regs) / sizeof(int) );
}
break;
case CPU_x86_64:
if (ctx.flags & SERVER_CTX_CONTROL)
{
dump_uint64( ",rip=", &ctx.ctl.x86_64_regs.rip );
dump_uint64( ",rbp=", &ctx.ctl.x86_64_regs.rbp );
dump_uint64( ",rsp=", &ctx.ctl.x86_64_regs.rsp );
fprintf( stderr, ",cs=%04x,ss=%04x,flags=%08x,mxcsr=%08x",
ctx.ctl.x86_64_regs.cs, ctx.ctl.x86_64_regs.ss,
ctx.ctl.x86_64_regs.flags, ctx.ctl.x86_64_regs.mxcsr );
}
if (ctx.flags & SERVER_CTX_INTEGER)
{
dump_uint64( ",rax=", &ctx.integer.x86_64_regs.rax );
dump_uint64( ",rbx=", &ctx.integer.x86_64_regs.rbx );
dump_uint64( ",rcx=", &ctx.integer.x86_64_regs.rcx );
dump_uint64( ",rdx=", &ctx.integer.x86_64_regs.rdx );
dump_uint64( ",rsi=", &ctx.integer.x86_64_regs.rsi );
dump_uint64( ",rdi=", &ctx.integer.x86_64_regs.rdi );
dump_uint64( ",r8=", &ctx.integer.x86_64_regs.r8 );
dump_uint64( ",r9=", &ctx.integer.x86_64_regs.r9 );
dump_uint64( ",r10=", &ctx.integer.x86_64_regs.r10 );
dump_uint64( ",r11=", &ctx.integer.x86_64_regs.r11 );
dump_uint64( ",r12=", &ctx.integer.x86_64_regs.r12 );
dump_uint64( ",r13=", &ctx.integer.x86_64_regs.r13 );
dump_uint64( ",r14=", &ctx.integer.x86_64_regs.r14 );
dump_uint64( ",r15=", &ctx.integer.x86_64_regs.r15 );
}
if (ctx.flags & SERVER_CTX_SEGMENTS)
fprintf( stderr, ",ds=%04x,es=%04x,fs=%04x,gs=%04x",
ctx.seg.x86_64_regs.ds, ctx.seg.x86_64_regs.es,
ctx.seg.x86_64_regs.fs, ctx.seg.x86_64_regs.gs );
if (ctx.flags & SERVER_CTX_DEBUG_REGISTERS)
{
dump_uint64( ",dr0=", &ctx.debug.x86_64_regs.dr0 );
dump_uint64( ",dr1=", &ctx.debug.x86_64_regs.dr1 );
dump_uint64( ",dr2=", &ctx.debug.x86_64_regs.dr2 );
dump_uint64( ",dr3=", &ctx.debug.x86_64_regs.dr3 );
dump_uint64( ",dr6=", &ctx.debug.x86_64_regs.dr6 );
dump_uint64( ",dr7=", &ctx.debug.x86_64_regs.dr7 );
}
if (ctx.flags & SERVER_CTX_FLOATING_POINT)
{
for (i = 0; i < 32; i++)
fprintf( stderr, ",fp%u=%08x%08x%08x%08x", i,
(unsigned int)(ctx.fp.x86_64_regs.fpregs[i].high >> 32),
(unsigned int)ctx.fp.x86_64_regs.fpregs[i].high,
(unsigned int)(ctx.fp.x86_64_regs.fpregs[i].low >> 32),
(unsigned int)ctx.fp.x86_64_regs.fpregs[i].low );
}
break;
case CPU_ALPHA:
if (ctx.flags & SERVER_CTX_CONTROL)
{
dump_uint64( ",fir=", &ctx.ctl.alpha_regs.fir );
fprintf( stderr, ",psr=%08x", ctx.ctl.alpha_regs.psr );
}
if (ctx.flags & SERVER_CTX_INTEGER)
{
dump_uint64( ",v0=", &ctx.integer.alpha_regs.v0 );
dump_uint64( ",t0=", &ctx.integer.alpha_regs.t0 );
dump_uint64( ",t1=", &ctx.integer.alpha_regs.t1 );
dump_uint64( ",t2=", &ctx.integer.alpha_regs.t2 );
dump_uint64( ",t3=", &ctx.integer.alpha_regs.t3 );
dump_uint64( ",t4=", &ctx.integer.alpha_regs.t4 );
dump_uint64( ",t5=", &ctx.integer.alpha_regs.t5 );
dump_uint64( ",t6=", &ctx.integer.alpha_regs.t6 );
dump_uint64( ",t7=", &ctx.integer.alpha_regs.t7 );
dump_uint64( ",t8=", &ctx.integer.alpha_regs.t8 );
dump_uint64( ",t9=", &ctx.integer.alpha_regs.t9 );
dump_uint64( ",t10=", &ctx.integer.alpha_regs.t10 );
dump_uint64( ",t11=", &ctx.integer.alpha_regs.t11 );
dump_uint64( ",t12=", &ctx.integer.alpha_regs.t12 );
dump_uint64( ",s0=", &ctx.integer.alpha_regs.s0 );
dump_uint64( ",s1=", &ctx.integer.alpha_regs.s1 );
dump_uint64( ",s2=", &ctx.integer.alpha_regs.s2 );
dump_uint64( ",s3=", &ctx.integer.alpha_regs.s3 );
dump_uint64( ",s4=", &ctx.integer.alpha_regs.s4 );
dump_uint64( ",s5=", &ctx.integer.alpha_regs.s5 );
dump_uint64( ",s6=", &ctx.integer.alpha_regs.s6 );
dump_uint64( ",a0=", &ctx.integer.alpha_regs.a0 );
dump_uint64( ",a1=", &ctx.integer.alpha_regs.a1 );
dump_uint64( ",a2=", &ctx.integer.alpha_regs.a2 );
dump_uint64( ",a3=", &ctx.integer.alpha_regs.a3 );
dump_uint64( ",a4=", &ctx.integer.alpha_regs.a4 );
dump_uint64( ",a5=", &ctx.integer.alpha_regs.a5 );
dump_uint64( ",at=", &ctx.integer.alpha_regs.at );
}
if (ctx.flags & SERVER_CTX_FLOATING_POINT)
{
for (i = 0; i < 32; i++)
{
fprintf( stderr, ",f%u", i );
dump_uint64( "=", &ctx.fp.alpha_regs.f[i] );
}
dump_uint64( ",fpcr=", &ctx.fp.alpha_regs.fpcr );
dump_uint64( ",softfpcr=", &ctx.fp.alpha_regs.softfpcr );
}
break;
case CPU_POWERPC:
if (ctx.flags & SERVER_CTX_CONTROL)
fprintf( stderr, ",iar=%08x,msr=%08x,ctr=%08x,lr=%08x,dar=%08x,dsisr=%08x,trap=%08x",
ctx.ctl.powerpc_regs.iar, ctx.ctl.powerpc_regs.msr, ctx.ctl.powerpc_regs.ctr,
ctx.ctl.powerpc_regs.lr, ctx.ctl.powerpc_regs.dar, ctx.ctl.powerpc_regs.dsisr,
ctx.ctl.powerpc_regs.trap );
if (ctx.flags & SERVER_CTX_INTEGER)
{
for (i = 0; i < 32; i++) fprintf( stderr, ",gpr%u=%08x", i, ctx.integer.powerpc_regs.gpr[i] );
fprintf( stderr, ",cr=%08x,xer=%08x",
ctx.integer.powerpc_regs.cr, ctx.integer.powerpc_regs.xer );
}
if (ctx.flags & SERVER_CTX_DEBUG_REGISTERS)
for (i = 0; i < 8; i++) fprintf( stderr, ",dr%u=%08x", i, ctx.debug.powerpc_regs.dr[i] );
if (ctx.flags & SERVER_CTX_FLOATING_POINT)
{
for (i = 0; i < 32; i++) fprintf( stderr, ",fpr%u=%g", i, ctx.fp.powerpc_regs.fpr[i] );
fprintf( stderr, ",fpscr=%g", ctx.fp.powerpc_regs.fpscr );
}
break;
case CPU_SPARC:
if (ctx.flags & SERVER_CTX_CONTROL)
fprintf( stderr, ",psr=%08x,pc=%08x,npc=%08x,y=%08x,wim=%08x,tbr=%08x",
ctx.ctl.sparc_regs.psr, ctx.ctl.sparc_regs.pc, ctx.ctl.sparc_regs.npc,
ctx.ctl.sparc_regs.y, ctx.ctl.sparc_regs.wim, ctx.ctl.sparc_regs.tbr );
if (ctx.flags & SERVER_CTX_INTEGER)
{
for (i = 0; i < 8; i++) fprintf( stderr, ",g%u=%08x", i, ctx.integer.sparc_regs.g[i] );
for (i = 0; i < 8; i++) fprintf( stderr, ",o%u=%08x", i, ctx.integer.sparc_regs.o[i] );
for (i = 0; i < 8; i++) fprintf( stderr, ",l%u=%08x", i, ctx.integer.sparc_regs.l[i] );
for (i = 0; i < 8; i++) fprintf( stderr, ",i%u=%08x", i, ctx.integer.sparc_regs.i[i] );
}
break;
}
fputc( '}', stderr );
remove_data( size );
}
static void dump_varargs_debug_event( const char *prefix, data_size_t size )
......@@ -2128,7 +2277,6 @@ static void dump_get_thread_context_reply( const struct get_thread_context_reply
static void dump_set_thread_context_request( const struct set_thread_context_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
fprintf( stderr, ", flags=%08x", req->flags );
fprintf( stderr, ", suspend=%d", req->suspend );
dump_varargs_context( ", context=", cur_size );
}
......
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