1 /* Process tracing interface `ptrace' for GNU Hurd.
2 Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
21 #include <sys/ptrace.h>
22 #include <sys/types.h>
25 #include <hurd/signal.h>
27 #include <thread_state.h>
29 /* Perform process tracing functions. REQUEST is one of the values
30 in <sys/ptrace.h>, and determines the action to be taken.
31 For all requests except PTRACE_TRACEME, PID specifies the process to be
34 PID and the other arguments described above for the various requests should
35 appear (those that are used for the particular request) as:
36 pid_t PID, void *ADDR, int DATA, void *ADDR2
39 ptrace (enum __ptrace_request request
, ... )
46 /* Read data from PID's address space, from ADDR for DATA bytes. */
47 error_t
read_data (task_t task
, vm_address_t
*ourpage
, vm_size_t
*size
)
49 /* Read the pages containing the addressed range. */
51 *size
= round_page (addr
+ data
) - trunc_page (addr
);
52 err
= __vm_read (task
, trunc_page (addr
), *size
, ourpage
, size
);
56 /* Fetch the thread port for PID's user thread. */
57 error_t
fetch_user_thread (task_t task
, thread_t
*thread
)
59 thread_t threadbuf
[3], *threads
= threadbuf
;
60 mach_msg_type_number_t nthreads
= 3, i
;
61 error_t err
= __task_threads (task
, &threads
, &nthreads
);
66 *thread
= threads
[0]; /* Assume user thread is first. */
67 for (i
= 1; i
< nthreads
; ++i
)
68 __mach_port_deallocate (__mach_task_self (), threads
[i
]);
69 if (threads
!= threadbuf
)
70 __vm_deallocate (__mach_task_self (),
71 (vm_address_t
) threads
, nthreads
* sizeof threads
[0]);
75 /* Fetch a thread state structure from PID and store it at ADDR. */
76 int get_regs (int flavor
, mach_msg_type_number_t count
)
79 task_t task
= __pid2task (pid
);
81 if (task
== MACH_PORT_NULL
)
83 err
= fetch_user_thread (task
, &thread
);
84 __mach_port_deallocate (__mach_task_self (), task
);
86 err
= __thread_get_state (thread
, flavor
, addr
, &count
);
87 __mach_port_deallocate (__mach_task_self (), thread
);
88 return err
? __hurd_fail (err
) : 0;
95 /* Make this process be traced. */
96 _hurd_exec_flags
|= EXEC_TRACED
;
97 __USEPORT (PROC
, __proc_mark_traced (port
));
101 va_start (ap
, request
);
102 pid
= va_arg (ap
, pid_t
);
103 addr
= va_arg (ap
, void *);
104 data
= va_arg (ap
, int);
107 /* Send a DATA signal to PID, telling it to take the signal
108 normally even if it's traced. */
110 task_t task
= __pid2task (pid
);
111 if (task
== MACH_PORT_NULL
)
114 err
= __task_terminate (task
);
117 if (addr
!= (void *) 1)
119 /* Move the user thread's PC to ADDR. */
121 err
= fetch_user_thread (task
, &thread
);
124 struct machine_thread_state state
;
125 mach_msg_type_number_t count
= MACHINE_THREAD_STATE_COUNT
;
126 err
= __thread_get_state (thread
,
127 MACHINE_THREAD_STATE_FLAVOR
,
128 (natural_t
*) &state
, &count
);
131 MACHINE_THREAD_STATE_SET_PC (&state
, addr
);
132 err
= __thread_set_state (thread
,
133 MACHINE_THREAD_STATE_FLAVOR
,
134 (natural_t
*) &state
, count
);
138 __mach_port_deallocate (__mach_task_self (), thread
);
144 /* Tell the process to take the signal (or just resume if 0). */
145 err
= HURD_MSGPORT_RPC
146 (__USEPORT (PROC
, __proc_getmsgport (port
, pid
, &msgport
)),
147 0, 0, __msg_sig_post_untraced (msgport
, data
, task
));
149 __mach_port_deallocate (__mach_task_self (), task
);
150 return err
? __hurd_fail (err
) : 0;
154 va_start (ap
, request
);
155 pid
= va_arg (ap
, pid_t
);
157 /* SIGKILL always just terminates the task,
158 so normal kill is just the same when traced. */
159 return kill (pid
, SIGKILL
);
161 case PTRACE_SINGLESTEP
:
162 /* This is a machine-dependent kernel RPC on
163 machines that support it. Punt. */
168 va_start (ap
, request
);
169 pid
= va_arg (ap
, pid_t
);
172 /* Tell PID to set or clear its trace bit. */
175 task_t task
= __pid2task (pid
);
176 if (task
== MACH_PORT_NULL
)
178 err
= __USEPORT (PROC
, __proc_getmsgport (port
, pid
, &msgport
));
181 err
= (request
== PTRACE_ATTACH
?
182 __msg_set_some_exec_flags
:
183 __msg_clear_some_exec_flags
) (msgport
, task
, EXEC_TRACED
);
184 #ifdef notyet /* XXX */
186 /* Request (or request an end to) SIGCHLD notification
187 when PID stops or dies, and proc_wait working on PID. */
188 err
= __USEPORT (PROC
,
189 __proc_trace_pid (port
, pid
,
190 request
== PTRACE_ATTACH
));
194 if (request
== PTRACE_ATTACH
)
195 /* Now stop the process. */
196 err
= __msg_sig_post (msgport
, SIGSTOP
, task
);
198 /* Resume the process from tracing stop. */
199 err
= __msg_sig_post_untraced (msgport
, 0, task
);
201 __mach_port_deallocate (__mach_task_self (), msgport
);
203 __mach_port_deallocate (__mach_task_self (), task
);
204 return err
? __hurd_fail (err
) : 0;
207 case PTRACE_PEEKTEXT
:
208 case PTRACE_PEEKDATA
:
209 va_start (ap
, request
);
210 pid
= va_arg (ap
, pid_t
);
211 addr
= va_arg (ap
, void *);
214 /* Read the page (or two pages, if the word lies on a boundary)
215 containing the addressed word. */
217 vm_address_t ourpage
;
220 task_t task
= __pid2task (pid
);
221 if (task
== MACH_PORT_NULL
)
226 err
= read_data (task
, &ourpage
, &size
);
227 __mach_port_deallocate (__mach_task_self (), task
);
229 return __hurd_fail (err
);
230 word
= *(natural_t
*) ((vm_address_t
) addr
- trunc_page (addr
)
232 __vm_deallocate (__mach_task_self (), ourpage
, size
);
236 case PTRACE_PEEKUSER
:
237 case PTRACE_POKEUSER
:
238 /* U area, what's that? */
243 va_start (ap
, request
);
244 pid
= va_arg (ap
, pid_t
);
245 addr
= va_arg (ap
, void *);
247 return get_regs (MACHINE_THREAD_STATE_FLAVOR
,
248 MACHINE_THREAD_STATE_COUNT
);
250 case PTRACE_GETFPREGS
:
251 case PTRACE_SETFPREGS
:
252 va_start (ap
, request
);
253 pid
= va_arg (ap
, pid_t
);
254 addr
= va_arg (ap
, void *);
256 #ifdef MACHINE_THREAD_FLOAT_STATE_FLAVOR
257 return get_regs (MACHINE_THREAD_FLOAT_STATE_FLAVOR
,
258 MACHINE_THREAD_FLOAT_STATE_COUNT
);
263 case PTRACE_GETFPAREGS
:
264 case PTRACE_SETFPAREGS
:
265 va_start (ap
, request
);
266 pid
= va_arg (ap
, pid_t
);
267 addr
= va_arg (ap
, void *);
269 #ifdef MACHINE_THREAD_FPA_STATE_FLAVOR
270 return get_regs (MACHINE_THREAD_FPA_STATE_FLAVOR
,
271 MACHINE_THREAD_FPA_STATE_COUNT
);
276 case PTRACE_POKETEXT
:
277 case PTRACE_POKEDATA
:
278 va_start (ap
, request
);
279 pid
= va_arg (ap
, pid_t
);
280 addr
= va_arg (ap
, void *);
281 data
= va_arg (ap
, int);
284 /* Read the page (or two pages, if the word lies on a boundary)
285 containing the addressed word. */
287 vm_address_t ourpage
;
289 task_t task
= __pid2task (pid
);
290 if (task
== MACH_PORT_NULL
)
292 data
= sizeof (natural_t
);
295 err
= read_data (task
, &ourpage
, &size
);
299 /* Now modify the specified word and write the page back. */
300 *(natural_t
*) ((vm_address_t
) addr
- trunc_page (addr
)
302 err
= __vm_write (task
, trunc_page (addr
), ourpage
, size
);
303 __vm_deallocate (__mach_task_self (), ourpage
, size
);
306 __mach_port_deallocate (__mach_task_self (), task
);
307 return err
? __hurd_fail (err
) : 0;
310 case PTRACE_READDATA
:
311 case PTRACE_READTEXT
:
312 va_start (ap
, request
);
313 pid
= va_arg (ap
, pid_t
);
314 addr
= va_arg (ap
, void *);
315 data
= va_arg (ap
, int);
316 addr2
= va_arg (ap
, void *);
320 vm_address_t ourpage
;
322 task_t task
= __pid2task (pid
);
323 if (task
== MACH_PORT_NULL
)
325 if (((vm_address_t
) addr2
+ data
) % __vm_page_size
== 0)
327 /* Perhaps we can write directly to the user's buffer. */
328 ourpage
= (vm_address_t
) addr2
;
336 err
= read_data (task
, &ourpage
, &size
);
337 __mach_port_deallocate (__mach_task_self (), task
);
338 if (!err
&& ourpage
!= (vm_address_t
) addr2
)
340 memcpy (addr2
, (void *) ourpage
, data
);
341 __vm_deallocate (__mach_task_self (), ourpage
, size
);
343 return err
? __hurd_fail (err
) : 0;
346 case PTRACE_WRITEDATA
:
347 case PTRACE_WRITETEXT
:
348 va_start (ap
, request
);
349 pid
= va_arg (ap
, pid_t
);
350 addr
= va_arg (ap
, void *);
351 data
= va_arg (ap
, int);
352 addr2
= va_arg (ap
, void *);
356 vm_address_t ourpage
;
358 task_t task
= __pid2task (pid
);
359 if (task
== MACH_PORT_NULL
)
361 if ((vm_address_t
) addr
% __vm_page_size
== 0 &&
362 (vm_address_t
) data
% __vm_page_size
== 0)
364 /* Writing whole pages; can go directly from the user's buffer. */
365 ourpage
= (vm_address_t
) addr2
;
371 /* Read the task's pages and modify our own copy. */
374 err
= read_data (task
, &ourpage
, &size
);
376 memcpy ((void *) ((vm_address_t
) addr
- trunc_page (addr
)
382 /* Write back the modified pages. */
383 err
= __vm_write (task
, trunc_page (addr
), ourpage
, size
);
384 __mach_port_deallocate (__mach_task_self (), task
);
385 return err
? __hurd_fail (err
) : 0;