Commit 3e2517ca authored by Alexandre Julliard's avatar Alexandre Julliard Committed by Alexandre Julliard

Added Get/SetThreadContext support through the server.

parent 681c75bf
......@@ -27,6 +27,86 @@
/* a path name for server requests (Unicode) */
typedef WCHAR path_t[MAX_PATH+1];
/* definitions of the event data depending on the event code */
struct debug_event_exception
{
int code; /* exception code */
int flags; /* exception flags */
void *record; /* exception record ptr */
void *addr; /* exception address */
int nb_params; /* exceptions parameters */
int params[15];
int first_chance; /* first chance to handle it? */
CONTEXT context; /* thread context */
};
struct debug_event_create_thread
{
int handle; /* handle to the new thread */
void *teb; /* thread teb (in debugged process address space) */
void *start; /* thread startup routine */
};
struct debug_event_create_process
{
int file; /* handle to the process exe file */
int process; /* handle to the new process */
int thread; /* handle to the new thread */
void *base; /* base of executable image */
int dbg_offset; /* offset of debug info in file */
int dbg_size; /* size of debug info */
void *teb; /* thread teb (in debugged process address space) */
void *start; /* thread startup routine */
void *name; /* image name (optional) */
int unicode; /* is it Unicode? */
};
struct debug_event_exit
{
int exit_code; /* thread or process exit code */
};
struct debug_event_load_dll
{
int handle; /* file handle for the dll */
void *base; /* base address of the dll */
int dbg_offset; /* offset of debug info in file */
int dbg_size; /* size of debug info */
void *name; /* image name (optional) */
int unicode; /* is it Unicode? */
};
struct debug_event_unload_dll
{
void *base; /* base address of the dll */
};
struct debug_event_output_string
{
void *string; /* string to display (in debugged process address space) */
int unicode; /* is it Unicode? */
int length; /* string length */
};
struct debug_event_rip_info
{
int error; /* ??? */
int type; /* ??? */
};
union debug_event_data
{
struct debug_event_exception exception;
struct debug_event_create_thread create_thread;
struct debug_event_create_process create_process;
struct debug_event_exit exit;
struct debug_event_load_dll load_dll;
struct debug_event_unload_dll unload_dll;
struct debug_event_output_string output_string;
struct debug_event_rip_info rip_info;
};
/* debug event data */
typedef struct
{
int code; /* event code */
union debug_event_data info; /* event information */
} debug_event_t;
/* Create a new process from the context of the parent */
struct new_process_request
{
......@@ -707,92 +787,18 @@ struct next_process_request
/* Wait for a debug event */
struct wait_debug_event_request
{
IN int timeout; /* timeout in ms */
OUT int code; /* event code */
OUT void* pid; /* process id */
OUT void* tid; /* thread id */
/* OUT union debug_event_data data; */
IN int timeout; /* timeout in ms */
OUT void* pid; /* process id */
OUT void* tid; /* thread id */
OUT debug_event_t event; /* debug event data */
};
/* Send a debug event */
struct send_debug_event_request
{
IN int code; /* event code */
OUT int status; /* event continuation status */
/* IN union debug_event_data data; */
};
/* definitions of the event data depending on the event code */
struct debug_event_exception
{
int code; /* exception code */
int flags; /* exception flags */
void *record; /* exception record ptr */
void *addr; /* exception address */
int nb_params; /* exceptions parameters */
int params[15];
int first_chance; /* first chance to handle it? */
CONTEXT context; /* thread context */
};
struct debug_event_create_thread
{
int handle; /* handle to the new thread */
void *teb; /* thread teb (in debugged process address space) */
void *start; /* thread startup routine */
};
struct debug_event_create_process
{
int file; /* handle to the process exe file */
int process; /* handle to the new process */
int thread; /* handle to the new thread */
void *base; /* base of executable image */
int dbg_offset; /* offset of debug info in file */
int dbg_size; /* size of debug info */
void *teb; /* thread teb (in debugged process address space) */
void *start; /* thread startup routine */
void *name; /* image name (optional) */
int unicode; /* is it Unicode? */
};
struct debug_event_exit
{
int exit_code; /* thread or process exit code */
};
struct debug_event_load_dll
{
int handle; /* file handle for the dll */
void *base; /* base address of the dll */
int dbg_offset; /* offset of debug info in file */
int dbg_size; /* size of debug info */
void *name; /* image name (optional) */
int unicode; /* is it Unicode? */
};
struct debug_event_unload_dll
{
void *base; /* base address of the dll */
};
struct debug_event_output_string
{
void *string; /* string to display (in debugged process address space) */
int unicode; /* is it Unicode? */
int length; /* string length */
};
struct debug_event_rip_info
{
int error; /* ??? */
int type; /* ??? */
};
union debug_event_data
{
struct debug_event_exception exception;
struct debug_event_create_thread create_thread;
struct debug_event_create_process create_process;
struct debug_event_exit exit;
struct debug_event_load_dll load_dll;
struct debug_event_unload_dll unload_dll;
struct debug_event_output_string output_string;
struct debug_event_rip_info rip_info;
OUT int status; /* event continuation status */
IN debug_event_t event; /* debug event data */
};
......@@ -1005,6 +1011,24 @@ struct cancel_timer_request
};
/* Retrieve the current context of a thread */
struct get_thread_context_request
{
IN int handle; /* thread handle */
IN unsigned int flags; /* context flags */
OUT CONTEXT context; /* thread context */
};
/* Set the current context of a thread */
struct set_thread_context_request
{
IN int handle; /* thread handle */
IN unsigned int flags; /* context flags */
IN CONTEXT context; /* thread context */
};
/* Everything below this line is generated automatically by tools/make_requests */
/* ### make_requests begin ### */
......@@ -1100,6 +1124,8 @@ enum request
REQ_OPEN_TIMER,
REQ_SET_TIMER,
REQ_CANCEL_TIMER,
REQ_GET_THREAD_CONTEXT,
REQ_SET_THREAD_CONTEXT,
REQ_NB_REQUESTS
};
......
......@@ -516,14 +516,17 @@ BOOL WINAPI TlsSetValue(
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI SetThreadContext(
HANDLE handle, /* [in] Handle to thread with context */
const CONTEXT *context) /* [out] Address of context structure */
BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
const CONTEXT *context ) /* [in] Address of context structure */
{
FIXME("not implemented\n" );
return TRUE;
struct set_thread_context_request *req = get_req_buffer();
req->handle = handle;
req->flags = context->ContextFlags;
memcpy( &req->context, context, sizeof(*context) );
return !server_call( REQ_SET_THREAD_CONTEXT );
}
/***********************************************************************
* GetThreadContext [KERNEL32.294] Retrieves context of thread.
*
......@@ -531,25 +534,15 @@ BOOL WINAPI SetThreadContext(
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI GetThreadContext(
HANDLE handle, /* [in] Handle to thread with context */
CONTEXT *context) /* [out] Address of context structure */
BOOL WINAPI GetThreadContext( HANDLE handle, /* [in] Handle to thread with context */
CONTEXT *context ) /* [out] Address of context structure */
{
#ifdef __i386__
WORD cs, ds;
FIXME("returning dummy info\n" );
/* make up some plausible values for segment registers */
GET_CS(cs);
GET_DS(ds);
context->SegCs = cs;
context->SegDs = ds;
context->SegEs = ds;
context->SegGs = ds;
context->SegSs = ds;
context->SegFs = ds;
#endif
struct get_thread_context_request *req = get_req_buffer();
req->handle = handle;
req->flags = context->ContextFlags;
memcpy( &req->context, context, sizeof(*context) );
if (server_call( REQ_GET_THREAD_CONTEXT )) return FALSE;
memcpy( context, &req->context, sizeof(*context) );
return TRUE;
}
......
......@@ -8,6 +8,7 @@ MODULE = server
C_SRCS = \
change.c \
console.c \
context_i386.c \
debugger.c \
device.c \
event.c \
......
/*
* i386 register context support
*
* Copyright (C) 1999 Alexandre Julliard
*/
#include "config.h"
#ifdef __i386__
#include <assert.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include "winbase.h"
#include "winerror.h"
#include "thread.h"
#include "request.h"
#ifndef PTRACE_PEEKUSER
#define PTRACE_PEEKUSER PT_READ_U
#endif
#ifndef PTRACE_POKEUSER
#define PTRACE_POKEUSER PT_WRITE_U
#endif
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS PT_GETREGS
#endif
#ifndef PTRACE_GETFPREGS
#define PTRACE_GETFPREGS PT_GETFPREGS
#endif
#ifdef linux
/* debug register offset in struct user */
#define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
/* retrieve a debug register */
static inline int get_debug_reg( int pid, int num, DWORD *data )
{
int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
if ((res == -1) && errno)
{
file_set_error();
return -1;
}
*data = res;
return 0;
}
/* retrieve a thread context */
static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
{
int pid = thread->unix_pid;
if (flags & CONTEXT_FULL)
{
struct user_regs_struct regs;
if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
if (flags & CONTEXT_INTEGER)
{
context->Eax = regs.eax;
context->Ebx = regs.ebx;
context->Ecx = regs.ecx;
context->Edx = regs.edx;
context->Esi = regs.esi;
context->Edi = regs.edi;
}
if (flags & CONTEXT_CONTROL)
{
context->Ebp = regs.ebp;
context->Esp = regs.esp;
context->Eip = regs.eip;
context->SegCs = regs.xcs & 0xffff;
context->SegSs = regs.xss & 0xffff;
context->EFlags = regs.eflags;
}
if (flags & CONTEXT_SEGMENTS)
{
context->SegDs = regs.xds & 0xffff;
context->SegEs = regs.xes & 0xffff;
context->SegFs = regs.xfs & 0xffff;
context->SegGs = regs.xgs & 0xffff;
}
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
}
if (flags & CONTEXT_FLOATING_POINT)
{
/* we can use context->FloatSave directly as it is using the */
/* correct structure (the same as fsave/frstor) */
if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
context->FloatSave.Cr0NpxState = 0; /* FIXME */
}
return;
error:
file_set_error();
}
/* set a thread context */
static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
{
int pid = thread->unix_pid;
if (flags & CONTEXT_FULL)
{
struct user_regs_struct regs;
if ((flags & CONTEXT_FULL) != CONTEXT_FULL) /* need to preserve some registers */
{
if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
}
if (flags & CONTEXT_INTEGER)
{
regs.eax = context->Eax;
regs.ebx = context->Ebx;
regs.ecx = context->Ecx;
regs.edx = context->Edx;
regs.esi = context->Esi;
regs.edi = context->Edi;
}
if (flags & CONTEXT_CONTROL)
{
regs.ebp = context->Ebp;
regs.esp = context->Esp;
regs.eip = context->Eip;
regs.xcs = context->SegCs;
regs.xss = context->SegSs;
regs.eflags = context->EFlags;
}
if (flags & CONTEXT_SEGMENTS)
{
regs.xds = context->SegDs;
regs.xes = context->SegEs;
regs.xfs = context->SegFs;
regs.xgs = context->SegGs;
}
if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
}
if (flags & CONTEXT_DEBUG_REGISTERS)
{
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
}
if (flags & CONTEXT_FLOATING_POINT)
{
/* we can use context->FloatSave directly as it is using the */
/* correct structure (the same as fsave/frstor) */
if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
context->FloatSave.Cr0NpxState = 0; /* FIXME */
}
return;
error:
file_set_error();
}
#else /* linux */
#error You must implement get/set_thread_context for your platform
#endif /* linux */
/* copy a context structure according to the flags */
static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
{
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_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;
}
if (flags & CONTEXT_FLOATING_POINT)
{
to->FloatSave = from->FloatSave;
}
}
/* retrieve the current context of a thread */
DECL_HANDLER(get_thread_context)
{
struct thread *thread;
CONTEXT *context;
if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
{
if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
{
copy_context( &req->context, context, req->flags );
}
else
{
suspend_thread( thread, 0 );
if (thread->attached) get_thread_context( thread, req->flags, &req->context );
else set_error( ERROR_ACCESS_DENIED );
resume_thread( thread );
}
release_object( thread );
}
}
/* set the current context of a thread */
DECL_HANDLER(set_thread_context)
{
struct thread *thread;
CONTEXT *context;
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
{
if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
{
copy_context( context, &req->context, req->flags );
}
else
{
suspend_thread( thread, 0 );
if (thread->attached) set_thread_context( thread, req->flags, &req->context );
else set_error( ERROR_ACCESS_DENIED );
resume_thread( thread );
}
release_object( thread );
}
}
#endif /* __i386__ */
......@@ -155,6 +155,7 @@ extern int free_console( struct process *process );
extern int debugger_attach( struct process *process, struct thread *debugger );
extern void debug_exit_thread( struct thread *thread, int exit_code );
extern CONTEXT *get_debug_context( struct thread *thread );
/* mapping functions */
......
......@@ -157,6 +157,8 @@ DECL_HANDLER(create_timer);
DECL_HANDLER(open_timer);
DECL_HANDLER(set_timer);
DECL_HANDLER(cancel_timer);
DECL_HANDLER(get_thread_context);
DECL_HANDLER(set_thread_context);
#ifdef WANT_REQUEST_HANDLERS
......@@ -254,6 +256,8 @@ static const struct handler {
{ (void(*)())req_open_timer, sizeof(struct open_timer_request) },
{ (void(*)())req_set_timer, sizeof(struct set_timer_request) },
{ (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) },
{ (void(*)())req_get_thread_context, sizeof(struct get_thread_context_request) },
{ (void(*)())req_set_thread_context, sizeof(struct set_thread_context_request) },
};
#endif /* WANT_REQUEST_HANDLERS */
......
......@@ -8,15 +8,17 @@
%formats =
(
"int" => "%d",
"long" => "%ld",
"char" => "%c",
"unsigned int" => "%08x",
"void*" => "%p",
"time_t" => "%ld",
"path_t" => "&dump_unicode_string",
"char[1]" => "\\\"%s\\\"",
"WCHAR[1]" => "&dump_unicode_string"
"int" => "%d",
"long" => "%ld",
"char" => "%c",
"unsigned int" => "%08x",
"void*" => "%p",
"time_t" => "%ld",
"path_t" => "&dump_path_t",
"debug_event_t" => "&dump_debug_event_t",
"CONTEXT" => "&dump_context",
"char[1]" => "\\\"%s\\\"",
"WCHAR[1]" => "&dump_unicode_string"
);
my @requests = ();
......@@ -123,7 +125,7 @@ sub DO_DUMP_FUNC
{
my $name = shift;
my $req = shift;
push @trace_lines, "static void dump_${name}_$req( struct ${name}_request *req )\n{\n";
push @trace_lines, "static void dump_${name}_$req( const struct ${name}_request *req )\n{\n";
while ($#_ >= 0)
{
my $type = shift;
......@@ -134,7 +136,8 @@ sub DO_DUMP_FUNC
{
my $func = $1;
push @trace_lines, " fprintf( stderr, \" $var=\" );\n";
push @trace_lines, " $func( req->$var );\n";
if ($type =~ /[1]/) { push @trace_lines, " $func( req->$var );\n"; }
else { push @trace_lines, " $func( &req->$var );\n"; }
push @trace_lines, " fprintf( stderr, \",\" );\n" if ($#_ > 0);
}
else
......
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