From 578c10090b415685478cdbb41bda4bbcac0c4e84 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Sun, 14 Nov 1999 21:23:21 +0000
Subject: [PATCH] Moved ptrace support to ptrace.c. Tried to improve
 portability.

---
 server/Makefile.in |   1 +
 server/process.c   |  42 +++---------
 server/ptrace.c    | 164 +++++++++++++++++++++++++++++++++++++++++++++
 server/thread.c    | 120 +++------------------------------
 server/thread.h    |  14 +++-
 5 files changed, 192 insertions(+), 149 deletions(-)
 create mode 100644 server/ptrace.c

diff --git a/server/Makefile.in b/server/Makefile.in
index fafd772fba1..f1f0f1da513 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -18,6 +18,7 @@ C_SRCS = \
 	object.c \
 	pipe.c \
 	process.c \
+	ptrace.c \
 	request.c \
 	snapshot.c \
 	select.c \
diff --git a/server/process.c b/server/process.c
index 034e90d28cb..ee3ca64a1b6 100644
--- a/server/process.c
+++ b/server/process.c
@@ -316,30 +316,6 @@ static void set_process_info( struct process *process,
     }
 }
 
-/* wrapper for reading an int with ptrace */
-static inline int read_word( int pid, const int *addr, int *data )
-{
-    if (((*data = ptrace( PT_READ_D, pid, addr )) == -1) && errno)
-    {
-        file_set_error();
-        return -1;
-    }
-    return 0;
-}
-
-/* wrapper for writing an int with ptrace */
-static inline int write_word( int pid, int *addr, int data, unsigned int mask )
-{
-    int res;
-    if (mask != ~0)
-    {
-        if (read_word( pid, addr, &res ) == -1) return -1;
-        data = (data & mask) | (res & ~mask);
-    }
-    if ((res = ptrace( PT_WRITE_D, pid, addr, data )) == -1) file_set_error();
-    return res;
-}
-
 /* read data from a process memory space */
 /* len is the total size (in ints), max is the size we can actually store in the output buffer */
 /* we read the total size in all cases to check for permissions */
@@ -347,7 +323,6 @@ static void read_process_memory( struct process *process, const int *addr,
                                  size_t len, size_t max, int *dest )
 {
     struct thread *thread = process->thread_list;
-    int pid = thread->unix_pid;
 
     if ((unsigned int)addr % sizeof(int))  /* address must be aligned */
     {
@@ -359,7 +334,7 @@ static void read_process_memory( struct process *process, const int *addr,
     {
         while (len > 0 && max)
         {
-            if (read_word( pid, addr++, dest++ ) == -1) goto done;
+            if (read_thread_int( thread, addr++, dest++ ) == -1) goto done;
             max--;
             len--;
         }
@@ -371,9 +346,9 @@ static void read_process_memory( struct process *process, const int *addr,
             {
                 addr += page;
                 len -= page;
-                if (read_word( pid, addr - 1, &dummy ) == -1) goto done;
+                if (read_thread_int( thread, addr - 1, &dummy ) == -1) goto done;
             }
-            if (len && (read_word( pid, addr + len - 1, &dummy ) == -1)) goto done;
+            if (len && (read_thread_int( thread, addr + len - 1, &dummy ) == -1)) goto done;
         }
     }
     else set_error( ERROR_ACCESS_DENIED );
@@ -389,7 +364,6 @@ static void write_process_memory( struct process *process, int *addr, size_t len
                                   unsigned int last_mask, const int *src )
 {
     struct thread *thread = process->thread_list;
-    int pid = thread->unix_pid;
 
     if (!len || ((unsigned int)addr % sizeof(int)))  /* address must be aligned */
     {
@@ -402,7 +376,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
         /* first word is special */
         if (len > 1)
         {
-            if (write_word( pid, addr++, *src++, first_mask ) == -1) goto done;
+            if (write_thread_int( thread, addr++, *src++, first_mask ) == -1) goto done;
             len--;
             max--;
         }
@@ -410,7 +384,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
 
         while (len > 1 && max)
         {
-            if (write_word( pid, addr++, *src++, ~0 ) == -1) goto done;
+            if (write_thread_int( thread, addr++, *src++, ~0 ) == -1) goto done;
             max--;
             len--;
         }
@@ -418,7 +392,7 @@ static void write_process_memory( struct process *process, int *addr, size_t len
         if (max)
         {
             /* last word is special too */
-            if (write_word( pid, addr, *src, last_mask ) == -1) goto done;
+            if (write_thread_int( thread, addr, *src, last_mask ) == -1) goto done;
         }
         else
         {
@@ -428,9 +402,9 @@ static void write_process_memory( struct process *process, int *addr, size_t len
             {
                 addr += page;
                 len -= page;
-                if (write_word( pid, addr - 1, 0, 0 ) == -1) goto done;
+                if (write_thread_int( thread, addr - 1, 0, 0 ) == -1) goto done;
             }
-            if (len && (write_word( pid, addr + len - 1, 0, 0 ) == -1)) goto done;
+            if (len && (write_thread_int( thread, addr + len - 1, 0, 0 ) == -1)) goto done;
         }
     }
     else set_error( ERROR_ACCESS_DENIED );
diff --git a/server/ptrace.c b/server/ptrace.c
new file mode 100644
index 00000000000..b2931267f92
--- /dev/null
+++ b/server/ptrace.c
@@ -0,0 +1,164 @@
+/*
+ * Server-side ptrace support
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <unistd.h>
+
+#include "process.h"
+#include "thread.h"
+
+
+#ifndef PTRACE_CONT
+#define PTRACE_CONT PT_CONTINUE
+#endif
+#ifndef PTRACE_ATTACH
+#define PTRACE_ATTACH PT_ATTACH
+#endif
+#ifndef PTRACE_DETACH
+#define PTRACE_DETACH PT_DETACH
+#endif
+#ifndef PTRACE_PEEKDATA
+#define PTRACE_PEEKDATA PT_READ_D
+#endif
+#ifndef PTRACE_POKEDATA
+#define PTRACE_POKEDATA PT_WRITE_D
+#endif
+
+static const int use_ptrace = 1;  /* set to 0 to disable ptrace */
+
+
+/* wait for a ptraced child to get a certain signal */
+/* if the signal is 0, we simply check if anything is pending and return at once */
+void wait4_thread( struct thread *thread, int signal )
+{
+    int status;
+    int pid;
+
+ restart:
+    pid = thread ? thread->unix_pid : -1;
+    if ((pid = wait4( pid, &status, WUNTRACED | (signal ? 0 : WNOHANG), NULL )) == -1)
+    {
+        perror( "wait4" );
+        return;
+    }
+    if (WIFSTOPPED(status))
+    {
+        int sig = WSTOPSIG(status);
+        if (debug_level) fprintf( stderr, "ptrace: pid %d got sig %d\n", pid, sig );
+        switch(sig)
+        {
+        case SIGSTOP:  /* continue at once if not suspended */
+            if (!thread)
+                if (!(thread = get_thread_from_pid( pid ))) break;
+            if (!(thread->process->suspend + thread->suspend))
+                ptrace( PTRACE_CONT, pid, 0, sig );
+            break;
+        default:  /* ignore other signals for now */
+            ptrace( PTRACE_CONT, pid, 0, sig );
+            break;
+        }
+        if (signal && sig != signal) goto restart;
+    }
+    else if (WIFSIGNALED(status))
+    {
+        int exit_code = WTERMSIG(status);
+        if (debug_level)
+            fprintf( stderr, "ptrace: pid %d killed by sig %d\n", pid, exit_code );
+        if (!thread)
+            if (!(thread = get_thread_from_pid( pid ))) return;
+        if (thread->client) remove_client( thread->client, exit_code );
+    }
+    else if (WIFEXITED(status))
+    {
+        int exit_code = WEXITSTATUS(status);
+        if (debug_level)
+            fprintf( stderr, "ptrace: pid %d exited with status %d\n", pid, exit_code );
+        if (!thread)
+            if (!(thread = get_thread_from_pid( pid ))) return;
+        if (thread->client) remove_client( thread->client, exit_code );
+    }
+    else fprintf( stderr, "wait4: pid %d unknown status %x\n", pid, status );
+}
+
+/* attach to a Unix thread */
+static int attach_thread( struct thread *thread )
+{
+    /* this may fail if the client is already being debugged */
+    if (!use_ptrace || (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)) return 0;
+    if (debug_level) fprintf( stderr, "ptrace: attached to pid %d\n", thread->unix_pid );
+    thread->attached = 1;
+    wait4_thread( thread, SIGSTOP );
+    return 1;
+}
+
+/* detach from a Unix thread and kill it */
+void detach_thread( struct thread *thread )
+{
+    if (!thread->unix_pid) return;
+    kill( thread->unix_pid, SIGTERM );
+    if (thread->suspend + thread->process->suspend) continue_thread( thread );
+    if (thread->attached)
+    {
+        wait4_thread( thread, SIGTERM );
+        if (debug_level) fprintf( stderr, "ptrace: detaching from %d\n", thread->unix_pid );
+        ptrace( PTRACE_DETACH, thread->unix_pid, 0, SIGTERM );
+        thread->attached = 0;
+    }
+}
+
+/* stop a thread (at the Unix level) */
+void stop_thread( struct thread *thread )
+{
+    /* can't stop a thread while initialisation is in progress */
+    if (!thread->unix_pid || thread->process->init_event) return;
+    /* first try to attach to it */
+    if (!thread->attached)
+        if (attach_thread( thread )) return;  /* this will have stopped it */
+    /* attached already, or attach failed -> send a signal */
+    kill( thread->unix_pid, SIGSTOP );
+    if (thread->attached) wait4_thread( thread, SIGSTOP );
+}
+
+/* make a thread continue (at the Unix level) */
+void continue_thread( struct thread *thread )
+{
+    if (!thread->unix_pid) return;
+    if (!thread->attached) kill( thread->unix_pid, SIGCONT );
+    else ptrace( PTRACE_CONT, thread->unix_pid, 0, SIGSTOP );
+}
+
+/* read an int from a thread address space */
+int read_thread_int( struct thread *thread, const int *addr, int *data )
+{
+    if (((*data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, addr )) == -1) && errno)
+    {
+        file_set_error();
+        return -1;
+    }
+    return 0;
+}
+
+/* write an int to a thread address space */
+int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask )
+{
+    int res;
+    if (mask != ~0)
+    {
+        if (read_thread_int( thread, addr, &res ) == -1) return -1;
+        data = (data & mask) | (res & ~mask);
+    }
+    if ((res = ptrace( PTRACE_POKEDATA, thread->unix_pid, addr, data )) == -1) file_set_error();
+    return res;
+}
diff --git a/server/thread.c b/server/thread.c
index d8885462ec8..6d96eac1f29 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -15,10 +15,8 @@
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
-#include <sys/ptrace.h>
 #include <sys/types.h>
 #include <sys/uio.h>
-#include <sys/wait.h>
 #include <unistd.h>
 #include <stdarg.h>
 
@@ -82,7 +80,6 @@ static const struct object_ops thread_ops =
     destroy_thread
 };
 
-static const int use_ptrace = 1;  /* set to 0 to disable ptrace */
 static struct thread *first_thread;
 
 /* allocate the buffer for the communication with the client */
@@ -214,6 +211,14 @@ struct thread *get_thread_from_handle( int handle, unsigned int access )
                                             access, &thread_ops );
 }
 
+/* find a thread from a Unix pid */
+struct thread *get_thread_from_pid( int pid )
+{
+    struct thread *t = first_thread;
+    while (t && (t->unix_pid != pid)) t = t->next;
+    return t;
+}
+
 /* set all information about a thread */
 static void set_thread_info( struct thread *thread,
                              struct set_thread_info_request *req )
@@ -227,115 +232,6 @@ static void set_thread_info( struct thread *thread,
     }
 }
 
-/* find a thread from a Unix pid */
-static struct thread *get_thread_from_pid( int pid )
-{
-    struct thread *t = first_thread;
-    while (t && (t->unix_pid != pid)) t = t->next;
-    return t;
-}
-
-/* wait for a ptraced child to get a certain signal */
-/* if the signal is 0, we simply check if anything is pending and return at once */
-void wait4_thread( struct thread *thread, int signal )
-{
-    int status;
-    int pid;
-
-
- restart:
-    pid = thread ? thread->unix_pid : -1;
-    if ((pid = wait4( pid, &status, WUNTRACED | (signal ? 0 : WNOHANG), NULL )) == -1)
-    {
-        perror( "wait4" );
-        return;
-    }
-    if (WIFSTOPPED(status))
-    {
-        int sig = WSTOPSIG(status);
-        if (debug_level) fprintf( stderr, "ptrace: pid %d got sig %d\n", pid, sig );
-        switch(sig)
-        {
-        case SIGSTOP:  /* continue at once if not suspended */
-            if (!thread)
-                if (!(thread = get_thread_from_pid( pid ))) break;
-            if (!(thread->process->suspend + thread->suspend))
-                ptrace( PT_CONTINUE, pid, 0, sig );
-            break;
-        default:  /* ignore other signals for now */
-            ptrace( PT_CONTINUE, pid, 0, sig );
-            break;
-        }
-        if (signal && sig != signal) goto restart;
-    }
-    else if (WIFSIGNALED(status))
-    {
-        int exit_code = WTERMSIG(status);
-        if (debug_level)
-            fprintf( stderr, "ptrace: pid %d killed by sig %d\n", pid, exit_code );
-        if (!thread)
-            if (!(thread = get_thread_from_pid( pid ))) return;
-        if (thread->client) remove_client( thread->client, exit_code );
-    }
-    else if (WIFEXITED(status))
-    {
-        int exit_code = WEXITSTATUS(status);
-        if (debug_level)
-            fprintf( stderr, "ptrace: pid %d exited with status %d\n", pid, exit_code );
-        if (!thread)
-            if (!(thread = get_thread_from_pid( pid ))) return;
-        if (thread->client) remove_client( thread->client, exit_code );
-    }
-    else fprintf( stderr, "wait4: pid %d unknown status %x\n", pid, status );
-}
-
-/* attach to a Unix thread */
-static int attach_thread( struct thread *thread )
-{
-    /* this may fail if the client is already being debugged */
-    if (!use_ptrace || (ptrace( PT_ATTACH, thread->unix_pid, 0, 0 ) == -1)) return 0;
-    if (debug_level) fprintf( stderr, "ptrace: attached to pid %d\n", thread->unix_pid );
-    thread->attached = 1;
-    wait4_thread( thread, SIGSTOP );
-    return 1;
-}
-
-/* detach from a Unix thread and kill it */
-static void detach_thread( struct thread *thread )
-{
-    if (!thread->unix_pid) return;
-    kill( thread->unix_pid, SIGTERM );
-    if (thread->suspend + thread->process->suspend) continue_thread( thread );
-    if (thread->attached)
-    {
-        wait4_thread( thread, SIGTERM );
-        if (debug_level) fprintf( stderr, "ptrace: detaching from %d\n", thread->unix_pid );
-        ptrace( PT_DETACH, thread->unix_pid, 0, SIGTERM );
-        thread->attached = 0;
-    }
-}
-
-/* stop a thread (at the Unix level) */
-void stop_thread( struct thread *thread )
-{
-    /* can't stop a thread while initialisation is in progress */
-    if (!thread->unix_pid || thread->process->init_event) return;
-    /* first try to attach to it */
-    if (!thread->attached)
-        if (attach_thread( thread )) return;  /* this will have stopped it */
-    /* attached already, or attach failed -> send a signal */
-    kill( thread->unix_pid, SIGSTOP );
-    if (thread->attached) wait4_thread( thread, SIGSTOP );
-}
-
-/* make a thread continue (at the Unix level) */
-void continue_thread( struct thread *thread )
-{
-    if (!thread->unix_pid) return;
-    if (!thread->attached) kill( thread->unix_pid, SIGCONT );
-    else ptrace( PT_CONTINUE, thread->unix_pid, 0, SIGSTOP );
-}
- 
 /* suspend a thread */
 int suspend_thread( struct thread *thread, int check_limit )
 {
diff --git a/server/thread.h b/server/thread.h
index 2d5c7a38875..ecb9226a0d0 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -66,9 +66,7 @@ extern struct thread *current;
 extern void create_initial_thread( int fd );
 extern struct thread *get_thread_from_id( void *id );
 extern struct thread *get_thread_from_handle( int handle, unsigned int access );
-extern void wait4_thread( struct thread *thread, int wait );
-extern void stop_thread( struct thread *thread );
-extern void continue_thread( struct thread *thread );
+extern struct thread *get_thread_from_pid( int pid );
 extern int suspend_thread( struct thread *thread, int check_limit );
 extern int resume_thread( struct thread *thread );
 extern void suspend_all_threads( void );
@@ -80,6 +78,16 @@ extern void thread_killed( struct thread *thread, int exit_code );
 extern void thread_timeout(void);
 extern void wake_up( struct object *obj, int max );
 
+/* ptrace functions */
+
+extern void wait4_thread( struct thread *thread, int wait );
+extern void stop_thread( struct thread *thread );
+extern void continue_thread( struct thread *thread );
+extern void detach_thread( struct thread *thread );
+extern int read_thread_int( struct thread *thread, const int *addr, int *data );
+extern int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask );
+
+
 static inline int get_error(void)       { return current->error; }
 static inline void set_error( int err ) { current->error = err; }
 static inline void clear_error(void)    { set_error(0); }
-- 
GitLab