No longer directly accessing debuggee memory.
[wine] / server / ptrace.c
1 /*
2  * Server-side ptrace support
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/ptrace.h>
15 #ifdef HAVE_SYS_WAIT_H
16 #include <sys/wait.h>
17 #endif
18 #include <unistd.h>
19
20 #include "process.h"
21 #include "thread.h"
22
23
24 #ifndef PTRACE_CONT
25 #define PTRACE_CONT PT_CONTINUE
26 #endif
27 #ifndef PTRACE_ATTACH
28 #define PTRACE_ATTACH PT_ATTACH
29 #endif
30 #ifndef PTRACE_DETACH
31 #define PTRACE_DETACH PT_DETACH
32 #endif
33 #ifndef PTRACE_PEEKDATA
34 #define PTRACE_PEEKDATA PT_READ_D
35 #endif
36 #ifndef PTRACE_POKEDATA
37 #define PTRACE_POKEDATA PT_WRITE_D
38 #endif
39
40 static const int use_ptrace = 1;  /* set to 0 to disable ptrace */
41
42 /* handle a status returned by wait4 */
43 static int handle_child_status( struct thread *thread, int pid, int status )
44 {
45     if (WIFSTOPPED(status))
46     {
47         int sig = WSTOPSIG(status);
48         if (debug_level && thread)
49             fprintf( stderr, "%08x: *signal* signal=%d\n", (unsigned int)thread, sig );
50         switch(sig)
51         {
52         case SIGSTOP:  /* continue at once if not suspended */
53             if (!thread || !(thread->process->suspend + thread->suspend))
54                 ptrace( PTRACE_CONT, pid, 1, sig );
55             break;
56         default:  /* ignore other signals for now */
57             ptrace( PTRACE_CONT, pid, 1, sig );
58             break;
59         }
60         return sig;
61     }
62     if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
63     {
64         thread->attached = 0;
65         thread->unix_pid = 0;
66         if (debug_level)
67         {
68             if (WIFSIGNALED(status))
69                 fprintf( stderr, "%08x: *exited* signal=%d\n",
70                          (unsigned int)thread, WTERMSIG(status) );
71             else
72                 fprintf( stderr, "%08x: *exited* status=%d\n",
73                          (unsigned int)thread, WEXITSTATUS(status) );
74         }
75     }
76     return 0;
77 }
78
79 /* handle a SIGCHLD signal */
80 void sigchld_handler()
81 {
82     int pid, status;
83
84     for (;;)
85     {
86         if (!(pid = wait4( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
87         if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status );
88         else break;
89     }
90 }
91
92 /* wait for a ptraced child to get a certain signal */
93 void wait4_thread( struct thread *thread, int signal )
94 {
95     int res, status;
96
97     do
98     {
99         if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
100         {
101             perror( "wait4" );
102             return;
103         }
104         res = handle_child_status( thread, res, status );
105     } while (res && res != signal);
106 }
107
108 /* attach to a Unix thread */
109 static int attach_thread( struct thread *thread )
110 {
111     /* this may fail if the client is already being debugged */
112     if (!use_ptrace || (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)) return 0;
113     if (debug_level) fprintf( stderr, "%08x: *attached*\n", (unsigned int)thread );
114     thread->attached = 1;
115     wait4_thread( thread, SIGSTOP );
116     return 1;
117 }
118
119 /* detach from a Unix thread and kill it */
120 void detach_thread( struct thread *thread )
121 {
122     if (!thread->unix_pid) return;
123     kill( thread->unix_pid, SIGTERM );
124     if (thread->suspend + thread->process->suspend) continue_thread( thread );
125     if (thread->attached)
126     {
127         wait4_thread( thread, SIGTERM );
128         if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
129         ptrace( PTRACE_DETACH, thread->unix_pid, 1, SIGTERM );
130         thread->attached = 0;
131     }
132 }
133
134 /* stop a thread (at the Unix level) */
135 void stop_thread( struct thread *thread )
136 {
137     /* can't stop a thread while initialisation is in progress */
138     if (!thread->unix_pid || thread->process->init_event) return;
139     /* first try to attach to it */
140     if (!thread->attached)
141         if (attach_thread( thread )) return;  /* this will have stopped it */
142     /* attached already, or attach failed -> send a signal */
143     kill( thread->unix_pid, SIGSTOP );
144     if (thread->attached) wait4_thread( thread, SIGSTOP );
145 }
146
147 /* make a thread continue (at the Unix level) */
148 void continue_thread( struct thread *thread )
149 {
150     if (!thread->unix_pid) return;
151     if (!thread->attached) kill( thread->unix_pid, SIGCONT );
152     else ptrace( PTRACE_CONT, thread->unix_pid, 1, SIGSTOP );
153 }
154
155 /* read an int from a thread address space */
156 int read_thread_int( struct thread *thread, const int *addr, int *data )
157 {
158     if (((*data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, addr, 0 )) == -1) && errno)
159     {
160         file_set_error();
161         return -1;
162     }
163     return 0;
164 }
165
166 /* write an int to a thread address space */
167 int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask )
168 {
169     int res;
170     if (mask != ~0)
171     {
172         if (read_thread_int( thread, addr, &res ) == -1) return -1;
173         data = (data & mask) | (res & ~mask);
174     }
175     if ((res = ptrace( PTRACE_POKEDATA, thread->unix_pid, addr, data )) == -1) file_set_error();
176     return res;
177 }