server: Moved get/set_thread_context implementation to ptrace.c.

This commit is contained in:
Alexandre Julliard 2006-06-27 21:27:47 +02:00
parent f2bfc7b12d
commit 498742ff6c
7 changed files with 226 additions and 481 deletions

View File

@ -37,6 +37,8 @@
#include "thread.h"
#include "request.h"
#if 0 /* no longer used */
#ifdef HAVE_SYS_USER_H
# include <sys/user.h>
#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__ */

View File

@ -24,17 +24,8 @@
#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
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#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 <sys/user.h>
#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 <machine/reg.h>
/* 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 )
{

View File

@ -34,6 +34,8 @@
# include <sys/ptrace.h>
#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__ */

View File

@ -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__ */

View File

@ -26,12 +26,6 @@
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_SYS_PTRACE_H
# include <sys/ptrace.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#define NONAMELESSUNION
#include "windef.h"
@ -41,167 +35,6 @@
#include "thread.h"
#include "request.h"
#ifdef __linux__
#ifdef HAVE_SYS_USER_H
# include <sys/user.h>
#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, &regs ) == -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, &regs ) == -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, &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->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__ */

View File

@ -29,6 +29,12 @@
#ifdef HAVE_SYS_PTRACE_H
# include <sys/ptrace.h>
#endif
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#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 <sys/user.h>
#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 <machine/reg.h>
/* 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__ */

View File

@ -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 );