/* Machine independent support for SVR4 /proc (process file system) for GDB.
- Copyright 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
- Written by Fred Fish at Cygnus Support.
+ Copyright 1991, 1992-97, 1998 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support. Changes for sysv4.2mp procfs
+ compatibility by Geoffrey Noer at Cygnus Solutions.
This file is part of GDB.
For information on the details of using /proc consult section proc(4)
in the UNIX System V Release 4 System Administrator's Reference Manual.
-The general register and floating point register sets are manipulated by
-separate ioctl's. This file makes the assumption that if FP0_REGNUM is
+The general register and floating point register sets are manipulated
+separately. This file makes the assumption that if FP0_REGNUM is
defined, then support for the floating point register set is desired,
regardless of whether or not the actual target has floating point hardware.
#include "target.h"
#include "command.h"
#include "gdbcore.h"
-#include "thread.h"
+#include "gdbthread.h"
-#define MAX_SYSCALLS 256 /* Maximum number of syscalls for table */
+#if !defined(SYS_lwp_create) && defined(SYS_lwpcreate)
+# define SYS_lwp_create SYS_lwpcreate
+#endif
+
+#if !defined(SYS_lwp_exit) && defined(SYS_lwpexit)
+# define SYS_lwp_exit SYS_lwpexit
+#endif
+
+#if !defined(SYS_lwp_wait) && defined(SYS_lwpwait)
+# define SYS_lwp_wait SYS_lwpwait
+#endif
+
+#if !defined(SYS_lwp_self) && defined(SYS_lwpself)
+# define SYS_lwp_self SYS_lwpself
+#endif
+
+#if !defined(SYS_lwp_info) && defined(SYS_lwpinfo)
+# define SYS_lwp_info SYS_lwpinfo
+#endif
+
+#if !defined(SYS_lwp_private) && defined(SYS_lwpprivate)
+# define SYS_lwp_private SYS_lwpprivate
+#endif
+
+#if !defined(SYS_lwp_kill) && defined(SYS_lwpkill)
+# define SYS_lwp_kill SYS_lwpkill
+#endif
+
+#if !defined(SYS_lwp_suspend) && defined(SYS_lwpsuspend)
+# define SYS_lwp_suspend SYS_lwpsuspend
+#endif
-#ifndef PROC_NAME_FMT
-#define PROC_NAME_FMT "/proc/%05d"
+#if !defined(SYS_lwp_continue) && defined(SYS_lwpcontinue)
+# define SYS_lwp_continue SYS_lwpcontinue
#endif
+/* the name of the proc status struct depends on the implementation */
+#ifdef HAVE_PSTATUS_T
+ typedef pstatus_t gdb_prstatus_t;
+#else
+ typedef prstatus_t gdb_prstatus_t;
+#endif
+
+#define MAX_SYSCALLS 256 /* Maximum number of syscalls for table */
+
+/* proc name formats may vary depending on the proc implementation */
+#ifdef HAVE_MULTIPLE_PROC_FDS
+# ifndef CTL_PROC_NAME_FMT
+# define CTL_PROC_NAME_FMT "/proc/%d/ctl"
+# define AS_PROC_NAME_FMT "/proc/%d/as"
+# define MAP_PROC_NAME_FMT "/proc/%d/map"
+# define STATUS_PROC_NAME_FMT "/proc/%d/status"
+# endif
+#else /* HAVE_MULTIPLE_PROC_FDS */
+# ifndef CTL_PROC_NAME_FMT
+# define CTL_PROC_NAME_FMT "/proc/%05d"
+# define AS_PROC_NAME_FMT "/proc/%05d"
+# define MAP_PROC_NAME_FMT "/proc/%05d"
+# define STATUS_PROC_NAME_FMT "/proc/%05d"
+# endif
+#endif /* HAVE_MULTIPLE_PROC_FDS */
+
+#define MAX_PROC_NAME_SIZE sizeof("/proc/1234567890/status")
+
extern struct target_ops procfs_ops; /* Forward declaration */
+int procfs_suppress_run = 0; /* Non-zero if procfs should pretend not to
+ be a runnable target. Used by targets
+ that can sit atop procfs, such as solaris
+ thread support. */
+
#if 1 /* FIXME: Gross and ugly hack to resolve coredep.c global */
CORE_ADDR kernel_u_addr;
#endif
#define si_uid _data._proc._pdata._kill.uid
#endif /* BROKEN_SIGINFO_H */
+/* Define structures for passing commands to /proc/pid/ctl file. Note that
+ while we create these for the PROCFS_USE_READ_WRITE world, we use them
+ and ignore the extra cmd int in other proc schemes.
+*/
+/* generic ctl msg */
+struct proc_ctl {
+ int cmd;
+ long data;
+};
+
+/* set general registers */
+struct greg_ctl {
+ int cmd;
+ gregset_t gregset;
+};
+
+/* set fp registers */
+struct fpreg_ctl {
+ int cmd;
+ fpregset_t fpregset;
+};
+
+/* set signals to be traced */
+struct sig_ctl {
+ int cmd;
+ sigset_t sigset;
+};
+
+/* set faults to be traced */
+struct flt_ctl {
+ int cmd;
+ fltset_t fltset;
+};
+
+/* set system calls to be traced */
+struct sys_ctl {
+ int cmd;
+ sysset_t sysset;
+};
+
+/* set current signal to be traced */
+struct sigi_ctl {
+ int cmd;
+ siginfo_t siginfo;
+};
+
/* All access to the inferior, either one started by gdb or one that has
been attached to, is controlled by an instance of a procinfo structure,
defined below. Since gdb currently only handles one inferior at a time,
struct procinfo {
struct procinfo *next;
int pid; /* Process ID of inferior */
- int fd; /* File descriptor for /proc entry */
+ int ctl_fd; /* File descriptor for /proc ctl file */
+ int status_fd; /* File descriptor for /proc status file */
+ int as_fd; /* File descriptor for /proc as file */
+ int map_fd; /* File descriptor for /proc map file */
char *pathname; /* Pathname to /proc entry */
int had_event; /* poll/select says something happened */
int was_stopped; /* Nonzero if was stopped prior to attach */
int nopass_next_sigstop; /* Don't pass a sigstop on next resume */
+#ifndef HAVE_NO_PRRUN_T
prrun_t prrun; /* Control state when it is run */
- prstatus_t prstatus; /* Current process status info */
- gregset_t gregset; /* General register set */
- fpregset_t fpregset; /* Floating point register set */
- fltset_t fltset; /* Current traced hardware fault set */
- sigset_t trace; /* Current traced signal set */
- sysset_t exitset; /* Current traced system call exit set */
- sysset_t entryset; /* Current traced system call entry set */
- fltset_t saved_fltset; /* Saved traced hardware fault set */
- sigset_t saved_trace; /* Saved traced signal set */
- sigset_t saved_sighold; /* Saved held signal set */
- sysset_t saved_exitset; /* Saved traced system call exit set */
- sysset_t saved_entryset; /* Saved traced system call entry set */
+#endif
+ gdb_prstatus_t prstatus; /* Current process status info */
+ struct greg_ctl gregset; /* General register set */
+ struct fpreg_ctl fpregset; /* Floating point register set */
+ struct flt_ctl fltset; /* Current traced hardware fault set */
+ struct sig_ctl trace; /* Current traced signal set */
+ struct sys_ctl exitset; /* Current traced system call exit set */
+ struct sys_ctl entryset; /* Current traced system call entry set */
+ struct sig_ctl saved_sighold; /* Saved held signal set */
+ struct flt_ctl saved_fltset; /* Saved traced hardware fault set */
+ struct sig_ctl saved_trace; /* Saved traced signal set */
+ struct sys_ctl saved_exitset; /* Saved traced system call exit set */
+ struct sys_ctl saved_entryset;/* Saved traced system call entry set */
+ int num_syscall_handlers; /* Number of syscall trap handlers
+ currently installed */
+ /* Pointer to list of syscall trap handlers */
+ struct procfs_syscall_handler *syscall_handlers;
+ int new_child; /* Non-zero if it's a new thread */
};
/* List of inferior process information */
static struct procinfo *procinfo_list = NULL;
-
static struct pollfd *poll_list; /* pollfds used for waiting on /proc */
static int num_poll_list = 0; /* Number of entries in poll_list */
-static int last_resume_pid = -1; /* Last pid used with procfs_resume */
-
/* Much of the information used in the /proc interface, particularly for
printing status information, is kept as tables of structures of the
following form. These tables can be used to map numeric values to
#endif
#if defined (PR_PCOMPAT)
{ PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect" },
+#endif
+#if defined (PR_MSACCT)
+ { PR_MSACCT, "PR_MSACCT", "Microstate accounting enabled" },
+#endif
+#if defined (PR_BPTADJ)
+ { PR_BPTADJ, "PR_BPTADJ", "Breakpoint PC adjustment in effect" },
+#endif
+#if defined (PR_ASLWP)
+ { PR_ASLWP, "PR_ASLWP", "Asynchronus signal LWP" },
#endif
{ 0, NULL, NULL }
};
#if defined (PR_SIGNALLED)
{ PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" },
#endif
-#if defined (PR_FAULTED)
- { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" },
-#endif
#if defined (PR_SYSENTRY)
{ PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" },
#endif
#if defined (PR_JOBCONTROL)
{ PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action" },
#endif
+#if defined (PR_FAULTED)
+ { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" },
+#endif
#if defined (PR_SUSPENDED)
{ PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" },
+#endif
+#if defined (PR_CHECKPOINT)
+ { PR_CHECKPOINT, "PR_CHECKPOINT", "(???)" },
#endif
{ 0, NULL, NULL }
};
/* Prototypes for local functions */
+static void procfs_stop PARAMS ((void));
+
+static int procfs_thread_alive PARAMS ((int));
+
+static int procfs_can_run PARAMS ((void));
+
+static void procfs_mourn_inferior PARAMS ((void));
+
+static void procfs_fetch_registers PARAMS ((int));
+
+static int procfs_wait PARAMS ((int, struct target_waitstatus *));
+
+static void procfs_open PARAMS ((char *, int));
+
+static void procfs_files_info PARAMS ((struct target_ops *));
+
+static void procfs_prepare_to_store PARAMS ((void));
+
+static void procfs_detach PARAMS ((char *, int));
+
+static void procfs_attach PARAMS ((char *, int));
+
+static void proc_set_exec_trap PARAMS ((void));
+
+static int procfs_init_inferior PARAMS ((int));
+
+static struct procinfo *create_procinfo PARAMS ((int));
+
+static void procfs_store_registers PARAMS ((int));
+
+static int procfs_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
+
+static void procfs_kill_inferior PARAMS ((void));
+
+static char *sigcodedesc PARAMS ((siginfo_t *));
+
+static char *sigcodename PARAMS ((siginfo_t *));
+
+static struct procinfo *wait_fd PARAMS ((void));
+
+static void remove_fd PARAMS ((struct procinfo *));
+
+static void add_fd PARAMS ((struct procinfo *));
+
static void set_proc_siginfo PARAMS ((struct procinfo *, int));
static void init_syscall_table PARAMS ((void));
static int proc_address_to_fd PARAMS ((struct procinfo *, CORE_ADDR, int));
-static int open_proc_file PARAMS ((int, struct procinfo *, int));
+static int open_proc_file PARAMS ((int, struct procinfo *, int, int));
static void close_proc_file PARAMS ((struct procinfo *));
static void unconditionally_kill_inferior PARAMS ((struct procinfo *));
-static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *)) ATTR_NORETURN;
+static NORETURN void proc_init_failed PARAMS ((struct procinfo *, char *, int)) ATTR_NORETURN;
static void info_proc PARAMS ((char *, int));
static void procfs_notice_signals PARAMS ((int pid));
+static void notice_signals PARAMS ((struct procinfo *, struct sig_ctl *));
+
static struct procinfo *find_procinfo PARAMS ((pid_t pid, int okfail));
+static int procfs_write_pcwstop PARAMS ((struct procinfo *));
+static int procfs_read_status PARAMS ((struct procinfo *));
+static void procfs_write_pckill PARAMS ((struct procinfo *));
+
+typedef int syscall_func_t PARAMS ((struct procinfo *pi, int syscall_num,
+ int why, int *rtnval, int *statval));
+
+static void procfs_set_syscall_trap PARAMS ((struct procinfo *pi,
+ int syscall_num, int flags,
+ syscall_func_t *func));
+
+static void procfs_clear_syscall_trap PARAMS ((struct procinfo *pi,
+ int syscall_num, int errok));
+
+#define PROCFS_SYSCALL_ENTRY 0x1 /* Trap on entry to sys call */
+#define PROCFS_SYSCALL_EXIT 0x2 /* Trap on exit from sys call */
+
+static syscall_func_t procfs_exit_handler;
+
+static syscall_func_t procfs_exec_handler;
+
+#ifdef SYS_sproc
+static syscall_func_t procfs_sproc_handler;
+static syscall_func_t procfs_fork_handler;
+#endif
+
+#ifdef SYS_lwp_create
+static syscall_func_t procfs_lwp_creation_handler;
+#endif
+
+static void modify_inherit_on_fork_flag PARAMS ((int fd, int flag));
+static void modify_run_on_last_close_flag PARAMS ((int fd, int flag));
+
+/* */
+
+struct procfs_syscall_handler
+{
+ int syscall_num; /* The number of the system call being handled */
+ /* The function to be called */
+ syscall_func_t *func;
+};
+
+static void procfs_resume PARAMS ((int pid, int step,
+ enum target_signal signo));
+
/* External function prototypes that can't be easily included in any
header file because the args are typedefs in system include files. */
extern void fill_gregset PARAMS ((gregset_t *, int));
+#ifdef FP0_REGNUM
extern void supply_fpregset PARAMS ((fpregset_t *));
extern void fill_fpregset PARAMS ((fpregset_t *, int));
+#endif
/*
poll_list = (struct pollfd *) xrealloc (poll_list,
(num_poll_list + 1)
* sizeof (struct pollfd));
- poll_list[num_poll_list].fd = pi->fd;
+ poll_list[num_poll_list].fd = pi->ctl_fd;
+#ifdef UNIXWARE
+ poll_list[num_poll_list].events = POLLWRNORM;
+#else
poll_list[num_poll_list].events = POLLPRI;
+#endif
num_poll_list++;
}
+/*
+
+LOCAL FUNCTION
+
+ remove_fd -- Remove the fd from the poll/select list
+
+SYNOPSIS
+
+ static void remove_fd (struct procinfo *);
+
+DESCRIPTION
+
+ Remove the fd of the supplied procinfo from the list of fds used
+ for poll/select operations.
+ */
+
static void
remove_fd (pi)
struct procinfo *pi;
for (i = 0; i < num_poll_list; i++)
{
- if (poll_list[i].fd == pi->fd)
+ if (poll_list[i].fd == pi->ctl_fd)
{
if (i != num_poll_list - 1)
- memcpy (poll_list, poll_list + i + 1,
+ memcpy (poll_list + i, poll_list + i + 1,
(num_poll_list - i - 1) * sizeof (struct pollfd));
num_poll_list--;
}
}
-#define LOSING_POLL unixware_sux
+/*
+
+LOCAL FUNCTION
+
+ procfs_read_status - get procfs fd status
+
+SYNOPSIS
+
+ static int procfs_read_status (pi) struct procinfo *pi;
+
+DESCRIPTION
+
+ Given a pointer to a procinfo struct, get the status of
+ the status_fd in the appropriate way. Returns 0 on failure,
+ 1 on success.
+ */
+
+static int
+procfs_read_status (pi)
+ struct procinfo *pi;
+{
+#ifdef PROCFS_USE_READ_WRITE
+ if ((lseek (pi->status_fd, 0, SEEK_SET) < 0) ||
+ (read (pi->status_fd, (char *) &pi->prstatus,
+ sizeof (gdb_prstatus_t)) != sizeof (gdb_prstatus_t)))
+#else
+ if (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) < 0)
+#endif
+ return 0;
+ else
+ return 1;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_write_pcwstop - send a PCWSTOP to procfs fd
+
+SYNOPSIS
+
+ static int procfs_write_pcwstop (pi) struct procinfo *pi;
+
+DESCRIPTION
+
+ Given a pointer to a procinfo struct, send a PCWSTOP to
+ the ctl_fd in the appropriate way. Returns 0 on failure,
+ 1 on success.
+ */
+
+static int
+procfs_write_pcwstop (pi)
+ struct procinfo *pi;
+{
+#ifdef PROCFS_USE_READ_WRITE
+ long cmd = PCWSTOP;
+ if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCWSTOP, &pi->prstatus) < 0)
+#endif
+ return 0;
+ else
+ return 1;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_write_pckill - send a kill to procfs fd
+
+SYNOPSIS
+
+ static void procfs_write_pckill (pi) struct procinfo *pi;
+
+DESCRIPTION
+
+ Given a pointer to a procinfo struct, send a kill to
+ the ctl_fd in the appropriate way. Returns 0 on failure,
+ 1 on success.
+ */
+
+static void
+procfs_write_pckill (pi)
+ struct procinfo *pi;
+{
+#ifdef PROCFS_USE_READ_WRITE
+ struct proc_ctl pctl;
+ pctl.cmd = PCKILL;
+ pctl.data = SIGKILL;
+ write (pi->ctl_fd, &pctl, sizeof (struct proc_ctl));
+#else
+ int signo = SIGKILL;
+ ioctl (pi->ctl_fd, PIOCKILL, &signo);
+#endif
+}
static struct procinfo *
wait_fd ()
{
- struct procinfo *pi;
+ struct procinfo *pi, *next_pi;
+#ifndef LOSING_POLL
int num_fds;
int i;
+#endif
set_sigint_trap (); /* Causes SIGINT to be passed on to the
attached process. */
set_sigio_trap ();
+ wait_again:
#ifndef LOSING_POLL
- num_fds = poll (poll_list, num_poll_list, -1);
-#else
+ while (1)
+ {
+ num_fds = poll (poll_list, num_poll_list, -1);
+ if (num_fds > 0)
+ break;
+ if (num_fds < 0 && errno == EINTR)
+ continue;
+ print_sys_errmsg ("poll failed", errno);
+ error ("Poll failed, returned %d", num_fds);
+ }
+#else /* LOSING_POLL */
pi = current_procinfo;
- while (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
+ while (!procfs_write_pcwstop (pi))
{
if (errno == ENOENT)
{
else if (errno != EINTR)
{
print_sys_errmsg (pi->pathname, errno);
- error ("PIOCWSTOP failed");
+ error ("procfs_write_pcwstop failed");
}
}
pi->had_event = 1;
-#endif
+#endif /* LOSING_POLL */
clear_sigint_trap ();
clear_sigio_trap ();
#ifndef LOSING_POLL
- if (num_fds <= 0)
- {
- print_sys_errmsg ("poll failed\n", errno);
- error ("Poll failed, returned %d", num_fds);
- }
-
for (i = 0; i < num_poll_list && num_fds > 0; i++)
{
- if ((poll_list[i].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL)) == 0)
+ if (0 == (poll_list[i].revents &
+ (POLLWRNORM | POLLPRI | POLLERR | POLLHUP | POLLNVAL)))
continue;
- for (pi = procinfo_list; pi; pi = pi->next)
+ for (pi = procinfo_list; pi; pi = next_pi)
{
- if (poll_list[i].fd == pi->fd)
+ next_pi = pi->next;
+ if (poll_list[i].fd == pi->ctl_fd)
{
- if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- error ("PIOCSTATUS failed");
- }
num_fds--;
+ if ((poll_list[i].revents & POLLHUP) != 0 ||
+ !procfs_read_status(pi))
+ { /* The LWP has apparently terminated. */
+ if (num_poll_list <= 1)
+ {
+ pi->prstatus.pr_flags = 0;
+ pi->had_event = 1;
+ break;
+ }
+ if (info_verbose)
+ printf_filtered ("LWP %d exited.\n",
+ (pi->pid >> 16) & 0xffff);
+ close_proc_file (pi);
+ if (num_fds != 0)
+ continue; /* already another event to process */
+ else
+ goto wait_again; /* wait for another event */
+ }
pi->had_event = 1;
break;
}
}
if (!pi)
- error ("procfs_wait: Couldn't find procinfo for fd %d\n",
+ error ("wait_fd: Couldn't find procinfo for fd %d\n",
poll_list[i].fd);
}
#endif /* LOSING_POLL */
int syscallnum;
{
static char locbuf[32];
- char *rtnval;
- if (syscallnum >= 0 && syscallnum < MAX_SYSCALLS)
- {
- rtnval = syscall_table[syscallnum];
- }
+ if (syscallnum >= 0 && syscallnum < MAX_SYSCALLS
+ && syscall_table[syscallnum] != NULL)
+ return syscall_table[syscallnum];
else
{
sprintf (locbuf, "syscall %u", syscallnum);
- rtnval = locbuf;
+ return locbuf;
}
- return (rtnval);
}
/*
#if defined (SYS_sys3b)
syscall_table[SYS_sys3b] = "sys3b";
#endif
+#if defined (SYS_sysi86)
+ syscall_table[SYS_sysi86] = "sysi86";
+#endif
#if defined (SYS_acct)
syscall_table[SYS_acct] = "acct";
#endif
#if defined (SYS_sproc)
syscall_table[SYS_sproc] = "sproc";
#endif
-}
-
-/*
-
-LOCAL FUNCTION
-
- procfs_kill_inferior - kill any currently inferior
-
-SYNOPSIS
-
- void procfs_kill_inferior (void)
-
-DESCRIPTION
-
- Kill any current inferior.
-
-NOTES
-
- Kills even attached inferiors. Presumably the user has already
- been prompted that the inferior is an attached one rather than
- one started by gdb. (FIXME?)
-
-*/
-
-static void
-procfs_kill_inferior ()
-{
- target_mourn_inferior ();
-}
-
-/*
-
-LOCAL FUNCTION
-
- unconditionally_kill_inferior - terminate the inferior
-
-SYNOPSIS
-
- static void unconditionally_kill_inferior (struct procinfo *)
-
-DESCRIPTION
-
- Kill the specified inferior.
-
-NOTE
-
- A possibly useful enhancement would be to first try sending
- the inferior a terminate signal, politely asking it to commit
- suicide, before we murder it (we could call that
- politely_kill_inferior()).
-
-*/
-
-static void
-unconditionally_kill_inferior (pi)
- struct procinfo *pi;
-{
- int signo;
- int ppid;
-
- ppid = pi->prstatus.pr_ppid;
-
- signo = SIGKILL;
-
-#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL
- /* Alpha OSF/1-3.x procfs needs a clear of the current signal
- before the PIOCKILL, otherwise it might generate a corrupted core
- file for the inferior. */
- ioctl (pi->fd, PIOCSSIG, NULL);
+#if defined (SYS_keyctl)
+ syscall_table[SYS_keyctl] = "keyctl";
+#endif
+#if defined (SYS_secsys)
+ syscall_table[SYS_secsys] = "secsys";
+#endif
+#if defined (SYS_filepriv)
+ syscall_table[SYS_filepriv] = "filepriv";
+#endif
+#if defined (SYS_procpriv)
+ syscall_table[SYS_procpriv] = "procpriv";
+#endif
+#if defined (SYS_devstat)
+ syscall_table[SYS_devstat] = "devstat";
+#endif
+#if defined (SYS_aclipc)
+ syscall_table[SYS_aclipc] = "aclipc";
+#endif
+#if defined (SYS_fdevstat)
+ syscall_table[SYS_fdevstat] = "fdevstat";
+#endif
+#if defined (SYS_flvlfile)
+ syscall_table[SYS_flvlfile] = "flvlfile";
+#endif
+#if defined (SYS_lvlfile)
+ syscall_table[SYS_lvlfile] = "lvlfile";
+#endif
+#if defined (SYS_lvlequal)
+ syscall_table[SYS_lvlequal] = "lvlequal";
+#endif
+#if defined (SYS_lvlproc)
+ syscall_table[SYS_lvlproc] = "lvlproc";
+#endif
+#if defined (SYS_lvlipc)
+ syscall_table[SYS_lvlipc] = "lvlipc";
+#endif
+#if defined (SYS_acl)
+ syscall_table[SYS_acl] = "acl";
+#endif
+#if defined (SYS_auditevt)
+ syscall_table[SYS_auditevt] = "auditevt";
+#endif
+#if defined (SYS_auditctl)
+ syscall_table[SYS_auditctl] = "auditctl";
+#endif
+#if defined (SYS_auditdmp)
+ syscall_table[SYS_auditdmp] = "auditdmp";
+#endif
+#if defined (SYS_auditlog)
+ syscall_table[SYS_auditlog] = "auditlog";
+#endif
+#if defined (SYS_auditbuf)
+ syscall_table[SYS_auditbuf] = "auditbuf";
+#endif
+#if defined (SYS_lvldom)
+ syscall_table[SYS_lvldom] = "lvldom";
+#endif
+#if defined (SYS_lvlvfs)
+ syscall_table[SYS_lvlvfs] = "lvlvfs";
+#endif
+#if defined (SYS_mkmld)
+ syscall_table[SYS_mkmld] = "mkmld";
+#endif
+#if defined (SYS_mldmode)
+ syscall_table[SYS_mldmode] = "mldmode";
+#endif
+#if defined (SYS_secadvise)
+ syscall_table[SYS_secadvise] = "secadvise";
+#endif
+#if defined (SYS_online)
+ syscall_table[SYS_online] = "online";
+#endif
+#if defined (SYS_setitimer)
+ syscall_table[SYS_setitimer] = "setitimer";
+#endif
+#if defined (SYS_getitimer)
+ syscall_table[SYS_getitimer] = "getitimer";
+#endif
+#if defined (SYS_gettimeofday)
+ syscall_table[SYS_gettimeofday] = "gettimeofday";
+#endif
+#if defined (SYS_settimeofday)
+ syscall_table[SYS_settimeofday] = "settimeofday";
+#endif
+#if defined (SYS_lwp_create)
+ syscall_table[SYS_lwp_create] = "_lwp_create";
+#endif
+#if defined (SYS_lwp_exit)
+ syscall_table[SYS_lwp_exit] = "_lwp_exit";
+#endif
+#if defined (SYS_lwp_wait)
+ syscall_table[SYS_lwp_wait] = "_lwp_wait";
+#endif
+#if defined (SYS_lwp_self)
+ syscall_table[SYS_lwp_self] = "_lwp_self";
+#endif
+#if defined (SYS_lwp_info)
+ syscall_table[SYS_lwp_info] = "_lwp_info";
+#endif
+#if defined (SYS_lwp_private)
+ syscall_table[SYS_lwp_private] = "_lwp_private";
+#endif
+#if defined (SYS_processor_bind)
+ syscall_table[SYS_processor_bind] = "processor_bind";
+#endif
+#if defined (SYS_processor_exbind)
+ syscall_table[SYS_processor_exbind] = "processor_exbind";
+#endif
+#if defined (SYS_prepblock)
+ syscall_table[SYS_prepblock] = "prepblock";
+#endif
+#if defined (SYS_block)
+ syscall_table[SYS_block] = "block";
+#endif
+#if defined (SYS_rdblock)
+ syscall_table[SYS_rdblock] = "rdblock";
+#endif
+#if defined (SYS_unblock)
+ syscall_table[SYS_unblock] = "unblock";
+#endif
+#if defined (SYS_cancelblock)
+ syscall_table[SYS_cancelblock] = "cancelblock";
+#endif
+#if defined (SYS_pread)
+ syscall_table[SYS_pread] = "pread";
+#endif
+#if defined (SYS_pwrite)
+ syscall_table[SYS_pwrite] = "pwrite";
+#endif
+#if defined (SYS_truncate)
+ syscall_table[SYS_truncate] = "truncate";
+#endif
+#if defined (SYS_ftruncate)
+ syscall_table[SYS_ftruncate] = "ftruncate";
+#endif
+#if defined (SYS_lwp_kill)
+ syscall_table[SYS_lwp_kill] = "_lwp_kill";
+#endif
+#if defined (SYS_sigwait)
+ syscall_table[SYS_sigwait] = "sigwait";
+#endif
+#if defined (SYS_fork1)
+ syscall_table[SYS_fork1] = "fork1";
+#endif
+#if defined (SYS_forkall)
+ syscall_table[SYS_forkall] = "forkall";
+#endif
+#if defined (SYS_modload)
+ syscall_table[SYS_modload] = "modload";
+#endif
+#if defined (SYS_moduload)
+ syscall_table[SYS_moduload] = "moduload";
+#endif
+#if defined (SYS_modpath)
+ syscall_table[SYS_modpath] = "modpath";
+#endif
+#if defined (SYS_modstat)
+ syscall_table[SYS_modstat] = "modstat";
+#endif
+#if defined (SYS_modadm)
+ syscall_table[SYS_modadm] = "modadm";
+#endif
+#if defined (SYS_getksym)
+ syscall_table[SYS_getksym] = "getksym";
+#endif
+#if defined (SYS_lwp_suspend)
+ syscall_table[SYS_lwp_suspend] = "_lwp_suspend";
+#endif
+#if defined (SYS_lwp_continue)
+ syscall_table[SYS_lwp_continue] = "_lwp_continue";
+#endif
+#if defined (SYS_priocntllst)
+ syscall_table[SYS_priocntllst] = "priocntllst";
+#endif
+#if defined (SYS_sleep)
+ syscall_table[SYS_sleep] = "sleep";
+#endif
+#if defined (SYS_lwp_sema_wait)
+ syscall_table[SYS_lwp_sema_wait] = "_lwp_sema_wait";
+#endif
+#if defined (SYS_lwp_sema_post)
+ syscall_table[SYS_lwp_sema_post] = "_lwp_sema_post";
+#endif
+#if defined (SYS_lwp_sema_trywait)
+ syscall_table[SYS_lwp_sema_trywait] = "lwp_sema_trywait";
+#endif
+#if defined(SYS_fstatvfs64)
+ syscall_table[SYS_fstatvfs64] = "fstatvfs64";
+#endif
+#if defined(SYS_statvfs64)
+ syscall_table[SYS_statvfs64] = "statvfs64";
+#endif
+#if defined(SYS_ftruncate64)
+ syscall_table[SYS_ftruncate64] = "ftruncate64";
+#endif
+#if defined(SYS_truncate64)
+ syscall_table[SYS_truncate64] = "truncate64";
+#endif
+#if defined(SYS_getrlimit64)
+ syscall_table[SYS_getrlimit64] = "getrlimit64";
+#endif
+#if defined(SYS_setrlimit64)
+ syscall_table[SYS_setrlimit64] = "setrlimit64";
+#endif
+#if defined(SYS_lseek64)
+ syscall_table[SYS_lseek64] = "lseek64";
+#endif
+#if defined(SYS_mmap64)
+ syscall_table[SYS_mmap64] = "mmap64";
+#endif
+#if defined(SYS_pread64)
+ syscall_table[SYS_pread64] = "pread64";
+#endif
+#if defined(SYS_creat64)
+ syscall_table[SYS_creat64] = "creat64";
+#endif
+#if defined(SYS_dshmsys)
+ syscall_table[SYS_dshmsys] = "dshmsys";
+#endif
+#if defined(SYS_invlpg)
+ syscall_table[SYS_invlpg] = "invlpg";
+#endif
+#if defined(SYS_cg_ids)
+ syscall_table[SYS_cg_ids] = "cg_ids";
+#endif
+#if defined(SYS_cg_processors)
+ syscall_table[SYS_cg_processors] = "cg_processors";
+#endif
+#if defined(SYS_cg_info)
+ syscall_table[SYS_cg_info] = "cg_info";
+#endif
+#if defined(SYS_cg_bind)
+ syscall_table[SYS_cg_bind] = "cg_bind";
+#endif
+#if defined(SYS_cg_current)
+ syscall_table[SYS_cg_current] = "cg_current";
+#endif
+#if defined(SYS_cg_memloc)
+ syscall_table[SYS_cg_memloc] = "cg_memloc";
+#endif
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_kill_inferior - kill any currently inferior
+
+SYNOPSIS
+
+ void procfs_kill_inferior (void)
+
+DESCRIPTION
+
+ Kill any current inferior.
+
+NOTES
+
+ Kills even attached inferiors. Presumably the user has already
+ been prompted that the inferior is an attached one rather than
+ one started by gdb. (FIXME?)
+
+*/
+
+static void
+procfs_kill_inferior ()
+{
+ target_mourn_inferior ();
+}
+
+/*
+
+LOCAL FUNCTION
+
+ unconditionally_kill_inferior - terminate the inferior
+
+SYNOPSIS
+
+ static void unconditionally_kill_inferior (struct procinfo *)
+
+DESCRIPTION
+
+ Kill the specified inferior.
+
+NOTE
+
+ A possibly useful enhancement would be to first try sending
+ the inferior a terminate signal, politely asking it to commit
+ suicide, before we murder it (we could call that
+ politely_kill_inferior()).
+
+*/
+
+static void
+unconditionally_kill_inferior (pi)
+ struct procinfo *pi;
+{
+ int ppid;
+ struct proc_ctl pctl;
+
+ ppid = pi->prstatus.pr_ppid;
+
+#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL
+ /* Alpha OSF/1-3.x procfs needs a clear of the current signal
+ before the PIOCKILL, otherwise it might generate a corrupted core
+ file for the inferior. */
+ ioctl (pi->ctl_fd, PIOCSSIG, NULL);
#endif
#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL
/* Alpha OSF/1-2.x procfs needs a PIOCSSIG call with a SIGKILL signal
struct siginfo newsiginfo;
memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
- newsiginfo.si_signo = signo;
+ newsiginfo.si_signo = SIGKILL;
newsiginfo.si_code = 0;
newsiginfo.si_errno = 0;
newsiginfo.si_pid = getpid ();
newsiginfo.si_uid = getuid ();
- ioctl (pi->fd, PIOCSSIG, &newsiginfo);
+ ioctl (pi->ctl_fd, PIOCSSIG, &newsiginfo);
}
-#else
- ioctl (pi->fd, PIOCKILL, &signo);
-#endif
+#else /* PROCFS_NEED_PIOCSSIG_FOR_KILL */
+ procfs_write_pckill (pi);
+#endif /* PROCFS_NEED_PIOCSSIG_FOR_KILL */
close_proc_file (pi);
pi = current_procinfo;
- if (lseek(pi->fd, (off_t) memaddr, 0) == (off_t) memaddr)
+ if (lseek(pi->as_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
{
if (dowrite)
{
- nbytes = write (pi->fd, myaddr, len);
+ nbytes = write (pi->as_fd, myaddr, len);
}
else
{
- nbytes = read (pi->fd, myaddr, len);
+ nbytes = read (pi->as_fd, myaddr, len);
}
if (nbytes < 0)
{
int regno;
{
struct procinfo *pi;
+#ifdef PROCFS_USE_READ_WRITE
+ struct greg_ctl greg;
+ struct fpreg_ctl fpreg;
+#endif
pi = current_procinfo;
+#ifdef PROCFS_USE_READ_WRITE
if (regno != -1)
{
- ioctl (pi->fd, PIOCGREG, &pi->gregset);
+ procfs_read_status (pi);
+ memcpy ((char *) &greg.gregset,
+ (char *) &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs,
+ sizeof (gregset_t));
}
- fill_gregset (&pi->gregset, regno);
- ioctl (pi->fd, PIOCSREG, &pi->gregset);
+ fill_gregset (&greg.gregset, regno);
+ greg.cmd = PCSREG;
+ write (pi->ctl_fd, &greg, sizeof (greg));
+#else /* PROCFS_USE_READ_WRITE */
+ if (regno != -1)
+ {
+ ioctl (pi->ctl_fd, PIOCGREG, &pi->gregset.gregset);
+ }
+ fill_gregset (&pi->gregset.gregset, regno);
+ ioctl (pi->ctl_fd, PIOCSREG, &pi->gregset.gregset);
+#endif /* PROCFS_USE_READ_WRITE */
#if defined (FP0_REGNUM)
target has floating point hardware. Since we ignore the returned value,
we'll never know whether it worked or not anyway. */
+#ifdef PROCFS_USE_READ_WRITE
+ if (regno != -1)
+ {
+ procfs_read_status (pi);
+ memcpy ((char *) &fpreg.fpregset,
+ (char *) &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs,
+ sizeof (fpregset_t));
+ }
+ fill_fpregset (&fpreg.fpregset, regno);
+ fpreg.cmd = PCSFPREG;
+ write (pi->ctl_fd, &fpreg, sizeof (fpreg));
+#else /* PROCFS_USE_READ_WRITE */
if (regno != -1)
{
- ioctl (pi->fd, PIOCGFPREG, &pi->fpregset);
+ ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset.fpregset);
}
- fill_fpregset (&pi->fpregset, regno);
- ioctl (pi->fd, PIOCSFPREG, &pi->fpregset);
+ fill_fpregset (&pi->fpregset.fpregset, regno);
+ ioctl (pi->ctl_fd, PIOCSFPREG, &pi->fpregset.fpregset);
+#endif /* PROCFS_USE_READ_WRITE */
#endif /* FP0_REGNUM */
LOCAL FUNCTION
- create_procinfo - initialize access to a /proc entry
+ init_procinfo - setup a procinfo struct and connect it to a process
SYNOPSIS
- struct procinfo * create_procinfo (int pid)
+ struct procinfo * init_procinfo (int pid)
DESCRIPTION
Allocate a procinfo structure, open the /proc file and then set up the
set of signals and faults that are to be traced. Returns a pointer to
- the new procinfo structure.
+ the new procinfo structure.
NOTES
*/
static struct procinfo *
-create_procinfo (pid)
+init_procinfo (pid, kill)
int pid;
+ int kill;
{
- struct procinfo *pi;
+ struct procinfo *pi = (struct procinfo *)
+ xmalloc (sizeof (struct procinfo));
+ struct sig_ctl sctl;
+ struct flt_ctl fctl;
- pi = find_procinfo (pid, 1);
- if (pi != NULL)
- return pi; /* All done! It already exists */
+ memset ((char *) pi, 0, sizeof (*pi));
+ if (!open_proc_file (pid, pi, O_RDWR, 1))
+ proc_init_failed (pi, "can't open process file", kill);
- pi = (struct procinfo *) xmalloc (sizeof (struct procinfo));
+ /* open_proc_file may modify pid. */
- if (!open_proc_file (pid, pi, O_RDWR))
- proc_init_failed (pi, "can't open process file");
+ pid = pi -> pid;
/* Add new process to process info list */
add_fd (pi); /* Add to list for poll/select */
+ /* Remember some things about the inferior that we will, or might, change
+ so that we can restore them when we detach. */
+#ifdef UNIXWARE
+ memcpy ((char *) &pi->saved_trace.sigset,
+ (char *) &pi->prstatus.pr_sigtrace, sizeof (sigset_t));
+ memcpy ((char *) &pi->saved_fltset.fltset,
+ (char *) &pi->prstatus.pr_flttrace, sizeof (fltset_t));
+ memcpy ((char *) &pi->saved_entryset.sysset,
+ (char *) &pi->prstatus.pr_sysentry, sizeof (sysset_t));
+ memcpy ((char *) &pi->saved_exitset.sysset,
+ (char *) &pi->prstatus.pr_sysexit, sizeof (sysset_t));
+
+ /* Set up trace and fault sets, as gdb expects them. */
+
+ prfillset (&sctl.sigset);
+ notice_signals (pi, &sctl);
+ prfillset (&fctl.fltset);
+ prdelset (&fctl.fltset, FLTPAGE);
+
+#else /* ! UNIXWARE */
+ ioctl (pi->ctl_fd, PIOCGTRACE, &pi->saved_trace.sigset);
+ ioctl (pi->ctl_fd, PIOCGHOLD, &pi->saved_sighold.sigset);
+ ioctl (pi->ctl_fd, PIOCGFAULT, &pi->saved_fltset.fltset);
+ ioctl (pi->ctl_fd, PIOCGENTRY, &pi->saved_entryset.sysset);
+ ioctl (pi->ctl_fd, PIOCGEXIT, &pi->saved_exitset.sysset);
+
+ /* Set up trace and fault sets, as gdb expects them. */
+
memset ((char *) &pi->prrun, 0, sizeof (pi->prrun));
prfillset (&pi->prrun.pr_trace);
procfs_notice_signals (pid);
prfillset (&pi->prrun.pr_fault);
prdelset (&pi->prrun.pr_fault, FLTPAGE);
-
#ifdef PROCFS_DONT_TRACE_FAULTS
premptyset (&pi->prrun.pr_fault);
#endif
+#endif /* UNIXWARE */
- if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
- proc_init_failed (pi, "PIOCWSTOP failed");
-
- if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0)
- proc_init_failed (pi, "PIOCSFAULT failed");
+ if (!procfs_read_status (pi))
+ proc_init_failed (pi, "procfs_read_status failed", kill);
return pi;
}
LOCAL FUNCTION
- procfs_init_inferior - initialize target vector and access to a
- /proc entry
+ create_procinfo - initialize access to a /proc entry
SYNOPSIS
- void procfs_init_inferior (int pid)
+ struct procinfo * create_procinfo (int pid)
DESCRIPTION
- When gdb starts an inferior, this function is called in the parent
- process immediately after the fork. It waits for the child to stop
- on the return from the exec system call (the child itself takes care
- of ensuring that this is set up), then sets up the set of signals
- and faults that are to be traced.
+ Allocate a procinfo structure, open the /proc file and then set up the
+ set of signals and faults that are to be traced. Returns a pointer to
+ the new procinfo structure.
NOTES
*/
-static void
-procfs_init_inferior (pid)
+static struct procinfo *
+create_procinfo (pid)
int pid;
{
- push_target (&procfs_ops);
+ struct procinfo *pi;
+ struct sig_ctl sctl;
+ struct flt_ctl fctl;
+
+ pi = find_procinfo (pid, 1);
+ if (pi != NULL)
+ return pi; /* All done! It already exists */
- create_procinfo (pid);
- add_thread (pid); /* Setup initial thread */
+ pi = init_procinfo (pid, 1);
-#ifdef START_INFERIOR_TRAPS_EXPECTED
- startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+#ifndef UNIXWARE
+/* A bug in Solaris (2.5 at least) causes PIOCWSTOP to hang on LWPs that are
+ already stopped, even if they all have PR_ASYNC set. */
+ if (!(pi->prstatus.pr_flags & PR_STOPPED))
+#endif
+ if (!procfs_write_pcwstop (pi))
+ proc_init_failed (pi, "procfs_write_pcwstop failed", 1);
+
+#ifdef PROCFS_USE_READ_WRITE
+ fctl.cmd = PCSFAULT;
+ if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0)
+ proc_init_failed (pi, "PCSFAULT failed", 1);
#else
- /* One trap to exec the shell, one to exec the program being debugged. */
- startup_inferior (2);
+ if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0)
+ proc_init_failed (pi, "PIOCSFAULT failed", 1);
#endif
+
+ return pi;
}
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- procfs_notice_signals
+ procfs_exit_handler - handle entry into the _exit syscall
SYNOPSIS
- static void procfs_notice_signals (int pid);
+ int procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp)
DESCRIPTION
- When the user changes the state of gdb's signal handling via the
- "handle" command, this function gets called to see if any change
- in the /proc interface is required. It is also called internally
- by other /proc interface functions to initialize the state of
- the traced signal set.
+ This routine is called when an inferior process enters the _exit()
+ system call. It continues the process, and then collects the exit
+ status and pid which are returned in *statvalp and *rtnvalp. After
+ that it returns non-zero to indicate that procfs_wait should wake up.
+
+NOTES
+ There is probably a better way to do this.
- One thing it does is that signals for which the state is "nostop",
- "noprint", and "pass", have their trace bits reset in the pr_trace
- field, so that they are no longer traced. This allows them to be
- delivered directly to the inferior without the debugger ever being
- involved.
*/
-static void
-procfs_notice_signals (pid)
- int pid;
+static int
+procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
{
- int signo;
- struct procinfo *pi;
+ struct procinfo *temp_pi, *next_pi;
+ struct proc_ctl pctl;
- pi = find_procinfo (pid, 0);
+#ifdef UNIXWARE
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+#else
+ pi->prrun.pr_flags = PRCFAULT;
+#endif
- for (signo = 0; signo < NSIG; signo++)
+#ifdef PROCFS_USE_READ_WRITE
+ if (write (pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+#endif
+ perror_with_name (pi->pathname);
+
+ if (attach_flag)
{
- if (signal_stop_state (target_signal_from_host (signo)) == 0 &&
- signal_print_state (target_signal_from_host (signo)) == 0 &&
- signal_pass_state (target_signal_from_host (signo)) == 1)
- {
- prdelset (&pi->prrun.pr_trace, signo);
- }
- else
- {
- praddset (&pi->prrun.pr_trace, signo);
- }
+ /* Claim it exited (don't call wait). */
+ if (info_verbose)
+ printf_filtered ("(attached process has exited)\n");
+ *statvalp = 0;
+ *rtnvalp = inferior_pid;
+ }
+ else
+ {
+ *rtnvalp = wait (statvalp);
+ if (*rtnvalp >= 0)
+ *rtnvalp = pi->pid;
}
- if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace))
+
+ /* Close ALL open proc file handles,
+ except the one that called SYS_exit. */
+ for (temp_pi = procinfo_list; temp_pi; temp_pi = next_pi)
{
- print_sys_errmsg ("PIOCSTRACE failed", errno);
+ next_pi = temp_pi->next;
+ if (temp_pi == pi)
+ continue; /* Handled below */
+ close_proc_file (temp_pi);
}
+ return 1;
}
/*
LOCAL FUNCTION
- proc_set_exec_trap -- arrange for exec'd child to halt at startup
+ procfs_exec_handler - handle exit from the exec family of syscalls
SYNOPSIS
- void proc_set_exec_trap (void)
+ int procfs_exec_handler (pi, syscall_num, why, rtnvalp, statvalp)
DESCRIPTION
- This function is called in the child process when starting up
- an inferior, prior to doing the exec of the actual inferior.
- It sets the child process's exitset to make exit from the exec
- system call an event of interest to stop on, and then simply
- returns. The child does the exec, the system call returns, and
- the child stops at the first instruction, ready for the gdb
- parent process to take control of it.
+ This routine is called when an inferior process is about to finish any
+ of the exec() family of system calls. It pretends that we got a
+ SIGTRAP (for compatibility with ptrace behavior), and returns non-zero
+ to tell procfs_wait to wake up.
-NOTE
+NOTES
+ This need for compatibility with ptrace is questionable. In the
+ future, it shouldn't be necessary.
+
+ */
+
+static int
+procfs_exec_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
+{
+ *statvalp = (SIGTRAP << 8) | 0177;
+
+ return 1;
+}
+
+#if defined(SYS_sproc) && !defined(UNIXWARE)
+/* IRIX lwp creation system call */
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_sproc_handler - handle exit from the sproc syscall
+
+SYNOPSIS
+
+ int procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+ This routine is called when an inferior process is about to finish an
+ sproc() system call. This is the system call that IRIX uses to create
+ a lightweight process. When the target process gets this event, we can
+ look at rval1 to find the new child processes ID, and create a new
+ procinfo struct from that.
+
+ After that, it pretends that we got a SIGTRAP, and returns non-zero
+ to tell procfs_wait to wake up. Subsequently, wait_for_inferior gets
+ woken up, sees the new process and continues it.
+
+NOTES
+ We actually never see the child exiting from sproc because we will
+ shortly stop the child with PIOCSTOP, which is then registered as the
+ event of interest.
+ */
+
+static int
+procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
+{
+/* We've just detected the completion of an sproc system call. Now we need to
+ setup a procinfo struct for this thread, and notify the thread system of the
+ new arrival. */
+
+/* If sproc failed, then nothing interesting happened. Continue the process
+ and go back to sleep. */
+
+ if (pi->prstatus.pr_errno != 0)
+ {
+ pi->prrun.pr_flags &= PRSTEP;
+ pi->prrun.pr_flags |= PRCFAULT;
+
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+ }
+
+ /* At this point, the new thread is stopped at it's first instruction, and
+ the parent is stopped at the exit from sproc. */
+
+ /* Notify the caller of the arrival of a new thread. */
+ create_procinfo (pi->prstatus.pr_rval1);
+
+ *rtnvalp = pi->prstatus.pr_rval1;
+ *statvalp = (SIGTRAP << 8) | 0177;
+
+ return 1;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_fork_handler - handle exit from the fork syscall
+
+SYNOPSIS
+
+ int procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+ This routine is called when an inferior process is about to finish a
+ fork() system call. We will open up the new process, and then close
+ it, which releases it from the clutches of the debugger.
+
+ After that, we continue the target process as though nothing had
+ happened.
+
+NOTES
+ This is necessary for IRIX because we have to set PR_FORK in order
+ to catch the creation of lwps (via sproc()). When an actual fork
+ occurs, it becomes necessary to reset the forks debugger flags and
+ continue it because we can't hack multiple processes yet.
+ */
+
+static int
+procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
+{
+ struct procinfo *pitemp;
+
+/* At this point, we've detected the completion of a fork (or vfork) call in
+ our child. The grandchild is also stopped because we set inherit-on-fork
+ earlier. (Note that nobody has the grandchilds' /proc file open at this
+ point.) We will release the grandchild from the debugger by opening it's
+ /proc file and then closing it. Since run-on-last-close is set, the
+ grandchild continues on its' merry way. */
+
+
+ pitemp = create_procinfo (pi->prstatus.pr_rval1);
+ if (pitemp)
+ close_proc_file (pitemp);
+
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+}
+#endif /* SYS_sproc && !UNIXWARE */
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_set_inferior_syscall_traps - setup the syscall traps
+
+SYNOPSIS
+
+ void procfs_set_inferior_syscall_traps (struct procinfo *pip)
+
+DESCRIPTION
+
+ Called for each "procinfo" (process, thread, or LWP) in the
+ inferior, to register for notification of and handlers for
+ syscall traps in the inferior.
+
+ */
+
+static void
+procfs_set_inferior_syscall_traps (pip)
+ struct procinfo *pip;
+{
+ procfs_set_syscall_trap (pip, SYS_exit, PROCFS_SYSCALL_ENTRY,
+ procfs_exit_handler);
+
+#ifndef PRFS_STOPEXEC
+#ifdef SYS_exec
+ procfs_set_syscall_trap (pip, SYS_exec, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#ifdef SYS_execv
+ procfs_set_syscall_trap (pip, SYS_execv, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#ifdef SYS_execve
+ procfs_set_syscall_trap (pip, SYS_execve, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#endif /* PRFS_STOPEXEC */
+
+ /* Setup traps on exit from sproc() */
+
+#ifdef SYS_sproc
+ procfs_set_syscall_trap (pip, SYS_sproc, PROCFS_SYSCALL_EXIT,
+ procfs_sproc_handler);
+ procfs_set_syscall_trap (pip, SYS_fork, PROCFS_SYSCALL_EXIT,
+ procfs_fork_handler);
+#ifdef SYS_vfork
+ procfs_set_syscall_trap (pip, SYS_vfork, PROCFS_SYSCALL_EXIT,
+ procfs_fork_handler);
+#endif
+/* Turn on inherit-on-fork flag so that all children of the target process
+ start with tracing flags set. This allows us to trap lwp creation. Note
+ that we also have to trap on fork and vfork in order to disable all tracing
+ in the targets child processes. */
+
+ modify_inherit_on_fork_flag (pip->ctl_fd, 1);
+#endif
+
+#ifdef SYS_lwp_create
+ procfs_set_syscall_trap (pip, SYS_lwp_create, PROCFS_SYSCALL_EXIT,
+ procfs_lwp_creation_handler);
+#endif
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_init_inferior - initialize target vector and access to a
+ /proc entry
+
+SYNOPSIS
+
+ int procfs_init_inferior (int pid)
+
+DESCRIPTION
+
+ When gdb starts an inferior, this function is called in the parent
+ process immediately after the fork. It waits for the child to stop
+ on the return from the exec system call (the child itself takes care
+ of ensuring that this is set up), then sets up the set of signals
+ and faults that are to be traced. Returns the pid, which may have had
+ the thread-id added to it.
+
+NOTES
+
+ If proc_init_failed ever gets called, control returns to the command
+ processing loop via the standard error handling code.
+
+ */
+
+static int
+procfs_init_inferior (pid)
+ int pid;
+{
+ struct procinfo *pip;
+
+ push_target (&procfs_ops);
+
+ pip = create_procinfo (pid);
+
+ procfs_set_inferior_syscall_traps (pip);
+
+ /* create_procinfo may change the pid, so we have to update inferior_pid
+ here before calling other gdb routines that need the right pid. */
+
+ pid = pip -> pid;
+ inferior_pid = pid;
+
+ add_thread (pip -> pid); /* Setup initial thread */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+#else
+ /* One trap to exec the shell, one to exec the program being debugged. */
+ startup_inferior (2);
+#endif
+
+ return pid;
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ procfs_notice_signals
+
+SYNOPSIS
+
+ static void procfs_notice_signals (int pid);
+
+DESCRIPTION
+
+ When the user changes the state of gdb's signal handling via the
+ "handle" command, this function gets called to see if any change
+ in the /proc interface is required. It is also called internally
+ by other /proc interface functions to initialize the state of
+ the traced signal set.
+
+ One thing it does is that signals for which the state is "nostop",
+ "noprint", and "pass", have their trace bits reset in the pr_trace
+ field, so that they are no longer traced. This allows them to be
+ delivered directly to the inferior without the debugger ever being
+ involved.
+ */
+
+static void
+procfs_notice_signals (pid)
+ int pid;
+{
+ struct procinfo *pi;
+ struct sig_ctl sctl;
+
+ pi = find_procinfo (pid, 0);
+
+#ifdef UNIXWARE
+ premptyset (&sctl.sigset);
+#else
+ sctl.sigset = pi->prrun.pr_trace;
+#endif
+
+ notice_signals (pi, &sctl);
+
+#ifndef UNIXWARE
+ pi->prrun.pr_trace = sctl.sigset;
+#endif
+}
+
+static void
+notice_signals (pi, sctl)
+ struct procinfo *pi;
+ struct sig_ctl *sctl;
+{
+ int signo;
+
+ for (signo = 0; signo < NSIG; signo++)
+ {
+ if (signal_stop_state (target_signal_from_host (signo)) == 0 &&
+ signal_print_state (target_signal_from_host (signo)) == 0 &&
+ signal_pass_state (target_signal_from_host (signo)) == 1)
+ {
+ prdelset (&sctl->sigset, signo);
+ }
+ else
+ {
+ praddset (&sctl->sigset, signo);
+ }
+ }
+#ifdef PROCFS_USE_READ_WRITE
+ sctl->cmd = PCSTRACE;
+ if (write (pi->ctl_fd, (char *) sctl, sizeof (struct sig_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSTRACE, &sctl->sigset))
+#endif
+ {
+ print_sys_errmsg ("PIOCSTRACE failed", errno);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ proc_set_exec_trap -- arrange for exec'd child to halt at startup
+
+SYNOPSIS
+
+ void proc_set_exec_trap (void)
+
+DESCRIPTION
+
+ This function is called in the child process when starting up
+ an inferior, prior to doing the exec of the actual inferior.
+ It sets the child process's exitset to make exit from the exec
+ system call an event of interest to stop on, and then simply
+ returns. The child does the exec, the system call returns, and
+ the child stops at the first instruction, ready for the gdb
+ parent process to take control of it.
+
+NOTE
We need to use all local variables since the child may be sharing
it's data space with the parent, if vfork was used rather than
static void
proc_set_exec_trap ()
{
- sysset_t exitset;
- sysset_t entryset;
- auto char procname[32];
+ struct sys_ctl exitset;
+ struct sys_ctl entryset;
+ char procname[MAX_PROC_NAME_SIZE];
int fd;
- sprintf (procname, PROC_NAME_FMT, getpid ());
+ sprintf (procname, CTL_PROC_NAME_FMT, getpid ());
+#ifdef UNIXWARE
+ if ((fd = open (procname, O_WRONLY)) < 0)
+#else
if ((fd = open (procname, O_RDWR)) < 0)
+#endif
{
perror (procname);
gdb_flush (gdb_stderr);
_exit (127);
}
- premptyset (&exitset);
- premptyset (&entryset);
+ premptyset (&exitset.sysset);
+ premptyset (&entryset.sysset);
-#ifdef PIOCSSPCACT
+#ifdef PRFS_STOPEXEC
/* Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace
exits from exec system calls because of the user level loader. */
{
_exit (127);
}
}
-#else
+#else /* PRFS_STOPEXEC */
/* GW: Rationale...
Not all systems with /proc have all the exec* syscalls with the same
names. On the SGI, for example, there is no SYS_exec, but there
*is* a SYS_execv. So, we try to account for that. */
#ifdef SYS_exec
- praddset (&exitset, SYS_exec);
+ praddset (&exitset.sysset, SYS_exec);
#endif
#ifdef SYS_execve
- praddset (&exitset, SYS_execve);
+ praddset (&exitset.sysset, SYS_execve);
#endif
#ifdef SYS_execv
- praddset (&exitset, SYS_execv);
+ praddset (&exitset.sysset, SYS_execv);
#endif
- if (ioctl (fd, PIOCSEXIT, &exitset) < 0)
+#ifdef PROCFS_USE_READ_WRITE
+ exitset.cmd = PCSEXIT;
+ if (write (fd, (char *) &exitset, sizeof (struct sys_ctl)) < 0)
+#else
+ if (ioctl (fd, PIOCSEXIT, &exitset.sysset) < 0)
+#endif
{
perror (procname);
gdb_flush (gdb_stderr);
_exit (127);
}
-#endif
+#endif /* PRFS_STOPEXEC */
- praddset (&entryset, SYS_exit);
+ praddset (&entryset.sysset, SYS_exit);
- if (ioctl (fd, PIOCSENTRY, &entryset) < 0)
+#ifdef PROCFS_USE_READ_WRITE
+ entryset.cmd = PCSENTRY;
+ if (write (fd, (char *) &entryset, sizeof (struct sys_ctl)) < 0)
+#else
+ if (ioctl (fd, PIOCSENTRY, &entryset.sysset) < 0)
+#endif
{
perror (procname);
gdb_flush (gdb_stderr);
/* Turn off inherit-on-fork flag so that all grand-children of gdb
start with tracing flags cleared. */
-#if defined (PIOCRESET) /* New method */
- {
- long pr_flags;
- pr_flags = PR_FORK;
- ioctl (fd, PIOCRESET, &pr_flags);
- }
-#else
-#if defined (PIOCRFORK) /* Original method */
- ioctl (fd, PIOCRFORK, NULL);
-#endif
-#endif
+ modify_inherit_on_fork_flag (fd, 0);
/* Turn on run-on-last-close flag so that this process will not hang
if GDB goes away for some reason. */
-#if defined (PIOCSET) /* New method */
+ modify_run_on_last_close_flag (fd, 1);
+
+#ifdef PR_ASYNC
{
- long pr_flags;
- pr_flags = PR_RLC;
- (void) ioctl (fd, PIOCSET, &pr_flags);
- }
+ long pr_flags;
+ struct proc_ctl pctl;
+
+/* Solaris needs this to make procfs treat all threads seperately. Without
+ this, all threads halt whenever something happens to any thread. Since
+ GDB wants to control all this itself, it needs to set PR_ASYNC. */
+
+ pr_flags = PR_ASYNC;
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.cmd = PCSET;
+ pctl.data = PR_FORK|PR_ASYNC;
+ write (fd, (char *) &pctl, sizeof (struct proc_ctl));
#else
-#if defined (PIOCSRLC) /* Original method */
- (void) ioctl (fd, PIOCSRLC, 0);
-#endif
+ ioctl (fd, PIOCSET, &pr_flags);
#endif
+ }
+#endif /* PR_ASYNC */
}
/*
the end of the mappings or the function returns nonzero.
*/
+#ifdef UNIXWARE
+int
+proc_iterate_over_mappings (func)
+ int (*func) PARAMS ((int, CORE_ADDR));
+{
+ int nmap;
+ int fd;
+ int funcstat = 0;
+ prmap_t *prmaps;
+ prmap_t *prmap;
+ struct procinfo *pi;
+ struct stat sbuf;
+
+ pi = current_procinfo;
+
+ if (fstat (pi->map_fd, &sbuf) < 0)
+ return 0;
+
+ nmap = sbuf.st_size / sizeof (prmap_t);
+ prmaps = (prmap_t *) alloca (nmap * sizeof(prmap_t));
+ if ((lseek (pi->map_fd, 0, SEEK_SET) == 0) &&
+ (read (pi->map_fd, (char *) prmaps, nmap * sizeof (prmap_t)) ==
+ (nmap * sizeof (prmap_t))))
+ {
+ int i = 0;
+ for (prmap = prmaps; i < nmap && funcstat == 0; ++prmap, ++i)
+ {
+ char name[sizeof ("/proc/1234567890/object") +
+ sizeof (prmap->pr_mapname)];
+ sprintf (name, "/proc/%d/object/%s", pi->pid, prmap->pr_mapname);
+ if ((fd = open (name, O_RDONLY)) == -1)
+ {
+ funcstat = 1;
+ break;
+ }
+ funcstat = (*func) (fd, (CORE_ADDR) prmap->pr_vaddr);
+ close (fd);
+ }
+ }
+ return (funcstat);
+}
+#else /* UNIXWARE */
int
proc_iterate_over_mappings (func)
int (*func) PARAMS ((int, CORE_ADDR));
pi = current_procinfo;
- if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0)
+ if (ioctl (pi->map_fd, PIOCNMAP, &nmap) == 0)
{
prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
- if (ioctl (pi->fd, PIOCMAP, prmaps) == 0)
+ if (ioctl (pi->map_fd, PIOCMAP, prmaps) == 0)
{
for (prmap = prmaps; prmap -> pr_size && funcstat == 0; ++prmap)
{
}
return (funcstat);
}
+#endif /* UNIXWARE */
#if 0 /* Currently unused */
/*
pi = current_procinfo;
- if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0)
+ if (ioctl (pi->map_fd, PIOCNMAP, &nmap) == 0)
{
prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
- if (ioctl (pi->fd, PIOCMAP, prmaps) == 0)
+ if (ioctl (pi->map_fd, PIOCMAP, prmaps) == 0)
{
for (prmap = prmaps; prmap -> pr_size; ++prmap)
{
#endif /* 0 */
+#ifndef UNIXWARE
/*
LOCAL FUNCTION
{
int fd = -1;
- if ((fd = ioctl (pi->fd, PIOCOPENM, (caddr_t *) &addr)) < 0)
+ if ((fd = ioctl (pi->ctl_fd, PIOCOPENM, (caddr_t *) &addr)) < 0)
{
if (complain)
{
}
return (fd);
}
-
+#endif /* !UNIXWARE */
/* Attach to process PID, then initialize for debugging it
and wait for the trace-trap that results from attaching. */
gdb_flush (gdb_stdout);
}
- do_attach (pid);
- inferior_pid = pid;
+ inferior_pid = pid = do_attach (pid);
push_target (&procfs_ops);
}
do_attach (pid)
int pid;
{
- int result;
struct procinfo *pi;
+ struct sig_ctl sctl;
+ struct flt_ctl fctl;
+ int nlwp, *lwps;
- pi = (struct procinfo *) xmalloc (sizeof (struct procinfo));
-
- if (!open_proc_file (pid, pi, O_RDWR))
- {
- free (pi);
- perror_with_name (pi->pathname);
- /* NOTREACHED */
- }
-
- /* Add new process to process info list */
-
- pi->next = procinfo_list;
- procinfo_list = pi;
+ pi = init_procinfo (pid, 0);
- add_fd (pi); /* Add to list for poll/select */
+#ifdef PIOCLWPIDS
+ nlwp = pi->prstatus.pr_nlwp;
+ lwps = alloca ((2 * nlwp + 2) * sizeof (id_t));
- /* Get current status of process and if it is not already stopped,
- then stop it. Remember whether or not it was stopped when we first
- examined it. */
-
- if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- close_proc_file (pi);
- error ("PIOCSTATUS failed");
- }
- if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+ if (ioctl (pi->ctl_fd, PIOCLWPIDS, lwps))
{
- pi->was_stopped = 1;
+ print_sys_errmsg (pi -> pathname, errno);
+ error ("PIOCLWPIDS failed");
}
- else
+#else /* PIOCLWPIDS */
+ nlwp = 1;
+ lwps = alloca ((2 * nlwp + 2) * sizeof *lwps);
+ lwps[0] = 0;
+#endif
+ for (; nlwp > 0; nlwp--, lwps++)
{
- pi->was_stopped = 0;
- if (1 || query ("Process is currently running, stop it? "))
+ /* First one has already been created above. */
+ if ((pi = find_procinfo ((*lwps << 16) | pid, 1)) == 0)
+ pi = init_procinfo ((*lwps << 16) | pid, 0);
+
+#ifdef UNIXWARE
+ if (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP))
+#else
+ if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+#endif
{
- /* Make it run again when we close it. */
-#if defined (PIOCSET) /* New method */
- {
- long pr_flags;
- pr_flags = PR_RLC;
- result = ioctl (pi->fd, PIOCSET, &pr_flags);
- }
+ pi->was_stopped = 1;
+ }
+ else
+ {
+ pi->was_stopped = 0;
+ if (1 || query ("Process is currently running, stop it? "))
+ {
+ long cmd;
+ /* Make it run again when we close it. */
+ modify_run_on_last_close_flag (pi->ctl_fd, 1);
+#ifdef PROCFS_USE_READ_WRITE
+ cmd = PCSTOP;
+ if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0)
#else
-#if defined (PIOCSRLC) /* Original method */
- result = ioctl (pi->fd, PIOCSRLC, 0);
+ if (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) < 0)
#endif
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ close_proc_file (pi);
+ error ("PIOCSTOP failed");
+ }
+#ifdef UNIXWARE
+ if (!procfs_read_status (pi))
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ close_proc_file (pi);
+ error ("procfs_read_status failed");
+ }
#endif
- if (result < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- close_proc_file (pi);
- error ("PIOCSRLC or PIOCSET failed");
+ pi->nopass_next_sigstop = 1;
}
- if (ioctl (pi->fd, PIOCSTOP, &pi->prstatus) < 0)
+ else
{
- print_sys_errmsg (pi->pathname, errno);
- close_proc_file (pi);
- error ("PIOCSTOP failed");
+ printf_unfiltered ("Ok, gdb will wait for %s to stop.\n",
+ target_pid_to_str (pi->pid));
}
- pi->nopass_next_sigstop = 1;
}
- else
+
+#ifdef PROCFS_USE_READ_WRITE
+ fctl.cmd = PCSFAULT;
+ if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0)
+ print_sys_errmsg ("PCSFAULT failed", errno);
+#else /* PROCFS_USE_READ_WRITE */
+ if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault))
{
- printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid));
+ print_sys_errmsg ("PIOCSFAULT failed", errno);
}
- }
-
- /* Remember some things about the inferior that we will, or might, change
- so that we can restore them when we detach. */
-
- ioctl (pi->fd, PIOCGTRACE, &pi->saved_trace);
- ioctl (pi->fd, PIOCGHOLD, &pi->saved_sighold);
- ioctl (pi->fd, PIOCGFAULT, &pi->saved_fltset);
- ioctl (pi->fd, PIOCGENTRY, &pi->saved_entryset);
- ioctl (pi->fd, PIOCGEXIT, &pi->saved_exitset);
-
- /* Set up trace and fault sets, as gdb expects them. */
-
- memset (&pi->prrun, 0, sizeof (pi->prrun));
- prfillset (&pi->prrun.pr_trace);
- procfs_notice_signals (pid);
- prfillset (&pi->prrun.pr_fault);
- prdelset (&pi->prrun.pr_fault, FLTPAGE);
-
-#ifdef PROCFS_DONT_TRACE_FAULTS
- premptyset (&pi->prrun.pr_fault);
-#endif
-
- if (ioctl (pi->fd, PIOCSFAULT, &pi->prrun.pr_fault))
- {
- print_sys_errmsg ("PIOCSFAULT failed", errno);
- }
- if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace))
- {
- print_sys_errmsg ("PIOCSTRACE failed", errno);
+ if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->prrun.pr_trace))
+ {
+ print_sys_errmsg ("PIOCSTRACE failed", errno);
+ }
+ add_thread (pi->pid);
+ procfs_set_inferior_syscall_traps (pi);
+#endif /* PROCFS_USE_READ_WRITE */
}
attach_flag = 1;
- return (pid);
+ return (pi->pid);
}
/*
do_detach (signal)
int signal;
{
- int result;
struct procinfo *pi;
- pi = current_procinfo;
-
- if (signal)
- {
- set_proc_siginfo (pi, signal);
- }
- if (ioctl (pi->fd, PIOCSEXIT, &pi->saved_exitset) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSEXIT failed.\n");
- }
- if (ioctl (pi->fd, PIOCSENTRY, &pi->saved_entryset) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSENTRY failed.\n");
- }
- if (ioctl (pi->fd, PIOCSTRACE, &pi->saved_trace) < 0)
+ for (pi = procinfo_list; pi; pi = pi->next)
{
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSTRACE failed.\n");
- }
- if (ioctl (pi->fd, PIOCSHOLD, &pi->saved_sighold) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOSCHOLD failed.\n");
- }
- if (ioctl (pi->fd, PIOCSFAULT, &pi->saved_fltset) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSFAULT failed.\n");
- }
- if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSTATUS failed.\n");
- }
- else
- {
- if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
+ if (signal)
+ {
+ set_proc_siginfo (pi, signal);
+ }
+#ifdef PROCFS_USE_READ_WRITE
+ pi->saved_exitset.cmd = PCSEXIT;
+ if (write (pi->ctl_fd, (char *) &pi->saved_exitset,
+ sizeof (struct sys_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSEXIT, &pi->saved_exitset.sysset) < 0)
+#endif
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOCSEXIT failed.\n");
+ }
+#ifdef PROCFS_USE_READ_WRITE
+ pi->saved_entryset.cmd = PCSENTRY;
+ if (write (pi->ctl_fd, (char *) &pi->saved_entryset,
+ sizeof (struct sys_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSENTRY, &pi->saved_entryset.sysset) < 0)
+#endif
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOCSENTRY failed.\n");
+ }
+#ifdef PROCFS_USE_READ_WRITE
+ pi->saved_trace.cmd = PCSTRACE;
+ if (write (pi->ctl_fd, (char *) &pi->saved_trace,
+ sizeof (struct sig_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSTRACE, &pi->saved_trace.sigset) < 0)
+#endif
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOCSTRACE failed.\n");
+ }
+#ifndef UNIXWARE
+ if (ioctl (pi->ctl_fd, PIOCSHOLD, &pi->saved_sighold.sigset) < 0)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOSCHOLD failed.\n");
+ }
+#endif
+#ifdef PROCFS_USE_READ_WRITE
+ pi->saved_fltset.cmd = PCSFAULT;
+ if (write (pi->ctl_fd, (char *) &pi->saved_fltset,
+ sizeof (struct flt_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->saved_fltset.fltset) < 0)
+#endif
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOCSFAULT failed.\n");
+ }
+ if (!procfs_read_status (pi))
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("procfs_read_status failed.\n");
+ }
+ else
{
- if (signal || !pi->was_stopped ||
- query ("Was stopped when attached, make it runnable again? "))
+#ifdef UNIXWARE
+ if (signal || (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP)))
+#else
+ if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
+#endif
{
- /* Clear any pending signal if we want to detach without
- a signal. */
- if (signal == 0)
- set_proc_siginfo (pi, signal);
+ long cmd;
+ struct proc_ctl pctl;
- /* Clear any fault that might have stopped it. */
- if (ioctl (pi->fd, PIOCCFAULT, 0))
+ if (signal || !pi->was_stopped ||
+ query ("Was stopped when attached, make it runnable again? "))
{
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCCFAULT failed.\n");
- }
-
- /* Make it run again when we close it. */
-#if defined (PIOCSET) /* New method */
- {
- long pr_flags;
- pr_flags = PR_RLC;
- result = ioctl (pi->fd, PIOCSET, &pr_flags);
- }
+ /* Clear any pending signal if we want to detach without
+ a signal. */
+ if (signal == 0)
+ set_proc_siginfo (pi, signal);
+
+ /* Clear any fault that might have stopped it. */
+#ifdef PROCFS_USE_READ_WRITE
+ cmd = PCCFAULT;
+ if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0)
#else
-#if defined (PIOCSRLC) /* Original method */
- result = ioctl (pi->fd, PIOCSRLC, 0);
+ if (ioctl (pi->ctl_fd, PIOCCFAULT, 0))
#endif
-#endif
- if (result)
- {
- print_sys_errmsg (pi->pathname, errno);
- printf_unfiltered ("PIOCSRLC or PIOCSET failed.\n");
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ printf_unfiltered ("PIOCCFAULT failed.\n");
+ }
+
+ /* Make it run again when we close it. */
+
+ modify_run_on_last_close_flag (pi->ctl_fd, 1);
}
}
}
+ close_proc_file (pi);
}
- close_proc_file (pi);
attach_flag = 0;
}
FIXME: Investigate why wait() seems to have problems with programs
being control by /proc routines. */
-
static int
procfs_wait (pid, ourstatus)
int pid;
int checkerr = 0;
int rtnval = -1;
struct procinfo *pi;
+ struct proc_ctl pctl;
if (pid != -1) /* Non-specific process? */
pi = NULL;
{
wait_again:
+ if (pi)
+ pi->had_event = 0;
+
pi = wait_fd ();
}
if (!pi && !checkerr)
goto wait_again;
+#ifdef UNIXWARE
+ if (!checkerr && !(pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP)))
+#else
if (!checkerr && !(pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
+#endif
{
- if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
+ if (!procfs_write_pcwstop (pi))
{
checkerr++;
}
- }
+ }
if (checkerr)
{
if (errno == ENOENT)
{
+ /* XXX Fixme -- what to do if attached? Can't call wait... */
rtnval = wait (&statval);
- if (rtnval != inferior_pid)
+ if ((rtnval) != (PIDGET (inferior_pid)))
{
print_sys_errmsg (pi->pathname, errno);
- error ("PIOCWSTOP, wait failed, returned %d", rtnval);
+ error ("procfs_wait: wait failed, returned %d", rtnval);
/* NOTREACHED */
}
}
/* NOTREACHED */
}
}
+#ifdef UNIXWARE
+ else if (pi->prstatus.pr_lwp.pr_flags & (PR_STOPPED | PR_ISTOP))
+#else
else if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+#endif
{
+#ifdef UNIXWARE
rtnval = pi->prstatus.pr_pid;
+ why = pi->prstatus.pr_lwp.pr_why;
+ what = pi->prstatus.pr_lwp.pr_what;
+#else
+ rtnval = pi->pid;
why = pi->prstatus.pr_why;
what = pi->prstatus.pr_what;
+#endif
switch (why)
{
statval = (what << 8) | 0177;
break;
case PR_SYSENTRY:
- if (what != SYS_exit)
- error ("PR_SYSENTRY, unknown system call %d", what);
-
- pi->prrun.pr_flags = PRCFAULT;
-
- if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
- perror_with_name (pi->pathname);
-
- rtnval = wait (&statval);
-
- break;
case PR_SYSEXIT:
- switch (what)
- {
-#ifdef SYS_exec
- case SYS_exec:
-#endif
-#ifdef SYS_execve
- case SYS_execve:
-#endif
-#ifdef SYS_execv
- case SYS_execv:
-#endif
- statval = (SIGTRAP << 8) | 0177;
- break;
-#ifdef SYS_sproc
- case SYS_sproc:
-/* We've just detected the completion of an sproc system call. Now we need to
- setup a procinfo struct for this thread, and notify the thread system of the
- new arrival. */
-
-/* If sproc failed, then nothing interesting happened. Continue the process and
- go back to sleep. */
+ {
+ int i;
+ int found_handler = 0;
- if (pi->prstatus.pr_errno != 0)
+ for (i = 0; i < pi->num_syscall_handlers; i++)
+ if (pi->syscall_handlers[i].syscall_num == what)
{
- pi->prrun.pr_flags &= PRSTEP;
- pi->prrun.pr_flags |= PRCFAULT;
+ found_handler = 1;
+ if (!pi->syscall_handlers[i].func (pi, what, why,
+ &rtnval, &statval))
+ goto wait_again;
- if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
- perror_with_name (pi->pathname);
-
- goto wait_again;
+ break;
}
-/* At this point, the new thread is stopped at it's first instruction, and
- the parent is stopped at the exit from sproc. */
-
-/* Notify the caller of the arrival of a new thread. */
- create_procinfo (pi->prstatus.pr_rval1);
-
- rtnval = pi->prstatus.pr_rval1;
- statval = (SIGTRAP << 8) | 0177;
-
- break;
- case SYS_fork:
-#ifdef SYS_vfork
- case SYS_vfork:
-#endif
-/* At this point, we've detected the completion of a fork (or vfork) call in
- our child. The grandchild is also stopped because we set inherit-on-fork
- earlier. (Note that nobody has the grandchilds' /proc file open at this
- point.) We will release the grandchild from the debugger by opening it's
- /proc file and then closing it. Since run-on-last-close is set, the
- grandchild continues on its' merry way. */
-
- {
- struct procinfo *pitemp;
-
- pitemp = create_procinfo (pi->prstatus.pr_rval1);
- if (pitemp)
- close_proc_file (pitemp);
-
- if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
- perror_with_name (pi->pathname);
- }
- goto wait_again;
-#endif /* SYS_sproc */
-
- default:
- error ("PIOCSTATUS (PR_SYSEXIT): Unknown system call %d", what);
- }
+ if (!found_handler)
+ if (why == PR_SYSENTRY)
+ error ("PR_SYSENTRY, unhandled system call %d", what);
+ else
+ error ("PR_SYSEXIT, unhandled system call %d", what);
+ }
break;
case PR_REQUESTED:
statval = (SIGSTOP << 8) | 0177;
case FLTBPT:
case FLTTRACE:
statval = (SIGTRAP << 8) | 0177;
- break;
+ break;
case FLTSTACK:
case FLTACCESS:
case FLTBOUNDS:
/* Use the signal which the kernel assigns. This is better than
trying to second-guess it from the fault. In fact, I suspect
that FLTACCESS can be either SIGSEGV or SIGBUS. */
+#ifdef UNIXWARE
+ statval = ((pi->prstatus.pr_lwp.pr_info.si_signo) << 8) | 0177;
+#else
statval = ((pi->prstatus.pr_info.si_signo) << 8) | 0177;
+#endif
break;
}
break;
default:
error ("PIOCWSTOP, unknown why %d, what %d", why, what);
}
-/* Stop all the other threads when any of them stops. */
+ /* Stop all the other threads when any of them stops. */
{
- struct procinfo *procinfo;
+ struct procinfo *procinfo, *next_pi;
- for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+ for (procinfo = procinfo_list; procinfo; procinfo = next_pi)
{
+ next_pi = procinfo->next;
if (!procinfo->had_event)
- if (ioctl (procinfo->fd, PIOCSTOP, &procinfo->prstatus) < 0)
- {
- print_sys_errmsg (procinfo->pathname, errno);
- error ("PIOCSTOP failed");
- }
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ long cmd = PCSTOP;
+ if (write (pi->ctl_fd, (char *) &cmd, sizeof (long)) < 0)
+ {
+ print_sys_errmsg (procinfo->pathname, errno);
+ error ("PCSTOP failed");
+ }
+#else
+ /* A bug in Solaris (2.5) causes us to hang when trying to
+ stop a stopped process. So, we have to check first in
+ order to avoid the hang. */
+ if (!procfs_read_status (procinfo))
+ {
+ /* The LWP has apparently terminated. */
+ if (info_verbose)
+ printf_filtered ("LWP %d doesn't respond.\n",
+ (procinfo->pid >> 16) & 0xffff);
+ close_proc_file (procinfo);
+ continue;
+ }
+
+ if (!(procinfo->prstatus.pr_flags & PR_STOPPED))
+ if (ioctl (procinfo->ctl_fd, PIOCSTOP, &procinfo->prstatus)
+ < 0)
+ {
+ print_sys_errmsg (procinfo->pathname, errno);
+ warning ("PIOCSTOP failed");
+ }
+#endif
+ }
}
}
}
else
{
- error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x",
+ error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x",
+#ifdef UNIXWARE
+ pi->prstatus.pr_lwp.pr_flags);
+#else
pi->prstatus.pr_flags);
+#endif
}
store_waitstatus (ourstatus, statval);
if (rtnval == -1) /* No more children to wait for */
{
- fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing.\n");
+ warning ("Child process unexpectedly missing");
/* Claim it exited with unknown signal. */
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
{
struct siginfo newsiginfo;
struct siginfo *sip;
+ struct sigi_ctl sictl;
#ifdef PROCFS_DONT_PIOCSSIG_CURSIG
/* With Alpha OSF/1 procfs, the kernel gets really confused if it
receives a PIOCSSIG with a signal identical to the current signal,
it messes up the current signal. Work around the kernel bug. */
+#ifdef UNIXWARE
+ if (signo == pip -> prstatus.pr_lwp.pr_cursig)
+#else
if (signo == pip -> prstatus.pr_cursig)
+#endif
return;
#endif
+#ifdef UNIXWARE
+ if (signo == pip->prstatus.pr_lwp.pr_info.si_signo)
+ {
+ memcpy ((char *) &sictl.siginfo, (char *) &pip->prstatus.pr_lwp.pr_info,
+ sizeof (siginfo_t));
+ }
+#else
if (signo == pip -> prstatus.pr_info.si_signo)
{
sip = &pip -> prstatus.pr_info;
}
+#endif
else
{
+#ifdef UNIXWARE
+ siginfo_t *sip = &sictl.siginfo;
+ memset ((char *) sip, 0, sizeof (siginfo_t));
+#else
memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
sip = &newsiginfo;
+#endif
sip -> si_signo = signo;
sip -> si_code = 0;
sip -> si_errno = 0;
sip -> si_pid = getpid ();
sip -> si_uid = getuid ();
}
- if (ioctl (pip -> fd, PIOCSSIG, sip) < 0)
+#ifdef PROCFS_USE_READ_WRITE
+ sictl.cmd = PCSSIG;
+ if (write (pip->ctl_fd, (char *) &sictl, sizeof (struct sigi_ctl)) < 0)
+#else
+ if (ioctl (pip->ctl_fd, PIOCSSIG, sip) < 0)
+#endif
{
print_sys_errmsg (pip -> pathname, errno);
warning ("PIOCSSIG failed");
enum target_signal signo;
{
int signal_to_pass;
- struct procinfo *pi, *procinfo;
+ struct procinfo *pi, *procinfo, *next_pi;
+ struct proc_ctl pctl;
pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
errno = 0;
+#ifdef UNIXWARE
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+#else
pi->prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT;
+#endif
#if 0
/* It should not be necessary. If the user explicitly changes the value,
an inferior to continue running at the same time as gdb. (FIXME?) */
signal_to_pass = 0;
else if (signo == TARGET_SIGNAL_TSTP
+#ifdef UNIXWARE
+ && pi->prstatus.pr_lwp.pr_cursig == SIGTSTP
+ && pi->prstatus.pr_lwp.pr_action.sa_handler == SIG_DFL
+#else
&& pi->prstatus.pr_cursig == SIGTSTP
- && pi->prstatus.pr_action.sa_handler == SIG_DFL)
+ && pi->prstatus.pr_action.sa_handler == SIG_DFL
+#endif
+ )
/* We are about to pass the inferior a SIGTSTP whose action is
SIG_DFL. The SIG_DFL action for a SIGTSTP is to stop
}
else
{
+#ifdef UNIXWARE
+ pctl.data |= PRCSIG;
+#else
pi->prrun.pr_flags |= PRCSIG;
+#endif
}
pi->nopass_next_sigstop = 0;
if (step)
{
+#ifdef UNIXWARE
+ pctl.data |= PRSTEP;
+#else
pi->prrun.pr_flags |= PRSTEP;
+#endif
}
- if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
+ pi->had_event = 0;
+ /* Don't try to start a process unless it's stopped on an
+ `event of interest'. Doing so will cause errors. */
+
+ if (!procfs_read_status (pi))
{
- perror_with_name (pi->pathname);
- /* NOTREACHED */
+ /* The LWP has apparently terminated. */
+ if (info_verbose)
+ printf_filtered ("LWP %d doesn't respond.\n",
+ (pi->pid >> 16) & 0xffff);
+ close_proc_file (pi);
+ }
+ else
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ if (write (pi->ctl_fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+#else
+ if ((pi->prstatus.pr_flags & PR_ISTOP)
+ && ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+#endif
+ {
+ /* The LWP has apparently terminated. */
+ if (info_verbose)
+ printf_filtered ("LWP %d doesn't respond.\n",
+ (pi->pid >> 16) & 0xffff);
+ close_proc_file (pi);
+ }
}
- pi->had_event = 0;
-
- /* Continue all the other threads that haven't had an event of
- interest. */
+ /* Continue all the other threads that haven't had an event of interest.
+ Also continue them if they have NOPASS_NEXT_SIGSTOP set; this is only
+ set by do_attach, and means this is the first resume after an attach.
+ All threads were CSTOP'd by do_attach, and should be resumed now. */
if (pid == -1)
- for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+ for (procinfo = procinfo_list; procinfo; procinfo = next_pi)
{
- if (pi != procinfo && !procinfo->had_event)
- {
- procinfo->prrun.pr_flags &= PRSTEP;
- procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG;
- ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus);
- if (ioctl (procinfo->fd, PIOCRUN, &procinfo->prrun) < 0)
- {
- if (ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus) < 0)
- {
- fprintf_unfiltered(gdb_stderr, "PIOCSTATUS failed, errno=%d\n", errno);
- }
- print_sys_errmsg (procinfo->pathname, errno);
- error ("PIOCRUN failed");
- }
- ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus);
- }
+ next_pi = procinfo->next;
+ if (pi != procinfo)
+ if (!procinfo->had_event ||
+ (procinfo->nopass_next_sigstop && signo == TARGET_SIGNAL_STOP))
+ {
+ procinfo->had_event = procinfo->nopass_next_sigstop = 0;
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.data = PRCFAULT | PRCSIG;
+ if (write (procinfo->ctl_fd, (char *) &pctl,
+ sizeof (struct proc_ctl)) < 0)
+ {
+ if (!procfs_read_status (procinfo))
+ fprintf_unfiltered(gdb_stderr,
+ "procfs_read_status failed, errno=%d\n",
+ errno);
+ print_sys_errmsg (procinfo->pathname, errno);
+ error ("PCRUN failed");
+ }
+#else
+ procinfo->prrun.pr_flags &= PRSTEP;
+ procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG;
+ if (!procfs_read_status (procinfo))
+ {
+ /* The LWP has apparently terminated. */
+ if (info_verbose)
+ printf_filtered ("LWP %d doesn't respond.\n",
+ (procinfo->pid >> 16) & 0xffff);
+ close_proc_file (procinfo);
+ continue;
+ }
+
+ /* Don't try to start a process unless it's stopped on an
+ `event of interest'. Doing so will cause errors. */
+
+ if ((procinfo->prstatus.pr_flags & PR_ISTOP)
+ && ioctl (procinfo->ctl_fd, PIOCRUN, &procinfo->prrun) < 0)
+ {
+ if (!procfs_read_status (procinfo))
+ fprintf_unfiltered(gdb_stderr,
+ "procfs_read_status failed, errno=%d\n",
+ errno);
+ print_sys_errmsg (procinfo->pathname, errno);
+ warning ("PIOCRUN failed");
+ }
+#endif
+ }
+ procfs_read_status (procinfo);
}
}
pi = current_procinfo;
- if (ioctl (pi->fd, PIOCGREG, &pi->gregset) != -1)
+#ifdef UNIXWARE
+ if (procfs_read_status (pi))
{
- supply_gregset (&pi->gregset);
+ supply_gregset (&pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs);
+#if defined (FP0_REGNUM)
+ supply_fpregset (&pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs);
+#endif
+ }
+#else /* UNIXWARE */
+ if (ioctl (pi->ctl_fd, PIOCGREG, &pi->gregset.gregset) != -1)
+ {
+ supply_gregset (&pi->gregset.gregset);
}
#if defined (FP0_REGNUM)
- if (ioctl (pi->fd, PIOCGFPREG, &pi->fpregset) != -1)
+ if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset.fpregset) != -1)
{
- supply_fpregset (&pi->fpregset);
+ supply_fpregset (&pi->fpregset.fpregset);
}
#endif
+#endif /* UNIXWARE */
}
/*
LOCAL FUNCTION
- proc_init_failed - called whenever /proc access initialization
+ proc_init_failed - called when /proc access initialization fails
fails
SYNOPSIS
- static void proc_init_failed (struct procinfo *pi, char *why)
+ static void proc_init_failed (struct procinfo *pi,
+ char *why, int kill_p)
DESCRIPTION
This function is called whenever initialization of access to a /proc
entry fails. It prints a suitable error message, does some cleanup,
and then invokes the standard error processing routine which dumps
- us back into the command loop.
+ us back into the command loop. If KILL_P is true, sends SIGKILL.
*/
static void
-proc_init_failed (pi, why)
+proc_init_failed (pi, why, kill_p)
struct procinfo *pi;
char *why;
+ int kill_p;
{
print_sys_errmsg (pi->pathname, errno);
- kill (pi->pid, SIGKILL);
+ if (kill_p)
+ kill (pi->pid, SIGKILL);
close_proc_file (pi);
error (why);
/* NOTREACHED */
{
struct procinfo *procinfo;
+ delete_thread (pip->pid); /* remove thread from GDB's thread list */
remove_fd (pip); /* Remove fd from poll/select list */
- close (pip -> fd);
+ close (pip->ctl_fd);
+#ifdef HAVE_MULTIPLE_PROC_FDS
+ close (pip->as_fd);
+ close (pip->status_fd);
+ close (pip->map_fd);
+#endif
free (pip -> pathname);
if (procinfo_list == pip)
procinfo_list = pip->next;
else
- for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
- if (procinfo->next == pip)
- procinfo->next = pip->next;
-
- free (pip);
+ {
+ for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+ {
+ if (procinfo->next == pip)
+ {
+ procinfo->next = pip->next;
+ break;
+ }
+ }
+ free (pip);
+ }
}
/*
Note that the pathname is left intact, even when the open fails,
so that callers can use it to construct meaningful error messages
rather than just "file open failed".
+
+ Note that for Solaris, the process-id also includes an LWP-id, so we
+ actually attempt to open that. If we are handed a pid with a 0 LWP-id,
+ then we will ask the kernel what it is and add it to the pid. Hence,
+ the pid can be changed by us.
*/
static int
-open_proc_file (pid, pip, mode)
+open_proc_file (pid, pip, mode, control)
int pid;
struct procinfo *pip;
int mode;
+ int control;
{
+ int tmp, tmpfd;
+
pip -> next = NULL;
pip -> had_event = 0;
- pip -> pathname = xmalloc (32);
+ pip -> pathname = xmalloc (MAX_PROC_NAME_SIZE);
pip -> pid = pid;
- sprintf (pip -> pathname, PROC_NAME_FMT, pid);
- if ((pip -> fd = open (pip -> pathname, mode)) < 0)
+#ifndef PIOCOPENLWP
+ tmp = pid;
+#else
+ tmp = pid & 0xffff;
+#endif
+
+#ifdef HAVE_MULTIPLE_PROC_FDS
+ sprintf (pip->pathname, STATUS_PROC_NAME_FMT, tmp);
+ if ((pip->status_fd = open (pip->pathname, O_RDONLY)) < 0)
+ {
+ return 0;
+ }
+
+ sprintf (pip->pathname, AS_PROC_NAME_FMT, tmp);
+ if ((pip->as_fd = open (pip->pathname, O_RDWR)) < 0)
+ {
+ close (pip->status_fd);
+ return 0;
+ }
+
+ sprintf (pip->pathname, MAP_PROC_NAME_FMT, tmp);
+ if ((pip->map_fd = open (pip->pathname, O_RDONLY)) < 0)
+ {
+ close (pip->status_fd);
+ close (pip->as_fd);
+ return 0;
+ }
+
+ sprintf (pip->pathname, MAP_PROC_NAME_FMT, tmp);
+ if ((pip->map_fd = open (pip->pathname, O_RDONLY)) < 0)
+ {
+ close (pip->status_fd);
+ close (pip->as_fd);
+ return 0;
+ }
+
+ if (control)
+ {
+ sprintf (pip->pathname, CTL_PROC_NAME_FMT, tmp);
+ if ((pip->ctl_fd = open (pip->pathname, O_WRONLY)) < 0)
+ {
+ close (pip->status_fd);
+ close (pip->as_fd);
+ close (pip->map_fd);
+ return 0;
+ }
+ }
+
+#else /* HAVE_MULTIPLE_PROC_FDS */
+ sprintf (pip -> pathname, CTL_PROC_NAME_FMT, tmp);
+
+ if ((tmpfd = open (pip -> pathname, mode)) < 0)
return 0;
+#ifndef PIOCOPENLWP
+ pip -> ctl_fd = tmpfd;
+ pip -> as_fd = tmpfd;
+ pip -> map_fd = tmpfd;
+ pip -> status_fd = tmpfd;
+#else
+ tmp = (pid >> 16) & 0xffff; /* Extract thread id */
+
+ if (tmp == 0)
+ { /* Don't know thread id yet */
+ if (ioctl (tmpfd, PIOCSTATUS, &pip -> prstatus) < 0)
+ {
+ print_sys_errmsg (pip -> pathname, errno);
+ close (tmpfd);
+ error ("open_proc_file: PIOCSTATUS failed");
+ }
+
+ tmp = pip -> prstatus.pr_who; /* Get thread id from prstatus_t */
+ pip -> pid = (tmp << 16) | pid; /* Update pip */
+ }
+
+ if ((pip -> ctl_fd = ioctl (tmpfd, PIOCOPENLWP, &tmp)) < 0)
+ {
+ close (tmpfd);
+ return 0;
+ }
+
+#ifdef PIOCSET /* New method */
+ {
+ long pr_flags;
+ pr_flags = PR_ASYNC;
+ ioctl (pip -> ctl_fd, PIOCSET, &pr_flags);
+ }
+#endif
+
+ /* keep extra fds in sync */
+ pip->as_fd = pip->ctl_fd;
+ pip->map_fd = pip->ctl_fd;
+ pip->status_fd = pip->ctl_fd;
+
+ close (tmpfd); /* All done with main pid */
+#endif /* PIOCOPENLWP */
+
+#endif /* HAVE_MULTIPLE_PROC_FDS */
+
return 1;
}
int summary;
{
struct trans *transp;
+#ifdef UNIXWARE
+ long flags = pip->prstatus.pr_flags | pip->prstatus.pr_lwp.pr_flags;
+#else
+ long flags = pip->prstatus.pr_flags;
+#endif
printf_filtered ("%-32s", "Process status flags:");
if (!summary)
}
for (transp = pr_flag_table; transp -> name != NULL; transp++)
{
- if (pip -> prstatus.pr_flags & transp -> value)
+ if (flags & transp -> value)
{
if (summary)
{
int why;
int what;
+#ifdef UNIXWARE
+ why = pip -> prstatus.pr_lwp.pr_why;
+ what = pip -> prstatus.pr_lwp.pr_what;
+#else
why = pip -> prstatus.pr_why;
what = pip -> prstatus.pr_what;
+#endif
+#ifdef UNIXWARE
+ if (pip -> prstatus.pr_lwp.pr_flags & PR_STOPPED)
+#else
if (pip -> prstatus.pr_flags & PR_STOPPED)
+#endif
{
printf_filtered ("%-32s", "Reason for stopping:");
if (!summary)
{
struct siginfo *sip;
+#ifdef UNIXWARE
+ if ((pip -> prstatus.pr_lwp.pr_flags & PR_STOPPED) &&
+ (pip -> prstatus.pr_lwp.pr_why == PR_SIGNALLED ||
+ pip -> prstatus.pr_lwp.pr_why == PR_FAULTED))
+#else
if ((pip -> prstatus.pr_flags & PR_STOPPED) &&
(pip -> prstatus.pr_why == PR_SIGNALLED ||
pip -> prstatus.pr_why == PR_FAULTED))
+#endif
{
printf_filtered ("%-32s", "Additional signal/fault info:");
+#ifdef UNIXWARE
+ sip = &pip -> prstatus.pr_lwp.pr_info;
+#else
sip = &pip -> prstatus.pr_info;
+#endif
if (summary)
{
printf_filtered ("%s ", signalname (sip -> si_signo));
}
#endif
- if (ioctl (pip -> fd, PIOCGENTRY, &pip -> entryset) < 0)
+#ifndef UNIXWARE
+ if (ioctl (pip -> ctl_fd, PIOCGENTRY, &pip -> entryset) < 0)
{
print_sys_errmsg (pip -> pathname, errno);
error ("PIOCGENTRY failed");
}
- if (ioctl (pip -> fd, PIOCGEXIT, &pip -> exitset) < 0)
+ if (ioctl (pip -> ctl_fd, PIOCGEXIT, &pip -> exitset) < 0)
{
print_sys_errmsg (pip -> pathname, errno);
error ("PIOCGEXIT failed");
}
+#endif
printf_filtered ("System call tracing information:\n\n");
{
QUIT;
if (syscall_table[syscallnum] != NULL)
- {
- printf_filtered ("\t%-12s ", syscall_table[syscallnum]);
- printf_filtered ("%-8s ",
- prismember (&pip -> entryset, syscallnum)
- ? "on" : "off");
- printf_filtered ("%-8s ",
- prismember (&pip -> exitset, syscallnum)
- ? "on" : "off");
- printf_filtered ("\n");
- }
- }
+ printf_filtered ("\t%-12s ", syscall_table[syscallnum]);
+ else
+ printf_filtered ("\t%-12d ", syscallnum);
+
+#ifdef UNIXWARE
+ printf_filtered ("%-8s ",
+ prismember (&pip->prstatus.pr_sysentry, syscallnum)
+ ? "on" : "off");
+ printf_filtered ("%-8s ",
+ prismember (&pip->prstatus.pr_sysexit, syscallnum)
+ ? "on" : "off");
+#else
+ printf_filtered ("%-8s ",
+ prismember (&pip -> entryset, syscallnum)
+ ? "on" : "off");
+ printf_filtered ("%-8s ",
+ prismember (&pip -> exitset, syscallnum)
+ ? "on" : "off");
+#endif
+ printf_filtered ("\n");
+ }
printf_filtered ("\n");
}
}
if (!summary)
{
- if (ioctl (pip -> fd, PIOCGTRACE, &pip -> trace) < 0)
+#ifndef PROCFS_USE_READ_WRITE
+ if (ioctl (pip -> ctl_fd, PIOCGTRACE, &pip -> trace) < 0)
{
print_sys_errmsg (pip -> pathname, errno);
error ("PIOCGTRACE failed");
}
+#endif
printf_filtered ("Disposition of signals:\n\n");
printf_filtered ("\t%-15s %-8s %-8s %-8s %s\n\n",
{
QUIT;
printf_filtered ("\t%-15s ", signalname (signo));
+#ifdef UNIXWARE
+ printf_filtered ("%-8s ",
+ prismember (&pip -> prstatus.pr_sigtrace, signo)
+ ? "on" : "off");
+ printf_filtered ("%-8s ",
+ prismember (&pip -> prstatus.pr_lwp.pr_context.uc_sigmask, signo)
+ ? "on" : "off");
+#else
printf_filtered ("%-8s ",
prismember (&pip -> trace, signo)
? "on" : "off");
printf_filtered ("%-8s ",
prismember (&pip -> prstatus.pr_sighold, signo)
? "on" : "off");
+#endif
+#ifdef UNIXWARE
+ if (prismember (&pip->prstatus.pr_sigpend, signo) ||
+ prismember (&pip->prstatus.pr_lwp.pr_lwppend, signo))
+ printf_filtered("%-8s ", "yes");
+ else
+ printf_filtered("%-8s ", "no");
+#else /* UNIXWARE */
#ifdef PROCFS_SIGPEND_OFFSET
/* Alpha OSF/1 numbers the pending signals from 1. */
printf_filtered ("%-8s ",
prismember (&pip -> prstatus.pr_sigpend, signo)
? "yes" : "no");
#endif
+#endif /* UNIXWARE */
printf_filtered (" %s\n", safe_strsignal (signo));
}
printf_filtered ("\n");
if (!summary)
{
- if (ioctl (pip -> fd, PIOCGFAULT, &pip -> fltset) < 0)
+#ifndef UNIXWARE
+ if (ioctl (pip -> ctl_fd, PIOCGFAULT, &pip->fltset.fltset) < 0)
{
print_sys_errmsg (pip -> pathname, errno);
error ("PIOCGFAULT failed");
}
+#endif
printf_filtered ("Current traced hardware fault set:\n\n");
printf_filtered ("\t%-12s %-8s\n", "Fault", "Trace");
{
QUIT;
printf_filtered ("\t%-12s ", transp -> name);
- printf_filtered ("%-8s", prismember (&pip -> fltset, transp -> value)
+#ifdef UNIXWARE
+ printf_filtered ("%-8s", prismember (&pip->prstatus.pr_flttrace, transp -> value)
? "on" : "off");
+#else
+ printf_filtered ("%-8s", prismember (&pip->fltset.fltset, transp -> value)
+ ? "on" : "off");
+#endif
printf_filtered ("\n");
}
printf_filtered ("\n");
int nmap;
struct prmap *prmaps;
struct prmap *prmap;
+ struct stat sbuf;
if (!summary)
{
" Size",
" Offset",
"Flags");
- if (ioctl (pip -> fd, PIOCNMAP, &nmap) == 0)
+#ifdef PROCFS_USE_READ_WRITE
+ if (fstat (pip->map_fd, &sbuf) == 0)
+ {
+ nmap = sbuf.st_size / sizeof (prmap_t);
+ prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+ if ((lseek (pip->map_fd, 0, SEEK_SET) == 0) &&
+ (read (pip->map_fd, (char *) prmaps,
+ nmap * sizeof (*prmaps)) == (nmap * sizeof (*prmaps))))
+ {
+ int i = 0;
+ for (prmap = prmaps; i < nmap; ++prmap, ++i)
+#else
+ if (ioctl (pip -> ctl_fd, PIOCNMAP, &nmap) == 0)
{
prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
- if (ioctl (pip -> fd, PIOCMAP, prmaps) == 0)
+ if (ioctl (pip -> ctl_fd, PIOCMAP, prmaps) == 0)
{
for (prmap = prmaps; prmap -> pr_size; ++prmap)
+#endif /* PROCFS_USE_READ_WRITE */
{
#ifdef BFD_HOST_64_BIT
printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n",
}
}
}
- printf_filtered ("\n");
+ printf_filtered ("\n");
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ info_proc -- implement the "info proc" command
+
+SYNOPSIS
+
+ void info_proc (char *args, int from_tty)
+
+DESCRIPTION
+
+ Implement gdb's "info proc" command by using the /proc interface
+ to print status information about any currently running process.
+
+ Examples of the use of "info proc" are:
+
+ info proc (prints summary info for current inferior)
+ info proc 123 (prints summary info for process with pid 123)
+ info proc mappings (prints address mappings)
+ info proc times (prints process/children times)
+ info proc id (prints pid, ppid, gid, sid, etc)
+ FIXME: i proc id not implemented.
+ info proc status (prints general process state info)
+ FIXME: i proc status not implemented.
+ info proc signals (prints info about signal handling)
+ info proc all (prints all info)
+
+ */
+
+static void
+info_proc (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ int pid;
+ struct procinfo *pip;
+ struct cleanup *old_chain;
+ char **argv;
+ int argsize;
+ int summary = 1;
+ int flags = 0;
+ int syscalls = 0;
+ int signals = 0;
+ int faults = 0;
+ int mappings = 0;
+ int times = 0;
+ int id = 0;
+ int status = 0;
+ int all = 0;
+ int nlwp;
+ int *lwps;
+
+ old_chain = make_cleanup (null_cleanup, 0);
+
+ /* Default to using the current inferior if no pid specified. Note
+ that inferior_pid may be 0, hence we set okerr. */
+
+ pid = inferior_pid & 0x7fffffff; /* strip off sol-thread bit */
+ if (!(pip = find_procinfo (pid, 1))) /* inferior_pid no good? */
+ pip = procinfo_list; /* take first available */
+ pid = pid & 0xffff; /* extract "real" pid */
+
+ if (args != NULL)
+ {
+ if ((argv = buildargv (args)) == NULL)
+ {
+ nomem (0);
+ }
+ make_cleanup (freeargv, (char *) argv);
+
+ while (*argv != NULL)
+ {
+ argsize = strlen (*argv);
+ if (argsize >= 1 && strncmp (*argv, "all", argsize) == 0)
+ {
+ summary = 0;
+ all = 1;
+ }
+ else if (argsize >= 2 && strncmp (*argv, "faults", argsize) == 0)
+ {
+ summary = 0;
+ faults = 1;
+ }
+ else if (argsize >= 2 && strncmp (*argv, "flags", argsize) == 0)
+ {
+ summary = 0;
+ flags = 1;
+ }
+ else if (argsize >= 1 && strncmp (*argv, "id", argsize) == 0)
+ {
+ summary = 0;
+ id = 1;
+ }
+ else if (argsize >= 1 && strncmp (*argv, "mappings", argsize) == 0)
+ {
+ summary = 0;
+ mappings = 1;
+ }
+ else if (argsize >= 2 && strncmp (*argv, "signals", argsize) == 0)
+ {
+ summary = 0;
+ signals = 1;
+ }
+ else if (argsize >= 2 && strncmp (*argv, "status", argsize) == 0)
+ {
+ summary = 0;
+ status = 1;
+ }
+ else if (argsize >= 2 && strncmp (*argv, "syscalls", argsize) == 0)
+ {
+ summary = 0;
+ syscalls = 1;
+ }
+ else if (argsize >= 1 && strncmp (*argv, "times", argsize) == 0)
+ {
+ summary = 0;
+ times = 1;
+ }
+ else if ((pid = atoi (*argv)) > 0)
+ {
+ pip = (struct procinfo *) xmalloc (sizeof (struct procinfo));
+ memset (pip, 0, sizeof (*pip));
+
+ pip->pid = pid;
+ if (!open_proc_file (pid, pip, O_RDONLY, 0))
+ {
+ perror_with_name (pip -> pathname);
+ /* NOTREACHED */
+ }
+ pid = pip->pid;
+ make_cleanup (close_proc_file, pip);
+ }
+ else if (**argv != '\000')
+ {
+ error ("Unrecognized or ambiguous keyword `%s'.", *argv);
+ }
+ argv++;
+ }
+ }
+
+ /* If we don't have a valid open process at this point, then we have no
+ inferior or didn't specify a specific pid. */
+
+ if (!pip)
+ {
+ error ("\
+No process. Start debugging a program or specify an explicit process ID.");
+ }
+
+ if (!procfs_read_status (pip))
+ {
+ print_sys_errmsg (pip -> pathname, errno);
+ error ("procfs_read_status failed");
+ }
+
+#ifndef PROCFS_USE_READ_WRITE
+#ifdef PIOCLWPIDS
+ nlwp = pip->prstatus.pr_nlwp;
+ lwps = alloca ((2 * nlwp + 2) * sizeof (*lwps));
+
+ if (ioctl (pip->ctl_fd, PIOCLWPIDS, lwps))
+ {
+ print_sys_errmsg (pip -> pathname, errno);
+ error ("PIOCLWPIDS failed");
+ }
+#else /* PIOCLWPIDS */
+ nlwp = 1;
+ lwps = alloca ((2 * nlwp + 2) * sizeof *lwps);
+ lwps[0] = 0;
+#endif /* PIOCLWPIDS */
+
+ for (; nlwp > 0; nlwp--, lwps++)
+ {
+ pip = find_procinfo ((*lwps << 16) | pid, 1);
+
+ if (!pip)
+ {
+ pip = (struct procinfo *) xmalloc (sizeof (struct procinfo));
+ memset (pip, 0, sizeof (*pip));
+ if (!open_proc_file ((*lwps << 16) | pid, pip, O_RDONLY, 0))
+ continue;
+
+ make_cleanup (close_proc_file, pip);
+
+ if (!procfs_read_status (pip))
+ {
+ print_sys_errmsg (pip -> pathname, errno);
+ error ("procfs_read_status failed");
+ }
+ }
+
+#endif /* PROCFS_USE_READ_WRITE */
+
+ /* Print verbose information of the requested type(s), or just a summary
+ of the information for all types. */
+
+ printf_filtered ("\nInformation for %s.%d:\n\n", pip -> pathname, *lwps);
+ if (summary || all || flags)
+ {
+ info_proc_flags (pip, summary);
+ }
+ if (summary || all)
+ {
+ info_proc_stop (pip, summary);
+#ifdef UNIXWARE
+ supply_gregset (&pip->prstatus.pr_lwp.pr_context.uc_mcontext.gregs);
+#else
+ supply_gregset (&pip->prstatus.pr_reg);
+#endif
+ printf_filtered ("PC: ");
+ print_address (read_pc (), gdb_stdout);
+ printf_filtered ("\n");
+ }
+ if (summary || all || signals || faults)
+ {
+ info_proc_siginfo (pip, summary);
+ }
+ if (summary || all || syscalls)
+ {
+ info_proc_syscalls (pip, summary);
+ }
+ if (summary || all || mappings)
+ {
+ info_proc_mappings (pip, summary);
+ }
+ if (summary || all || signals)
+ {
+ info_proc_signals (pip, summary);
+ }
+ if (summary || all || faults)
+ {
+ info_proc_faults (pip, summary);
+ }
+ printf_filtered ("\n");
+
+ /* All done, deal with closing any temporary process info structure,
+ freeing temporary memory , etc. */
+
+ do_cleanups (old_chain);
+#ifndef PROCFS_USE_READ_WRITE
+ }
+#endif
+}
+
+/*
+
+LOCAL FUNCTION
+
+ modify_inherit_on_fork_flag - Change the inherit-on-fork flag
+
+SYNOPSIS
+
+ void modify_inherit_on_fork_flag (fd, flag)
+
+DESCRIPTION
+
+ Call this routine to modify the inherit-on-fork flag. This routine is
+ just a nice wrapper to hide the #ifdefs needed by various systems to
+ control this flag.
+
+ */
+
+static void
+modify_inherit_on_fork_flag (fd, flag)
+ int fd;
+ int flag;
+{
+#if defined (PIOCSET) || defined (PCSET)
+ long pr_flags;
+#endif
+ int retval = 0;
+ struct proc_ctl pctl;
+
+#if defined (PIOCSET) || defined (PCSET) /* New method */
+ pr_flags = PR_FORK;
+ if (flag)
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.cmd = PCSET;
+ pctl.data = PR_FORK;
+ if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+ retval = -1;
+#else
+ retval = ioctl (fd, PIOCSET, &pr_flags);
+#endif
+ }
+ else
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.cmd = PCRESET;
+ pctl.data = PR_FORK;
+ if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+ retval = -1;
+#else
+ retval = ioctl (fd, PIOCRESET, &pr_flags);
+#endif
+ }
+
+#else
+#ifdef PIOCSFORK /* Original method */
+ if (flag)
+ {
+ retval = ioctl (fd, PIOCSFORK, NULL);
+ }
+ else
+ {
+ retval = ioctl (fd, PIOCRFORK, NULL);
+ }
+#else
+ Neither PR_FORK nor PIOCSFORK exist!!!
+#endif
+#endif
+
+ if (!retval)
+ return;
+
+ print_sys_errmsg ("modify_inherit_on_fork_flag", errno);
+ error ("PIOCSFORK or PR_FORK modification failed");
+}
+
+/*
+
+LOCAL FUNCTION
+
+ modify_run_on_last_close_flag - Change the run-on-last-close flag
+
+SYNOPSIS
+
+ void modify_run_on_last_close_flag (fd, flag)
+
+DESCRIPTION
+
+ Call this routine to modify the run-on-last-close flag. This routine
+ is just a nice wrapper to hide the #ifdefs needed by various systems to
+ control this flag.
+
+ */
+
+static void
+modify_run_on_last_close_flag (fd, flag)
+ int fd;
+ int flag;
+{
+#if defined (PIOCSET) || defined (PCSET)
+ long pr_flags;
+#endif
+ int retval = 0;
+ struct proc_ctl pctl;
+
+#if defined (PIOCSET) || defined (PCSET) /* New method */
+ pr_flags = PR_RLC;
+ if (flag)
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.cmd = PCSET;
+ pctl.data = PR_RLC;
+ if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+ retval = -1;
+#else
+ retval = ioctl (fd, PIOCSET, &pr_flags);
+#endif
+ }
+ else
+ {
+#ifdef PROCFS_USE_READ_WRITE
+ pctl.cmd = PCRESET;
+ pctl.data = PR_RLC;
+ if (write (fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+ retval = -1;
+#else
+ retval = ioctl (fd, PIOCRESET, &pr_flags);
+#endif
+ }
+
+#else
+#ifdef PIOCSRLC /* Original method */
+ if (flag)
+ retval = ioctl (fd, PIOCSRLC, NULL);
+ else
+ retval = ioctl (fd, PIOCRRLC, NULL);
+#else
+ Neither PR_RLC nor PIOCSRLC exist!!!
+#endif
+#endif
+
+ if (!retval)
+ return;
+
+ print_sys_errmsg ("modify_run_on_last_close_flag", errno);
+ error ("PIOCSRLC or PR_RLC modification failed");
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_clear_syscall_trap -- Deletes the trap for the specified system call.
+
+SYNOPSIS
+
+ void procfs_clear_syscall_trap (struct procinfo *, int syscall_num, int errok)
+
+DESCRIPTION
+
+ This function function disables traps for the specified system call.
+ errok is non-zero if errors should be ignored.
+ */
+
+static void
+procfs_clear_syscall_trap (pi, syscall_num, errok)
+ struct procinfo *pi;
+ int syscall_num;
+ int errok;
+{
+ sysset_t sysset;
+ int goterr, i;
+
+#ifndef UNIXWARE
+ goterr = ioctl (pi->ctl_fd, PIOCGENTRY, &sysset) < 0;
+
+ if (goterr && !errok)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCGENTRY failed");
+ }
+
+ if (!goterr)
+ {
+ prdelset (&sysset, syscall_num);
+
+ if ((ioctl (pi->ctl_fd, PIOCSENTRY, &sysset) < 0) && !errok)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCSENTRY failed");
+ }
+ }
+
+ goterr = ioctl (pi->ctl_fd, PIOCGEXIT, &sysset) < 0;
+
+ if (goterr && !errok)
+ {
+ procfs_clear_syscall_trap (pi, syscall_num, 1);
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCGEXIT failed");
+ }
+
+ if (!goterr)
+ {
+ praddset (&sysset, syscall_num);
+
+ if ((ioctl (pi->ctl_fd, PIOCSEXIT, &sysset) < 0) && !errok)
+ {
+ procfs_clear_syscall_trap (pi, syscall_num, 1);
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCSEXIT failed");
+ }
+ }
+#endif
+
+ if (!pi->syscall_handlers)
+ {
+ if (!errok)
+ error ("procfs_clear_syscall_trap: syscall_handlers is empty");
+ return;
}
+
+ /* Remove handler func from the handler list */
+
+ for (i = 0; i < pi->num_syscall_handlers; i++)
+ if (pi->syscall_handlers[i].syscall_num == syscall_num)
+ {
+ if (i + 1 != pi->num_syscall_handlers)
+ { /* Not the last entry.
+ Move subsequent entries fwd. */
+ memcpy (&pi->syscall_handlers[i], &pi->syscall_handlers[i + 1],
+ (pi->num_syscall_handlers - i - 1)
+ * sizeof (struct procfs_syscall_handler));
+ }
+
+ pi->syscall_handlers = xrealloc (pi->syscall_handlers,
+ (pi->num_syscall_handlers - 1)
+ * sizeof (struct procfs_syscall_handler));
+ pi->num_syscall_handlers--;
+ return;
+ }
+
+ if (!errok)
+ error ("procfs_clear_syscall_trap: Couldn't find handler for sys call %d",
+ syscall_num);
}
/*
LOCAL FUNCTION
- info_proc -- implement the "info proc" command
+ procfs_set_syscall_trap -- arrange for a function to be called when the
+ child executes the specified system call.
SYNOPSIS
- void info_proc (char *args, int from_tty)
+ void procfs_set_syscall_trap (struct procinfo *, int syscall_num, int flags,
+ syscall_func_t *function)
DESCRIPTION
- Implement gdb's "info proc" command by using the /proc interface
- to print status information about any currently running process.
-
- Examples of the use of "info proc" are:
-
- info proc (prints summary info for current inferior)
- info proc 123 (prints summary info for process with pid 123)
- info proc mappings (prints address mappings)
- info proc times (prints process/children times)
- info proc id (prints pid, ppid, gid, sid, etc)
- FIXME: i proc id not implemented.
- info proc status (prints general process state info)
- FIXME: i proc status not implemented.
- info proc signals (prints info about signal handling)
- info proc all (prints all info)
-
+ This function sets up an entry and/or exit trap for the specified system
+ call. When the child executes the specified system call, your function
+ will be called with the call #, a flag that indicates entry or exit, and
+ pointers to rtnval and statval (which are used by procfs_wait). The
+ function should return non-zero if something interesting happened, zero
+ otherwise.
*/
static void
-info_proc (args, from_tty)
- char *args;
- int from_tty;
+procfs_set_syscall_trap (pi, syscall_num, flags, func)
+ struct procinfo *pi;
+ int syscall_num;
+ int flags;
+ syscall_func_t *func;
{
- int pid;
- struct procinfo *pip;
- struct cleanup *old_chain;
- char **argv;
- int argsize;
- int summary = 1;
- int flags = 0;
- int syscalls = 0;
- int signals = 0;
- int faults = 0;
- int mappings = 0;
- int times = 0;
- int id = 0;
- int status = 0;
- int all = 0;
-
- old_chain = make_cleanup (null_cleanup, 0);
-
- /* Default to using the current inferior if no pid specified. Note
- that inferior_pid may be 0, hence we set okerr. */
-
- pip = find_procinfo (inferior_pid, 1);
+ sysset_t sysset;
- if (args != NULL)
+#ifndef UNIXWARE
+ if (flags & PROCFS_SYSCALL_ENTRY)
{
- if ((argv = buildargv (args)) == NULL)
+ if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysset) < 0)
{
- nomem (0);
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCGENTRY failed");
}
- make_cleanup (freeargv, (char *) argv);
- while (*argv != NULL)
- {
- argsize = strlen (*argv);
- if (argsize >= 1 && strncmp (*argv, "all", argsize) == 0)
- {
- summary = 0;
- all = 1;
- }
- else if (argsize >= 2 && strncmp (*argv, "faults", argsize) == 0)
- {
- summary = 0;
- faults = 1;
- }
- else if (argsize >= 2 && strncmp (*argv, "flags", argsize) == 0)
- {
- summary = 0;
- flags = 1;
- }
- else if (argsize >= 1 && strncmp (*argv, "id", argsize) == 0)
- {
- summary = 0;
- id = 1;
- }
- else if (argsize >= 1 && strncmp (*argv, "mappings", argsize) == 0)
- {
- summary = 0;
- mappings = 1;
- }
- else if (argsize >= 2 && strncmp (*argv, "signals", argsize) == 0)
- {
- summary = 0;
- signals = 1;
- }
- else if (argsize >= 2 && strncmp (*argv, "status", argsize) == 0)
- {
- summary = 0;
- status = 1;
- }
- else if (argsize >= 2 && strncmp (*argv, "syscalls", argsize) == 0)
- {
- summary = 0;
- syscalls = 1;
- }
- else if (argsize >= 1 && strncmp (*argv, "times", argsize) == 0)
- {
- summary = 0;
- times = 1;
- }
- else if ((pid = atoi (*argv)) > 0)
- {
- pip = (struct procinfo *) xmalloc (sizeof (struct procinfo));
- memset (pip, 0, sizeof (*pip));
+ praddset (&sysset, syscall_num);
- pip->pid = pid;
- if (!open_proc_file (pid, pip, O_RDONLY))
- {
- perror_with_name (pip -> pathname);
- /* NOTREACHED */
- }
- make_cleanup (close_proc_file, pip);
- }
- else if (**argv != '\000')
- {
- error ("Unrecognized or ambiguous keyword `%s'.", *argv);
- }
- argv++;
+ if (ioctl (pi->ctl_fd, PIOCSENTRY, &sysset) < 0)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCSENTRY failed");
}
}
- /* If we don't have a valid open process at this point, then we have no
- inferior or didn't specify a specific pid. */
-
- if (!pip)
- {
- error ("\
-No process. Start debugging a program or specify an explicit process ID.");
- }
- if (ioctl (pip -> fd, PIOCSTATUS, &(pip -> prstatus)) < 0)
+ if (flags & PROCFS_SYSCALL_EXIT)
{
- print_sys_errmsg (pip -> pathname, errno);
- error ("PIOCSTATUS failed");
- }
+ if (ioctl (pi->ctl_fd, PIOCGEXIT, &sysset) < 0)
+ {
+ procfs_clear_syscall_trap (pi, syscall_num, 1);
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCGEXIT failed");
+ }
- /* Print verbose information of the requested type(s), or just a summary
- of the information for all types. */
+ praddset (&sysset, syscall_num);
- printf_filtered ("\nInformation for %s:\n\n", pip -> pathname);
- if (summary || all || flags)
- {
- info_proc_flags (pip, summary);
- }
- if (summary || all)
- {
- info_proc_stop (pip, summary);
- }
- if (summary || all || signals || faults)
- {
- info_proc_siginfo (pip, summary);
- }
- if (summary || all || syscalls)
- {
- info_proc_syscalls (pip, summary);
- }
- if (summary || all || mappings)
- {
- info_proc_mappings (pip, summary);
+ if (ioctl (pi->ctl_fd, PIOCSEXIT, &sysset) < 0)
+ {
+ procfs_clear_syscall_trap (pi, syscall_num, 1);
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCSEXIT failed");
+ }
}
- if (summary || all || signals)
+#endif
+
+ if (!pi->syscall_handlers)
{
- info_proc_signals (pip, summary);
+ pi->syscall_handlers = xmalloc (sizeof (struct procfs_syscall_handler));
+ pi->syscall_handlers[0].syscall_num = syscall_num;
+ pi->syscall_handlers[0].func = func;
+ pi->num_syscall_handlers = 1;
}
- if (summary || all || faults)
+ else
{
- info_proc_faults (pip, summary);
- }
- printf_filtered ("\n");
+ int i;
- /* All done, deal with closing any temporary process info structure,
- freeing temporary memory , etc. */
+ for (i = 0; i < pi->num_syscall_handlers; i++)
+ if (pi->syscall_handlers[i].syscall_num == syscall_num)
+ {
+ pi->syscall_handlers[i].func = func;
+ return;
+ }
- do_cleanups (old_chain);
+ pi->syscall_handlers = xrealloc (pi->syscall_handlers, (i + 1)
+ * sizeof (struct procfs_syscall_handler));
+ pi->syscall_handlers[i].syscall_num = syscall_num;
+ pi->syscall_handlers[i].func = func;
+ pi->num_syscall_handlers++;
+ }
}
+#ifdef SYS_lwp_create
+
/*
LOCAL FUNCTION
- procfs_set_sproc_trap -- arrange for child to stop on sproc().
+ procfs_lwp_creation_handler - handle exit from the _lwp_create syscall
SYNOPSIS
- void procfs_set_sproc_trap (struct procinfo *)
+ int procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp)
DESCRIPTION
- This function sets up a trap on sproc system call exits so that we can
- detect the arrival of a new thread. We are called with the new thread
- stopped prior to it's first instruction.
+ This routine is called both when an inferior process and it's new lwp
+ are about to finish a _lwp_create() system call. This is the system
+ call that Solaris uses to create a lightweight process. When the
+ target process gets this event, we can look at sysarg[2] to find the
+ new childs lwp ID, and create a procinfo struct from that. After that,
+ we pretend that we got a SIGTRAP, and return non-zero to tell
+ procfs_wait to wake up. Subsequently, wait_for_inferior gets woken up,
+ sees the new process and continues it.
- Also note that we turn on the inherit-on-fork flag in the child process
- so that any grand-children start with all tracing flags set.
- */
+ When we see the child exiting from lwp_create, we just contine it,
+ since everything was handled when the parent trapped.
-#ifdef SYS_sproc
+NOTES
+ In effect, we are only paying attention to the parent's completion of
+ the lwp_create syscall. If we only paid attention to the child
+ instead, then we wouldn't detect the creation of a suspended thread.
+ */
-static void
-procfs_set_sproc_trap (pi)
+static int
+procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp)
struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
{
- sysset_t exitset;
-
- if (ioctl (pi->fd, PIOCGEXIT, &exitset) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- error ("PIOCGEXIT failed");
- }
+ int lwp_id;
+ struct procinfo *childpi;
+ struct proc_ctl pctl;
- praddset (&exitset, SYS_sproc);
+ /* We've just detected the completion of an lwp_create system call. Now we
+ need to setup a procinfo struct for this thread, and notify the thread
+ system of the new arrival. */
- /* We trap on fork() and vfork() in order to disable debugging in our grand-
- children and descendant processes. At this time, GDB can only handle
- threads (multiple processes, one address space). forks (and execs) result
- in the creation of multiple address spaces, which GDB can't handle yet. */
+ /* If lwp_create failed, then nothing interesting happened. Continue the
+ process and go back to sleep. */
- praddset (&exitset, SYS_fork);
-#ifdef SYS_vfork
- praddset (&exitset, SYS_vfork);
+#ifdef UNIXWARE
+ /* Joel ... can you check this logic out please? JKJ */
+ if (pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs[R_EFL] & 1)
+ { /* _lwp_create failed */
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+
+ if (write (pi->ctl_fd, (char *) &pctl, sizeof (struct proc_ctl)) < 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+ }
+#else /* UNIXWARE */
+ if (PROCFS_GET_CARRY (pi->prstatus.pr_reg))
+ { /* _lwp_create failed */
+ pi->prrun.pr_flags &= PRSTEP;
+ pi->prrun.pr_flags |= PRCFAULT;
+
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+ }
#endif
- if (ioctl (pi->fd, PIOCSEXIT, &exitset) < 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- error ("PIOCSEXIT failed");
+ /* At this point, the new thread is stopped at it's first instruction, and
+ the parent is stopped at the exit from lwp_create. */
+
+ if (pi->new_child) /* Child? */
+ { /* Yes, just continue it */
+#ifdef UNIXWARE
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+
+ if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0)
+#else /* !UNIXWARE */
+ pi->prrun.pr_flags &= PRSTEP;
+ pi->prrun.pr_flags |= PRCFAULT;
+
+ if ((pi->prstatus.pr_flags & PR_ISTOP)
+ && ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+#endif /* !UNIXWARE */
+ perror_with_name (pi->pathname);
+
+ pi->new_child = 0; /* No longer new */
+
+ return 0;
}
- /* Turn on inherit-on-fork flag so that all grand-children of gdb start with
- tracing flags set. */
+ /* We're the proud parent of a new thread. Setup an exit trap for lwp_create
+ in the child and continue the parent. */
-#ifdef PIOCSET /* New method */
- {
- long pr_flags;
- pr_flags = PR_FORK;
- ioctl (pi->fd, PIOCSET, &pr_flags);
- }
+ /* Third arg is pointer to new thread id. */
+#ifdef UNIXWARE
+ lwp_id = read_memory_integer (pi->prstatus.pr_lwp.pr_sysarg[2], sizeof (int));
#else
-#ifdef PIOCSFORK /* Original method */
- ioctl (pi->fd, PIOCSFORK, NULL);
+ lwp_id = read_memory_integer (pi->prstatus.pr_sysarg[2], sizeof (int));
+#endif
+
+ lwp_id = (lwp_id << 16) | PIDGET (pi->pid);
+
+ childpi = create_procinfo (lwp_id);
+
+ /* The new process has actually inherited the lwp_create syscall trap from
+ it's parent, but we still have to call this to register handlers for
+ that child. */
+
+ procfs_set_inferior_syscall_traps (childpi);
+ add_thread (lwp_id);
+ printf_filtered ("[New %s]\n", target_pid_to_str (lwp_id));
+
+ /* Continue the parent */
+#ifdef UNIXWARE
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+
+ if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0)
+#else
+ pi->prrun.pr_flags &= PRSTEP;
+ pi->prrun.pr_flags |= PRCFAULT;
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+#endif
+ perror_with_name (pi->pathname);
+
+ /* The new child may have been created in one of two states:
+ SUSPENDED or RUNNABLE. If runnable, we will simply signal it to run.
+ If suspended, we flag it to be continued later, when it has an event. */
+
+#ifdef UNIXWARE
+ if (childpi->prstatus.pr_lwp.pr_why == PR_SUSPENDED)
+#else
+ if (childpi->prstatus.pr_why == PR_SUSPENDED)
#endif
+ childpi->new_child = 1; /* Flag this as an unseen child process */
+ else
+ {
+ /* Continue the child */
+#ifdef UNIXWARE
+ pctl.cmd = PCRUN;
+ pctl.data = PRCFAULT;
+
+ if (write(pi->ctl_fd, (char *)&pctl, sizeof (struct proc_ctl)) < 0)
+#else
+ childpi->prrun.pr_flags &= PRSTEP;
+ childpi->prrun.pr_flags |= PRCFAULT;
+
+ if (ioctl (childpi->ctl_fd, PIOCRUN, &childpi->prrun) != 0)
#endif
+ perror_with_name (childpi->pathname);
+ }
+ return 0;
}
-#endif /* SYS_sproc */
+#endif /* SYS_lwp_create */
/* Fork an inferior process, and start debugging it with /proc. */
/* We are at the first instruction we care about. */
/* Pedal to the metal... */
- /* Setup traps on exit from sproc() */
-
-#ifdef SYS_sproc
- procfs_set_sproc_trap (current_procinfo);
-#endif
-
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
}
static int
procfs_can_run ()
{
- return(1);
+ /* This variable is controlled by modules that sit atop procfs that may layer
+ their own process structure atop that provided here. sol-thread.c does
+ this because of the Solaris two-level thread model. */
+
+ return !procfs_suppress_run;
}
#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
+#ifndef UNIXWARE
\f
/* Insert a watchpoint */
int
wpt.pr_vaddr = (caddr_t)addr;
wpt.pr_size = len;
wpt.pr_wflags = ((rw & 1) ? MA_READ : 0) | ((rw & 2) ? MA_WRITE : 0);
- if (ioctl (pi->fd, PIOCSWATCH, &wpt) < 0)
+ if (ioctl (pi->ctl_fd, PIOCSWATCH, &wpt) < 0)
{
if (errno == E2BIG)
return -1;
what = pi->prstatus.pr_what;
if (why == PR_FAULTED
#if defined (FLTWATCH) && defined (FLTKWATCH)
- && (what == FLTWATCH) || (what == FLTKWATCH)
+ && (what == FLTWATCH || what == FLTKWATCH)
#else
#ifdef FLTWATCH
&& (what == FLTWATCH)
}
return 0;
}
-#endif
+#endif /* !UNIXWARE */
+#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
+
+/* Why is this necessary? Shouldn't dead threads just be removed from the
+ thread database? */
+
+static int
+procfs_thread_alive (pid)
+ int pid;
+{
+ struct procinfo *pi, *next_pi;
+
+ for (pi = procinfo_list; pi; pi = next_pi)
+ {
+ next_pi = pi->next;
+ if (pi -> pid == pid)
+ if (procfs_read_status (pi)) /* alive */
+ return 1;
+ else /* defunct (exited) */
+ {
+ close_proc_file (pi);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+procfs_first_available ()
+{
+ struct procinfo *pi;
+
+ for (pi = procinfo_list; pi; pi = pi->next)
+ {
+ if (procfs_read_status (pi))
+ return pi->pid;
+ }
+ return -1;
+}
+
+int
+procfs_get_pid_fd (pid)
+ int pid;
+{
+ struct procinfo *pi = find_procinfo (pid, 1);
+
+ if (pi == NULL)
+ return -1;
+
+ return pi->ctl_fd;
+}
/* Send a SIGINT to the process group. This acts just like the user typed a
^C on the controlling terminal.
XXX - This may not be correct for all systems. Some may want to use
killpg() instead of kill (-pgrp). */
-void
+static void
procfs_stop ()
{
extern pid_t inferior_process_group;
kill (-inferior_process_group, SIGINT);
}
+\f
+/* Convert a pid to printable form. */
+
+#ifdef TIDGET
+char *
+procfs_pid_to_str (pid)
+ int pid;
+{
+ static char buf[100];
+ sprintf (buf, "Kernel thread %d", TIDGET (pid));
+
+ return buf;
+}
+#endif /* TIDGET */
\f
struct target_ops procfs_ops = {
"procfs", /* to_shortname */
procfs_mourn_inferior, /* to_mourn_inferior */
procfs_can_run, /* to_can_run */
procfs_notice_signals, /* to_notice_signals */
- 0, /* to_thread_alive */
+ procfs_thread_alive, /* to_thread_alive */
procfs_stop, /* to_stop */
process_stratum, /* to_stratum */
0, /* to_next */
_initialize_procfs ()
{
#ifdef HAVE_OPTIONAL_PROC_FS
- char procname[32];
+ char procname[MAX_PROC_NAME_SIZE];
int fd;
/* If we have an optional /proc filesystem (e.g. under OSF/1),
don't add procfs support if we cannot access the running
GDB via /proc. */
- sprintf (procname, PROC_NAME_FMT, getpid ());
+ sprintf (procname, STATUS_PROC_NAME_FMT, getpid ());
if ((fd = open (procname, O_RDONLY)) < 0)
return;
close (fd);
add_target (&procfs_ops);
- add_info ("proc", info_proc,
+ add_info ("processes", info_proc,
"Show process status information using /proc entry.\n\
Specify process id or use current inferior by default.\n\
Specify keywords for detailed information; default is summary.\n\