server: Moved get/set_thread_context implementation to ptrace.c.
This commit is contained in:
parent
f2bfc7b12d
commit
498742ff6c
|
@ -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__ */
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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, ®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__ */
|
||||
|
|
231
server/ptrace.c
231
server/ptrace.c
|
@ -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__ */
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue