+SYNOPSIS
+
+ int procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+ This routine is called when an inferior process is about to finish an
+ sproc() system call. This is the system call that IRIX uses to create
+ a lightweight process. When the target process gets this event, we can
+ look at rval1 to find the new child processes ID, and create a new
+ procinfo struct from that.
+
+ After that, it pretends that we got a SIGTRAP, and returns non-zero
+ to tell procfs_wait to wake up. Subsequently, wait_for_inferior gets
+ woken up, sees the new process and continues it.
+
+NOTES
+ We actually never see the child exiting from sproc because we will
+ shortly stop the child with PIOCSTOP, which is then registered as the
+ event of interest.
+ */
+
+static int
+procfs_sproc_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
+{
+/* We've just detected the completion of an sproc system call. Now we need to
+ setup a procinfo struct for this thread, and notify the thread system of the
+ new arrival. */
+
+/* If sproc failed, then nothing interesting happened. Continue the process
+ and go back to sleep. */
+
+ if (pi->prstatus.pr_errno != 0)
+ {
+ pi->prrun.pr_flags &= PRSTEP;
+ pi->prrun.pr_flags |= PRCFAULT;
+
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+ }
+
+ /* At this point, the new thread is stopped at it's first instruction, and
+ the parent is stopped at the exit from sproc. */
+
+ /* Notify the caller of the arrival of a new thread. */
+ create_procinfo (pi->prstatus.pr_rval1);
+
+ *rtnvalp = pi->prstatus.pr_rval1;
+ *statvalp = (SIGTRAP << 8) | 0177;
+
+ return 1;
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_fork_handler - handle exit from the fork syscall
+
+SYNOPSIS
+
+ int procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp)
+
+DESCRIPTION
+
+ This routine is called when an inferior process is about to finish a
+ fork() system call. We will open up the new process, and then close
+ it, which releases it from the clutches of the debugger.
+
+ After that, we continue the target process as though nothing had
+ happened.
+
+NOTES
+ This is necessary for IRIX because we have to set PR_FORK in order
+ to catch the creation of lwps (via sproc()). When an actual fork
+ occurs, it becomes necessary to reset the forks debugger flags and
+ continue it because we can't hack multiple processes yet.
+ */
+
+static int
+procfs_fork_handler (pi, syscall_num, why, rtnvalp, statvalp)
+ struct procinfo *pi;
+ int syscall_num;
+ int why;
+ int *rtnvalp;
+ int *statvalp;
+{
+ struct procinfo *pitemp;
+
+/* At this point, we've detected the completion of a fork (or vfork) call in
+ our child. The grandchild is also stopped because we set inherit-on-fork
+ earlier. (Note that nobody has the grandchilds' /proc file open at this
+ point.) We will release the grandchild from the debugger by opening it's
+ /proc file and then closing it. Since run-on-last-close is set, the
+ grandchild continues on its' merry way. */
+
+
+ pitemp = create_procinfo (pi->prstatus.pr_rval1);
+ if (pitemp)
+ close_proc_file (pitemp);
+
+ if (ioctl (pi->ctl_fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ return 0;
+}
+#endif /* SYS_sproc && !UNIXWARE */
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_set_inferior_syscall_traps - setup the syscall traps
+
+SYNOPSIS
+
+ void procfs_set_inferior_syscall_traps (struct procinfo *pip)
+
+DESCRIPTION
+
+ Called for each "procinfo" (process, thread, or LWP) in the
+ inferior, to register for notification of and handlers for
+ syscall traps in the inferior.
+
+ */
+
+static void
+procfs_set_inferior_syscall_traps (pip)
+ struct procinfo *pip;
+{
+ procfs_set_syscall_trap (pip, SYS_exit, PROCFS_SYSCALL_ENTRY,
+ procfs_exit_handler);
+
+#ifndef PRFS_STOPEXEC
+#ifdef SYS_exec
+ procfs_set_syscall_trap (pip, SYS_exec, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#ifdef SYS_execv
+ procfs_set_syscall_trap (pip, SYS_execv, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#ifdef SYS_execve
+ procfs_set_syscall_trap (pip, SYS_execve, PROCFS_SYSCALL_EXIT,
+ procfs_exec_handler);
+#endif
+#endif /* PRFS_STOPEXEC */
+
+ /* Setup traps on exit from sproc() */
+
+#ifdef SYS_sproc
+ procfs_set_syscall_trap (pip, SYS_sproc, PROCFS_SYSCALL_EXIT,
+ procfs_sproc_handler);
+ procfs_set_syscall_trap (pip, SYS_fork, PROCFS_SYSCALL_EXIT,
+ procfs_fork_handler);
+#ifdef SYS_vfork
+ procfs_set_syscall_trap (pip, SYS_vfork, PROCFS_SYSCALL_EXIT,
+ procfs_fork_handler);
+#endif
+/* Turn on inherit-on-fork flag so that all children of the target process
+ start with tracing flags set. This allows us to trap lwp creation. Note
+ that we also have to trap on fork and vfork in order to disable all tracing
+ in the targets child processes. */
+
+ modify_inherit_on_fork_flag (pip->ctl_fd, 1);
+#endif
+
+#ifdef SYS_lwp_create
+ procfs_set_syscall_trap (pip, SYS_lwp_create, PROCFS_SYSCALL_EXIT,
+ procfs_lwp_creation_handler);
+#endif
+}
+
+/*
+
+LOCAL FUNCTION
+
+ procfs_init_inferior - initialize target vector and access to a
+ /proc entry
+
+SYNOPSIS
+
+ void 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 void
+procfs_init_inferior (pid)
+ int pid;
+{
+ struct procinfo *pip;
+
+ push_target (&procfs_ops);
+
+ pip = create_procinfo (pid);
+
+ procfs_set_inferior_syscall_traps (pip);
+
+ /* create_procinfo may change the pid, so we have to update inferior_pid
+ here before calling other gdb routines that need the right pid. */
+
+ pid = pip -> pid;
+ inferior_pid = pid;
+
+ add_thread (pip -> pid); /* Setup initial thread */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+ startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+#else
+ /* One trap to exec the shell, one to exec the program being debugged. */
+ startup_inferior (2);
+#endif
+}
+
+/*
+
+GLOBAL FUNCTION
+
+ procfs_notice_signals
+
+SYNOPSIS
+
+ static void procfs_notice_signals (int pid);
+
+DESCRIPTION
+
+ When the user changes the state of gdb's signal handling via the
+ "handle" command, this function gets called to see if any change
+ in the /proc interface is required. It is also called internally
+ by other /proc interface functions to initialize the state of
+ the traced signal set.
+
+ One thing it does is that signals for which the state is "nostop",
+ "noprint", and "pass", have their trace bits reset in the pr_trace
+ field, so that they are no longer traced. This allows them to be
+ delivered directly to the inferior without the debugger ever being
+ involved.
+ */
+
+static void
+procfs_notice_signals (pid)
+ int pid;
+{
+ struct procinfo *pi;
+ struct sig_ctl sctl;
+
+ pi = find_procinfo (pid, 0);
+
+#ifndef HAVE_PRRUN_T
+ premptyset (&sctl.sigset);
+#else
+ sctl.sigset = pi->prrun.pr_trace;
+#endif
+
+ notice_signals (pi, &sctl);
+
+#ifdef HAVE_PRRUN_T
+ pi->prrun.pr_trace = sctl.sigset;
+#endif
+}
+
+static void
+notice_signals (pi, sctl)
+ struct procinfo *pi;
+ struct sig_ctl *sctl;
+{
+ int signo;
+
+ for (signo = 0; signo < NSIG; signo++)
+ {
+ if (signal_stop_state (target_signal_from_host (signo)) == 0 &&
+ signal_print_state (target_signal_from_host (signo)) == 0 &&
+ signal_pass_state (target_signal_from_host (signo)) == 1)
+ {
+ prdelset (&sctl->sigset, signo);
+ }
+ else
+ {
+ praddset (&sctl->sigset, signo);
+ }
+ }
+#ifdef PROCFS_USE_READ_WRITE
+ sctl->cmd = PCSTRACE;
+ if (write (pi->ctl_fd, (char *) sctl, sizeof (struct sig_ctl)) < 0)
+#else
+ if (ioctl (pi->ctl_fd, PIOCSTRACE, &sctl->sigset))
+#endif
+ {
+ print_sys_errmsg ("PIOCSTRACE failed", errno);
+ }
+}
+
+/*
+
+LOCAL FUNCTION
+
+ proc_set_exec_trap -- arrange for exec'd child to halt at startup
+
+SYNOPSIS
+
+ void proc_set_exec_trap (void)
+
+DESCRIPTION
+
+ This function is called in the child process when starting up
+ an inferior, prior to doing the exec of the actual inferior.
+ It sets the child process's exitset to make exit from the exec
+ system call an event of interest to stop on, and then simply
+ returns. The child does the exec, the system call returns, and
+ the child stops at the first instruction, ready for the gdb
+ parent process to take control of it.
+
+NOTE
+
+ We need to use all local variables since the child may be sharing
+ it's data space with the parent, if vfork was used rather than
+ fork.
+
+ Also note that we want to turn off the inherit-on-fork flag in
+ the child process so that any grand-children start with all
+ tracing flags cleared.
+ */