#include "defs.h"
+#include <sys/types.h>
#include <time.h>
#include <sys/procfs.h>
#include <fcntl.h>
#include <string.h>
#include <stropts.h>
#include <poll.h>
+#include <unistd.h>
+#include <sys/stat.h>
#include "inferior.h"
#include "target.h"
procfs_create_inferior PARAMS ((char *, char *, char **));
static void
-procfs_notice_signals PARAMS ((pid_t pid));
+procfs_notice_signals PARAMS ((int pid));
static struct procinfo *
find_procinfo PARAMS ((pid_t pid, int okfail));
/*
+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
}
}
-/*
+#define LOSING_POLL unixware_sux
-LOCAL MACRO
+static struct procinfo *
+wait_fd ()
+{
+ struct procinfo *pi;
+ int num_fds;
+ int i;
- current_procinfo -- convert inferior_pid to a struct procinfo
+ if (attach_flag)
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
-SYNOPSIS
+#ifndef LOSING_POLL
+ num_fds = poll (poll_list, num_poll_list, -1);
+#else
+ pi = current_procinfo;
- static struct procinfo * current_procinfo;
+ if (ioctl (pi->fd, PIOCWSTOP, &pi->prstatus) < 0)
+ {
+ print_sys_errmsg (pi->pathname, errno);
+ error ("PIOCWSTOP failed");
+ }
+ pi->had_event = 1;
+#endif
+
+ if (attach_flag)
+ clear_sigint_trap();
-DESCRIPTION
-
- Looks up inferior_pid in the procinfo chain. Always returns a
- struct procinfo *. If process can't be found, we error() out.
- */
+#ifndef LOSING_POLL
-#define current_procinfo find_procinfo (inferior_pid, 0)
+ if (num_fds <= 0)
+ {
+ print_sys_errmsg ("poll failed\n", errno);
+ error ("Poll failed, returned %d", num_fds);
+ }
+
+ for (i = 0; i < num_poll_list && num_fds > 0; i++)
+ {
+ if ((poll_list[i].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL)) == 0)
+ 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 ("procfs_wait: Couldn't find procinfo for fd %d\n",
+ poll_list[i].fd);
+ }
+#endif /* LOSING_POLL */
+
+ return pi;
+}
/*
/*
-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*/
-}
-
-/*
-
LOCAL FUNCTION
procfs_kill_inferior - kill any currently inferior
static void
procfs_kill_inferior ()
{
- struct procinfo *pi;
-
- for (pi = procinfo_list; pi; pi = pi->next)
- unconditionally_kill_inferior (pi);
-
target_mourn_inferior ();
}
create_procinfo (pid);
add_thread (pid); /* Setup initial thread */
+
+ /* One trap to exec the shell, one to exec the program being debugged. */
+ startup_inferior (2);
}
/*
SYNOPSIS
- static void procfs_notice_signals (pid_t pid);
+ static void procfs_notice_signals (int pid);
DESCRIPTION
static void
procfs_notice_signals (pid)
- pid_t pid;
+ int pid;
{
int signo;
struct procinfo *pi;
for (signo = 0; signo < NSIG; signo++)
{
- if (signal_stop_state (signo) == 0 &&
- signal_print_state (signo) == 0 &&
- signal_pass_state (signo) == 1)
+ 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);
}
proc_set_exec_trap ()
{
sysset_t exitset;
+ sysset_t entryset;
auto char procname[32];
int fd;
if ((fd = open (procname, O_RDWR)) < 0)
{
perror (procname);
- fflush (stderr);
+ gdb_flush (gdb_stderr);
_exit (127);
}
premptyset (&exitset);
+ premptyset (&entryset);
/* GW: Rationale...
Not all systems with /proc have all the exec* syscalls with the same
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);
}
+ 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. */
exec_file = (char *) get_exec_file (0);
if (exec_file)
- printf ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
+ printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
else
- printf ("Attaching to %s\n", target_pid_to_str (pid));
+ printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
- fflush (stdout);
+ gdb_flush (gdb_stdout);
}
do_attach (pid);
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
- printf ("Detaching from program: %s %s\n",
+ printf_unfiltered ("Detaching from program: %s %s\n",
exec_file, target_pid_to_str (inferior_pid));
- fflush (stdout);
+ gdb_flush (gdb_stdout);
}
if (args)
siggnal = atoi (args);
procfs_files_info (ignore)
struct target_ops *ignore;
{
- printf ("\tUsing the running image of %s %s via /proc.\n",
+ printf_unfiltered ("\tUsing the running image of %s %s via /proc.\n",
attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
}
}
else
{
- printf ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid));
+ printf_unfiltered ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid));
}
}
if (ioctl (pi->fd, PIOCSEXIT, &pi->saved_exitset) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSEXIT failed.\n");
+ printf_unfiltered ("PIOCSEXIT failed.\n");
}
if (ioctl (pi->fd, PIOCSENTRY, &pi->saved_entryset) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSENTRY failed.\n");
+ printf_unfiltered ("PIOCSENTRY failed.\n");
}
if (ioctl (pi->fd, PIOCSTRACE, &pi->saved_trace) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSTRACE failed.\n");
+ printf_unfiltered ("PIOCSTRACE failed.\n");
}
if (ioctl (pi->fd, PIOCSHOLD, &pi->saved_sighold) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOSCHOLD failed.\n");
+ printf_unfiltered ("PIOSCHOLD failed.\n");
}
if (ioctl (pi->fd, PIOCSFAULT, &pi->saved_fltset) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSFAULT failed.\n");
+ printf_unfiltered ("PIOCSFAULT failed.\n");
}
if (ioctl (pi->fd, PIOCSTATUS, &pi->prstatus) < 0)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSTATUS failed.\n");
+ printf_unfiltered ("PIOCSTATUS failed.\n");
}
else
{
if (ioctl (pi->fd, PIOCCFAULT, 0))
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCCFAULT failed.\n");
+ printf_unfiltered ("PIOCCFAULT failed.\n");
}
/* Make it run again when we close it. */
if (result)
{
print_sys_errmsg (pi->pathname, errno);
- printf ("PIOCSRLC or PIOCSET failed.\n");
+ printf_unfiltered ("PIOCSRLC or PIOCSET failed.\n");
}
}
}
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 pid, 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 (pid, statloc)
+procfs_wait (pid, ourstatus)
int pid;
- int *statloc;
+ struct target_waitstatus *ourstatus;
{
short what;
short why;
wait_again:
if (!pi)
- {
- int num_fds;
- int i;
-
- if (attach_flag)
- set_sigint_trap(); /* Causes SIGINT to be passed on to the
- attached process. */
-
- num_fds = poll (poll_list, num_poll_list, -1);
-
- if (attach_flag)
- clear_sigint_trap();
-
- if (num_fds <= 0)
- {
- print_sys_errmsg (pi->pathname, errno);
- error ("poll failed, returned %d\n", num_fds);
- }
-
- 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)
- checkerr++;
- /* perror_with_name (pi->pathname);*/
- num_fds--;
- pi->had_event = 1;
- break;
- }
- }
- if (!pi)
- error ("procfs_wait: Couldn't find procinfo for fd %d\n",
- poll_list[i].fd);
- }
- }
+ pi = wait_fd ();
if (pid != -1)
for (pi = procinfo_list; pi; pi = pi->next)
{
case PR_SIGNALLED:
statval = (what << 8) | 0177;
+ break;
+ case PR_SYSENTRY:
+ if (what != SYS_exit)
+ error ("PR_SYSENTRY, unknown system call %d", what);
+
+ pi->prrun.pr_flags = PRCFAULT;
+
+ if (ioctl (pi->fd, PIOCRUN, &pi->prrun) != 0)
+ perror_with_name (pi->pathname);
+
+ rtnval = wait (&statval);
+
break;
case PR_SYSEXIT:
switch (what)
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;
}
procfs_resume (pid, step, signo)
int pid;
int step;
- int signo;
+ enum target_signal signo;
{
int signal_to_pass;
struct procinfo *pi, *procinfo;
#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
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
+ else if (signo == TARGET_SIGNAL_TSTP
&& pi->prstatus.pr_cursig == SIGTSTP
&& pi->prstatus.pr_action.sa_handler == SIG_DFL)
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)
{
{
if (ioctl (procinfo->fd, PIOCSTATUS, &procinfo->prstatus) < 0)
{
- fprintf(stderr, "PIOCSTATUS failed, errno=%d\n", errno);
+ fprintf_unfiltered(gdb_stderr, "PIOCSTATUS failed, errno=%d\n", errno);
}
print_sys_errmsg (procinfo->pathname, errno);
error ("PIOCRUN failed");
so that any grand-children start with all tracing flags set.
*/
+#ifdef SYS_sproc
+
static void
procfs_set_sproc_trap (pi)
struct procinfo *pi;
error ("PIOCGEXIT failed");
}
-#ifdef SYS_sproc
praddset (&exitset, SYS_sproc);
-#endif
if (ioctl (pi->fd, PIOCSEXIT, &exitset) < 0)
{
#endif
#endif
}
+#endif /* SYS_sproc */
/* Fork an inferior process, and start debugging it with /proc. */
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 to replace putenv hack
+ in set_in_environ. */
+ 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... */
/* Setup traps on exit from sproc() */
- procfs_set_sproc_trap(current_procinfo);
+#ifdef SYS_sproc
+ procfs_set_sproc_trap (current_procinfo);
+#endif
- proceed ((CORE_ADDR) -1, 0, 0);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
}
/* Clean up after the inferior dies. */
static void
procfs_mourn_inferior ()
{
+ struct procinfo *pi;
+
+ for (pi = procinfo_list; pi; pi = pi->next)
+ unconditionally_kill_inferior (pi);
+
unpush_target (&procfs_ops);
generic_mourn_inferior ();
}
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 ()
{