mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
8f0c527e13
* hurd/hurd-raise.c (_hurd_raise_signal): Pass sigcode in msg_sig_post rpc. * hurd/hurdmsg.c (_S_msg_set_environment): Use argz.h functions instead of _hurd_split_args. (_S_msg_*_exec_flags): Functions removed. (_S_msg_startup_dosync): Stub removed. Sat May 4 02:11:55 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> * sysdeps/mach/hurd/ptrace.c: Set _hurdsig_traced instead of EXEC_TRACED bit in _hurd_exec_flags. Pass sigcode arg in msg_sig_post_untraced rpc. * sysdeps/mach/hurd/access.c: Don't pass io port in auth_user_authenticate rpc. * posix/sched.h: Fix typos. * sysdeps/mach/hurd/fork.c: Use new critical section lock. Clear _hurdsig_traced instead of EXEC_TRACED. * sysdeps/stub/nanosleep.c (nanosleep): Fix typo. * wcsmbs/wcstol.c: Find strtol.c in ../stdlib. * wcsmbs/wcstof.c: Find strtod.c in ../stdlib. * wcsmbs/wcstod.c: Likewise. * wcsmbs/wcstold.c: Likewise. * wcsmbs/wcwidth.h: Find cname-lookup.h in ../wctype. * string/envz.c (envz_entry): Use const. (envz_get, envz_remove): Likewise. (envz_entry): Return char *, not const char *. * string/envz.h: Fix decl. * string/argz-create.c: Use const in prototype. * string/argz-next.c: Likewise. * sysdeps/mach/hurd/sigprocmask.c: Pass sigcode arg to msg_sig_post. * sysdeps/mach/hurd/i386/sigreturn.c: Likewise. * sysdeps/mach/hurd/sigsuspend.c: Likewise. * sysdeps/mach/hurd/kill.c: Likewise. * hurd/hurdexec.c (_hurd_exec): Use new critical section lock. * hurd/catch-exc.c (_S_catch_exception_raise): Likewise. * hurd/sigunwind.c (_hurdsig_longjmp_from_handler): Likewise. * hurd/thread-cancel.c (hurd_thread_cancel, hurd_check_cancel): Likewise. * sysdeps/mach/hurd/jmp-unwind.c (_longjmp_unwind): Likewise. * sysdeps/mach/hurd/sigaction.c: Likewise. * sysdeps/mach/hurd/errnos.awk: Don't use ARGV in comment; it can change meaninglessly. * hurd/hurd/signal.h (struct hurd_sigstate): Replace critical section flag with a spin lock. (_hurd_critical_section_lock): Use spin_try_lock on that to see if we get it. No need to take SS->lock at all. (_hurd_critical_section_unlock): Unlock SS->critical_section_lock instead of clearing the old flag member. * hurd/hurdsig.c (_hurd_internal_post_signal): Use spin_lock_locked to test the critical section state. * hurd/hurdinit.c (_hurd_init): Set _hurdsig_traced from the intarray. * hurd/hurdkill.c (_hurd_sig_post): Pass 0 sigcode in msg_sig_post. * hurd/hurdsig.c (_hurd_internal_post_signal): Test _hurdsig_traced instead of testing (_hurd_exec_flags & EXEC_TRACED). (_S_msg_sig_post): Take sigcode arg and pass it through. (_S_msg_sig_post_untraced): Likewise. (reauth_proc): Don't pass proc port in auth_user_authenticate. * hurd/setauth.c (_hurd_setauth): Don't pass object ports in auth_user_authenticate RPCs, just the one-off rendezvous port. * hurd/dtable.c (reauth_dtable): Likewise. * hurd/hurdlookup.c (__hurd_file_name_lookup_retry): Likewise. * hurd/hurdexec.c (_hurd_exec): Pass 0 flags to file_exec. Pass sigcode arg to msg_sig_post. * string/argz.h (argz_create): Use const in prototype. * hurd/hurdinit.c (_hurd_proc_init): Test _hurdsig_traced instead of testing (_hurd_exec_flags & EXEC_TRACED). Pass sigcode arg to msg_sig_post. * hurd/hurd.h: Declare _hurdsig_traced. * string/argz.h (__argz_next): Cast ENTRY before returning it. * hurd/hurd/signal.h (_hurd_critical_section_unlock): Pass sigcode arg to msg_sig_post. * hurd/path-lookup.c: New file. * hurd/Makefile (routines): Add path-lookup. * hurd/hurd/lookup.h: Declare file_name_path_scan, hurd_file_name_path_lookup. * hurd/hurd.h: Declare file_name_path_lookup. * sysdeps/mach/hurd/select.c: The io_select rpc no longer has a TAG_ID argument. Instead, use a separate reply port for each RPC and put them all in a port set to wait for slow replies.
387 lines
11 KiB
C
387 lines
11 KiB
C
/* Process tracing interface `ptrace' for GNU Hurd.
|
|
Copyright (C) 1991, 1992, 1993, 1995, 1996 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with the GNU C Library; see the file COPYING.LIB. If
|
|
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
|
Cambridge, MA 02139, USA. */
|
|
|
|
#include <errno.h>
|
|
#include <sys/ptrace.h>
|
|
#include <sys/types.h>
|
|
#include <stdarg.h>
|
|
#include <hurd.h>
|
|
#include <hurd/signal.h>
|
|
#include <hurd/msg.h>
|
|
#include <thread_state.h>
|
|
|
|
/* Perform process tracing functions. REQUEST is one of the values
|
|
in <sys/ptrace.h>, and determines the action to be taken.
|
|
For all requests except PTRACE_TRACEME, PID specifies the process to be
|
|
traced.
|
|
|
|
PID and the other arguments described above for the various requests should
|
|
appear (those that are used for the particular request) as:
|
|
pid_t PID, void *ADDR, int DATA, void *ADDR2
|
|
after PID. */
|
|
int
|
|
ptrace (enum __ptrace_request request, ... )
|
|
{
|
|
pid_t pid;
|
|
void *addr, *addr2;
|
|
natural_t data;
|
|
va_list ap;
|
|
|
|
/* Read data from PID's address space, from ADDR for DATA bytes. */
|
|
error_t read_data (task_t task, vm_address_t *ourpage, vm_size_t *size)
|
|
{
|
|
/* Read the pages containing the addressed range. */
|
|
error_t err;
|
|
*size = round_page (addr + data) - trunc_page (addr);
|
|
err = __vm_read (task, trunc_page (addr), *size, ourpage, size);
|
|
return err;
|
|
}
|
|
|
|
/* Fetch the thread port for PID's user thread. */
|
|
error_t fetch_user_thread (task_t task, thread_t *thread)
|
|
{
|
|
thread_t threadbuf[3], *threads = threadbuf;
|
|
mach_msg_type_number_t nthreads = 3, i;
|
|
error_t err = __task_threads (task, &threads, &nthreads);
|
|
if (err)
|
|
return err;
|
|
if (nthreads == 0)
|
|
return EINVAL;
|
|
*thread = threads[0]; /* Assume user thread is first. */
|
|
for (i = 1; i < nthreads; ++i)
|
|
__mach_port_deallocate (__mach_task_self (), threads[i]);
|
|
if (threads != threadbuf)
|
|
__vm_deallocate (__mach_task_self (),
|
|
(vm_address_t) threads, nthreads * sizeof threads[0]);
|
|
return 0;
|
|
}
|
|
|
|
/* Fetch a thread state structure from PID and store it at ADDR. */
|
|
int get_regs (int flavor, mach_msg_type_number_t count)
|
|
{
|
|
error_t err;
|
|
task_t task = __pid2task (pid);
|
|
thread_t thread;
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
err = fetch_user_thread (task, &thread);
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
if (!err)
|
|
err = __thread_get_state (thread, flavor, addr, &count);
|
|
__mach_port_deallocate (__mach_task_self (), thread);
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
|
|
switch (request)
|
|
{
|
|
case PTRACE_TRACEME:
|
|
/* Make this process be traced. */
|
|
__sigfillset (&_hurdsig_traced);
|
|
__USEPORT (PROC, __proc_mark_traced (port));
|
|
break;
|
|
|
|
case PTRACE_CONT:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
data = va_arg (ap, int);
|
|
va_end (ap);
|
|
{
|
|
/* Send a DATA signal to PID, telling it to take the signal
|
|
normally even if it's traced. */
|
|
error_t err;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
if (data == SIGKILL)
|
|
err = __task_terminate (task);
|
|
else
|
|
{
|
|
if (addr != (void *) 1)
|
|
{
|
|
/* Move the user thread's PC to ADDR. */
|
|
thread_t thread;
|
|
err = fetch_user_thread (task, &thread);
|
|
if (!err)
|
|
{
|
|
struct machine_thread_state state;
|
|
mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
|
|
err = __thread_get_state (thread,
|
|
MACHINE_THREAD_STATE_FLAVOR,
|
|
(natural_t *) &state, &count);
|
|
if (!err)
|
|
{
|
|
MACHINE_THREAD_STATE_SET_PC (&state, addr);
|
|
err = __thread_set_state (thread,
|
|
MACHINE_THREAD_STATE_FLAVOR,
|
|
(natural_t *) &state, count);
|
|
}
|
|
|
|
}
|
|
__mach_port_deallocate (__mach_task_self (), thread);
|
|
}
|
|
else
|
|
err = 0;
|
|
|
|
if (! err)
|
|
/* Tell the process to take the signal (or just resume if 0). */
|
|
err = HURD_MSGPORT_RPC
|
|
(__USEPORT (PROC, __proc_getmsgport (port, pid, &msgport)),
|
|
0, 0, __msg_sig_post_untraced (msgport, data, 0, task));
|
|
}
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
case PTRACE_KILL:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
va_end (ap);
|
|
/* SIGKILL always just terminates the task,
|
|
so normal kill is just the same when traced. */
|
|
return kill (pid, SIGKILL);
|
|
|
|
case PTRACE_SINGLESTEP:
|
|
/* This is a machine-dependent kernel RPC on
|
|
machines that support it. Punt. */
|
|
return EOPNOTSUPP;
|
|
|
|
case PTRACE_ATTACH:
|
|
case PTRACE_DETACH:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
va_end (ap);
|
|
{
|
|
/* Tell PID to set or clear its trace bit. */
|
|
error_t err;
|
|
mach_port_t msgport;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
err = __USEPORT (PROC, __proc_getmsgport (port, pid, &msgport));
|
|
if (! err)
|
|
{
|
|
err = __msg_set_init_int (msgport, task, INIT_TRACEMASK,
|
|
request == PTRACE_DETACH ? 0 :
|
|
~(sigset_t) 0);
|
|
if (! err)
|
|
{
|
|
if (request == PTRACE_ATTACH)
|
|
/* Now stop the process. */
|
|
err = __msg_sig_post (msgport, SIGSTOP, 0, task);
|
|
else
|
|
/* Resume the process from tracing stop. */
|
|
err = __msg_sig_post_untraced (msgport, 0, 0, task);
|
|
}
|
|
__mach_port_deallocate (__mach_task_self (), msgport);
|
|
}
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
case PTRACE_PEEKTEXT:
|
|
case PTRACE_PEEKDATA:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
va_end (ap);
|
|
{
|
|
/* Read the page (or two pages, if the word lies on a boundary)
|
|
containing the addressed word. */
|
|
error_t err;
|
|
vm_address_t ourpage;
|
|
vm_size_t size;
|
|
natural_t word;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
data = sizeof word;
|
|
ourpage = 0;
|
|
size = 0;
|
|
err = read_data (task, &ourpage, &size);
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
if (err)
|
|
return __hurd_fail (err);
|
|
word = *(natural_t *) ((vm_address_t) addr - trunc_page (addr)
|
|
+ ourpage);
|
|
__vm_deallocate (__mach_task_self (), ourpage, size);
|
|
return word;
|
|
}
|
|
|
|
case PTRACE_PEEKUSER:
|
|
case PTRACE_POKEUSER:
|
|
/* U area, what's that? */
|
|
return EOPNOTSUPP;
|
|
|
|
case PTRACE_GETREGS:
|
|
case PTRACE_SETREGS:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
va_end (ap);
|
|
return get_regs (MACHINE_THREAD_STATE_FLAVOR,
|
|
MACHINE_THREAD_STATE_COUNT);
|
|
|
|
case PTRACE_GETFPREGS:
|
|
case PTRACE_SETFPREGS:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
va_end (ap);
|
|
#ifdef MACHINE_THREAD_FLOAT_STATE_FLAVOR
|
|
return get_regs (MACHINE_THREAD_FLOAT_STATE_FLAVOR,
|
|
MACHINE_THREAD_FLOAT_STATE_COUNT);
|
|
#else
|
|
return EOPNOTSUPP;
|
|
#endif
|
|
|
|
case PTRACE_GETFPAREGS:
|
|
case PTRACE_SETFPAREGS:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
va_end (ap);
|
|
#ifdef MACHINE_THREAD_FPA_STATE_FLAVOR
|
|
return get_regs (MACHINE_THREAD_FPA_STATE_FLAVOR,
|
|
MACHINE_THREAD_FPA_STATE_COUNT);
|
|
#else
|
|
return EOPNOTSUPP;
|
|
#endif
|
|
|
|
case PTRACE_POKETEXT:
|
|
case PTRACE_POKEDATA:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
data = va_arg (ap, int);
|
|
va_end (ap);
|
|
{
|
|
/* Read the page (or two pages, if the word lies on a boundary)
|
|
containing the addressed word. */
|
|
error_t err;
|
|
vm_address_t ourpage;
|
|
vm_size_t size;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
data = sizeof (natural_t);
|
|
ourpage = 0;
|
|
size = 0;
|
|
err = read_data (task, &ourpage, &size);
|
|
|
|
if (!err)
|
|
{
|
|
/* Now modify the specified word and write the page back. */
|
|
*(natural_t *) ((vm_address_t) addr - trunc_page (addr)
|
|
+ ourpage) = data;
|
|
err = __vm_write (task, trunc_page (addr), ourpage, size);
|
|
__vm_deallocate (__mach_task_self (), ourpage, size);
|
|
}
|
|
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
case PTRACE_READDATA:
|
|
case PTRACE_READTEXT:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
data = va_arg (ap, int);
|
|
addr2 = va_arg (ap, void *);
|
|
va_end (ap);
|
|
{
|
|
error_t err;
|
|
vm_address_t ourpage;
|
|
vm_size_t size;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
if (((vm_address_t) addr2 + data) % __vm_page_size == 0)
|
|
{
|
|
/* Perhaps we can write directly to the user's buffer. */
|
|
ourpage = (vm_address_t) addr2;
|
|
size = data;
|
|
}
|
|
else
|
|
{
|
|
ourpage = 0;
|
|
size = 0;
|
|
}
|
|
err = read_data (task, &ourpage, &size);
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
if (!err && ourpage != (vm_address_t) addr2)
|
|
{
|
|
memcpy (addr2, (void *) ourpage, data);
|
|
__vm_deallocate (__mach_task_self (), ourpage, size);
|
|
}
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
case PTRACE_WRITEDATA:
|
|
case PTRACE_WRITETEXT:
|
|
va_start (ap, request);
|
|
pid = va_arg (ap, pid_t);
|
|
addr = va_arg (ap, void *);
|
|
data = va_arg (ap, int);
|
|
addr2 = va_arg (ap, void *);
|
|
va_end (ap);
|
|
{
|
|
error_t err;
|
|
vm_address_t ourpage;
|
|
vm_size_t size;
|
|
task_t task = __pid2task (pid);
|
|
if (task == MACH_PORT_NULL)
|
|
return -1;
|
|
if ((vm_address_t) addr % __vm_page_size == 0 &&
|
|
(vm_address_t) data % __vm_page_size == 0)
|
|
{
|
|
/* Writing whole pages; can go directly from the user's buffer. */
|
|
ourpage = (vm_address_t) addr2;
|
|
size = data;
|
|
err = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Read the task's pages and modify our own copy. */
|
|
ourpage = 0;
|
|
size = 0;
|
|
err = read_data (task, &ourpage, &size);
|
|
if (!err)
|
|
memcpy ((void *) ((vm_address_t) addr - trunc_page (addr)
|
|
+ ourpage),
|
|
addr2,
|
|
data);
|
|
}
|
|
if (!err)
|
|
/* Write back the modified pages. */
|
|
err = __vm_write (task, trunc_page (addr), ourpage, size);
|
|
__mach_port_deallocate (__mach_task_self (), task);
|
|
return err ? __hurd_fail (err) : 0;
|
|
}
|
|
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|