-/* Subroutines for handling an "inferior" (child) process as a target
- for debugging, in GDB.
- Copyright 1990, 1991 Free Software Foundation, Inc.
+/* Target-vector operations for controlling Unix child processes, for GDB.
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB.
#include "target.h"
#include "wait.h"
#include "gdbcore.h"
-#include "ieee-float.h" /* Required by REGISTER_CONVERT_TO_XXX */
+#include "command.h"
+#include <signal.h>
static void
child_prepare_to_store PARAMS ((void));
-static int
-child_wait PARAMS ((int *));
+#ifndef CHILD_WAIT
+static int child_wait PARAMS ((int, struct target_waitstatus *));
+#endif /* CHILD_WAIT */
-static void
-child_open PARAMS ((char *, int));
+static void child_open PARAMS ((char *, int));
static void
child_files_info PARAMS ((struct target_ops *));
static void
child_detach PARAMS ((char *, int));
+static void
+child_attach PARAMS ((char *, int));
+
+static void
+ptrace_me PARAMS ((void));
+
+static void
+ptrace_him PARAMS ((int));
+
+static void child_create_inferior PARAMS ((char *, char *, char **));
+
+static void
+child_mourn_inferior PARAMS ((void));
+
+static int
+child_can_run PARAMS ((void));
+
+extern char **environ;
+
/* Forward declaration */
extern struct target_ops child_ops;
+#ifndef CHILD_WAIT
+
/* Wait for child to do something. Return pid of child, or -1 in case
- of error; store status through argument pointer STATUS. */
+ of error; store status through argument pointer OURSTATUS. */
static int
-child_wait (status)
- int *status;
+child_wait (pid, ourstatus)
+ int pid;
+ struct target_waitstatus *ourstatus;
{
- int pid;
+ int save_errno;
+ int status;
do {
-#ifdef USE_PROC_FS
- pid = proc_wait (status);
-#else
- pid = wait (status);
-#endif
- if (pid == -1) /* No more children to wait for */
+ if (attach_flag)
+ set_sigint_trap(); /* Causes SIGINT to be passed on to the
+ attached process. */
+ set_sigio_trap ();
+
+ pid = wait (&status);
+ save_errno = errno;
+
+ clear_sigio_trap ();
+
+ if (attach_flag)
+ clear_sigint_trap();
+
+ if (pid == -1)
{
- fprintf (stderr, "Child process unexpectedly missing.\n");
- *status = 42; /* Claim it exited with signal 42 */
+ if (save_errno == EINTR)
+ continue;
+ fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
+ safe_strerror (save_errno));
+ /* Claim it exited with unknown signal. */
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
return -1;
}
} while (pid != inferior_pid); /* Some other child died or stopped */
+ store_waitstatus (ourstatus, status);
return pid;
}
+#endif /* CHILD_WAIT */
+
+/* Attach to process PID, then initialize for debugging it. */
+
+static void
+child_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+#ifndef ATTACH_DETACH
+ error ("Can't attach to a process on this machine.");
+#else
+ {
+ char *exec_file;
+ int pid;
+
+ pid = atoi (args);
+
+ if (pid == getpid()) /* Trying to masturbate? */
+ error ("I refuse to debug myself!");
+
+ if (from_tty)
+ {
+ exec_file = (char *) get_exec_file (0);
+
+ if (exec_file)
+ printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
+ target_pid_to_str (pid));
+ else
+ printf_unfiltered ("Attaching to %s\n", target_pid_to_str (pid));
+
+ gdb_flush (gdb_stdout);
+ }
+
+ attach (pid);
+ inferior_pid = pid;
+ push_target (&child_ops);
+ }
+#endif /* ATTACH_DETACH */
+}
-/*
- * child_detach()
- * takes a program previously attached to and detaches it.
- * The program resumes execution and will no longer stop
- * on signals, etc. We better not have left any breakpoints
- * in the program or it'll die when it hits one. For this
- * to work, it may be necessary for the process to have been
- * previously attached. It *might* work if the program was
- * started via the normal ptrace (PTRACE_TRACEME).
- */
+/* Take a program previously attached to and detaches it.
+ The program resumes execution and will no longer stop
+ on signals, etc. We'd better not have left any breakpoints
+ in the program or it'll die when it hits one. For this
+ to work, it may be necessary for the process to have been
+ previously attached. It *might* work if the program was
+ started via the normal ptrace (PTRACE_TRACEME). */
static void
child_detach (args, from_tty)
char *args;
int from_tty;
{
- int siggnal = 0;
-
#ifdef ATTACH_DETACH
- if (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);
- }
- if (args)
- siggnal = atoi (args);
-
- detach (siggnal);
- inferior_pid = 0;
- unpush_target (&child_ops); /* Pop out of handling an inferior */
+ {
+ int siggnal = 0;
+
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ 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);
+
+ detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&child_ops);
+ }
#else
- error ("This version of Unix does not support detaching a process.");
+ error ("This version of Unix does not support detaching a process.");
#endif
}
child_files_info (ignore)
struct target_ops *ignore;
{
- printf ("\tUsing the running image of %s process %d.\n",
- attach_flag? "attached": "child", inferior_pid);
+ printf_unfiltered ("\tUsing the running image of %s %s.\n",
+ attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
}
/* ARGSUSED */
error ("Use the \"run\" command to start a Unix child process.");
}
+/* Stub function which causes the inferior that runs it, to be ptrace-able
+ by its parent process. */
+
+static void
+ptrace_me ()
+{
+ /* "Trace me, Dr. Memory!" */
+ call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0);
+}
+
+/* Stub function which causes the GDB that runs it, to start ptrace-ing
+ the child process. */
+
+static void
+ptrace_him (pid)
+ int pid;
+{
+ push_target (&child_ops);
+
+#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
+}
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. Errors reported with error(). */
+
+static void
+child_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ fork_inferior (exec_file, allargs, env, ptrace_me, ptrace_him, NULL);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+}
+
+static void
+child_mourn_inferior ()
+{
+ unpush_target (&child_ops);
+ generic_mourn_inferior ();
+}
+
+static int
+child_can_run ()
+{
+ return(1);
+}
+\f
struct target_ops child_ops = {
"child", /* to_shortname */
"Unix child process", /* to_longname */
0, /* to_lookup_symbol */
child_create_inferior, /* to_create_inferior */
child_mourn_inferior, /* to_mourn_inferior */
+ child_can_run, /* to_can_run */
+ 0, /* to_notice_signals */
process_stratum, /* to_stratum */
0, /* to_next */
1, /* to_has_all_memory */