* stabsread.c (get_substring): Declare second arg as int.
[deliverable/binutils-gdb.git] / gdb / procfs.c
index 72a9c69f7c5e3d9cc7c798503cb582210910ff13..8a2eda47fbe31515a3e1f9eb70cb1e4e14171ff0 100644 (file)
@@ -1,5 +1,5 @@
 /* Machine independent support for SVR4 /proc (process file system) for GDB.
-   Copyright 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
    Written by Fred Fish at Cygnus Support.
 
 This file is part of GDB.
@@ -16,7 +16,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 
 /*                     N  O  T  E  S
@@ -34,16 +34,24 @@ regardless of whether or not the actual target has floating point hardware.
 
 #include "defs.h"
 
+#include <sys/types.h>
 #include <time.h>
+#include <sys/fault.h>
+#include <sys/syscall.h>
 #include <sys/procfs.h>
 #include <fcntl.h>
 #include <errno.h>
-#include <string.h>
+#include "gdb_string.h"
+#include <stropts.h>
+#include <poll.h>
+#include <unistd.h>
+#include "gdb_stat.h"
 
 #include "inferior.h"
 #include "target.h"
 #include "command.h"
 #include "gdbcore.h"
+#include "gdbthread.h"
 
 #define MAX_SYSCALLS   256     /* Maximum number of syscalls for table */
 
@@ -53,6 +61,11 @@ regardless of whether or not the actual target has floating point hardware.
 
 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
@@ -74,10 +87,11 @@ CORE_ADDR kernel_u_addr;
     the inferior's procinfo information. */
 
 struct procinfo {
-  int valid;                   /* Nonzero if pid, fd, & pathname are valid */
+  struct procinfo *next;
   int pid;                     /* Process ID of inferior */
   int fd;                      /* File descriptor for /proc entry */
   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 */
   prrun_t prrun;               /* Control state when it is run */
@@ -93,9 +107,17 @@ struct procinfo {
   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 */
+  int num_syscall_handlers;    /* Number of syscall handlers currently installed */
+  struct procfs_syscall_handler *syscall_handlers; /* Pointer to list of syscall trap handlers */
+  int new_child;               /* Non-zero if it's a new thread */
 };
 
-static struct procinfo pi;     /* Inferior's process information */
+/* 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 */
 
 /*  Much of the information used in the /proc interface, particularly for
     printing status information, is kept as tables of structures of the
@@ -114,45 +136,45 @@ struct trans {
 static struct trans pr_flag_table[] =
 {
 #if defined (PR_STOPPED)
-  PR_STOPPED, "PR_STOPPED", "Process is stopped",
+  { PR_STOPPED, "PR_STOPPED", "Process is stopped" },
 #endif
 #if defined (PR_ISTOP)
-  PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest",
+  { PR_ISTOP, "PR_ISTOP", "Stopped on an event of interest" },
 #endif
 #if defined (PR_DSTOP)
-  PR_DSTOP, "PR_DSTOP", "A stop directive is in effect",
+  { PR_DSTOP, "PR_DSTOP", "A stop directive is in effect" },
 #endif
 #if defined (PR_ASLEEP)
-  PR_ASLEEP, "PR_ASLEEP", "Sleeping in an interruptible system call",
+  { PR_ASLEEP, "PR_ASLEEP", "Sleeping in an interruptible system call" },
 #endif
 #if defined (PR_FORK)
-  PR_FORK, "PR_FORK", "Inherit-on-fork is in effect",
+  { PR_FORK, "PR_FORK", "Inherit-on-fork is in effect" },
 #endif
 #if defined (PR_RLC)
-  PR_RLC, "PR_RLC", "Run-on-last-close is in effect",
+  { PR_RLC, "PR_RLC", "Run-on-last-close is in effect" },
 #endif
 #if defined (PR_PTRACE)
-  PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace",
+  { PR_PTRACE, "PR_PTRACE", "Process is being controlled by ptrace" },
 #endif
 #if defined (PR_PCINVAL)
-  PR_PCINVAL, "PR_PCINVAL", "PC refers to an invalid virtual address",
+  { PR_PCINVAL, "PR_PCINVAL", "PC refers to an invalid virtual address" },
 #endif
 #if defined (PR_ISSYS)
-  PR_ISSYS, "PR_ISSYS", "Is a system process",
+  { PR_ISSYS, "PR_ISSYS", "Is a system process" },
 #endif
 #if defined (PR_STEP)
-  PR_STEP, "PR_STEP", "Process has single step pending",
+  { PR_STEP, "PR_STEP", "Process has single step pending" },
 #endif
 #if defined (PR_KLC)
-  PR_KLC, "PR_KLC", "Kill-on-last-close is in effect",
+  { PR_KLC, "PR_KLC", "Kill-on-last-close is in effect" },
 #endif
 #if defined (PR_ASYNC)
-  PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect",
+  { PR_ASYNC, "PR_ASYNC", "Asynchronous stop is in effect" },
 #endif
 #if defined (PR_PCOMPAT)
-  PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect",
+  { PR_PCOMPAT, "PR_PCOMPAT", "Ptrace compatibility mode in effect" },
 #endif
- 0, NULL, NULL
+  { 0, NULL, NULL }
 };
 
 /*  Translate values in the pr_why field of the prstatus struct. */
@@ -160,27 +182,27 @@ static struct trans pr_flag_table[] =
 static struct trans pr_why_table[] =
 {
 #if defined (PR_REQUESTED)
PR_REQUESTED, "PR_REQUESTED", "Directed to stop via PIOCSTOP/PIOCWSTOP",
 { PR_REQUESTED, "PR_REQUESTED", "Directed to stop via PIOCSTOP/PIOCWSTOP" },
 #endif
 #if defined (PR_SIGNALLED)
PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal",
 { PR_SIGNALLED, "PR_SIGNALLED", "Receipt of a traced signal" },
 #endif
 #if defined (PR_FAULTED)
PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault",
 { PR_FAULTED, "PR_FAULTED", "Incurred a traced hardware fault" },
 #endif
 #if defined (PR_SYSENTRY)
PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call",
 { PR_SYSENTRY, "PR_SYSENTRY", "Entry to a traced system call" },
 #endif
 #if defined (PR_SYSEXIT)
PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call",
 { PR_SYSEXIT, "PR_SYSEXIT", "Exit from a traced system call" },
 #endif
 #if defined (PR_JOBCONTROL)
PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action",
 { PR_JOBCONTROL, "PR_JOBCONTROL", "Default job control stop signal action" },
 #endif
 #if defined (PR_SUSPENDED)
PR_SUSPENDED, "PR_SUSPENDED", "Process suspended",
 { PR_SUSPENDED, "PR_SUSPENDED", "Process suspended" },
 #endif
- 0, NULL, NULL
+  { 0, NULL, NULL }
 };
 
 /*  Hardware fault translation table. */
@@ -188,39 +210,39 @@ static struct trans pr_why_table[] =
 static struct trans faults_table[] =
 {
 #if defined (FLTILL)
FLTILL, "FLTILL", "Illegal instruction",
 { FLTILL, "FLTILL", "Illegal instruction" },
 #endif
 #if defined (FLTPRIV)
FLTPRIV, "FLTPRIV", "Privileged instruction",
 { FLTPRIV, "FLTPRIV", "Privileged instruction" },
 #endif
 #if defined (FLTBPT)
FLTBPT, "FLTBPT", "Breakpoint trap",
 { FLTBPT, "FLTBPT", "Breakpoint trap" },
 #endif
 #if defined (FLTTRACE)
FLTTRACE, "FLTTRACE", "Trace trap",
 { FLTTRACE, "FLTTRACE", "Trace trap" },
 #endif
 #if defined (FLTACCESS)
FLTACCESS, "FLTACCESS", "Memory access fault",
 { FLTACCESS, "FLTACCESS", "Memory access fault" },
 #endif
 #if defined (FLTBOUNDS)
FLTBOUNDS, "FLTBOUNDS", "Memory bounds violation",
 { FLTBOUNDS, "FLTBOUNDS", "Memory bounds violation" },
 #endif
 #if defined (FLTIOVF)
FLTIOVF, "FLTIOVF", "Integer overflow",
 { FLTIOVF, "FLTIOVF", "Integer overflow" },
 #endif
 #if defined (FLTIZDIV)
FLTIZDIV, "FLTIZDIV", "Integer zero divide",
 { FLTIZDIV, "FLTIZDIV", "Integer zero divide" },
 #endif
 #if defined (FLTFPE)
FLTFPE, "FLTFPE", "Floating-point exception",
 { FLTFPE, "FLTFPE", "Floating-point exception" },
 #endif
 #if defined (FLTSTACK)
FLTSTACK, "FLTSTACK", "Unrecoverable stack fault",
 { FLTSTACK, "FLTSTACK", "Unrecoverable stack fault" },
 #endif
 #if defined (FLTPAGE)
FLTPAGE, "FLTPAGE", "Recoverable page fault",
 { FLTPAGE, "FLTPAGE", "Recoverable page fault" },
 #endif
- 0, NULL, NULL
+  { 0, NULL, NULL }
 };
 
 /* Translation table for signal generation information.  See UNIX System
@@ -233,206 +255,448 @@ static struct sigcode {
   char *desc;
 } siginfo_table[] = {
 #if defined (SIGILL) && defined (ILL_ILLOPC)
-  SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode",
+  { SIGILL, ILL_ILLOPC, "ILL_ILLOPC", "Illegal opcode" },
 #endif
 #if defined (SIGILL) && defined (ILL_ILLOPN)
-  SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand",
+  { SIGILL, ILL_ILLOPN, "ILL_ILLOPN", "Illegal operand", },
 #endif
 #if defined (SIGILL) && defined (ILL_ILLADR)
-  SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode",
+  { SIGILL, ILL_ILLADR, "ILL_ILLADR", "Illegal addressing mode" },
 #endif
 #if defined (SIGILL) && defined (ILL_ILLTRP)
-  SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap",
+  { SIGILL, ILL_ILLTRP, "ILL_ILLTRP", "Illegal trap" },
 #endif
 #if defined (SIGILL) && defined (ILL_PRVOPC)
-  SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode",
+  { SIGILL, ILL_PRVOPC, "ILL_PRVOPC", "Privileged opcode" },
 #endif
 #if defined (SIGILL) && defined (ILL_PRVREG)
-  SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register",
+  { SIGILL, ILL_PRVREG, "ILL_PRVREG", "Privileged register" },
 #endif
 #if defined (SIGILL) && defined (ILL_COPROC)
-  SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error",
+  { SIGILL, ILL_COPROC, "ILL_COPROC", "Coprocessor error" },
 #endif
 #if defined (SIGILL) && defined (ILL_BADSTK)
-  SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error",
+  { SIGILL, ILL_BADSTK, "ILL_BADSTK", "Internal stack error" },
 #endif
 #if defined (SIGFPE) && defined (FPE_INTDIV)
-  SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero",
+  { SIGFPE, FPE_INTDIV, "FPE_INTDIV", "Integer divide by zero" },
 #endif
 #if defined (SIGFPE) && defined (FPE_INTOVF)
-  SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow",
+  { SIGFPE, FPE_INTOVF, "FPE_INTOVF", "Integer overflow" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTDIV)
-  SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating point divide by zero",
+  { SIGFPE, FPE_FLTDIV, "FPE_FLTDIV", "Floating point divide by zero" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTOVF)
-  SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating point overflow",
+  { SIGFPE, FPE_FLTOVF, "FPE_FLTOVF", "Floating point overflow" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTUND)
-  SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating point underflow",
+  { SIGFPE, FPE_FLTUND, "FPE_FLTUND", "Floating point underflow" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTRES)
-  SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating point inexact result",
+  { SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating point inexact result" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTINV)
-  SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating point operation",
+  { SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating point operation" },
 #endif
 #if defined (SIGFPE) && defined (FPE_FLTSUB)
-  SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range",
+  { SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range" },
 #endif
 #if defined (SIGSEGV) && defined (SEGV_MAPERR)
-  SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object",
+  { SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object" },
 #endif
 #if defined (SIGSEGV) && defined (SEGV_ACCERR)
-  SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for object",
+  { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for object" },
 #endif
 #if defined (SIGBUS) && defined (BUS_ADRALN)
-  SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment",
+  { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment" },
 #endif
 #if defined (SIGBUS) && defined (BUS_ADRERR)
-  SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Non-existent physical address",
+  { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Non-existent physical address" },
 #endif
 #if defined (SIGBUS) && defined (BUS_OBJERR)
-  SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object specific hardware error",
+  { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object specific hardware error" },
 #endif
 #if defined (SIGTRAP) && defined (TRAP_BRKPT)
-  SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint",
+  { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint" },
 #endif
 #if defined (SIGTRAP) && defined (TRAP_TRACE)
-  SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap",
+  { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap" },
 #endif
 #if defined (SIGCLD) && defined (CLD_EXITED)
-  SIGCLD, CLD_EXITED, "CLD_EXITED", "Child has exited",
+  { SIGCLD, CLD_EXITED, "CLD_EXITED", "Child has exited" },
 #endif
 #if defined (SIGCLD) && defined (CLD_KILLED)
-  SIGCLD, CLD_KILLED, "CLD_KILLED", "Child was killed",
+  { SIGCLD, CLD_KILLED, "CLD_KILLED", "Child was killed" },
 #endif
 #if defined (SIGCLD) && defined (CLD_DUMPED)
-  SIGCLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally",
+  { SIGCLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally" },
 #endif
 #if defined (SIGCLD) && defined (CLD_TRAPPED)
-  SIGCLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped",
+  { SIGCLD, CLD_TRAPPED, "CLD_TRAPPED", "Traced child has trapped" },
 #endif
 #if defined (SIGCLD) && defined (CLD_STOPPED)
-  SIGCLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped",
+  { SIGCLD, CLD_STOPPED, "CLD_STOPPED", "Child has stopped" },
 #endif
 #if defined (SIGCLD) && defined (CLD_CONTINUED)
-  SIGCLD, CLD_CONTINUED, "CLD_CONTINUED", "Stopped child had continued",
+  { SIGCLD, CLD_CONTINUED, "CLD_CONTINUED", "Stopped child had continued" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_IN)
-  SIGPOLL, POLL_IN, "POLL_IN", "Input input available",
+  { SIGPOLL, POLL_IN, "POLL_IN", "Input input available" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_OUT)
-  SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available",
+  { SIGPOLL, POLL_OUT, "POLL_OUT", "Output buffers available" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_MSG)
-  SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available",
+  { SIGPOLL, POLL_MSG, "POLL_MSG", "Input message available" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_ERR)
-  SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error",
+  { SIGPOLL, POLL_ERR, "POLL_ERR", "I/O error" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_PRI)
-  SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available",
+  { SIGPOLL, POLL_PRI, "POLL_PRI", "High priority input available" },
 #endif
 #if defined (SIGPOLL) && defined (POLL_HUP)
-  SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected",
+  { SIGPOLL, POLL_HUP, "POLL_HUP", "Device disconnected" },
 #endif
-  0, 0, NULL, NULL
+  { 0, 0, NULL, NULL }
 };
 
 static char *syscall_table[MAX_SYSCALLS];
 
 /* Prototypes for local functions */
 
-static void
-set_proc_siginfo PARAMS ((struct procinfo *, int));
+static void procfs_stop PARAMS ((void));
 
-static void
-init_syscall_table PARAMS ((void));
+static int procfs_thread_alive PARAMS ((int));
 
-static char *
-syscallname PARAMS ((int));
+static int procfs_can_run PARAMS ((void));
 
-static char *
-signalname PARAMS ((int));
+static void procfs_mourn_inferior PARAMS ((void));
 
-static char *
-errnoname PARAMS ((int));
+static void procfs_fetch_registers PARAMS ((int));
 
-static int
-proc_address_to_fd PARAMS ((CORE_ADDR, int));
+static int procfs_wait PARAMS ((int, struct target_waitstatus *));
 
-static int
-open_proc_file PARAMS ((int, struct procinfo *, int));
+static void procfs_open PARAMS ((char *, int));
 
-static void
-close_proc_file PARAMS ((struct procinfo *));
+static void procfs_files_info PARAMS ((struct target_ops *));
 
-static void
-unconditionally_kill_inferior PARAMS ((void));
+static void procfs_prepare_to_store PARAMS ((void));
 
-static void
-proc_init_failed PARAMS ((char *));
+static void procfs_detach PARAMS ((char *, int));
 
-static void
-info_proc PARAMS ((char *, int));
+static void procfs_attach PARAMS ((char *, int));
 
-static void
-info_proc_flags PARAMS ((struct procinfo *, int));
+static void proc_set_exec_trap PARAMS ((void));
 
-static void
-info_proc_stop PARAMS ((struct procinfo *, int));
+static int procfs_init_inferior PARAMS ((int));
 
-static void
-info_proc_siginfo PARAMS ((struct procinfo *, int));
+static struct procinfo *create_procinfo PARAMS ((int));
 
-static void
-info_proc_syscalls PARAMS ((struct procinfo *, int));
+static void procfs_store_registers PARAMS ((int));
 
-static void
-info_proc_mappings PARAMS ((struct procinfo *, int));
+static int procfs_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
 
-static void
-info_proc_signals PARAMS ((struct procinfo *, int));
+static void procfs_kill_inferior PARAMS ((void));
 
-static void
-info_proc_faults PARAMS ((struct procinfo *, int));
+static char *sigcodedesc PARAMS ((siginfo_t *));
 
-static char *
-mappingflags PARAMS ((long));
+static char *sigcodename PARAMS ((siginfo_t *));
 
-static char *
-lookupname PARAMS ((struct trans *, unsigned int, char *));
+static struct procinfo *wait_fd PARAMS ((void));
 
-static char *
-lookupdesc PARAMS ((struct trans *, unsigned int));
+static void remove_fd PARAMS ((struct procinfo *));
 
-static int
-do_attach PARAMS ((int pid));
+static void add_fd PARAMS ((struct procinfo *));
 
-static void
-do_detach PARAMS ((int siggnal));
+static void set_proc_siginfo PARAMS ((struct procinfo *, int));
 
-static void
-procfs_create_inferior PARAMS ((char *, char *, char **));
+static void init_syscall_table PARAMS ((void));
 
-static void
-procfs_notice_signals PARAMS ((void));
+static char *syscallname PARAMS ((int));
+
+static char *signalname PARAMS ((int));
+
+static char *errnoname PARAMS ((int));
+
+static int proc_address_to_fd PARAMS ((struct procinfo *, CORE_ADDR, int));
+
+static int open_proc_file PARAMS ((int, struct procinfo *, 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 void info_proc PARAMS ((char *, int));
+
+static void info_proc_flags PARAMS ((struct procinfo *, int));
+
+static void info_proc_stop PARAMS ((struct procinfo *, int));
+
+static void info_proc_siginfo PARAMS ((struct procinfo *, int));
+
+static void info_proc_syscalls PARAMS ((struct procinfo *, int));
+
+static void info_proc_mappings PARAMS ((struct procinfo *, int));
+
+static void info_proc_signals PARAMS ((struct procinfo *, int));
+
+static void info_proc_faults PARAMS ((struct procinfo *, int));
+
+static char *mappingflags PARAMS ((long));
+
+static char *lookupname PARAMS ((struct trans *, unsigned int, char *));
+
+static char *lookupdesc PARAMS ((struct trans *, unsigned int));
+
+static int do_attach PARAMS ((int pid));
+
+static void do_detach PARAMS ((int siggnal));
+
+static void procfs_create_inferior PARAMS ((char *, char *, char **));
+
+static void procfs_notice_signals PARAMS ((int pid));
+
+static struct procinfo *find_procinfo PARAMS ((pid_t pid, int okfail));
+
+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
-supply_gregset PARAMS ((gregset_t *));
+extern void supply_gregset PARAMS ((gregset_t *));
+
+extern void fill_gregset PARAMS ((gregset_t *, int));
+
+extern void supply_fpregset PARAMS ((fpregset_t *));
+
+extern void fill_fpregset PARAMS ((fpregset_t *, int));
+
+/*
+
+LOCAL FUNCTION
+
+       find_procinfo -- convert a process id to a struct procinfo
+
+SYNOPSIS
+
+       static struct procinfo * find_procinfo (pid_t pid, int okfail);
+
+DESCRIPTION
+       
+       Given a process id, look it up in the procinfo chain.  Returns
+       a struct procinfo *.  If can't find pid, then call error(),
+       unless okfail is set, in which case, return NULL;
+ */
+
+static struct procinfo *
+find_procinfo (pid, okfail)
+     pid_t pid;
+     int okfail;
+{
+  struct procinfo *procinfo;
+
+  for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+    if (procinfo->pid == pid)
+      return procinfo;
+
+  if (okfail)
+    return NULL;
+
+  error ("procfs (find_procinfo):  Couldn't locate pid %d", pid);
+}
+
+/*
+
+LOCAL MACRO
+
+       current_procinfo -- convert inferior_pid to a struct procinfo
+
+SYNOPSIS
+
+       static struct procinfo * current_procinfo;
+
+DESCRIPTION
+       
+       Looks up inferior_pid in the procinfo chain.  Always returns a
+       struct procinfo *.  If process can't be found, we error() out.
+ */
+
+#define current_procinfo find_procinfo (inferior_pid, 0)
+
+/*
+
+LOCAL FUNCTION
+
+       add_fd -- Add the fd to the poll/select list
+
+SYNOPSIS
+
+       static void add_fd (struct procinfo *);
+
+DESCRIPTION
+       
+       Add the fd of the supplied procinfo to the list of fds used for
+       poll/select operations.
+ */
+
+static void
+add_fd (pi)
+     struct procinfo *pi;
+{
+  if (num_poll_list <= 0)
+    poll_list = (struct pollfd *) xmalloc (sizeof (struct pollfd));
+  else
+    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].events = POLLPRI;
+
+  num_poll_list++;
+}
+
+static void
+remove_fd (pi)
+     struct procinfo *pi;
+{
+  int i;
+
+  for (i = 0; i < num_poll_list; i++)
+    {
+      if (poll_list[i].fd == pi->fd)
+       {
+         if (i != num_poll_list - 1)
+           memcpy (poll_list + i, poll_list + i + 1,
+                   (num_poll_list - i - 1) * sizeof (struct pollfd));
+
+         num_poll_list--;
+
+         if (num_poll_list == 0)
+           free (poll_list);
+         else
+           poll_list = (struct pollfd *) xrealloc (poll_list,
+                                                   num_poll_list
+                                                   * sizeof (struct pollfd));
+         return;
+       }
+    }
+}
+
+static struct procinfo *
+wait_fd ()
+{
+  struct procinfo *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 ();
+
+#ifndef LOSING_POLL
+  num_fds = poll (poll_list, num_poll_list, -1);
+#else
+  pi = current_procinfo;
+
+  while (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
+    {
+      if (errno == ENOENT)
+       {
+         /* Process exited.  */
+         pi->prstatus.pr_flags = 0;
+         break;
+       }
+      else if (errno != EINTR)
+       {
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCWSTOP failed");
+       }
+    }
+  pi->had_event = 1;
+#endif  
+  
+  clear_sigint_trap ();
+  clear_sigio_trap ();
+
+#ifndef LOSING_POLL
 
-extern void
-fill_gregset PARAMS ((gregset_t *, int));
+  if (num_fds <= 0)
+    {
+      print_sys_errmsg ("poll failed\n", errno);
+      error ("Poll failed, returned %d", num_fds);
+    }
 
-extern void
-supply_fpregset PARAMS ((fpregset_t *));
+  for (i = 0; i < num_poll_list && num_fds > 0; i++)
+    {
+      if ((poll_list[i].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL)) == 0)
+       continue;
+      for (pi = procinfo_list; pi; pi = pi->next)
+       {
+         if (poll_list[i].fd == pi->fd)
+           {
+             if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
+               {
+                 print_sys_errmsg (pi->pathname, errno);
+                 error ("PIOCSTATUS failed");
+               }
+             num_fds--;
+             pi->had_event = 1;
+             break;
+           }
+       }
+      if (!pi)
+       error ("wait_fd: Couldn't find procinfo for fd %d\n",
+              poll_list[i].fd);
+    }
+#endif /* LOSING_POLL */
 
-extern void
-fill_fpregset PARAMS ((fpregset_t *, int));
+  return pi;
+}
 
 /*
 
@@ -603,18 +867,15 @@ syscallname (syscallnum)
      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);
 }
 
 /*
@@ -1011,36 +1272,9 @@ init_syscall_table ()
 #if defined (SYS_seteuid)
   syscall_table[SYS_seteuid] = "seteuid";
 #endif
-}
-
-/*
-
-GLOBAL FUNCTION
-
-       ptrace -- override library version to force errors for /proc version
-
-SYNOPSIS
-
-       int ptrace (int request, int pid, PTRACE_ARG3_TYPE arg3, int arg4)
-
-DESCRIPTION
-
-       When gdb is configured to use /proc, it should not be calling
-       or otherwise attempting to use ptrace.  In order to catch errors
-       where use of /proc is configured, but some routine is still calling
-       ptrace, we provide a local version of a function with that name
-       that does nothing but issue an error message.
-*/
-
-int
-ptrace (request, pid, arg3, arg4)
-     int request;
-     int pid;
-     PTRACE_ARG3_TYPE arg3;
-     int arg4;
-{
-  error ("internal error - there is a call to ptrace() somewhere");
-  /*NOTREACHED*/
+#if defined (SYS_sproc)
+  syscall_table[SYS_sproc] = "sproc";
+#endif
 }
 
 /*
@@ -1068,11 +1302,7 @@ NOTES
 static void
 procfs_kill_inferior ()
 {
-  if (inferior_pid != 0)
-    {
-      unconditionally_kill_inferior ();
-      target_mourn_inferior ();
-    }
+  target_mourn_inferior ();
 }
 
 /*
@@ -1083,30 +1313,66 @@ LOCAL FUNCTION
 
 SYNOPSIS
 
-       static void unconditionally_kill_inferior (void)
+       static void unconditionally_kill_inferior (struct procinfo *)
 
 DESCRIPTION
 
-       Kill the current inferior.  Should not be called until it
-       is at least tested that there is an inferior.
+       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.
+       suicide, before we murder it (we could call that
+       politely_kill_inferior()).
 
 */
 
 static void
-unconditionally_kill_inferior ()
+unconditionally_kill_inferior (pi)
+     struct procinfo *pi;
 {
   int signo;
+  int ppid;
   
+  ppid = pi->prstatus.pr_ppid;
+
   signo = SIGKILL;
-  ioctl (pi.fd, PIOCKILL, &signo);
-  close_proc_file (&pi);
-  wait ((int *) 0);
+
+#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);
+#endif
+#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL
+  /* Alpha OSF/1-2.x procfs needs a PIOCSSIG call with a SIGKILL signal
+     to kill the inferior, otherwise it might remain stopped with a
+     pending SIGKILL.
+     We do not check the result of the PIOCSSIG, the inferior might have
+     died already.  */
+  {
+    struct siginfo newsiginfo;
+
+    memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
+    newsiginfo.si_signo = signo;
+    newsiginfo.si_code = 0;
+    newsiginfo.si_errno = 0;
+    newsiginfo.si_pid = getpid ();
+    newsiginfo.si_uid = getuid ();
+    ioctl (pi->fd, PIOCSSIG, &newsiginfo);
+  }
+#else
+  ioctl (pi->fd, PIOCKILL, &signo);
+#endif
+
+  close_proc_file (pi);
+
+/* Only wait() for our direct children.  Our grandchildren zombies are killed
+   by the death of their parents.  */
+
+  if (ppid == getpid())
+    wait ((int *) 0);
 }
 
 /*
@@ -1145,16 +1411,19 @@ procfs_xfer_memory (memaddr, myaddr, len, dowrite, target)
      struct target_ops *target; /* ignored */
 {
   int nbytes = 0;
+  struct procinfo *pi;
+
+  pi = current_procinfo;
 
-  if (lseek (pi.fd, (off_t) memaddr, 0) == (off_t) memaddr)
+  if (lseek(pi->fd, (off_t) memaddr, 0) == (off_t) memaddr)
     {
       if (dowrite)
        {
-         nbytes = write (pi.fd, myaddr, len);
+         nbytes = write (pi->fd, myaddr, len);
        }
       else
        {
-         nbytes = read (pi.fd, myaddr, len);
+         nbytes = read (pi->fd, myaddr, len);
        }
       if (nbytes < 0)
        {
@@ -1206,12 +1475,16 @@ static void
 procfs_store_registers (regno)
      int regno;
 {
+  struct procinfo *pi;
+
+  pi = current_procinfo;
+
   if (regno != -1)
     {
-      ioctl (pi.fd, PIOCGREG, &pi.gregset);
+      ioctl (pi->fd, PIOCGREG, &pi->gregset);
     }
-  fill_gregset (&pi.gregset, regno);
-  ioctl (pi.fd, PIOCSREG, &pi.gregset);
+  fill_gregset (&pi->gregset, regno);
+  ioctl (pi->fd, PIOCSREG, &pi->gregset);
 
 #if defined (FP0_REGNUM)
 
@@ -1221,10 +1494,10 @@ procfs_store_registers (regno)
 
   if (regno != -1)
     {
-      ioctl (pi.fd, PIOCGFPREG, &pi.fpregset);
+      ioctl (pi->fd, PIOCGFPREG, &pi->fpregset);
     }
-  fill_fpregset (&pi.fpregset, regno);
-  ioctl (pi.fd, PIOCSFPREG, &pi.fpregset);
+  fill_fpregset (&pi->fpregset, regno);
+  ioctl (pi->fd, PIOCSFPREG, &pi->fpregset);
 
 #endif /* FP0_REGNUM */
 
@@ -1234,19 +1507,17 @@ procfs_store_registers (regno)
 
 LOCAL FUNCTION
 
-       procfs_init_inferior - initialize 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
 
@@ -1255,108 +1526,432 @@ NOTES
 
  */
 
-static void
-procfs_init_inferior (pid)
+static struct procinfo *
+create_procinfo (pid)
      int pid;
 {
+  struct procinfo *pi;
 
-  push_target (&procfs_ops);
+  pi = find_procinfo (pid, 1);
+  if (pi != NULL)
+    return pi;                 /* All done!  It already exists */
 
-  if (!open_proc_file (pid, &pi, O_RDWR))
-    {
-      proc_init_failed ("can't open process file");
-    }
-  else
-    {
-      memset ((char *) &pi.prrun, 0, sizeof (pi.prrun));
-      prfillset (&pi.prrun.pr_trace);
-      procfs_notice_signals ();
-      prfillset (&pi.prrun.pr_fault);
-      prdelset (&pi.prrun.pr_fault, FLTPAGE);
-      if (ioctl (pi.fd, PIOCWSTOP, &pi.prstatus) < 0)
-       {
-         proc_init_failed ("PIOCWSTOP failed");
-       }
-      else if (ioctl (pi.fd, PIOCSFAULT, &pi.prrun.pr_fault) < 0)
-       {
-         proc_init_failed ("PIOCSFAULT failed");
-       }
-    }
-}
+  pi = (struct procinfo *) xmalloc (sizeof (struct procinfo));
 
-/*
+  if (!open_proc_file (pid, pi, O_RDWR))
+    proc_init_failed (pi, "can't open process file");
 
-GLOBAL FUNCTION
+  /* open_proc_file may modify pid.  */
 
-       procfs_notice_signals
+  pid = pi -> pid;
 
-SYNOPSIS
+  /* Add new process to process info list */
 
-       static void procfs_notice_signals (void);
+  pi->next = procinfo_list;
+  procinfo_list = pi;
 
-DESCRIPTION
+  add_fd (pi);                 /* Add to list for poll/select */
 
-       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.
+  pi->num_syscall_handlers = 0;
+  pi->syscall_handlers = NULL;
+  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);
 
-       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.
- */
+#ifdef PROCFS_DONT_TRACE_FAULTS
+  premptyset (&pi->prrun.pr_fault);
+#endif
 
-static void
-procfs_notice_signals ()
-{
-  int signo;
+  if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
+    proc_init_failed (pi, "PIOCSTATUS failed");
 
-  if (pi.valid)
-    {
-      for (signo = 0; signo < NSIG; signo++)
-       {
-         if (signal_stop_state (signo) == 0 &&
-             signal_print_state (signo) == 0 &&
-             signal_pass_state (signo) == 1)
-           {
-             prdelset (&pi.prrun.pr_trace, signo);
-           }
-         else
-           {
-             praddset (&pi.prrun.pr_trace, signo);
-           }
-       }
-      if (ioctl (pi.fd, PIOCSTRACE, &pi.prrun.pr_trace))
-       {
-         print_sys_errmsg ("PIOCSTRACE failed", errno);
-       }
-    }
+/* 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))
+    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");
+
+  return pi;
 }
 
 /*
 
 LOCAL FUNCTION
 
-       proc_set_exec_trap -- arrange for exec'd child to halt at startup
+       procfs_exit_handler - handle entry into the _exit syscall
 
 SYNOPSIS
 
-       void proc_set_exec_trap (void)
+       int procfs_exit_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 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.
 
-NOTE
+NOTES
+       There is probably a better way to do this.
+
+ */
+
+static int
+procfs_exit_handler (pi, syscall_num, why, rtnvalp, statvalp)
+     struct procinfo *pi;
+     int syscall_num;
+     int why;
+     int *rtnvalp;
+     int *statvalp;
+{
+  pi->prrun.pr_flags = PRCFAULT;
+
+  if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
+    perror_with_name (pi->pathname);
+
+  *rtnvalp = wait (statvalp);
+  if (*rtnvalp >= 0)
+    *rtnvalp = pi->pid;
+
+  return 1;
+}
+
+/*
+
+LOCAL FUNCTION
+
+       procfs_exec_handler - handle exit from the exec family of syscalls
+
+SYNOPSIS
+
+       int procfs_exec_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+       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.
+
+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;
+}
+
+#ifdef SYS_sproc               /* 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->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->fd, PIOCRUN, &pi->prrun) != 0)
+    perror_with_name (pi->pathname);
+
+  return 0;
+}
+#endif /* SYS_sproc */
+
+/*
+
+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_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->fd, 1);
+#endif
+
+#ifdef SYS_lwp_create
+  procfs_set_syscall_trap (pip, SYS_lwp_create, PROCFS_SYSCALL_EXIT,
+                          procfs_lwp_creation_handler);
+#endif
+
+  /* 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;
+{
+  int signo;
+  struct procinfo *pi;
+
+  pi = find_procinfo (pid, 0);
+
+  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 (&pi->prrun.pr_trace, signo);
+       }
+      else
+       {
+         praddset (&pi->prrun.pr_trace, signo);
+       }
+    }
+  if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace))
+    {
+      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
@@ -1371,6 +1966,7 @@ static void
 proc_set_exec_trap ()
 {
   sysset_t exitset;
+  sysset_t entryset;
   auto char procname[32];
   int fd;
   
@@ -1378,11 +1974,33 @@ proc_set_exec_trap ()
   if ((fd = open (procname, O_RDWR)) < 0)
     {
       perror (procname);
-      fflush (stderr);
+      gdb_flush (gdb_stderr);
       _exit (127);
     }
   premptyset (&exitset);
+  premptyset (&entryset);
 
+#ifdef PIOCSSPCACT
+  /* Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace
+     exits from exec system calls because of the user level loader.  */
+  {
+    int prfs_flags;
+
+    if (ioctl (fd, PIOCGSPCACT, &prfs_flags) < 0)
+      {
+       perror (procname);
+       gdb_flush (gdb_stderr);
+       _exit (127);
+      }
+    prfs_flags |= PRFS_STOPEXEC;
+    if (ioctl (fd, PIOCSSPCACT, &prfs_flags) < 0)
+      {
+       perror (procname);
+       gdb_flush (gdb_stderr);
+       _exit (127);
+      }
+  }
+#else
   /* 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
@@ -1395,45 +2013,49 @@ proc_set_exec_trap ()
   praddset (&exitset, SYS_execve);
 #endif
 #ifdef SYS_execv
-  praddset(&exitset, SYS_execv);
+  praddset (&exitset, SYS_execv);
 #endif
 
   if (ioctl (fd, PIOCSEXIT, &exitset) < 0)
     {
       perror (procname);
-      fflush (stderr);
+      gdb_flush (gdb_stderr);
       _exit (127);
     }
+#endif
+
+  praddset (&entryset, SYS_exit);
+
+  if (ioctl (fd, PIOCSENTRY, &entryset) < 0)
+    {
+      perror (procname);
+      gdb_flush (gdb_stderr);
+      _exit (126);
+    }
 
   /* 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;
+
+/* 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;
+
+    ioctl (fd, PIOCSET, &pr_flags);
   }
-#else
-#if defined (PIOCSRLC) /* Original method */
-  (void) ioctl (fd, PIOCSRLC, 0);
-#endif
-#endif
+#endif /* PR_ASYNC */
 }
 
 /*
@@ -1464,15 +2086,18 @@ proc_iterate_over_mappings (func)
   int funcstat = 0;
   struct prmap *prmaps;
   struct prmap *prmap;
+  struct procinfo *pi;
 
-  if (pi.valid && (ioctl (pi.fd, PIOCNMAP, &nmap) == 0))
+  pi = current_procinfo;
+
+  if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0)
     {
       prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
-      if (ioctl (pi.fd, PIOCMAP, prmaps) == 0)
+      if (ioctl (pi->fd, PIOCMAP, prmaps) == 0)
        {
          for (prmap = prmaps; prmap -> pr_size && funcstat == 0; ++prmap)
            {
-             fd = proc_address_to_fd ((CORE_ADDR) prmap -> pr_vaddr, 0);
+             fd = proc_address_to_fd (pi, (CORE_ADDR) prmap -> pr_vaddr, 0);
              funcstat = (*func) (fd, (CORE_ADDR) prmap -> pr_vaddr);
              close (fd);
            }
@@ -1511,11 +2136,14 @@ proc_base_address (addr)
   struct prmap *prmaps;
   struct prmap *prmap;
   CORE_ADDR baseaddr = 0;
+  struct procinfo *pi;
+
+  pi = current_procinfo;
 
-  if (pi.valid && (ioctl (pi.fd, PIOCNMAP, &nmap) == 0))
+  if (ioctl (pi->fd, PIOCNMAP, &nmap) == 0)
     {
       prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
-      if (ioctl (pi.fd, PIOCMAP, prmaps) == 0)
+      if (ioctl (pi->fd, PIOCMAP, prmaps) == 0)
        {
          for (prmap = prmaps; prmap -> pr_size; ++prmap)
            {
@@ -1541,7 +2169,7 @@ LOCAL FUNCTION
 
 SYNOPSIS
 
-       int proc_address_to_fd (CORE_ADDR addr, complain)
+       int proc_address_to_fd (struct procinfo *pi, CORE_ADDR addr, complain)
 
 DESCRIPTION
 
@@ -1554,21 +2182,19 @@ DESCRIPTION
 */
 
 static int
-proc_address_to_fd (addr, complain)
+proc_address_to_fd (pi, addr, complain)
+     struct procinfo *pi;
      CORE_ADDR addr;
      int complain;
 {
   int fd = -1;
 
-  if (pi.valid)
+  if ((fd = ioctl (pi->fd, PIOCOPENM, (caddr_t *) &addr)) < 0)
     {
-      if ((fd = ioctl (pi.fd, PIOCOPENM, (caddr_t *) &addr)) < 0)
+      if (complain)
        {
-         if (complain)
-           {
-             print_sys_errmsg (pi.pathname, errno);
-             warning ("can't find mapped file for address 0x%x", addr);
-           }
+         print_sys_errmsg (pi->pathname, errno);
+         warning ("can't find mapped file for address 0x%x", addr);
        }
     }
   return (fd);
@@ -1599,15 +2225,14 @@ procfs_attach (args, from_tty)
       exec_file = (char *) get_exec_file (0);
 
       if (exec_file)
-       printf ("Attaching program `%s', pid %d\n", exec_file, pid);
+       printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
       else
-       printf ("Attaching pid %d\n", pid);
+       printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
 
-      fflush (stdout);
+      gdb_flush (gdb_stdout);
     }
 
-  do_attach (pid);
-  inferior_pid = pid;
+  inferior_pid = pid = do_attach (pid);
   push_target (&procfs_ops);
 }
 
@@ -1632,9 +2257,9 @@ procfs_detach (args, from_tty)
       char *exec_file = get_exec_file (0);
       if (exec_file == 0)
        exec_file = "";
-      printf ("Detaching program: %s pid %d\n",
-             exec_file, inferior_pid);
-      fflush (stdout);
+      printf_unfiltered ("Detaching from program: %s %s\n",
+             exec_file, target_pid_to_str (inferior_pid));
+      gdb_flush (gdb_stdout);
     }
   if (args)
     siggnal = atoi (args);
@@ -1664,8 +2289,8 @@ static void
 procfs_files_info (ignore)
      struct target_ops *ignore;
 {
-  printf ("\tUsing the running image of %s process %d via /proc.\n",
-         attach_flag? "attached": "child", inferior_pid);
+  printf_unfiltered ("\tUsing the running image of %s %s via /proc.\n",
+         attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
 }
 
 /* ARGSUSED */
@@ -1706,86 +2331,89 @@ static int
 do_attach (pid)
      int pid;
 {
-  int result;
+  struct procinfo *pi;
+
+  pi = (struct procinfo *) xmalloc (sizeof (struct procinfo));
 
-  if (!open_proc_file (pid, &pi, O_RDWR))
+  if (!open_proc_file (pid, pi, O_RDWR))
     {
-      perror_with_name (pi.pathname);
+      free (pi);
+      perror_with_name (pi->pathname);
       /* NOTREACHED */
     }
   
+  pid = pi -> pid;
+
+  /* Add new process to process info list */
+
+  pi->next = procinfo_list;
+  procinfo_list = pi;
+
+  add_fd (pi);                 /* Add to list for poll/select */
+
   /*  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)
+  if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      close_proc_file (&pi);
+      print_sys_errmsg (pi->pathname, errno);
+      close_proc_file (pi);
       error ("PIOCSTATUS failed");
     }
-  if (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+  if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
     {
-      pi.was_stopped = 1;
+      pi->was_stopped = 1;
     }
   else
     {
-      pi.was_stopped = 0;
+      pi->was_stopped = 0;
       if (1 || query ("Process is currently running, stop it? "))
        {
          /* 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);
-         }
-#else
-#if defined (PIOCSRLC) /* Original method */
-         result = ioctl (pi.fd, PIOCSRLC, 0);
-#endif
-#endif
-         if (result < 0)
-           {
-             print_sys_errmsg (pi.pathname, errno);
-             close_proc_file (&pi);
-             error ("PIOCSRLC or PIOCSET failed");
-           }
-         if (ioctl (pi.fd, PIOCSTOP, &pi.prstatus) < 0)
+
+         modify_run_on_last_close_flag (pi->fd, 1);
+
+         if (ioctl (pi->fd, PIOCSTOP, &pi->prstatus) < 0)
            {
-             print_sys_errmsg (pi.pathname, errno);
-             close_proc_file (&pi);
+             print_sys_errmsg (pi->pathname, errno);
+             close_proc_file (pi);
              error ("PIOCSTOP failed");
            }
-         pi.nopass_next_sigstop = 1;
+         pi->nopass_next_sigstop = 1;
        }
       else
        {
-         printf ("Ok, gdb will wait for process %u to stop.\n", pid);
+         printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid));
        }
     }
 
   /*  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);
+  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 ();
-  prfillset (&pi.prrun.pr_fault);
-  prdelset (&pi.prrun.pr_fault, FLTPAGE);
-  if (ioctl (pi.fd, PIOCSFAULT, &pi.prrun.pr_fault))
+  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))
+  if (ioctl (pi->fd, PIOCSTRACE, &pi->prrun.pr_trace))
     {
       print_sys_errmsg ("PIOCSTRACE failed", errno);
     }
@@ -1826,147 +2454,141 @@ static void
 do_detach (signal)
      int signal;
 {
-  int result;
+  struct procinfo *pi;
+
+  pi = current_procinfo;
 
   if (signal)
     {
-      set_proc_siginfo (&pi, signal);
+      set_proc_siginfo (pi, signal);
     }
-  if (ioctl (pi.fd, PIOCSEXIT, &pi.saved_exitset) < 0)
+  if (ioctl (pi->fd, PIOCSEXIT, &pi->saved_exitset) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOCSEXIT failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOCSEXIT failed.\n");
     }
-  if (ioctl (pi.fd, PIOCSENTRY, &pi.saved_entryset) < 0)
+  if (ioctl (pi->fd, PIOCSENTRY, &pi->saved_entryset) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOCSENTRY failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOCSENTRY failed.\n");
     }
-  if (ioctl (pi.fd, PIOCSTRACE, &pi.saved_trace) < 0)
+  if (ioctl (pi->fd, PIOCSTRACE, &pi->saved_trace) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOCSTRACE failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOCSTRACE failed.\n");
     }
-  if (ioctl (pi.fd, PIOCSHOLD, &pi.saved_sighold) < 0)
+  if (ioctl (pi->fd, PIOCSHOLD, &pi->saved_sighold) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOSCHOLD failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOSCHOLD failed.\n");
     }
-  if (ioctl (pi.fd, PIOCSFAULT, &pi.saved_fltset) < 0)
+  if (ioctl (pi->fd, PIOCSFAULT, &pi->saved_fltset) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOCSFAULT failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOCSFAULT failed.\n");
     }
-  if (ioctl (pi.fd, PIOCSTATUS, &pi.prstatus) < 0)
+  if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
     {
-      print_sys_errmsg (pi.pathname, errno);
-      printf ("PIOCSTATUS failed.\n");
+      print_sys_errmsg (pi->pathname, errno);
+      printf_unfiltered ("PIOCSTATUS failed.\n");
     }
   else
     {
-      if (signal || (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
+      if (signal || (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
        {
-         if (signal || !pi.was_stopped ||
+         if (signal || !pi->was_stopped ||
              query ("Was stopped when attached, make it runnable again? "))
            {
+             /* 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.  */
-             if (ioctl (pi.fd, PIOCCFAULT, 0))
-               {
-                 print_sys_errmsg (pi.pathname, errno);
-                 printf ("PIOCCFAULT failed.\n");
-               }
+             if (ioctl (pi->fd, PIOCCFAULT, 0))
+               {
+                 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);
-             }
-#else
-#if defined (PIOCSRLC) /* Original method */
-             result = ioctl (pi.fd, PIOCSRLC, 0);
-#endif
-#endif
-             if (result)
-               {
-                 print_sys_errmsg (pi.pathname, errno);
-                 printf ("PIOCSRLC or PIOCSET failed.\n");
-               }
+
+             modify_run_on_last_close_flag (pi->fd, 1);
            }
        }
     }
-  close_proc_file (&pi);
+  close_proc_file (pi);
   attach_flag = 0;
 }
 
-/*
-
-LOCAL FUNCTION
-
-       procfs_wait -- emulate wait() as much as possible
-       Wait for child to do something.  Return pid of child, or -1 in case
-       of error; store status through argument pointer STATUS.
-
-
-SYNOPSIS
-
-       int procfs_wait (int *statloc)
-
-DESCRIPTION
-
-       Try to emulate wait() as much as possible.  Not sure why we can't
-       just use wait(), but it seems to have problems when applied to a
-       process being controlled with the /proc interface.
-
-NOTES
-
-       We have a race problem here with no obvious solution.  We need to let
-       the inferior run until it stops on an event of interest, which means
-       that we need to use the PIOCWSTOP ioctl.  However, we cannot use this
-       ioctl if the process is already stopped on something that is not an
-       event of interest, or the call will hang indefinitely.  Thus we first
-       use PIOCSTATUS to see if the process is not stopped.  If not, then we
-       use PIOCWSTOP.  But during the window between the two, if the process
-       stops for any reason that is not an event of interest (such as a job
-       control signal) then gdb will hang.  One possible workaround is to set
-       an alarm to wake up every minute of so and check to see if the process
-       is still running, and if so, then reissue the PIOCWSTOP.  But this is
-       a real kludge, so has not been implemented.  FIXME: investigate
-       alternatives.
-
-       FIXME:  Investigate why wait() seems to have problems with programs
-       being control by /proc routines.
-
- */
+/*  emulate wait() as much as possible.
+    Wait for child to do something.  Return pid of child, or -1 in case
+    of error; store status in *OURSTATUS.
+
+    Not sure why we can't
+    just use wait(), but it seems to have problems when applied to a
+    process being controlled with the /proc interface.
+
+    We have a race problem here with no obvious solution.  We need to let
+    the inferior run until it stops on an event of interest, which means
+    that we need to use the PIOCWSTOP ioctl.  However, we cannot use this
+    ioctl if the process is already stopped on something that is not an
+    event of interest, or the call will hang indefinitely.  Thus we first
+    use PIOCSTATUS to see if the process is not stopped.  If not, then we
+    use PIOCWSTOP.  But during the window between the two, if the process
+    stops for any reason that is not an event of interest (such as a job
+    control signal) then gdb will hang.  One possible workaround is to set
+    an alarm to wake up every minute of so and check to see if the process
+    is still running, and if so, then reissue the PIOCWSTOP.  But this is
+    a real kludge, so has not been implemented.  FIXME: investigate
+    alternatives.
+
+    FIXME:  Investigate why wait() seems to have problems with programs
+    being control by /proc routines.  */
 
 static int
-procfs_wait (statloc)
-     int *statloc;
+procfs_wait (pid, ourstatus)
+     int pid;
+     struct target_waitstatus *ourstatus;
 {
   short what;
   short why;
   int statval = 0;
   int checkerr = 0;
   int rtnval = -1;
-  
-  if (ioctl (pi.fd, PIOCSTATUS, &pi.prstatus) < 0)
+  struct procinfo *pi;
+
+  if (pid != -1)               /* Non-specific process? */
+    pi = NULL;
+  else
+    for (pi = procinfo_list; pi; pi = pi->next)
+      if (pi->had_event)
+       break;
+
+  if (!pi)
     {
-      checkerr++;
+    wait_again:
+
+      if (pi)
+       pi->had_event = 0;
+
+      pi = wait_fd ();
     }
-  else if (!(pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
-    {
-      if (attach_flag)
-       set_sigint_trap();      /* Causes SIGINT to be passed on to the
-                                  attached process. */
 
-      if (ioctl (pi.fd, PIOCWSTOP, &pi.prstatus) < 0)
+  if (pid != -1)
+    for (pi = procinfo_list; pi; pi = pi->next)
+      if (pi->pid == pid && pi->had_event)
+       break;
+
+  if (!pi && !checkerr)
+    goto wait_again;
+
+  if (!checkerr && !(pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)))
+    {
+      if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
        {
          checkerr++;
        }
-
-      if (attach_flag)
-       clear_sigint_trap();
     }    
   if (checkerr)
     {
@@ -1975,57 +2597,75 @@ procfs_wait (statloc)
          rtnval = wait (&statval);
          if (rtnval != inferior_pid)
            {
-             print_sys_errmsg (pi.pathname, errno);
+             print_sys_errmsg (pi->pathname, errno);
              error ("PIOCWSTOP, wait failed, returned %d", rtnval);
              /* NOTREACHED */
            }
        }
       else
        {
-         print_sys_errmsg (pi.pathname, errno);
+         print_sys_errmsg (pi->pathname, errno);
          error ("PIOCSTATUS or PIOCWSTOP failed.");
          /* NOTREACHED */
        }
     }
-  else if (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+  else if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
     {
-      rtnval = pi.prstatus.pr_pid;
-      why = pi.prstatus.pr_why;
-      what = pi.prstatus.pr_what;
-      if (why == PR_SIGNALLED)
+      rtnval = pi->pid;
+      why = pi->prstatus.pr_why;
+      what = pi->prstatus.pr_what;
+
+      switch (why)
        {
+       case PR_SIGNALLED:
          statval = (what << 8) | 0177;
-       }
-      else if ((why == PR_SYSEXIT)
-              &&
-              (
-#ifdef SYS_exec
-               what == SYS_exec
-#else
-               0 == 0
-#endif
-#ifdef SYS_execve
-               || what == SYS_execve
-#endif
-#ifdef SYS_execv
-               || what == SYS_execv
-#endif
-               ))
-       {
-         statval = (SIGTRAP << 8) | 0177;
-       }
-      else if (why == PR_REQUESTED)
-       {
+         break;
+       case PR_SYSENTRY:
+       case PR_SYSEXIT:
+         {
+           int i;
+           int found_handler = 0;
+
+           for (i = 0; i < pi->num_syscall_handlers; i++)
+             if (pi->syscall_handlers[i].syscall_num == what)
+               {
+                 found_handler = 1;
+                 if (!pi->syscall_handlers[i].func (pi, what, why,
+                                                    &rtnval, &statval))
+                   goto wait_again;
+
+                 break;
+               }
+
+           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;
-       }
-      else if (why == PR_JOBCONTROL)
-       {
+         break;
+       case PR_JOBCONTROL:
          statval = (what << 8) | 0177;
-       }
-      else if (why == PR_FAULTED)
-       {
+         break;
+       case PR_FAULTED:
          switch (what)
            {
+#ifdef FLTWATCH
+           case FLTWATCH:
+             statval = (SIGTRAP << 8) | 0177;
+             break;
+#endif
+#ifdef FLTKWATCH
+           case FLTKWATCH:
+             statval = (SIGTRAP << 8) | 0177;
+             break;
+#endif
+#ifndef FAULTED_USE_SIGINFO
+             /* Irix, contrary to the documentation, fills in 0 for si_signo.
+                Solaris fills in si_signo.  I'm not sure about others.  */
            case FLTPRIV:
            case FLTILL:
              statval = (SIGILL << 8) | 0177;
@@ -2033,7 +2673,7 @@ procfs_wait (statloc)
            case FLTBPT:
            case FLTTRACE:
              statval = (SIGTRAP << 8) | 0177;
-             break;
+             break;          
            case FLTSTACK:
            case FLTACCESS:
            case FLTBOUNDS:
@@ -2045,38 +2685,63 @@ procfs_wait (statloc)
              statval = (SIGFPE << 8) | 0177;
              break;
            case FLTPAGE:               /* Recoverable page fault */
+#endif /* not FAULTED_USE_SIGINFO */
            default:
-             rtnval = -1;
-             error ("PIOCWSTOP, unknown why %d, what %d", why, what);
-             /* NOTREACHED */
+             /* 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.  */
+             statval = ((pi->prstatus.pr_info.si_signo) << 8) | 0177;
+             break;
            }
-       }
-      else
-       {
-         rtnval = -1;
+         break;
+       default:
          error ("PIOCWSTOP, unknown why %d, what %d", why, what);
-         /* NOTREACHED */
        }
+/* Stop all the other threads when any of them stops.  */
+
+      {
+       struct procinfo *procinfo;
+
+       for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+         {
+           if (!procinfo->had_event)
+             {
+               /* 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 (ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus) < 0)
+                 {
+                   print_sys_errmsg (procinfo->pathname, errno);
+                   error ("PIOCSTATUS failed");
+                 }
+               if (!(procinfo->prstatus.pr_flags & PR_STOPPED))
+                 if (ioctl (procinfo->fd, PIOCSTOP, &procinfo->prstatus) < 0)
+                   {
+                     print_sys_errmsg (procinfo->pathname, errno);
+                     error ("PIOCSTOP failed");
+                   }
+             }
+         }
+      }
     }
   else
     {
       error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x", 
-            pi.prstatus.pr_flags);
-         /* NOTREACHED */
+            pi->prstatus.pr_flags);
     }
 
-  if (statloc)
-    {
-      *statloc = statval;
-    }
+  store_waitstatus (ourstatus, statval);
 
   if (rtnval == -1)            /* No more children to wait for */
     {
-      fprintf (stderr, "Child process unexpectedly missing.\n");
-      *statloc = 42;   /* Claim it exited with signal 42 */
+      fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing.\n");
+      /* Claim it exited with unknown signal.  */
+      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
       return rtnval;
     }
 
+  pi->had_event = 0;           /* Indicate that we've seen this one */
   return (rtnval);
 }
 
@@ -2126,43 +2791,52 @@ set_proc_siginfo (pip, signo)
   struct siginfo newsiginfo;
   struct siginfo *sip;
 
-  if (pip -> valid)
+#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.  */
+  if (signo == pip -> prstatus.pr_cursig)
+    return;
+#endif
+
+  if (signo == pip -> prstatus.pr_info.si_signo)
     {
-      if (signo == pip -> prstatus.pr_info.si_signo)
-       {
-         sip = &pip -> prstatus.pr_info;
-       }
-      else
-       {
-         memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
-         sip = &newsiginfo;
-         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)
-       {
-         print_sys_errmsg (pip -> pathname, errno);
-         warning ("PIOCSSIG failed");
-       }
+      sip = &pip -> prstatus.pr_info;
+    }
+  else
+    {
+      memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
+      sip = &newsiginfo;
+      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)
+    {
+      print_sys_errmsg (pip -> pathname, errno);
+      warning ("PIOCSSIG failed");
     }
 }
 
-/* Resume execution of the inferior process.  If STEP is nozero, then
+/* Resume execution of process PID.  If STEP is nozero, then
    just single step it.  If SIGNAL is nonzero, restart it with that
    signal activated.  */
 
 static void
-procfs_resume (step, signo)
+procfs_resume (pid, step, signo)
+     int pid;
      int step;
-     int signo;
+     enum target_signal signo;
 {
   int signal_to_pass;
+  struct procinfo *pi, *procinfo;
+
+  pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
 
   errno = 0;
-  pi.prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT;
+  pi->prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT;
 
 #if 0
   /* It should not be necessary.  If the user explicitly changes the value,
@@ -2179,12 +2853,12 @@ procfs_resume (step, signo)
    random garbage.  We have to rely on the fact that PC and nPC have been
    written previously via PIOCSREG during a register flush. */
 
-  pi.prrun.pr_vaddr = (caddr_t) *(int *) &registers[REGISTER_BYTE (PC_REGNUM)];
-  pi.prrun.pr_flags != PRSVADDR;
+  pi->prrun.pr_vaddr = (caddr_t) *(int *) &registers[REGISTER_BYTE (PC_REGNUM)];
+  pi->prrun.pr_flags != PRSVADDR;
 #endif
 #endif
 
-  if (signo == SIGSTOP && pi.nopass_next_sigstop)
+  if (signo == TARGET_SIGNAL_STOP && pi->nopass_next_sigstop)
     /* When attaching to a child process, if we forced it to stop with
        a PIOCSTOP, then we will have set the nopass_next_sigstop flag.
        Upon resuming the first time after such a stop, we explicitly
@@ -2196,9 +2870,9 @@ procfs_resume (step, signo)
        deal with the inferior a little smarter, and possibly even allow
        an inferior to continue running at the same time as gdb.  (FIXME?)  */
     signal_to_pass = 0;
-  else if (signo == SIGTSTP
-          && pi.prstatus.pr_cursig == SIGTSTP
-          && pi.prstatus.pr_action.sa_handler == SIG_DFL)
+  else if (signo == TARGET_SIGNAL_TSTP
+          && pi->prstatus.pr_cursig == SIGTSTP
+          && pi->prstatus.pr_action.sa_handler == SIG_DFL)
 
     /* We are about to pass the inferior a SIGTSTP whose action is
        SIG_DFL.  The SIG_DFL action for a SIGTSTP is to stop
@@ -2216,26 +2890,62 @@ procfs_resume (step, signo)
        because the handler needs to get executed.  */
     signal_to_pass = 0;
   else
-    signal_to_pass = signo;
+    signal_to_pass = target_signal_to_host (signo);
 
   if (signal_to_pass)
     {
-      set_proc_siginfo (&pi, signal_to_pass);
+      set_proc_siginfo (pi, signal_to_pass);
     }
   else
     {
-      pi.prrun.pr_flags |= PRCSIG;
+      pi->prrun.pr_flags |= PRCSIG;
     }
-  pi.nopass_next_sigstop = 0;
+  pi->nopass_next_sigstop = 0;
   if (step)
     {
-      pi.prrun.pr_flags |= PRSTEP;
+      pi->prrun.pr_flags |= PRSTEP;
     }
-  if (ioctl (pi.fd, PIOCRUN, &pi.prrun) != 0)
+
+  /* Don't try to start a process unless it's stopped on an
+     `event of interest'.  Doing so will cause errors.  */
+
+  if ((pi->prstatus.pr_flags & PR_ISTOP)
+       && ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
     {
-      perror_with_name (pi.pathname);
+      perror_with_name (pi->pathname);
       /* NOTREACHED */
     }
+
+  pi->had_event = 0;
+
+  /* Continue all the other threads that haven't had an event of
+     interest.  */
+
+  if (pid == -1)
+    for (procinfo = procinfo_list; procinfo; procinfo = procinfo->next)
+      {
+       if (pi != procinfo && !procinfo->had_event)
+         {
+           procinfo->prrun.pr_flags &= PRSTEP;
+           procinfo->prrun.pr_flags |= PRCFAULT | PRCSIG;
+           ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus);
+
+           /* 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->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);
+         }
+      }
 }
 
 /*
@@ -2260,14 +2970,18 @@ static void
 procfs_fetch_registers (regno)
      int regno;
 {
-  if (ioctl (pi.fd, PIOCGREG, &pi.gregset) != -1)
+  struct procinfo *pi;
+
+  pi = current_procinfo;
+
+  if (ioctl (pi->fd, PIOCGREG, &pi->gregset) != -1)
     {
-      supply_gregset (&pi.gregset);
+      supply_gregset (&pi->gregset);
     }
 #if defined (FP0_REGNUM)
-  if (ioctl (pi.fd, PIOCGFPREG, &pi.fpregset) != -1)
+  if (ioctl (pi->fd, PIOCGFPREG, &pi->fpregset) != -1)
     {
-      supply_fpregset (&pi.fpregset);
+      supply_fpregset (&pi->fpregset);
     }
 #endif
 }
@@ -2276,11 +2990,12 @@ procfs_fetch_registers (regno)
 
 LOCAL FUNCTION
 
-       proc_init_failed - called whenever /proc access initialization fails
+       proc_init_failed - called whenever /proc access initialization
+fails
 
 SYNOPSIS
 
-       static void proc_init_failed (char *why)
+       static void proc_init_failed (struct procinfo *pi, char *why)
 
 DESCRIPTION
 
@@ -2291,12 +3006,13 @@ DESCRIPTION
  */
 
 static void
-proc_init_failed (why)
+proc_init_failed (pi, why)
+     struct procinfo *pi;
      char *why;
 {
-  print_sys_errmsg (pi.pathname, errno);
-  kill (pi.pid, SIGKILL);
-  close_proc_file (&pi);
+  print_sys_errmsg (pi->pathname, errno);
+  kill (pi->pid, SIGKILL);
+  close_proc_file (pi);
   error (why);
   /* NOTREACHED */
 }
@@ -2324,18 +3040,24 @@ static void
 close_proc_file (pip)
      struct procinfo *pip;
 {
-  pip -> pid = 0;
-  if (pip -> valid)
-    {
-      close (pip -> fd);
-    }
-  pip -> fd = -1;
-  if (pip -> pathname)
-    {
-      free (pip -> pathname);
-      pip -> pathname = NULL;
-    }
-  pip -> valid = 0;
+  struct procinfo *procinfo;
+
+  remove_fd (pip);             /* Remove fd from poll/select list */
+
+  close (pip -> fd);
+
+  free (pip -> pathname);
+
+  /* Unlink pip from the procinfo chain.  Note pip might not be on the list. */
+
+  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);
 }
 
 /*
@@ -2360,6 +3082,11 @@ DESCRIPTION
        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
@@ -2368,22 +3095,59 @@ open_proc_file (pid, pip, mode)
      struct procinfo *pip;
      int mode;
 {
-  pip -> valid = 0;            /* FIXME, what is this? ?!  */
-  if (pip -> valid)
-    {
-      close (pip -> fd);
-    }
-  if (pip -> pathname == NULL)
-    {
-      pip -> pathname = xmalloc (32);
+  int tmp, tmpfd;
+
+  pip -> next = NULL;
+  pip -> had_event = 0;
+  pip -> pathname = xmalloc (32);
+  pip -> pid = pid;
+
+#ifndef PIOCOPENLWP
+  tmp = pid;
+#else
+  tmp = pid & 0xffff;
+#endif
+
+  sprintf (pip -> pathname, PROC_NAME_FMT, tmp);
+  if ((tmpfd = open (pip -> pathname, mode)) < 0)
+    return 0;
+
+#ifndef PIOCOPENLWP
+  pip -> 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 */
     }
-  sprintf (pip -> pathname, PROC_NAME_FMT, pid);
-  if ((pip -> fd = open (pip -> pathname, mode)) >= 0)
+
+  if ((pip -> fd = ioctl (tmpfd, PIOCOPENLWP, &tmp)) < 0)
     {
-      pip -> valid = 1;
-      pip -> pid = pid;
+      close (tmpfd);
+      return 0;
     }
-  return (pip -> valid);
+
+#ifdef PIOCSET                 /* New method */
+  {
+      long pr_flags;
+      pr_flags = PR_ASYNC;
+      ioctl (pip -> fd, PIOCSET, &pr_flags);
+  }
+#endif
+
+  close (tmpfd);               /* All done with main pid */
+#endif /* PIOCOPENLWP */
+
+  return 1;
 }
 
 static char *
@@ -2552,7 +3316,8 @@ info_proc_siginfo (pip, summary)
            }
          if (sip -> si_code <= 0)
            {
-             printf_filtered ("sent by pid %d, uid %d ", sip -> si_pid,
+             printf_filtered ("sent by %s, uid %d ",
+                              target_pid_to_str (sip -> si_pid),
                               sip -> si_uid);
            }
          else
@@ -2563,12 +3328,13 @@ info_proc_siginfo (pip, summary)
                  (sip -> si_signo == SIGSEGV) ||
                  (sip -> si_signo == SIGBUS))
                {
-                 printf_filtered ("addr=%#x ", sip -> si_addr);
+                 printf_filtered ("addr=%#lx ",
+                                  (unsigned long) sip -> si_addr);
                }
              else if ((sip -> si_signo == SIGCHLD))
                {
-                 printf_filtered ("child pid %u, status %u ",
-                                  sip -> si_pid,
+                 printf_filtered ("child %s, status %u ",
+                                  target_pid_to_str (sip -> si_pid),
                                   sip -> si_status);
                }
              else if ((sip -> si_signo == SIGPOLL))
@@ -2590,7 +3356,7 @@ info_proc_siginfo (pip, summary)
            }
          if (sip -> si_code <= 0)
            {
-             printf_filtered ("\t%-16u %s\n", sip -> si_pid,
+             printf_filtered ("\t%-16u %s\n", sip -> si_pid, /* XXX need target_pid_to_str() */
                               "PID of process sending signal");
              printf_filtered ("\t%-16u %s\n", sip -> si_uid,
                               "UID of process sending signal");
@@ -2602,18 +3368,20 @@ info_proc_siginfo (pip, summary)
              if ((sip -> si_signo == SIGILL) ||
                  (sip -> si_signo == SIGFPE))
                {
-                 printf_filtered ("\t%-16#x %s.\n", sip -> si_addr,
+                 printf_filtered ("\t%#-16lx %s.\n",
+                                  (unsigned long) sip -> si_addr,
                                   "Address of faulting instruction");
                }
              else if ((sip -> si_signo == SIGSEGV) ||
                       (sip -> si_signo == SIGBUS))
                {
-                 printf_filtered ("\t%-16#x %s.\n", sip -> si_addr,
+                 printf_filtered ("\t%#-16lx %s.\n",
+                                  (unsigned long) sip -> si_addr,
                                   "Address of faulting memory reference");
                }
              else if ((sip -> si_signo == SIGCHLD))
                {
-                 printf_filtered ("\t%-16u %s.\n", sip -> si_pid,
+                 printf_filtered ("\t%-16u %s.\n", sip -> si_pid, /* XXX need target_pid_to_str() */
                                   "Child process ID");
                  printf_filtered ("\t%-16u %s.\n", sip -> si_status,
                                   "Child process exit value or signal");
@@ -2678,17 +3446,18 @@ info_proc_syscalls (pip, summary)
        {
          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);
+
+         printf_filtered ("%-8s ",
+                          prismember (&pip -> entryset, syscallnum)
+                          ? "on" : "off");
+         printf_filtered ("%-8s ",
+                          prismember (&pip -> exitset, syscallnum)
+                          ? "on" : "off");
+         printf_filtered ("\n");
+       }
       printf_filtered ("\n");
     }
 }
@@ -2697,7 +3466,7 @@ static char *
 signalname (signo)
      int signo;
 {
-  char *name;
+  const char *name;
   static char locbuf[32];
 
   name = strsigno (signo);
@@ -2716,7 +3485,7 @@ static char *
 errnoname (errnum)
      int errnum;
 {
-  char *name;
+  const char *name;
   static char locbuf[32];
 
   name = strerrno (errnum);
@@ -2759,9 +3528,19 @@ info_proc_signals (pip, summary)
          printf_filtered ("%-8s ",
                           prismember (&pip -> prstatus.pr_sighold, signo)
                           ? "on" : "off");
+
+#ifdef PROCFS_SIGPEND_OFFSET
+         /* Alpha OSF/1 numbers the pending signals from 1.  */
+         printf_filtered ("%-8s ",
+                          (signo ? prismember (&pip -> prstatus.pr_sigpend,
+                                               signo - 1)
+                                 : 0)
+                          ? "yes" : "no");
+#else
          printf_filtered ("%-8s ",
                           prismember (&pip -> prstatus.pr_sigpend, signo)
                           ? "yes" : "no");
+#endif
          printf_filtered (" %s\n", safe_strsignal (signo));
        }
       printf_filtered ("\n");
@@ -2810,7 +3589,11 @@ info_proc_mappings (pip, summary)
   if (!summary)
     {
       printf_filtered ("Mapped address spaces:\n\n");
+#ifdef BFD_HOST_64_BIT
+      printf_filtered ("  %18s %18s %10s %10s %7s\n",
+#else
       printf_filtered ("\t%10s %10s %10s %10s %7s\n",
+#endif
                       "Start Addr",
                       "  End Addr",
                       "      Size",
@@ -2823,9 +3606,14 @@ info_proc_mappings (pip, summary)
            {
              for (prmap = prmaps; prmap -> pr_size; ++prmap)
                {
-                 printf_filtered ("\t%#10x %#10x %#10x %#10x %7s\n",
-                                  prmap -> pr_vaddr,
-                                  prmap -> pr_vaddr + prmap -> pr_size - 1,
+#ifdef BFD_HOST_64_BIT
+                 printf_filtered ("  %#18lx %#18lx %#10x %#10x %7s\n",
+#else
+                 printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
+#endif
+                                  (unsigned long)prmap -> pr_vaddr,
+                                  (unsigned long)prmap -> pr_vaddr
+                                    + prmap -> pr_size - 1,
                                   prmap -> pr_size,
                                   prmap -> pr_off,
                                   mappingflags (prmap -> pr_mflags));
@@ -2871,8 +3659,7 @@ info_proc (args, from_tty)
      char *args;
      int from_tty;
 {
-  int pid;
-  struct procinfo pii;
+  int pid = inferior_pid;
   struct procinfo *pip;
   struct cleanup *old_chain;
   char **argv;
@@ -2887,12 +3674,15 @@ info_proc (args, from_tty)
   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 */
+  /* Default to using the current inferior if no pid specified.  Note
+     that inferior_pid may be 0, hence we set okerr.  */
 
-  pip = &pi;
+  pip = find_procinfo (inferior_pid, 1);
 
   if (args != NULL)
     {
@@ -2950,16 +3740,18 @@ info_proc (args, from_tty)
              summary = 0;
              times = 1;
            }
-         else if ((pii.pid = atoi (*argv)) > 0)
+         else if ((pid = atoi (*argv)) > 0)
            {
-             pid = pii.pid;
-             pip = &pii;
-             memset (&pii, 0, sizeof (pii));
+             pip = (struct procinfo *) xmalloc (sizeof (struct procinfo));
+             memset (pip, 0, sizeof (*pip));
+
+             pip->pid = pid;
              if (!open_proc_file (pid, pip, O_RDONLY))
                {
                  perror_with_name (pip -> pathname);
                  /* NOTREACHED */
                }
+             pid = pip->pid;
              make_cleanup (close_proc_file, pip);
            }
          else if (**argv != '\000')
@@ -2973,7 +3765,7 @@ info_proc (args, from_tty)
   /* 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 -> valid)
+  if (!pip)
     {
       error ("\
 No process.  Start debugging a program or specify an explicit process ID.");
@@ -2984,45 +3776,481 @@ No process.  Start debugging a program or specify an explicit process ID.");
       error ("PIOCSTATUS failed");
     }
 
-  /* Print verbose information of the requested type(s), or just a summary
-     of the information for all types. */
+#ifdef PIOCLWPIDS
+  nlwp = pip->prstatus.pr_nlwp;
+  lwps = alloca ((2 * nlwp + 2) * sizeof (id_t));
 
-  printf_filtered ("\nInformation for %s:\n\n", pip -> pathname);
-  if (summary || all || flags)
+  if (ioctl (pip->fd, PIOCLWPIDS, lwps))
     {
-      info_proc_flags (pip, summary);
+      print_sys_errmsg (pip -> pathname, errno);
+      error ("PIOCSTATUS failed");      
     }
-  if (summary || all)
+#else /* PIOCLWPIDS */
+  nlwp = 1;
+  lwps = alloca ((2 * nlwp + 2) * sizeof *lwps);
+  lwps[0] = 0;
+#endif /* PIOCLWPIDS */
+
+  for (; nlwp > 0; nlwp--, lwps++)
     {
-      info_proc_stop (pip, summary);
+      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))
+           continue;
+
+         make_cleanup (close_proc_file, pip);
+
+         if (ioctl (pip -> fd, PIOCSTATUS, &(pip -> prstatus)) < 0)
+           {
+             print_sys_errmsg (pip -> pathname, errno);
+             error ("PIOCSTATUS failed");
+           }
+       }
+
+      /* 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);
+       }
+      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);
     }
-  if (summary || all || signals || faults)
+}
+
+/*
+
+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;
+{
+#ifdef PIOCSET
+  long pr_flags;
+#endif
+  int retval;
+
+#ifdef PIOCSET                 /* New method */
+  pr_flags = PR_FORK;
+  if (flag)
+    retval = ioctl (fd, PIOCSET, &pr_flags);
+  else
+    retval = ioctl (fd, PIOCRESET, &pr_flags);
+
+#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;
+{
+#ifdef PIOCSET
+  long pr_flags;
+#endif
+  int retval;
+
+#ifdef PIOCSET                 /* New method */
+  pr_flags = PR_RLC;
+  if (flag)
+    retval = ioctl (fd, PIOCSET, &pr_flags);
+  else
+    retval = ioctl (fd, PIOCRESET, &pr_flags);
+
+#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;
+  
+  goterr = ioctl (pi->fd, PIOCGENTRY, &sysset) < 0;
+
+  if (goterr && !errok)
     {
-      info_proc_siginfo (pip, summary);
+      print_sys_errmsg (pi->pathname, errno);
+      error ("PIOCGENTRY failed");
     }
-  if (summary || all || syscalls)
+
+  if (!goterr)
     {
-      info_proc_syscalls (pip, summary);
+      prdelset (&sysset, syscall_num);
+
+      if ((ioctl (pi->fd, PIOCSENTRY, &sysset) < 0) && !errok)
+       {
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCSENTRY failed");
+       }
     }
-  if (summary || all || mappings)
+
+  goterr = ioctl (pi->fd, PIOCGEXIT, &sysset) < 0;
+
+  if (goterr && !errok)
     {
-      info_proc_mappings (pip, summary);
+      procfs_clear_syscall_trap (pi, syscall_num, 1);
+      print_sys_errmsg (pi->pathname, errno);
+      error ("PIOCGEXIT failed");
     }
-  if (summary || all || signals)
+
+  if (!goterr)
     {
-      info_proc_signals (pip, summary);
+      praddset (&sysset, syscall_num);
+
+      if ((ioctl (pi->fd, PIOCSEXIT, &sysset) < 0) && !errok)
+       {
+         procfs_clear_syscall_trap (pi, syscall_num, 1);
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCSEXIT failed");
+       }
     }
-  if (summary || all || faults)
+
+  if (!pi->syscall_handlers)
     {
-      info_proc_faults (pip, summary);
+      if (!errok)
+       error ("procfs_clear_syscall_trap:  syscall_handlers is empty");
+      return;
     }
-  printf_filtered ("\n");
 
-  /* All done, deal with closing any temporary process info structure,
-     freeing temporary memory , etc. */
+  /* 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
+
+       procfs_set_syscall_trap -- arrange for a function to be called when the
+                                  child executes the specified system call.
+
+SYNOPSIS
+
+       void procfs_set_syscall_trap (struct procinfo *, int syscall_num, int flags,
+                                     syscall_func_t *function)
+
+DESCRIPTION
+
+       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
+procfs_set_syscall_trap (pi, syscall_num, flags, func)
+     struct procinfo *pi;
+     int syscall_num;
+     int flags;
+     syscall_func_t *func;
+{
+  sysset_t sysset;
+  
+  if (flags & PROCFS_SYSCALL_ENTRY)
+    {
+      if (ioctl (pi->fd, PIOCGENTRY, &sysset) < 0)
+       {
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCGENTRY failed");
+       }
+
+      praddset (&sysset, syscall_num);
+
+      if (ioctl (pi->fd, PIOCSENTRY, &sysset) < 0)
+       {
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCSENTRY failed");
+       }
+    }
+
+  if (flags & PROCFS_SYSCALL_EXIT)
+    {
+      if (ioctl (pi->fd, PIOCGEXIT, &sysset) < 0)
+       {
+         procfs_clear_syscall_trap (pi, syscall_num, 1);
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCGEXIT failed");
+       }
+
+      praddset (&sysset, syscall_num);
+
+      if (ioctl (pi->fd, PIOCSEXIT, &sysset) < 0)
+       {
+         procfs_clear_syscall_trap (pi, syscall_num, 1);
+         print_sys_errmsg (pi->pathname, errno);
+         error ("PIOCSEXIT failed");
+       }
+    }
+
+  if (!pi->syscall_handlers)
+    {
+      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;
+    }
+  else
+    {
+      int i;
+
+      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;
+         }
+
+      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_lwp_creation_handler - handle exit from the _lwp_create syscall
+
+SYNOPSIS
+
+       int procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+       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.
+
+       When we see the child exiting from lwp_create, we just contine it,
+       since everything was handled when the parent trapped.
+
+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 int
+procfs_lwp_creation_handler (pi, syscall_num, why, rtnvalp, statvalp)
+     struct procinfo *pi;
+     int syscall_num;
+     int why;
+     int *rtnvalp;
+     int *statvalp;
+{
+  int lwp_id;
+  struct procinfo *childpi;
+
+  /* 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.  */
+
+  /* If lwp_create failed, then nothing interesting happened.  Continue the
+     process and go back to sleep. */
+
+  if (pi->prstatus.pr_reg[R_PSR] & PS_FLAG_CARRY)
+    {                          /* _lwp_create failed */
+      pi->prrun.pr_flags &= PRSTEP;
+      pi->prrun.pr_flags |= PRCFAULT;
+
+      if (ioctl (pi->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 lwp_create.  */
+
+  if (pi->new_child)           /* Child? */
+    {                          /* Yes, just continue it */
+      pi->prrun.pr_flags &= PRSTEP;
+      pi->prrun.pr_flags |= PRCFAULT;
+
+      if ((pi->prstatus.pr_flags & PR_ISTOP)
+         && ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
+       perror_with_name (pi->pathname);
 
-  do_cleanups (old_chain);
+      pi->new_child = 0;       /* No longer new */
+
+      return 0;
+    }
+
+  /* We're the proud parent of a new thread.  Setup an exit trap for lwp_create
+     in the child and continue the parent.  */
+  
+  /* Third arg is pointer to new thread id. */
+  lwp_id = read_memory_integer (pi->prstatus.pr_sysarg[2], sizeof (int));
+
+  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 a handler for
+     that child.  */
+
+  procfs_set_syscall_trap (childpi, SYS_lwp_create, PROCFS_SYSCALL_EXIT,
+                          procfs_lwp_creation_handler);
+
+  childpi->new_child = 1;      /* Flag this as an unseen child process */
+
+  *rtnvalp = lwp_id;   /* the new arrival. */
+  *statvalp = (SIGTRAP << 8) | 0177;
+
+  return 1;
 }
+#endif /* SYS_lwp_create */
 
 /* Fork an inferior process, and start debugging it with /proc.  */
 
@@ -3032,11 +4260,82 @@ procfs_create_inferior (exec_file, allargs, env)
      char *allargs;
      char **env;
 {
+  char *shell_file = getenv ("SHELL");
+  char *tryname;
+  if (shell_file != NULL && strchr (shell_file, '/') == NULL)
+    {
+
+      /* We will be looking down the PATH to find shell_file.  If we
+        just do this the normal way (via execlp, which operates by
+        attempting an exec for each element of the PATH until it
+        finds one which succeeds), then there will be an exec for
+        each failed attempt, each of which will cause a PR_SYSEXIT
+        stop, and we won't know how to distinguish the PR_SYSEXIT's
+        for these failed execs with the ones for successful execs
+        (whether the exec has succeeded is stored at that time in the
+        carry bit or some such architecture-specific and
+        non-ABI-specified place).
+
+        So I can't think of anything better than to search the PATH
+        now.  This has several disadvantages: (1) There is a race
+        condition; if we find a file now and it is deleted before we
+        exec it, we lose, even if the deletion leaves a valid file
+        further down in the PATH, (2) there is no way to know exactly
+        what an executable (in the sense of "capable of being
+        exec'd") file is.  Using access() loses because it may lose
+        if the caller is the superuser; failing to use it loses if
+        there are ACLs or some such.  */
+
+      char *p;
+      char *p1;
+      /* FIXME-maybe: might want "set path" command so user can change what
+        path is used from within GDB.  */
+      char *path = getenv ("PATH");
+      int len;
+      struct stat statbuf;
+
+      if (path == NULL)
+       path = "/bin:/usr/bin";
+
+      tryname = alloca (strlen (path) + strlen (shell_file) + 2);
+      for (p = path; p != NULL; p = p1 ? p1 + 1: NULL)
+       {
+         p1 = strchr (p, ':');
+         if (p1 != NULL)
+           len = p1 - p;
+         else
+           len = strlen (p);
+         strncpy (tryname, p, len);
+         tryname[len] = '\0';
+         strcat (tryname, "/");
+         strcat (tryname, shell_file);
+         if (access (tryname, X_OK) < 0)
+           continue;
+         if (stat (tryname, &statbuf) < 0)
+           continue;
+         if (!S_ISREG (statbuf.st_mode))
+           /* We certainly need to reject directories.  I'm not quite
+              as sure about FIFOs, sockets, etc., but I kind of doubt
+              that people want to exec() these things.  */
+           continue;
+         break;
+       }
+      if (p == NULL)
+       /* Not found.  This must be an error rather than merely passing
+          the file to execlp(), because execlp() would try all the
+          exec()s, causing GDB to get confused.  */
+       error ("Can't find shell %s in PATH", shell_file);
+
+      shell_file = tryname;
+    }
+
   fork_inferior (exec_file, allargs, env,
-                proc_set_exec_trap, procfs_init_inferior);
+                proc_set_exec_trap, procfs_init_inferior, shell_file);
+
   /* We are at the first instruction we care about.  */
   /* Pedal to the metal... */
-  proceed ((CORE_ADDR) -1, 0, 0);
+
+  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
 }
 
 /* Clean up after the inferior dies.  */
@@ -3044,16 +4343,130 @@ procfs_create_inferior (exec_file, allargs, env)
 static void
 procfs_mourn_inferior ()
 {
+  struct procinfo *pi;
+  struct procinfo *next_pi;
+
+  for (pi = procinfo_list; pi; pi = next_pi)
+    {
+      next_pi = pi->next;
+      unconditionally_kill_inferior (pi);
+    }
+
   unpush_target (&procfs_ops);
   generic_mourn_inferior ();
 }
 
+
 /* Mark our target-struct as eligible for stray "run" and "attach" commands.  */
 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
+\f
+/* Insert a watchpoint */
+int
+procfs_set_watchpoint(pid, addr, len, rw)
+     int               pid;
+     CORE_ADDR         addr;
+     int               len;
+     int               rw;
+{
+  struct procinfo      *pi;
+  prwatch_t            wpt;
+
+  pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
+  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 (errno == E2BIG)
+       return -1;
+      /* Currently it sometimes happens that the same watchpoint gets
+        deleted twice - don't die in this case (FIXME please) */
+      if (errno == ESRCH && len == 0)
+       return 0;
+      print_sys_errmsg (pi->pathname, errno);
+      error ("PIOCSWATCH failed");
+    }
+  return 0;
+}
+
+int
+procfs_stopped_by_watchpoint(pid)
+    int                        pid;
+{
+  struct procinfo      *pi;
+  short                what;
+  short                why;
+
+  pi = find_procinfo (pid == -1 ? inferior_pid : pid, 0);
+  if (pi->prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))
+    {
+      why = pi->prstatus.pr_why;
+      what = pi->prstatus.pr_what;
+      if (why == PR_FAULTED 
+#if defined (FLTWATCH) && defined (FLTKWATCH)
+         && (what == FLTWATCH || what == FLTKWATCH)
+#else
+#ifdef FLTWATCH
+         && (what == FLTWATCH) 
+#endif
+#ifdef FLTKWATCH
+         && (what == FLTKWATCH)
+#endif
+#endif
+         )
+       return what;
+    }
+  return 0;
+}
+#endif
+
+/* Why is this necessary?  Shouldn't dead threads just be removed from the
+   thread database?  */
+
+static int
+procfs_thread_alive (pid)
+     int pid;
+{
+  return 1;
+}
+
+/* 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). */
+
+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 */
@@ -3084,6 +4497,8 @@ struct target_ops procfs_ops = {
   procfs_mourn_inferior,       /* to_mourn_inferior */
   procfs_can_run,              /* to_can_run */
   procfs_notice_signals,       /* to_notice_signals */
+  procfs_thread_alive,         /* to_thread_alive */
+  procfs_stop,                 /* to_stop */
   process_stratum,             /* to_stratum */
   0,                           /* to_next */
   1,                           /* to_has_all_memory */
@@ -3096,26 +4511,22 @@ struct target_ops procfs_ops = {
   OPS_MAGIC                    /* to_magic */
 };
 
-/*
-
-GLOBAL FUNCTION
-
-       _initialize_procfs -- initialize the process file system stuff
-
-SYNOPSIS
-
-       void _initialize_procfs (void)
-
-DESCRIPTION
-
-       Do required initializations during gdb startup for using the
-       /proc file system interface.
-
-*/
-
 void
 _initialize_procfs ()
 {
+#ifdef HAVE_OPTIONAL_PROC_FS
+  char procname[32];
+  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 ());
+  if ((fd = open (procname, O_RDONLY)) < 0)
+    return;
+  close (fd);
+#endif
+
   add_target (&procfs_ops);
 
   add_info ("proc", info_proc, 
This page took 0.064559 seconds and 4 git commands to generate.