diff --git a/server/context_alpha.c b/server/context_alpha.c index f4d86935846..dd24c6db295 100644 --- a/server/context_alpha.c +++ b/server/context_alpha.c @@ -37,6 +37,8 @@ #include "thread.h" #include "request.h" +#if 0 /* no longer used */ + #ifdef HAVE_SYS_USER_H # include #endif @@ -238,6 +240,8 @@ static void set_thread_context( struct thread *thread, unsigned int flags, const file_set_error(); } +#endif /* 0 */ + /* copy a context structure according to the flags */ void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { @@ -338,27 +342,7 @@ unsigned int get_context_cpu_flag(void) /* (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_ALPHA; -} - -/* retrieve the thread context */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - get_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } -} - -/* set the thread context */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - set_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } + return 0; /* FIXME: implement client-side handling */ } #endif /* __ALPHA__ */ diff --git a/server/context_i386.c b/server/context_i386.c index 82faf8b2953..575d5b96e57 100644 --- a/server/context_i386.c +++ b/server/context_i386.c @@ -24,17 +24,8 @@ #include #include -#ifdef HAVE_SYS_REG_H -#include -#endif #include #include -#ifdef HAVE_SYS_PTRACE_H -# include -#endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif #include "windef.h" @@ -42,207 +33,6 @@ #include "thread.h" #include "request.h" -#ifndef PTRACE_PEEKUSER -# ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */ -# define PTRACE_PEEKUSER PTRACE_PEEKUSR -# else -# define PTRACE_PEEKUSER PT_READ_U -# endif -#endif - -#ifndef PTRACE_POKEUSER -# ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */ -# define PTRACE_POKEUSER PTRACE_POKEUSR -# else -# define PTRACE_POKEUSER PT_WRITE_U -# endif -#endif - -#ifdef PT_GETDBREGS -#define PTRACE_GETDBREGS PT_GETDBREGS -#endif - -#ifdef PT_SETDBREGS -#define PTRACE_SETDBREGS PT_SETDBREGS -#endif - -#ifdef linux -#ifdef HAVE_SYS_USER_H -# include -#endif - -/* 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; - errno = 0; - res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 ); - if ((res == -1) && errno) - { - file_set_error(); - return -1; - } - *data = res; - return 0; -} - -/* retrieve the thread x86 registers */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ - int pid = get_ptrace_pid(thread); - - /* all other regs are handled on the client side */ - assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); - - if (!suspend_for_ptrace( thread )) return; - - 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; - context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; - resume_after_ptrace( thread ); - return; - error: - file_set_error(); - resume_after_ptrace( thread ); -} - -/* set the thread x86 registers */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ - int pid = get_ptrace_pid( thread ); - - /* all other regs are handled on the client side */ - assert( (flags | CONTEXT_i386) == CONTEXT_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; - resume_after_ptrace( thread ); - return; - error: - file_set_error(); - resume_after_ptrace( thread ); -} - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) -#include - -/* retrieve the thread x86 registers */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ -#ifdef PTRACE_GETDBREGS - int pid = get_ptrace_pid(thread); - struct dbreg dbregs; - - /* all other regs are handled on the client side */ - assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); - - if (!suspend_for_ptrace( thread )) return; - - if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); - else - { -#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); -#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; -#endif - context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; - } - resume_after_ptrace( thread ); -#endif -} - -/* set the thread x86 registers */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ -#ifdef PTRACE_SETDBREGS - int pid = get_ptrace_pid(thread); - struct dbreg dbregs; - - /* all other regs are handled on the client side */ - assert( (flags | CONTEXT_i386) == CONTEXT_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), 4) = 0; - DBREG_DRX((&dbregs), 5) = 0; - DBREG_DRX((&dbregs), 6) = context->Dr6; - DBREG_DRX((&dbregs), 7) = context->Dr7; -#else - dbregs.dr0 = context->Dr0; - dbregs.dr1 = context->Dr1; - dbregs.dr2 = context->Dr2; - dbregs.dr3 = context->Dr3; - dbregs.dr4 = 0; - dbregs.dr5 = 0; - dbregs.dr6 = context->Dr6; - dbregs.dr7 = context->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; - } - resume_after_ptrace( thread ); -#endif -} - -#else /* linux || __FreeBSD__ */ - -/* retrieve the thread x86 registers */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ -} - -/* set the thread x86 debug registers */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ -} - -#endif /* linux || __FreeBSD__ */ - - /* copy a context structure according to the flags */ void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { diff --git a/server/context_powerpc.c b/server/context_powerpc.c index b984a587abf..e7c44555f99 100644 --- a/server/context_powerpc.c +++ b/server/context_powerpc.c @@ -34,6 +34,8 @@ # include #endif +#if 0 /* no longer used */ + #ifndef PTRACE_PEEKUSER # ifdef PT_READ_D # define PTRACE_PEEKUSER PT_READ_D @@ -197,6 +199,8 @@ static void set_thread_context_ptrace( struct thread *thread, unsigned int flags #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; @@ -276,27 +280,7 @@ unsigned int get_context_cpu_flag(void) /* (system regs are the ones we can't access on the client side) */ unsigned int get_context_system_regs( unsigned int flags ) { - return flags; -} - -/* retrieve the thread context */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - get_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } -} - -/* set the thread context */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - set_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } + return 0; /* FIXME: implement client-side handling */ } #endif /* __powerpc__ */ diff --git a/server/context_sparc.c b/server/context_sparc.c index ce6b9cc5dcd..5d70271d0e2 100644 --- a/server/context_sparc.c +++ b/server/context_sparc.c @@ -40,6 +40,7 @@ #include "thread.h" #include "request.h" +#if 0 /* no longer used */ #if defined(__sun) || defined(__sun__) @@ -104,6 +105,7 @@ static void set_thread_context_ptrace( struct thread *thread, unsigned int flags #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 ) @@ -176,27 +178,7 @@ unsigned int get_context_cpu_flag(void) /* (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_SPARC; -} - -/* retrieve the thread context */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - get_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } -} - -/* set the thread context */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - set_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } + return 0; /* FIXME: implement client-side handling */ } #endif /* __sparc__ */ diff --git a/server/context_x86_64.c b/server/context_x86_64.c index 2f742b2e497..e45cbc0e251 100644 --- a/server/context_x86_64.c +++ b/server/context_x86_64.c @@ -26,12 +26,6 @@ #include #include #include -#ifdef HAVE_SYS_PTRACE_H -# include -#endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif #define NONAMELESSUNION #include "windef.h" @@ -41,167 +35,6 @@ #include "thread.h" #include "request.h" -#ifdef __linux__ - -#ifdef HAVE_SYS_USER_H -# include -#endif - -/* debug register offset in struct user */ -#define DR_OFFSET(dr) ((unsigned long)((((struct user *)0)->u_debugreg) + (dr))) - -/* retrieve a debug register */ -static inline int get_debug_reg( int pid, int num, DWORD64 *data ) -{ - int res; - errno = 0; - 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_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context ) -{ - int pid = get_ptrace_pid(thread); - if (flags & CONTEXT_FULL) - { - struct user_regs_struct regs; - if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error; - if (flags & CONTEXT_INTEGER) - { - context->Rax = regs.rax; - context->Rbx = regs.rbx; - context->Rcx = regs.rcx; - context->Rdx = regs.rdx; - context->Rsi = regs.rsi; - context->Rdi = regs.rdi; - context->R8 = regs.r8; - context->R9 = regs.r9; - context->R10 = regs.r10; - context->R11 = regs.r11; - context->R12 = regs.r12; - context->R13 = regs.r13; - context->R14 = regs.r14; - context->R15 = regs.r15; - } - if (flags & CONTEXT_CONTROL) - { - context->Rbp = regs.rbp; - context->Rsp = regs.rsp; - context->Rip = regs.rip; - context->SegCs = regs.cs; - context->SegSs = regs.ss; - context->EFlags = regs.eflags; - } - if (flags & CONTEXT_SEGMENTS) - { - context->SegDs = regs.ds; - context->SegEs = regs.es; - context->SegFs = regs.fs; - context->SegGs = regs.gs; - } - context->ContextFlags |= flags & CONTEXT_FULL; - } - 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; - context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; - } - 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->u.FltSave ) == -1) goto error; - context->ContextFlags |= CONTEXT_FLOATING_POINT; - } - return; - error: - file_set_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) - { - struct user_regs_struct regs; - - /* need to preserve some registers (at a minimum orig_eax must always be preserved) */ - if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error; - - if (flags & CONTEXT_INTEGER) - { - regs.rax = context->Rax; - regs.rbx = context->Rbx; - regs.rcx = context->Rcx; - regs.rdx = context->Rdx; - regs.rsi = context->Rsi; - regs.rdi = context->Rdi; - regs.r8 = context->R8; - regs.r9 = context->R9; - regs.r10 = context->R10; - regs.r11 = context->R11; - regs.r12 = context->R12; - regs.r13 = context->R13; - regs.r14 = context->R14; - regs.r15 = context->R15; - } - if (flags & CONTEXT_CONTROL) - { - regs.rbp = context->Rbp; - regs.rip = context->Rip; - regs.rsp = context->Rsp; - regs.cs = context->SegCs; - regs.ss = context->SegSs; - regs.eflags = context->EFlags; - } - if (flags & CONTEXT_SEGMENTS) - { - regs.ds = context->SegDs; - regs.es = context->SegEs; - regs.fs = context->SegFs; - regs.gs = context->SegGs; - } - if (ptrace( PTRACE_SETREGS, pid, 0, ®s ) == -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->u.FltSave ) == -1) goto error; - } - return; - error: - file_set_error(); -} - -#else /* linux */ -#error You must implement get/set_thread_context_ptrace for your platform -#endif /* linux */ - - /* copy a context structure according to the flags */ void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { @@ -268,24 +101,4 @@ unsigned int get_context_system_regs( unsigned int flags ) return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64); } -/* retrieve the thread context */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - get_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } -} - -/* set the thread context */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) -{ - if (suspend_for_ptrace( thread )) - { - set_thread_context_ptrace( thread, flags, context ); - resume_after_ptrace( thread ); - } -} - #endif /* __x86_64__ */ diff --git a/server/ptrace.c b/server/ptrace.c index 805913d817d..7aea8d5dfdf 100644 --- a/server/ptrace.c +++ b/server/ptrace.c @@ -29,6 +29,12 @@ #ifdef HAVE_SYS_PTRACE_H # include #endif +#ifdef HAVE_SYS_REG_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif #ifdef HAVE_SYS_WAIT_H # include #endif @@ -60,6 +66,19 @@ #ifndef PTRACE_POKEDATA #define PTRACE_POKEDATA PT_WRITE_D #endif +#ifndef PTRACE_PEEKUSER +#define PTRACE_PEEKUSER PT_READ_U +#endif +#ifndef PTRACE_POKEUSER +#define PTRACE_POKEUSER PT_WRITE_U +#endif + +#ifdef PT_GETDBREGS +#define PTRACE_GETDBREGS PT_GETDBREGS +#endif +#ifdef PT_SETDBREGS +#define PTRACE_SETDBREGS PT_SETDBREGS +#endif #ifndef HAVE_SYS_PTRACE_H #define PT_CONTINUE 0 @@ -133,6 +152,13 @@ void sigchld_callback(void) } } +/* return the Unix pid to use in ptrace calls for a given thread */ +static int get_ptrace_pid( struct thread *thread ) +{ + if (thread->unix_tid != -1) return thread->unix_tid; + return thread->unix_pid; +} + /* wait for a ptraced child to get a certain signal */ static int wait4_thread( struct thread *thread, int signal ) { @@ -164,13 +190,6 @@ static int wait4_thread( struct thread *thread, int signal ) return (thread->unix_pid != -1); } -/* return the Unix pid to use in ptrace calls for a given thread */ -int get_ptrace_pid( struct thread *thread ) -{ - if (thread->unix_tid != -1) return thread->unix_tid; - return thread->unix_pid; -} - /* send a signal to a specific thread */ static inline int tkill( int tgid, int pid, int sig ) { @@ -225,9 +244,19 @@ int send_thread_signal( struct thread *thread, int sig ) return (ret != -1); } +/* resume a thread after we have used ptrace on it */ +static void resume_after_ptrace( struct thread *thread ) +{ + if (thread->unix_pid == -1) return; + if (ptrace( PTRACE_DETACH, get_ptrace_pid(thread), (caddr_t)1, 0 ) == -1) + { + if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1; /* thread got killed */ + } +} + /* suspend a thread to allow using ptrace on it */ /* you must do a resume_after_ptrace when finished with the thread */ -int suspend_for_ptrace( struct thread *thread ) +static int suspend_for_ptrace( struct thread *thread ) { /* can't stop a thread while initialisation is in progress */ if (thread->unix_pid == -1 || !is_process_init_done(thread->process)) goto error; @@ -245,16 +274,6 @@ int suspend_for_ptrace( struct thread *thread ) return 0; } -/* resume a thread after we have used ptrace on it */ -void resume_after_ptrace( struct thread *thread ) -{ - if (thread->unix_pid == -1) return; - if (ptrace( PTRACE_DETACH, get_ptrace_pid(thread), (caddr_t)1, 0 ) == -1) - { - if (errno == ESRCH) thread->unix_pid = thread->unix_tid = -1; /* thread got killed */ - } -} - /* read an int from a thread address space */ static int read_thread_int( struct thread *thread, const int *addr, int *data ) { @@ -440,3 +459,179 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base, resume_after_ptrace( thread ); } } + + +#if defined(linux) && (defined(__i386__) || defined(__x86_64__)) + +#ifdef HAVE_SYS_USER_H +# include +#endif + +/* 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; + errno = 0; + res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 ); + if ((res == -1) && errno) + { + file_set_error(); + return -1; + } + *data = res; + return 0; +} + +/* retrieve the thread x86 registers */ +void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) +{ + int pid = get_ptrace_pid(thread); + + /* all other regs are handled on the client side */ + assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); + + if (!suspend_for_ptrace( thread )) return; + + 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; + context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + resume_after_ptrace( thread ); + return; + error: + file_set_error(); + resume_after_ptrace( thread ); +} + +/* set the thread x86 registers */ +void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) +{ + int pid = get_ptrace_pid( thread ); + + /* all other regs are handled on the client side */ + assert( (flags | CONTEXT_i386) == CONTEXT_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; + resume_after_ptrace( thread ); + return; + error: + file_set_error(); + resume_after_ptrace( thread ); +} + +#elif defined(__i386__) && defined(PTRACE_GETDBREGS) && defined(PTRACE_SETDBREGS) && \ + (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__)) + +#include + +/* retrieve the thread x86 registers */ +void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) +{ + int pid = get_ptrace_pid(thread); + struct dbreg dbregs; + + /* all other regs are handled on the client side */ + assert( (flags | CONTEXT_i386) == CONTEXT_DEBUG_REGISTERS ); + + if (!suspend_for_ptrace( thread )) return; + + if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); + else + { +#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); +#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; +#endif + context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + } + resume_after_ptrace( thread ); +} + +/* set the thread x86 registers */ +void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) +{ + int pid = get_ptrace_pid(thread); + struct dbreg dbregs; + + /* all other regs are handled on the client side */ + assert( (flags | CONTEXT_i386) == CONTEXT_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), 4) = 0; + DBREG_DRX((&dbregs), 5) = 0; + DBREG_DRX((&dbregs), 6) = context->Dr6; + DBREG_DRX((&dbregs), 7) = context->Dr7; +#else + dbregs.dr0 = context->Dr0; + dbregs.dr1 = context->Dr1; + dbregs.dr2 = context->Dr2; + dbregs.dr3 = context->Dr3; + dbregs.dr4 = 0; + dbregs.dr5 = 0; + dbregs.dr6 = context->Dr6; + dbregs.dr7 = context->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; + } + resume_after_ptrace( thread ); +} + +#else /* linux || __FreeBSD__ */ + +/* retrieve the thread x86 registers */ +void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) +{ +} + +/* set the thread x86 debug registers */ +void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) +{ +} + +#endif /* linux || __FreeBSD__ */ diff --git a/server/thread.h b/server/thread.h index 0a40565a62c..fdc69d47c28 100644 --- a/server/thread.h +++ b/server/thread.h @@ -128,9 +128,6 @@ extern unsigned int get_context_system_regs( unsigned int flags ); /* ptrace functions */ extern void sigchld_callback(void); -extern int get_ptrace_pid( struct thread *thread ); -extern int suspend_for_ptrace( struct thread *thread ); -extern void resume_after_ptrace( struct thread *thread ); 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 int send_thread_signal( struct thread *thread, int sig );