From 498742ff6cee580a82a42d5f05e8c570b4b71dc5 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 27 Jun 2006 21:27:47 +0200 Subject: [PATCH] server: Moved get/set_thread_context implementation to ptrace.c. --- server/context_alpha.c | 26 +-- server/context_i386.c | 410 ++++++++++++----------------------------------- server/context_powerpc.c | 26 +-- server/context_sparc.c | 24 +-- server/context_x86_64.c | 395 ++++++++++++--------------------------------- server/ptrace.c | 231 +++++++++++++++++++++++--- server/thread.h | 3 - 7 files changed, 430 insertions(+), 685 deletions(-) rewrite server/context_i386.c (70%) rewrite server/context_x86_64.c (67%) 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 dissimilarity index 70% index 82faf8b2953..575d5b96e57 100644 --- a/server/context_i386.c +++ b/server/context_i386.c @@ -1,310 +1,100 @@ -/* - * i386 register context support - * - * Copyright (C) 1999 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#ifdef __i386__ - -#include -#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" - -#include "file.h" -#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 ) -{ - flags &= ~CONTEXT_i386; /* get rid of CPU id */ - if (flags & CONTEXT_CONTROL) - { - to->Ebp = from->Ebp; - to->Eip = from->Eip; - to->Esp = from->Esp; - to->SegCs = from->SegCs; - to->SegSs = from->SegSs; - to->EFlags = from->EFlags; - } - if (flags & CONTEXT_INTEGER) - { - to->Eax = from->Eax; - to->Ebx = from->Ebx; - to->Ecx = from->Ecx; - to->Edx = from->Edx; - to->Esi = from->Esi; - to->Edi = from->Edi; - } - if (flags & CONTEXT_SEGMENTS) - { - to->SegDs = from->SegDs; - to->SegEs = from->SegEs; - to->SegFs = from->SegFs; - to->SegGs = from->SegGs; - } - if (flags & CONTEXT_FLOATING_POINT) - { - to->FloatSave = from->FloatSave; - } - if (flags & CONTEXT_DEBUG_REGISTERS) - { - to->Dr0 = from->Dr0; - to->Dr1 = from->Dr1; - to->Dr2 = from->Dr2; - to->Dr3 = from->Dr3; - to->Dr6 = from->Dr6; - to->Dr7 = from->Dr7; - } - to->ContextFlags |= flags; -} - -/* retrieve the current instruction pointer of a context */ -void *get_context_ip( const CONTEXT *context ) -{ - return (void *)context->Eip; -} - -/* return the context flag that contains the CPU id */ -unsigned int get_context_cpu_flag(void) -{ - return CONTEXT_i386; -} - -/* return only the context flags that correspond to system regs */ -/* (system regs are the ones we can't access on the client side) */ -unsigned int get_context_system_regs( unsigned int flags ) -{ - return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386); -} - -#endif /* __i386__ */ +/* + * i386 register context support + * + * Copyright (C) 1999 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#ifdef __i386__ + +#include +#include +#include +#include + +#include "windef.h" + +#include "file.h" +#include "thread.h" +#include "request.h" + +/* copy a context structure according to the flags */ +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +{ + flags &= ~CONTEXT_i386; /* get rid of CPU id */ + if (flags & CONTEXT_CONTROL) + { + to->Ebp = from->Ebp; + to->Eip = from->Eip; + to->Esp = from->Esp; + to->SegCs = from->SegCs; + to->SegSs = from->SegSs; + to->EFlags = from->EFlags; + } + if (flags & CONTEXT_INTEGER) + { + to->Eax = from->Eax; + to->Ebx = from->Ebx; + to->Ecx = from->Ecx; + to->Edx = from->Edx; + to->Esi = from->Esi; + to->Edi = from->Edi; + } + if (flags & CONTEXT_SEGMENTS) + { + to->SegDs = from->SegDs; + to->SegEs = from->SegEs; + to->SegFs = from->SegFs; + to->SegGs = from->SegGs; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->FloatSave = from->FloatSave; + } + if (flags & CONTEXT_DEBUG_REGISTERS) + { + to->Dr0 = from->Dr0; + to->Dr1 = from->Dr1; + to->Dr2 = from->Dr2; + to->Dr3 = from->Dr3; + to->Dr6 = from->Dr6; + to->Dr7 = from->Dr7; + } + to->ContextFlags |= flags; +} + +/* retrieve the current instruction pointer of a context */ +void *get_context_ip( const CONTEXT *context ) +{ + return (void *)context->Eip; +} + +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) +{ + return CONTEXT_i386; +} + +/* return only the context flags that correspond to system regs */ +/* (system regs are the ones we can't access on the client side) */ +unsigned int get_context_system_regs( unsigned int flags ) +{ + return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386); +} + +#endif /* __i386__ */ 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 dissimilarity index 67% index 2f742b2e497..e45cbc0e251 100644 --- a/server/context_x86_64.c +++ b/server/context_x86_64.c @@ -1,291 +1,104 @@ -/* - * x86-64 register context support - * - * Copyright (C) 1999, 2005 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#ifdef __x86_64__ - -#include -#include -#include -#include -#ifdef HAVE_SYS_PTRACE_H -# include -#endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif - -#define NONAMELESSUNION -#include "windef.h" -#include "winbase.h" - -#include "file.h" -#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 ) -{ - flags &= ~CONTEXT_AMD64; /* get rid of CPU id */ - if (flags & CONTEXT_CONTROL) - { - to->Rbp = from->Rbp; - to->Rip = from->Rip; - to->Rsp = from->Rsp; - to->SegCs = from->SegCs; - to->SegSs = from->SegSs; - to->EFlags = from->EFlags; - to->MxCsr = from->MxCsr; - } - if (flags & CONTEXT_INTEGER) - { - to->Rax = from->Rax; - to->Rcx = from->Rcx; - to->Rdx = from->Rdx; - to->Rbx = from->Rbx; - to->Rsi = from->Rsi; - to->Rdi = from->Rdi; - to->R8 = from->R8; - to->R9 = from->R9; - to->R10 = from->R10; - to->R11 = from->R11; - to->R12 = from->R12; - to->R13 = from->R13; - to->R14 = from->R14; - to->R15 = from->R15; - } - if (flags & CONTEXT_SEGMENTS) - { - to->SegDs = from->SegDs; - to->SegEs = from->SegEs; - to->SegFs = from->SegFs; - to->SegGs = from->SegGs; - } - if (flags & CONTEXT_FLOATING_POINT) - { - to->u.FltSave = from->u.FltSave; - } - /* we don't bother copying the debug registers, since they */ - /* always need to be accessed by ptrace anyway */ - to->ContextFlags |= flags & ~CONTEXT_DEBUG_REGISTERS; -} - -/* retrieve the current instruction pointer of a context */ -void *get_context_ip( const CONTEXT *context ) -{ - return (void *)context->Rip; -} - -/* return the context flag that contains the CPU id */ -unsigned int get_context_cpu_flag(void) -{ - return CONTEXT_AMD64; -} - -/* return only the context flags that correspond to system regs */ -/* (system regs are the ones we can't access on the client side) */ -unsigned int get_context_system_regs( unsigned int flags ) -{ - return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64); -} - -/* 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__ */ +/* + * x86-64 register context support + * + * Copyright (C) 1999, 2005 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#ifdef __x86_64__ + +#include +#include +#include +#include + +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" + +#include "file.h" +#include "thread.h" +#include "request.h" + +/* copy a context structure according to the flags */ +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +{ + flags &= ~CONTEXT_AMD64; /* get rid of CPU id */ + if (flags & CONTEXT_CONTROL) + { + to->Rbp = from->Rbp; + to->Rip = from->Rip; + to->Rsp = from->Rsp; + to->SegCs = from->SegCs; + to->SegSs = from->SegSs; + to->EFlags = from->EFlags; + to->MxCsr = from->MxCsr; + } + if (flags & CONTEXT_INTEGER) + { + to->Rax = from->Rax; + to->Rcx = from->Rcx; + to->Rdx = from->Rdx; + to->Rbx = from->Rbx; + to->Rsi = from->Rsi; + to->Rdi = from->Rdi; + to->R8 = from->R8; + to->R9 = from->R9; + to->R10 = from->R10; + to->R11 = from->R11; + to->R12 = from->R12; + to->R13 = from->R13; + to->R14 = from->R14; + to->R15 = from->R15; + } + if (flags & CONTEXT_SEGMENTS) + { + to->SegDs = from->SegDs; + to->SegEs = from->SegEs; + to->SegFs = from->SegFs; + to->SegGs = from->SegGs; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->u.FltSave = from->u.FltSave; + } + /* we don't bother copying the debug registers, since they */ + /* always need to be accessed by ptrace anyway */ + to->ContextFlags |= flags & ~CONTEXT_DEBUG_REGISTERS; +} + +/* retrieve the current instruction pointer of a context */ +void *get_context_ip( const CONTEXT *context ) +{ + return (void *)context->Rip; +} + +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) +{ + return CONTEXT_AMD64; +} + +/* return only the context flags that correspond to system regs */ +/* (system regs are the ones we can't access on the client side) */ +unsigned int get_context_system_regs( unsigned int flags ) +{ + return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64); +} + +#endif /* __x86_64__ */ 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 ); -- 2.11.4.GIT