#include "defs.h"
-#ifdef USE_PROC_FS /* Entire file goes away if not using /proc */
-
#include <time.h>
#include <sys/procfs.h>
#include <fcntl.h>
#include "inferior.h"
#include "target.h"
#include "command.h"
+#include "gdbcore.h"
#define MAX_SYSCALLS 256 /* Maximum number of syscalls for table */
#define PROC_NAME_FMT "/proc/%05d"
#endif
+extern struct target_ops procfs_ops; /* Forward declaration */
+
#if 1 /* FIXME: Gross and ugly hack to resolve coredep.c global */
CORE_ADDR kernel_u_addr;
#endif
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 ((void));
+
/* External function prototypes that can't be easily included in any
header file because the args are typedefs in system include files. */
return (name);
}
-static char *sigcodedesc (sip)
+static char *
+sigcodedesc (sip)
siginfo_t *sip;
{
struct sigcode *scp;
/*
-GLOBAL FUNCTION
-
- kill_inferior_fast -- kill inferior while gdb is exiting
-
-SYNOPSIS
-
- void kill_inferior_fast (void)
-
-DESCRIPTION
-
- This is used when GDB is exiting. It gives less chance of error.
-
-NOTES
-
- Don't attempt to kill attached inferiors since we may be called
- when gdb is in the process of aborting, and killing the attached
- inferior may be very anti-social. This is particularly true if we
- were attached just so we could use the /proc facilities to get
- detailed information about it's status.
-
-*/
-
-void
-kill_inferior_fast ()
-{
- if (inferior_pid != 0 && !attach_flag)
- {
- unconditionally_kill_inferior ();
- }
-}
-
-/*
-
-GLOBAL FUNCTION
+LOCAL FUNCTION
- kill_inferior - kill any currently inferior
+ procfs_kill_inferior - kill any currently inferior
SYNOPSIS
- void kill_inferior (void)
+ void procfs_kill_inferior (void)
DESCRIPTION
*/
-void
-kill_inferior ()
+static void
+procfs_kill_inferior ()
{
if (inferior_pid != 0)
{
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- child_xfer_memory -- copy data to or from inferior memory space
+ procfs_xfer_memory -- copy data to or from inferior memory space
SYNOPSIS
- int child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
int dowrite, struct target_ops target)
DESCRIPTION
if DOWRITE is zero or to inferior if DOWRITE is nonzero.
Returns the length copied, which is either the LEN argument or
- zero. This xfer function does not do partial moves, since child_ops
+ zero. This xfer function does not do partial moves, since procfs_ops
doesn't allow memory operations to cross below us in the target stack
anyway.
The /proc interface makes this an almost trivial task.
*/
-
-int
-child_xfer_memory (memaddr, myaddr, len, dowrite, target)
+static int
+procfs_xfer_memory (memaddr, myaddr, len, dowrite, target)
CORE_ADDR memaddr;
char *myaddr;
int len;
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- store_inferior_registers -- copy register values back to inferior
+ procfs_store_registers -- copy register values back to inferior
SYNOPSIS
- void store_inferior_registers (int regno)
+ void procfs_store_registers (int regno)
DESCRIPTION
*/
-void
-store_inferior_registers (regno)
+static void
+procfs_store_registers (regno)
int regno;
{
if (regno != -1)
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- inferior_proc_init - initialize access to a /proc entry
+ procfs_init_inferior - initialize access to a /proc entry
SYNOPSIS
- void inferior_proc_init (int pid)
+ void procfs_init_inferior (int pid)
DESCRIPTION
*/
-void
-inferior_proc_init (pid)
+static void
+procfs_init_inferior (pid)
int pid;
{
+
+ push_target (&procfs_ops);
+
if (!open_proc_file (pid, &pi, O_RDWR))
{
proc_init_failed ("can't open process file");
{
memset ((char *) &pi.prrun, 0, sizeof (pi.prrun));
prfillset (&pi.prrun.pr_trace);
- proc_signal_handling_change ();
+ procfs_notice_signals ();
prfillset (&pi.prrun.pr_fault);
prdelset (&pi.prrun.pr_fault, FLTPAGE);
if (ioctl (pi.fd, PIOCWSTOP, &pi.prstatus) < 0)
GLOBAL FUNCTION
- proc_signal_handling_change
+ procfs_notice_signals
SYNOPSIS
- void proc_signal_handling_change (void);
+ static void procfs_notice_signals (void);
DESCRIPTION
involved.
*/
-void
-proc_signal_handling_change ()
+static void
+procfs_notice_signals ()
{
int signo;
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
proc_set_exec_trap -- arrange for exec'd child to halt at startup
tracing flags cleared.
*/
-void
+static void
proc_set_exec_trap ()
{
sysset_t exitset;
return (funcstat);
}
+#if 0 /* Currently unused */
/*
GLOBAL FUNCTION
segment containing that address.
*/
-
-#if 0 /* Currently unused */
-
CORE_ADDR
proc_base_address (addr)
CORE_ADDR addr;
}
-#ifdef ATTACH_DETACH
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+
+static void
+procfs_attach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char *exec_file;
+ int pid;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+ 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 ("Attaching to program `%s', %s\n", exec_file, target_pid_to_str (pid));
+ else
+ printf ("Attaching to %s\n", target_pid_to_str (pid));
+
+ fflush (stdout);
+ }
+
+ do_attach (pid);
+ inferior_pid = pid;
+ push_target (&procfs_ops);
+}
+
+
+/* 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
+procfs_detach (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ int siggnal = 0;
+
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf ("Detaching from program: %s %s\n",
+ exec_file, target_pid_to_str (inferior_pid));
+ fflush (stdout);
+ }
+ if (args)
+ siggnal = atoi (args);
+
+ do_detach (siggnal);
+ inferior_pid = 0;
+ unpush_target (&procfs_ops); /* Pop out of handling an inferior */
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+
+static void
+procfs_prepare_to_store ()
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Print status information about what we're accessing. */
+
+static void
+procfs_files_info (ignore)
+ struct target_ops *ignore;
+{
+ printf ("\tUsing the running image of %s %s via /proc.\n",
+ attach_flag? "attached": "child", target_pid_to_str (inferior_pid));
+}
+
+/* ARGSUSED */
+static void
+procfs_open (arg, from_tty)
+ char *arg;
+ int from_tty;
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- attach -- attach to an already existing process
+ do_attach -- attach to an already existing process
SYNOPSIS
- int attach (int pid)
+ int do_attach (int pid)
DESCRIPTION
*/
-int
-attach (pid)
+static int
+do_attach (pid)
int pid;
{
int result;
}
else
{
- printf ("Ok, gdb will wait for process %u to stop.\n", pid);
+ printf ("Ok, gdb will wait for %s to stop.\n", target_pid_to_str (pid));
}
}
memset (&pi.prrun, 0, sizeof (pi.prrun));
prfillset (&pi.prrun.pr_trace);
- proc_signal_handling_change ();
+ procfs_notice_signals ();
prfillset (&pi.prrun.pr_fault);
prdelset (&pi.prrun.pr_fault, FLTPAGE);
if (ioctl (pi.fd, PIOCSFAULT, &pi.prrun.pr_fault))
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- detach -- detach from an attached-to process
+ do_detach -- detach from an attached-to process
SYNOPSIS
- void detach (int signal)
+ void do_detach (int signal)
DESCRIPTION
be the ideal situation. (FIXME).
*/
-void
-detach (signal)
+static void
+do_detach (signal)
int signal;
{
int result;
attach_flag = 0;
}
-#endif /* ATTACH_DETACH */
-
/*
-GLOBAL FUNCTION
+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.
- proc_wait -- emulate wait() as much as possible
SYNOPSIS
- int proc_wait (int *statloc)
+ int procfs_wait (int *statloc)
DESCRIPTION
*/
-int
-proc_wait (statloc)
+static int
+procfs_wait (statloc)
int *statloc;
{
short what;
}
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)
{
checkerr++;
}
+
+ if (attach_flag)
+ clear_sigint_trap();
}
if (checkerr)
{
rtnval = wait (&statval);
if (rtnval != inferior_pid)
{
+ print_sys_errmsg (pi.pathname, errno);
error ("PIOCWSTOP, wait failed, returned %d", rtnval);
/* NOTREACHED */
}
pi.prstatus.pr_flags);
/* NOTREACHED */
}
+
if (statloc)
{
*statloc = 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 */
+ return rtnval;
+ }
+
return (rtnval);
}
}
}
-/*
-
-GLOBAL FUNCTION
-
- child_resume -- resume execution of the inferior process
+/* Resume execution of process PID. If STEP is nozero, then
+ just single step it. If SIGNAL is nonzero, restart it with that
+ signal activated. */
-SYNOPSIS
-
- void child_resume (int step, int signo)
-
-DESCRIPTION
-
- Resume execution of the inferior process. If STEP is nozero, then
- just single step it. If SIGNAL is nonzero, restart it with that
- signal activated.
-
-NOTE
-
- It may not be absolutely necessary to specify the PC value for
- restarting, but to be safe we use the value that gdb considers
- to be current. One case where this might be necessary is if the
- user explicitly changes the PC value that gdb considers to be
- current. FIXME: Investigate if this is necessary or not.
-
- 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
- inhibit sending it another SIGSTOP, which would be the normal
- result of default signal handling. One potential drawback to
- this is that we will also ignore any attempt to by the user
- to explicitly continue after the attach with a SIGSTOP. Ultimately
- this problem should be dealt with by making the routines that
- deal with the inferior a little smarter, and possibly even allow
- an inferior to continue running at the same time as gdb. (FIXME?)
- */
-
-void
-child_resume (step, signo)
+static void
+procfs_resume (pid, step, signo)
+ int pid;
int step;
int signo;
{
+ int signal_to_pass;
+
errno = 0;
pi.prrun.pr_flags = PRSTRACE | PRSFAULT | PRCFAULT;
+#if 0
+ /* It should not be necessary. If the user explicitly changes the value,
+ value_assign calls write_register_bytes, which writes it. */
+/* It may not be absolutely necessary to specify the PC value for
+ restarting, but to be safe we use the value that gdb considers
+ to be current. One case where this might be necessary is if the
+ user explicitly changes the PC value that gdb considers to be
+ current. FIXME: Investigate if this is necessary or not. */
+
#ifdef PRSVADDR_BROKEN
/* Can't do this under Solaris running on a Sparc, as there seems to be no
place to put nPC. In fact, if you use this, nPC seems to be set to some
pi.prrun.pr_vaddr = (caddr_t) *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)];
pi.prrun.pr_flags != PRSVADDR;
+#endif
#endif
- if (signo && !(signo == SIGSTOP && pi.nopass_next_sigstop))
+ if (signo == SIGSTOP && 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
+ inhibit sending it another SIGSTOP, which would be the normal
+ result of default signal handling. One potential drawback to
+ this is that we will also ignore any attempt to by the user
+ to explicitly continue after the attach with a SIGSTOP. Ultimately
+ this problem should be dealt with by making the routines that
+ 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)
+
+ /* We are about to pass the inferior a SIGTSTP whose action is
+ SIG_DFL. The SIG_DFL action for a SIGTSTP is to stop
+ (notifying the parent via wait()), and then keep going from the
+ same place when the parent is ready for you to keep going. So
+ under the debugger, it should do nothing (as if the program had
+ been stopped and then later resumed. Under ptrace, this
+ happens for us, but under /proc, the system obligingly stops
+ the process, and wait_for_inferior would have no way of
+ distinguishing that type of stop (which indicates that we
+ should just start it again), with a stop due to the pr_trace
+ field of the prrun_t struct.
+
+ Note that if the SIGTSTP is being caught, we *do* need to pass it,
+ because the handler needs to get executed. */
+ signal_to_pass = 0;
+ else
+ signal_to_pass = signo;
+
+ if (signal_to_pass)
{
- set_proc_siginfo (&pi, signo);
+ set_proc_siginfo (&pi, signal_to_pass);
}
else
{
/*
-GLOBAL FUNCTION
+LOCAL FUNCTION
- fetch_inferior_registers -- fetch current registers from inferior
+ procfs_fetch_registers -- fetch current registers from inferior
SYNOPSIS
- void fetch_inferior_registers (int regno)
+ void procfs_fetch_registers (int regno)
DESCRIPTION
*/
-void
-fetch_inferior_registers (regno)
+static void
+procfs_fetch_registers (regno)
int regno;
{
if (ioctl (pi.fd, PIOCGREG, &pi.gregset) != -1)
/*
-GLOBAL FUNCTION
-
- fetch_core_registers -- fetch current registers from core file data
-
-SYNOPSIS
-
- void fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
- int which, unsigned in reg_addr)
-
-DESCRIPTION
-
- Read the values of either the general register set (WHICH equals 0)
- or the floating point register set (WHICH equals 2) from the core
- file data (pointed to by CORE_REG_SECT), and update gdb's idea of
- their current values. The CORE_REG_SIZE parameter is ignored.
-
-NOTES
-
- Use the indicated sizes to validate the gregset and fpregset
- structures.
-*/
-
-void
-fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
- char *core_reg_sect;
- unsigned core_reg_size;
- int which;
- unsigned int reg_addr; /* Unused in this version */
-{
-
- if (which == 0)
- {
- if (core_reg_size != sizeof (pi.gregset))
- {
- warning ("wrong size gregset struct in core file");
- }
- else
- {
- memcpy ((char *) &pi.gregset, core_reg_sect, sizeof (pi.gregset));
- supply_gregset (&pi.gregset);
- }
- }
- else if (which == 2)
- {
- if (core_reg_size != sizeof (pi.fpregset))
- {
- warning ("wrong size fpregset struct in core file");
- }
- else
- {
- memcpy ((char *) &pi.fpregset, core_reg_sect, sizeof (pi.fpregset));
-#if defined (FP0_REGNUM)
- supply_fpregset (&pi.fpregset);
-#endif
- }
- }
-}
-
-/*
-
LOCAL FUNCTION
proc_init_failed - called whenever /proc access initialization fails
}
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
}
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))
}
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");
}
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");
info proc mappings (prints address mappings)
info proc times (prints process/children times)
info proc id (prints pid, ppid, gid, sid, etc)
+ FIXME: i proc id not implemented.
info proc status (prints general process state info)
+ FIXME: i proc status not implemented.
info proc signals (prints info about signal handling)
info proc all (prints all info)
if (!pip -> valid)
{
- error ("No process. Run an inferior or specify an explicit pid.");
+ error ("\
+No process. Start debugging a program or specify an explicit process ID.");
}
if (ioctl (pip -> fd, PIOCSTATUS, &(pip -> prstatus)) < 0)
{
do_cleanups (old_chain);
}
+/* Fork an inferior process, and start debugging it with /proc. */
+
+static void
+procfs_create_inferior (exec_file, allargs, env)
+ char *exec_file;
+ char *allargs;
+ char **env;
+{
+ fork_inferior (exec_file, allargs, env,
+ proc_set_exec_trap, procfs_init_inferior);
+ /* We are at the first instruction we care about. */
+ /* Pedal to the metal... */
+ proceed ((CORE_ADDR) -1, 0, 0);
+}
+
+/* Clean up after the inferior dies. */
+
+static void
+procfs_mourn_inferior ()
+{
+ 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);
+}
+\f
+struct target_ops procfs_ops = {
+ "procfs", /* to_shortname */
+ "Unix /proc child process", /* to_longname */
+ "Unix /proc child process (started by the \"run\" command).", /* to_doc */
+ procfs_open, /* to_open */
+ 0, /* to_close */
+ procfs_attach, /* to_attach */
+ procfs_detach, /* to_detach */
+ procfs_resume, /* to_resume */
+ procfs_wait, /* to_wait */
+ procfs_fetch_registers, /* to_fetch_registers */
+ procfs_store_registers, /* to_store_registers */
+ procfs_prepare_to_store, /* to_prepare_to_store */
+ procfs_xfer_memory, /* to_xfer_memory */
+ procfs_files_info, /* to_files_info */
+ memory_insert_breakpoint, /* to_insert_breakpoint */
+ memory_remove_breakpoint, /* to_remove_breakpoint */
+ terminal_init_inferior, /* to_terminal_init */
+ terminal_inferior, /* to_terminal_inferior */
+ terminal_ours_for_output, /* to_terminal_ours_for_output */
+ terminal_ours, /* to_terminal_ours */
+ child_terminal_info, /* to_terminal_info */
+ procfs_kill_inferior, /* to_kill */
+ 0, /* to_load */
+ 0, /* to_lookup_symbol */
+ procfs_create_inferior, /* to_create_inferior */
+ procfs_mourn_inferior, /* to_mourn_inferior */
+ procfs_can_run, /* to_can_run */
+ procfs_notice_signals, /* to_notice_signals */
+ process_stratum, /* to_stratum */
+ 0, /* to_next */
+ 1, /* to_has_all_memory */
+ 1, /* to_has_memory */
+ 1, /* to_has_stack */
+ 1, /* to_has_registers */
+ 1, /* to_has_execution */
+ 0, /* sections */
+ 0, /* sections_end */
+ OPS_MAGIC /* to_magic */
+};
+
/*
GLOBAL FUNCTION
- _initialize_proc_fs -- initialize the process file system stuff
+ _initialize_procfs -- initialize the process file system stuff
SYNOPSIS
- void _initialize_proc_fs (void)
+ void _initialize_procfs (void)
DESCRIPTION
*/
-static char *proc_desc =
+void
+_initialize_procfs ()
+{
+ add_target (&procfs_ops);
+
+ add_info ("proc", info_proc,
"Show process status information using /proc entry.\n\
Specify process id or use current inferior by default.\n\
Specify keywords for detailed information; default is summary.\n\
Keywords are: `all', `faults', `flags', `id', `mappings', `signals',\n\
`status', `syscalls', and `times'.\n\
-Unambiguous abbreviations may be used.";
+Unambiguous abbreviations may be used.");
-void
-_initialize_proc_fs ()
-{
- add_info ("proc", info_proc, proc_desc);
init_syscall_table ();
}
-
-#endif /* USE_PROC_FS */