1 /* Process tracing interface `ptrace' for GNU Hurd.
2 Copyright (C) 1991, 92, 93, 95, 96, 97 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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
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 __sigfillset (&_hurdsig_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
, 0, 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
= __msg_set_init_int (msgport
, task
, INIT_TRACEMASK
,
182 request
== PTRACE_DETACH
? 0 :
186 if (request
== PTRACE_ATTACH
)
187 /* Now stop the process. */
188 err
= __msg_sig_post (msgport
, SIGSTOP
, 0, task
);
190 /* Resume the process from tracing stop. */
191 err
= __msg_sig_post_untraced (msgport
, 0, 0, task
);
193 __mach_port_deallocate (__mach_task_self (), msgport
);
195 __mach_port_deallocate (__mach_task_self (), task
);
196 return err
? __hurd_fail (err
) : 0;
199 case PTRACE_PEEKTEXT
:
200 case PTRACE_PEEKDATA
:
201 va_start (ap
, request
);
202 pid
= va_arg (ap
, pid_t
);
203 addr
= va_arg (ap
, void *);
206 /* Read the page (or two pages, if the word lies on a boundary)
207 containing the addressed word. */
209 vm_address_t ourpage
;
212 task_t task
= __pid2task (pid
);
213 if (task
== MACH_PORT_NULL
)
218 err
= read_data (task
, &ourpage
, &size
);
219 __mach_port_deallocate (__mach_task_self (), task
);
221 return __hurd_fail (err
);
222 word
= *(natural_t
*) ((vm_address_t
) addr
- trunc_page (addr
)
224 __vm_deallocate (__mach_task_self (), ourpage
, size
);
228 case PTRACE_PEEKUSER
:
229 case PTRACE_POKEUSER
:
230 /* U area, what's that? */
235 va_start (ap
, request
);
236 pid
= va_arg (ap
, pid_t
);
237 addr
= va_arg (ap
, void *);
239 return get_regs (MACHINE_THREAD_STATE_FLAVOR
,
240 MACHINE_THREAD_STATE_COUNT
);
242 case PTRACE_GETFPREGS
:
243 case PTRACE_SETFPREGS
:
244 va_start (ap
, request
);
245 pid
= va_arg (ap
, pid_t
);
246 addr
= va_arg (ap
, void *);
248 #ifdef MACHINE_THREAD_FLOAT_STATE_FLAVOR
249 return get_regs (MACHINE_THREAD_FLOAT_STATE_FLAVOR
,
250 MACHINE_THREAD_FLOAT_STATE_COUNT
);
255 case PTRACE_GETFPAREGS
:
256 case PTRACE_SETFPAREGS
:
257 va_start (ap
, request
);
258 pid
= va_arg (ap
, pid_t
);
259 addr
= va_arg (ap
, void *);
261 #ifdef MACHINE_THREAD_FPA_STATE_FLAVOR
262 return get_regs (MACHINE_THREAD_FPA_STATE_FLAVOR
,
263 MACHINE_THREAD_FPA_STATE_COUNT
);
268 case PTRACE_POKETEXT
:
269 case PTRACE_POKEDATA
:
270 va_start (ap
, request
);
271 pid
= va_arg (ap
, pid_t
);
272 addr
= va_arg (ap
, void *);
273 data
= va_arg (ap
, int);
276 /* Read the page (or two pages, if the word lies on a boundary)
277 containing the addressed word. */
279 vm_address_t ourpage
;
281 task_t task
= __pid2task (pid
);
282 if (task
== MACH_PORT_NULL
)
284 data
= sizeof (natural_t
);
287 err
= read_data (task
, &ourpage
, &size
);
291 /* Now modify the specified word and write the page back. */
292 *(natural_t
*) ((vm_address_t
) addr
- trunc_page (addr
)
294 err
= __vm_write (task
, trunc_page (addr
), ourpage
, size
);
295 __vm_deallocate (__mach_task_self (), ourpage
, size
);
298 __mach_port_deallocate (__mach_task_self (), task
);
299 return err
? __hurd_fail (err
) : 0;
302 case PTRACE_READDATA
:
303 case PTRACE_READTEXT
:
304 va_start (ap
, request
);
305 pid
= va_arg (ap
, pid_t
);
306 addr
= va_arg (ap
, void *);
307 data
= va_arg (ap
, int);
308 addr2
= va_arg (ap
, void *);
312 vm_address_t ourpage
;
314 task_t task
= __pid2task (pid
);
315 if (task
== MACH_PORT_NULL
)
317 if (((vm_address_t
) addr2
+ data
) % __vm_page_size
== 0)
319 /* Perhaps we can write directly to the user's buffer. */
320 ourpage
= (vm_address_t
) addr2
;
328 err
= read_data (task
, &ourpage
, &size
);
329 __mach_port_deallocate (__mach_task_self (), task
);
330 if (!err
&& ourpage
!= (vm_address_t
) addr2
)
332 memcpy (addr2
, (void *) ourpage
, data
);
333 __vm_deallocate (__mach_task_self (), ourpage
, size
);
335 return err
? __hurd_fail (err
) : 0;
338 case PTRACE_WRITEDATA
:
339 case PTRACE_WRITETEXT
:
340 va_start (ap
, request
);
341 pid
= va_arg (ap
, pid_t
);
342 addr
= va_arg (ap
, void *);
343 data
= va_arg (ap
, int);
344 addr2
= va_arg (ap
, void *);
348 vm_address_t ourpage
;
350 task_t task
= __pid2task (pid
);
351 if (task
== MACH_PORT_NULL
)
353 if ((vm_address_t
) addr
% __vm_page_size
== 0 &&
354 (vm_address_t
) data
% __vm_page_size
== 0)
356 /* Writing whole pages; can go directly from the user's buffer. */
357 ourpage
= (vm_address_t
) addr2
;
363 /* Read the task's pages and modify our own copy. */
366 err
= read_data (task
, &ourpage
, &size
);
368 memcpy ((void *) ((vm_address_t
) addr
- trunc_page (addr
)
374 /* Write back the modified pages. */
375 err
= __vm_write (task
, trunc_page (addr
), ourpage
, size
);
376 __mach_port_deallocate (__mach_task_self (), task
);
377 return err
? __hurd_fail (err
) : 0;