From 86d46881719d07fff9f3379709f331342a55978c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 23 Jun 2006 13:16:14 +0200 Subject: [PATCH] server: Moved some common bits of get/set_thread_context to thread.c. --- server/context_alpha.c | 33 ++++----- server/context_i386.c | 152 ++++++++++++++++++++++----------------- server/context_powerpc.c | 27 ++++--- server/context_sparc.c | 33 ++++----- server/context_x86_64.c | 37 +++++----- server/thread.c | 19 +++-- server/thread.h | 7 +- 7 files changed, 173 insertions(+), 135 deletions(-) diff --git a/server/context_alpha.c b/server/context_alpha.c index 05506f810de..f4d86935846 100644 --- a/server/context_alpha.c +++ b/server/context_alpha.c @@ -239,8 +239,9 @@ static void set_thread_context( struct thread *thread, unsigned int flags, const } /* copy a context structure according to the flags */ -static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { + flags &= ~CONTEXT_ALPHA; /* get rid of CPU id */ if (flags & CONTEXT_CONTROL) { to->IntRa = from->IntRa; @@ -327,17 +328,23 @@ void *get_context_ip( const CONTEXT *context ) return (void *)context->Fir; } +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) +{ + return CONTEXT_ALPHA; +} + +/* 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_ALPHA; +} + /* retrieve the thread context */ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) { - context->ContextFlags |= CONTEXT_ALPHA; - flags &= ~CONTEXT_ALPHA; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( context, thread->context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { get_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); @@ -347,13 +354,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f /* set the thread context */ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - flags &= ~CONTEXT_ALPHA; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( thread->context, context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { set_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); diff --git a/server/context_i386.c b/server/context_i386.c index 35c30ae8d49..82faf8b2953 100644 --- a/server/context_i386.c +++ b/server/context_i386.c @@ -89,81 +89,111 @@ static inline int get_debug_reg( int pid, int num, DWORD *data ) return 0; } -/* retrieve the thread x86 debug registers */ -static int get_thread_debug_regs( struct thread *thread, CONTEXT *context ) +/* 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; - return 1; + context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + resume_after_ptrace( thread ); + return; error: file_set_error(); - return 0; + resume_after_ptrace( thread ); } -/* set the thread x86 debug registers */ -static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context ) +/* set the thread x86 registers */ +void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - int pid = get_ptrace_pid(thread); + 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; - return 1; + if (thread->context) thread->context->Dr7 = context->Dr7; + resume_after_ptrace( thread ); + return; error: file_set_error(); - return 0; + resume_after_ptrace( thread ); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) #include -/* retrieve the thread x86 debug registers */ -static int get_thread_debug_regs( struct thread *thread, CONTEXT *context ) +/* 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; - if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) - goto error; + + /* 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); + /* 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; + 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 - return 1; - error: - file_set_error(); + context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + } + resume_after_ptrace( thread ); #endif - return 0; } -/* set the thread x86 debug registers */ -static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context ) +/* 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; @@ -184,32 +214,39 @@ static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context dbregs.dr6 = context->Dr6; dbregs.dr7 = context->Dr7; #endif - if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) != -1) return 1; - file_set_error(); + 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 - return 0; } #else /* linux || __FreeBSD__ */ -/* retrieve the thread x86 debug registers */ -static int get_thread_debug_regs( struct thread *thread, CONTEXT *context ) +/* retrieve the thread x86 registers */ +void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) { - return 0; } /* set the thread x86 debug registers */ -static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context ) +void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - return 0; } #endif /* linux || __FreeBSD__ */ /* copy a context structure according to the flags */ -static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int 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; @@ -257,34 +294,17 @@ void *get_context_ip( const CONTEXT *context ) return (void *)context->Eip; } -/* retrieve the thread context */ -void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) { - context->ContextFlags |= CONTEXT_i386; - flags &= ~CONTEXT_i386; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - copy_context( context, thread->context, flags & ~CONTEXT_DEBUG_REGISTERS ); - - if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread )) - { - if (get_thread_debug_regs( thread, context )) context->ContextFlags |= CONTEXT_DEBUG_REGISTERS; - resume_after_ptrace( thread ); - } + return CONTEXT_i386; } -/* set the thread context */ -void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) +/* 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 ) { - flags &= ~CONTEXT_i386; /* get rid of CPU id */ - - if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread )) - { - if (!set_thread_debug_regs( thread, context )) flags &= ~CONTEXT_DEBUG_REGISTERS; - resume_after_ptrace( thread ); - } - - if (thread->context) copy_context( thread->context, context, flags ); + return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386); } #endif /* __i386__ */ diff --git a/server/context_powerpc.c b/server/context_powerpc.c index 1ee63a7ca7d..b984a587abf 100644 --- a/server/context_powerpc.c +++ b/server/context_powerpc.c @@ -201,7 +201,7 @@ static void set_thread_context_ptrace( struct thread *thread, unsigned int flags #define FREG(x) to->Fpr##x = from->Fpr##x; #define CREG(x) to->x = from->x; /* copy a context structure according to the flags */ -static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { if (flags & CONTEXT_CONTROL) { @@ -266,14 +266,23 @@ void *get_context_ip( const CONTEXT *context ) return (void *)context->Iar; } +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) +{ + return 0; +} + +/* 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; +} + /* retrieve the thread context */ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) { - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( context, thread->context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { get_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); @@ -283,11 +292,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f /* set the thread context */ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( thread->context, context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { set_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); diff --git a/server/context_sparc.c b/server/context_sparc.c index ccc841999f2..ce6b9cc5dcd 100644 --- a/server/context_sparc.c +++ b/server/context_sparc.c @@ -106,8 +106,9 @@ static void set_thread_context_ptrace( struct thread *thread, unsigned int flags /* copy a context structure according to the flags */ -static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) { + flags &= ~CONTEXT_SPARC; /* get rid of CPU id */ if (flags & CONTEXT_CONTROL) { to->psr = from->psr; @@ -165,17 +166,23 @@ void *get_context_ip( const CONTEXT *context ) return (void *)context->pc; } +/* return the context flag that contains the CPU id */ +unsigned int get_context_cpu_flag(void) +{ + return CONTEXT_SPARC; +} + +/* 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_SPARC; +} + /* retrieve the thread context */ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags ) { - context->ContextFlags |= CONTEXT_SPARC; - flags &= ~CONTEXT_SPARC; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( context, thread->context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { get_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); @@ -185,13 +192,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f /* set the thread context */ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - flags &= ~CONTEXT_SPARC; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( thread->context, context, flags ); - } - else if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { set_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); diff --git a/server/context_x86_64.c b/server/context_x86_64.c index f2200ae1a80..2f742b2e497 100644 --- a/server/context_x86_64.c +++ b/server/context_x86_64.c @@ -203,8 +203,9 @@ static void set_thread_context_ptrace( struct thread *thread, unsigned int flags /* copy a context structure according to the flags */ -static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int 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; @@ -254,19 +255,23 @@ 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 ) { - context->ContextFlags |= CONTEXT_AMD64; - flags &= ~CONTEXT_AMD64; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( context, thread->context, flags ); - flags &= CONTEXT_DEBUG_REGISTERS; - } - - if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { get_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); @@ -276,15 +281,7 @@ void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int f /* set the thread context */ void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags ) { - flags &= ~CONTEXT_AMD64; /* get rid of CPU id */ - - if (thread->context) /* thread is inside an exception event or suspended */ - { - copy_context( thread->context, context, flags ); - flags &= CONTEXT_DEBUG_REGISTERS; - } - - if (flags && suspend_for_ptrace( thread )) + if (suspend_for_ptrace( thread )) { set_thread_context_ptrace( thread, flags, context ); resume_after_ptrace( thread ); diff --git a/server/thread.c b/server/thread.c index e2c8807b26a..7e4ba3bbf10 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1043,7 +1043,7 @@ DECL_HANDLER(get_apc) DECL_HANDLER(get_thread_context) { struct thread *thread; - void *data; + CONTEXT *context; if (get_reply_max_size() < sizeof(CONTEXT)) { @@ -1072,10 +1072,14 @@ DECL_HANDLER(get_thread_context) if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); else set_error( STATUS_PENDING ); } - else if ((data = set_reply_data_size( sizeof(CONTEXT) ))) + else if ((context = set_reply_data_size( sizeof(CONTEXT) ))) { - memset( data, 0, sizeof(CONTEXT) ); - get_thread_context( thread, data, req->flags ); + unsigned int flags = get_context_system_regs( req->flags ); + + memset( context, 0, sizeof(CONTEXT) ); + context->ContextFlags = get_context_cpu_flag(); + if (thread->context) copy_context( context, thread->context, req->flags & ~flags ); + if (flags) get_thread_context( thread, context, flags ); } reply->self = (thread == current); release_object( thread ); @@ -1115,7 +1119,12 @@ DECL_HANDLER(set_thread_context) } else { - set_thread_context( thread, get_req_data(), req->flags ); + const CONTEXT *context = get_req_data(); + unsigned int flags = get_context_system_regs( req->flags ); + + if (flags) set_thread_context( thread, context, flags ); + if (thread->context && !get_error()) + copy_context( thread->context, context, req->flags & ~flags ); } reply->self = (thread == current); release_object( thread ); diff --git a/server/thread.h b/server/thread.h index ace5be3b550..0a40565a62c 100644 --- a/server/thread.h +++ b/server/thread.h @@ -119,13 +119,18 @@ extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct thread_snapshot *thread_snap( int *count ); extern struct token *thread_get_impersonation_token( struct thread *thread ); +/* CPU context functions */ +extern void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ); +extern void *get_context_ip( const CONTEXT *context ); +extern unsigned int get_context_cpu_flag(void); +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_context_ip( const CONTEXT *context ); 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 );