blob: a36bed7f762f8c2edb3bf3089855ac9ea20dad5a [file] [log] [blame]
Alexandre Julliard578c1001999-11-14 21:23:21 +00001/*
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>
Alexandre Julliard42666ee1999-11-21 01:10:16 +000013#include <sys/types.h>
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000014#ifdef HAVE_SYS_PTRACE_H
15# include <sys/ptrace.h>
16#endif
Alexandre Julliard578c1001999-11-14 21:23:21 +000017#ifdef HAVE_SYS_WAIT_H
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000018# include <sys/wait.h>
Alexandre Julliard578c1001999-11-14 21:23:21 +000019#endif
20#include <unistd.h>
21
22#include "process.h"
23#include "thread.h"
24
25
26#ifndef PTRACE_CONT
27#define PTRACE_CONT PT_CONTINUE
28#endif
Ove Kaavenada73832001-04-27 18:39:47 +000029#ifndef PTRACE_SINGLESTEP
30#define PTRACE_SINGLESTEP PT_STEP
31#endif
Alexandre Julliard578c1001999-11-14 21:23:21 +000032#ifndef PTRACE_ATTACH
33#define PTRACE_ATTACH PT_ATTACH
34#endif
35#ifndef PTRACE_DETACH
36#define PTRACE_DETACH PT_DETACH
37#endif
38#ifndef PTRACE_PEEKDATA
39#define PTRACE_PEEKDATA PT_READ_D
40#endif
41#ifndef PTRACE_POKEDATA
42#define PTRACE_POKEDATA PT_WRITE_D
43#endif
44
Alexandre Julliard5f258c62001-07-14 00:50:30 +000045#ifndef HAVE_SYS_PTRACE_H
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000046#define PT_CONTINUE 0
47#define PT_ATTACH 1
48#define PT_DETACH 2
49#define PT_READ_D 3
50#define PT_WRITE_D 4
Ove Kaavenada73832001-04-27 18:39:47 +000051#define PT_STEP 5
Alexandre Julliard5f258c62001-07-14 00:50:30 +000052inline static int ptrace(int req, ...) { errno = EPERM; return -1; /*FAIL*/ }
53#endif /* HAVE_SYS_PTRACE_H */
Dimitrie O. Paun2af03e42000-11-29 20:04:09 +000054
Alexandre Julliard5f258c62001-07-14 00:50:30 +000055static const int use_ptrace = 1; /* set to 0 to disable ptrace */
Alexandre Julliard578c1001999-11-14 21:23:21 +000056
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000057/* handle a status returned by wait4 */
58static int handle_child_status( struct thread *thread, int pid, int status )
Alexandre Julliard578c1001999-11-14 21:23:21 +000059{
Alexandre Julliard578c1001999-11-14 21:23:21 +000060 if (WIFSTOPPED(status))
61 {
62 int sig = WSTOPSIG(status);
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000063 if (debug_level && thread)
64 fprintf( stderr, "%08x: *signal* signal=%d\n", (unsigned int)thread, sig );
Alexandre Julliard578c1001999-11-14 21:23:21 +000065 switch(sig)
66 {
67 case SIGSTOP: /* continue at once if not suspended */
Ove Kaavenada73832001-04-27 18:39:47 +000068 if (thread && (thread->process->suspend + thread->suspend)) break;
69 /* fall through */
Alexandre Julliard578c1001999-11-14 21:23:21 +000070 default: /* ignore other signals for now */
Ove Kaavenada73832001-04-27 18:39:47 +000071 if (thread && get_thread_single_step( thread ))
72 ptrace( PTRACE_SINGLESTEP, pid, (caddr_t)1, sig );
73 else
74 ptrace( PTRACE_CONT, pid, (caddr_t)1, sig );
Alexandre Julliard578c1001999-11-14 21:23:21 +000075 break;
76 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000077 return sig;
Alexandre Julliard578c1001999-11-14 21:23:21 +000078 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000079 if (thread && (WIFSIGNALED(status) || WIFEXITED(status)))
Alexandre Julliard578c1001999-11-14 21:23:21 +000080 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000081 thread->attached = 0;
82 thread->unix_pid = 0;
Alexandre Julliard578c1001999-11-14 21:23:21 +000083 if (debug_level)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000084 {
85 if (WIFSIGNALED(status))
86 fprintf( stderr, "%08x: *exited* signal=%d\n",
87 (unsigned int)thread, WTERMSIG(status) );
88 else
89 fprintf( stderr, "%08x: *exited* status=%d\n",
90 (unsigned int)thread, WEXITSTATUS(status) );
91 }
Alexandre Julliard578c1001999-11-14 21:23:21 +000092 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000093 return 0;
94}
95
96/* handle a SIGCHLD signal */
97void sigchld_handler()
98{
99 int pid, status;
100
101 for (;;)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000102 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000103 if (!(pid = wait4( -1, &status, WUNTRACED | WNOHANG, NULL ))) break;
104 if (pid != -1) handle_child_status( get_thread_from_pid(pid), pid, status );
105 else break;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000106 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000107}
108
109/* wait for a ptraced child to get a certain signal */
110void wait4_thread( struct thread *thread, int signal )
111{
112 int res, status;
113
114 do
115 {
116 if ((res = wait4( thread->unix_pid, &status, WUNTRACED, NULL )) == -1)
117 {
118 perror( "wait4" );
119 return;
120 }
121 res = handle_child_status( thread, res, status );
122 } while (res && res != signal);
Alexandre Julliard578c1001999-11-14 21:23:21 +0000123}
124
125/* attach to a Unix thread */
126static int attach_thread( struct thread *thread )
127{
128 /* this may fail if the client is already being debugged */
Alexandre Julliard5f258c62001-07-14 00:50:30 +0000129 if (!use_ptrace) return 0;
130 if (ptrace( PTRACE_ATTACH, thread->unix_pid, 0, 0 ) == -1)
131 {
132 if (errno == ESRCH) thread->unix_pid = 0; /* process got killed */
133 return 0;
134 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000135 if (debug_level) fprintf( stderr, "%08x: *attached*\n", (unsigned int)thread );
Alexandre Julliard578c1001999-11-14 21:23:21 +0000136 thread->attached = 1;
137 wait4_thread( thread, SIGSTOP );
138 return 1;
139}
140
141/* detach from a Unix thread and kill it */
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000142void detach_thread( struct thread *thread, int sig )
Alexandre Julliard578c1001999-11-14 21:23:21 +0000143{
144 if (!thread->unix_pid) return;
Alexandre Julliard578c1001999-11-14 21:23:21 +0000145 if (thread->attached)
146 {
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000147 /* make sure it is stopped */
Alexandre Julliard5f258c62001-07-14 00:50:30 +0000148 suspend_thread( thread, 0 );
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000149 if (sig) kill( thread->unix_pid, sig );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000150 if (debug_level) fprintf( stderr, "%08x: *detached*\n", (unsigned int)thread );
Gerald Pfeifer1f012362000-10-17 00:25:59 +0000151 ptrace( PTRACE_DETACH, thread->unix_pid, (caddr_t)1, sig );
Alexandre Julliard5f258c62001-07-14 00:50:30 +0000152 thread->suspend = 0; /* detach makes it continue */
Alexandre Julliard578c1001999-11-14 21:23:21 +0000153 thread->attached = 0;
154 }
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000155 else
156 {
Alexandre Julliard12f29b52000-03-17 15:16:57 +0000157 if (sig) kill( thread->unix_pid, sig );
Alexandre Julliard05f0b712000-03-09 18:18:41 +0000158 if (thread->suspend + thread->process->suspend) continue_thread( thread );
159 }
Alexandre Julliard578c1001999-11-14 21:23:21 +0000160}
161
162/* stop a thread (at the Unix level) */
163void stop_thread( struct thread *thread )
164{
165 /* can't stop a thread while initialisation is in progress */
166 if (!thread->unix_pid || thread->process->init_event) return;
167 /* first try to attach to it */
168 if (!thread->attached)
169 if (attach_thread( thread )) return; /* this will have stopped it */
170 /* attached already, or attach failed -> send a signal */
171 kill( thread->unix_pid, SIGSTOP );
172 if (thread->attached) wait4_thread( thread, SIGSTOP );
173}
174
175/* make a thread continue (at the Unix level) */
176void continue_thread( struct thread *thread )
177{
178 if (!thread->unix_pid) return;
179 if (!thread->attached) kill( thread->unix_pid, SIGCONT );
Ove Kaavenada73832001-04-27 18:39:47 +0000180 else ptrace( get_thread_single_step(thread) ? PTRACE_SINGLESTEP : PTRACE_CONT,
181 thread->unix_pid, (caddr_t)1, SIGSTOP );
Alexandre Julliard578c1001999-11-14 21:23:21 +0000182}
183
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000184/* suspend a thread to allow using ptrace on it */
185/* you must do a resume_thread when finished with the thread */
186int suspend_for_ptrace( struct thread *thread )
187{
188 if (thread->attached)
189 {
190 suspend_thread( thread, 0 );
191 return 1;
192 }
Alexandre Julliardd3928312000-04-04 19:55:28 +0000193 /* can't stop a thread while initialisation is in progress */
194 if (!thread->unix_pid || thread->process->init_event) goto error;
195 thread->suspend++;
196 if (attach_thread( thread )) return 1;
197 thread->suspend--;
198 error:
Alexandre Julliard98aacc72000-03-15 19:46:14 +0000199 set_error( STATUS_ACCESS_DENIED );
200 return 0;
201}
202
Alexandre Julliard578c1001999-11-14 21:23:21 +0000203/* read an int from a thread address space */
204int read_thread_int( struct thread *thread, const int *addr, int *data )
205{
Gerald Pfeifer1f012362000-10-17 00:25:59 +0000206 *data = ptrace( PTRACE_PEEKDATA, thread->unix_pid, (caddr_t)addr, 0 );
207 if ( *data == -1 && errno)
Alexandre Julliard578c1001999-11-14 21:23:21 +0000208 {
209 file_set_error();
210 return -1;
211 }
212 return 0;
213}
214
215/* write an int to a thread address space */
216int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask )
217{
218 int res;
219 if (mask != ~0)
220 {
221 if (read_thread_int( thread, addr, &res ) == -1) return -1;
222 data = (data & mask) | (res & ~mask);
223 }
Gerald Pfeifer1f012362000-10-17 00:25:59 +0000224 if ((res = ptrace( PTRACE_POKEDATA, thread->unix_pid, (caddr_t)addr, data )) == -1)
225 file_set_error();
Alexandre Julliard578c1001999-11-14 21:23:21 +0000226 return res;
227}