/* Machine independent support for SVR4 /proc (process file system) for GDB.
- Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation,
+ Inc.
+
Written by Michael Snyder at Cygnus Solutions.
Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with this program; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "inferior.h"
#include "target.h"
#include "gdbcore.h"
+#include "elf-bfd.h" /* for elfcore_write_* */
#include "gdbcmd.h"
#include "gdbthread.h"
#include <sys/syscall.h>
#endif
#include <sys/errno.h>
-#include <sys/wait.h>
+#include "gdb_wait.h"
#include <signal.h>
#include <ctype.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "inflow.h"
+#include "auxv.h"
-/*
+/*
* PROCFS.C
*
* This module provides the interface between GDB and the
* Unixware
* AIX5
*
- * /proc works by immitating a file system: you open a simulated file
+ * /proc works by imitating a file system: you open a simulated file
* that represents the process you wish to interact with, and
* perform operations on that "file" in order to examine or change
* the state of the other process.
* This module has to support both /proc interfaces. This means
* that there are two different ways of doing every basic operation.
*
- * In order to keep most of the code simple and clean, I have
+ * In order to keep most of the code simple and clean, I have
* defined an interface "layer" which hides all these system calls.
* An ifdef (NEW_PROC_API) determines which interface we are using,
* and most or all occurrances of this ifdef should be confined to
/* Determine which /proc API we are using:
- The ioctl API defines PIOCSTATUS, while
+ The ioctl API defines PIOCSTATUS, while
the read/write (multiple fd) API never does. */
#ifdef NEW_PROC_API
static void procfs_prepare_to_store (void);
static void procfs_kill_inferior (void);
static void procfs_mourn_inferior (void);
-static void procfs_create_inferior (char *, char *, char **);
+static void procfs_create_inferior (char *, char *, char **, int);
static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
struct mem_attrib *attrib,
struct target_ops *);
+static LONGEST procfs_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len);
static int procfs_thread_alive (ptid_t);
void procfs_find_new_threads (void);
char *procfs_pid_to_str (ptid_t);
+static int proc_find_memory_regions (int (*) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *);
+
+static char * procfs_make_note_section (bfd *, int *);
+
+static int procfs_can_use_hw_breakpoint (int, int, int);
+
struct target_ops procfs_ops; /* the target vector */
static void
init_procfs_ops (void)
{
- procfs_ops.to_shortname = "procfs";
- procfs_ops.to_longname = "Unix /proc child process";
- procfs_ops.to_doc =
+ procfs_ops.to_shortname = "procfs";
+ procfs_ops.to_longname = "Unix /proc child process";
+ procfs_ops.to_doc =
"Unix /proc child process (started by the \"run\" command).";
- procfs_ops.to_open = procfs_open;
- procfs_ops.to_can_run = procfs_can_run;
- procfs_ops.to_create_inferior = procfs_create_inferior;
- procfs_ops.to_kill = procfs_kill_inferior;
- procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
- procfs_ops.to_attach = procfs_attach;
- procfs_ops.to_detach = procfs_detach;
- procfs_ops.to_wait = procfs_wait;
- procfs_ops.to_resume = procfs_resume;
- procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
- procfs_ops.to_fetch_registers = procfs_fetch_registers;
- procfs_ops.to_store_registers = procfs_store_registers;
- procfs_ops.to_xfer_memory = procfs_xfer_memory;
- procfs_ops.to_insert_breakpoint = memory_insert_breakpoint;
- procfs_ops.to_remove_breakpoint = memory_remove_breakpoint;
- procfs_ops.to_notice_signals = procfs_notice_signals;
- procfs_ops.to_files_info = procfs_files_info;
- procfs_ops.to_stop = procfs_stop;
-
- procfs_ops.to_terminal_init = terminal_init_inferior;
- procfs_ops.to_terminal_inferior = terminal_inferior;
+ procfs_ops.to_open = procfs_open;
+ procfs_ops.to_can_run = procfs_can_run;
+ procfs_ops.to_create_inferior = procfs_create_inferior;
+ procfs_ops.to_kill = procfs_kill_inferior;
+ procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
+ procfs_ops.to_attach = procfs_attach;
+ procfs_ops.to_detach = procfs_detach;
+ procfs_ops.to_wait = procfs_wait;
+ procfs_ops.to_resume = procfs_resume;
+ procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
+ procfs_ops.to_fetch_registers = procfs_fetch_registers;
+ procfs_ops.to_store_registers = procfs_store_registers;
+ procfs_ops.to_xfer_partial = procfs_xfer_partial;
+ procfs_ops.deprecated_xfer_memory = procfs_xfer_memory;
+ procfs_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ procfs_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ procfs_ops.to_notice_signals = procfs_notice_signals;
+ procfs_ops.to_files_info = procfs_files_info;
+ procfs_ops.to_stop = procfs_stop;
+
+ procfs_ops.to_terminal_init = terminal_init_inferior;
+ procfs_ops.to_terminal_inferior = terminal_inferior;
procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
- procfs_ops.to_terminal_ours = terminal_ours;
- procfs_ops.to_terminal_info = child_terminal_info;
-
- procfs_ops.to_find_new_threads = procfs_find_new_threads;
- procfs_ops.to_thread_alive = procfs_thread_alive;
- procfs_ops.to_pid_to_str = procfs_pid_to_str;
-
- procfs_ops.to_has_all_memory = 1;
- procfs_ops.to_has_memory = 1;
- procfs_ops.to_has_execution = 1;
- procfs_ops.to_has_stack = 1;
- procfs_ops.to_has_registers = 1;
- procfs_ops.to_stratum = process_stratum;
- procfs_ops.to_has_thread_control = tc_schedlock;
- procfs_ops.to_magic = OPS_MAGIC;
+ procfs_ops.to_terminal_ours = terminal_ours;
+ procfs_ops.to_terminal_save_ours = terminal_save_ours;
+ procfs_ops.to_terminal_info = child_terminal_info;
+
+ procfs_ops.to_find_new_threads = procfs_find_new_threads;
+ procfs_ops.to_thread_alive = procfs_thread_alive;
+ procfs_ops.to_pid_to_str = procfs_pid_to_str;
+
+ procfs_ops.to_has_all_memory = 1;
+ procfs_ops.to_has_memory = 1;
+ procfs_ops.to_has_execution = 1;
+ procfs_ops.to_has_stack = 1;
+ procfs_ops.to_has_registers = 1;
+ procfs_ops.to_stratum = process_stratum;
+ procfs_ops.to_has_thread_control = tc_schedlock;
+ procfs_ops.to_find_memory_regions = proc_find_memory_regions;
+ procfs_ops.to_make_corefile_notes = procfs_make_note_section;
+ procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
+ procfs_ops.to_magic = OPS_MAGIC;
}
/* =================== END, TARGET_OPS "MODULE" =================== */
#ifdef NEW_PROC_API /* Solaris 7 && 8 method for watchpoints */
#ifdef WA_READ
- enum { READ_WATCHFLAG = WA_READ,
+ enum { READ_WATCHFLAG = WA_READ,
WRITE_WATCHFLAG = WA_WRITE,
EXEC_WATCHFLAG = WA_EXEC,
AFTER_WATCHFLAG = WA_TRAPAFTER
};
#endif
#else /* Irix method for watchpoints */
- enum { READ_WATCHFLAG = MA_READ,
+ enum { READ_WATCHFLAG = MA_READ,
WRITE_WATCHFLAG = MA_WRITE,
EXEC_WATCHFLAG = MA_EXEC,
AFTER_WATCHFLAG = 0 /* trapafter not implemented */
int was_stopped;
int ignore_next_sigstop;
- /* The following four fd fields may be identical, or may contain
+ /* The following four fd fields may be identical, or may contain
several different fd's, depending on the version of /proc
(old ioctl or new read/write). */
/*
* The next three file descriptors are actually only needed in the
* read/write, multiple-file-descriptor implemenation (NEW_PROC_API).
- * However, to avoid a bunch of #ifdefs in the code, we will use
+ * However, to avoid a bunch of #ifdefs in the code, we will use
* them uniformly by (in the case of the ioctl single-file-descriptor
* implementation) filling them with copies of the control fd.
*/
int num_syscalls; /* Total number of syscalls */
char **syscall_names; /* Syscall number to name map */
#endif
-
+
struct procinfo *thread_list;
int status_valid : 1;
* Returns: pointer to procinfo, or NULL if not found.
*/
-static procinfo *
+static procinfo *
find_procinfo (int pid, int tid)
{
procinfo *pi;
if (pi == NULL)
{
if (tid)
- error ("procfs: couldn't find pid %d (kernel thread %d) in procinfo list.",
+ error (_("procfs: couldn't find pid %d (kernel thread %d) in procinfo list."),
pid, tid);
else
- error ("procfs: couldn't find pid %d in procinfo list.", pid);
+ error (_("procfs: couldn't find pid %d in procinfo list."), pid);
}
return pi;
}
/* open_with_retry() is a wrapper for open(). The appropriate
open() call is attempted; if unsuccessful, it will be retried as
many times as needed for the EAGAIN and EINTR conditions.
-
+
For other conditions, open_with_retry() will retry the open() a
limited number of times. In addition, a short sleep is imposed
prior to retrying the open(). The reason for this sleep is to give
the kernel a chance to catch up and create the file in question in
the event that GDB "wins" the race to open a file before the kernel
has created it. */
-
+
static int
open_with_retry (const char *pathname, int flags)
{
#endif
int fd;
- /*
+ /*
* This function is getting ALMOST long enough to break up into several.
* Here is some rationale:
*
* NEW_PROC_API (Solaris 2.6, Solaris 2.7, Unixware):
- * There are several file descriptors that may need to be open
+ * There are several file descriptors that may need to be open
* for any given process or LWP. The ones we're intereted in are:
* - control (ctl) write-only change the state
* - status (status) read-only query the state
* - address space (as) read/write access memory
* - map (map) read-only virtual addr map
* Most of these are opened lazily as they are needed.
- * The pathnames for the 'files' for an LWP look slightly
+ * The pathnames for the 'files' for an LWP look slightly
* different from those of a first-class process:
* Pathnames for a process (<proc-id>):
* /proc/<proc-id>/ctl
* For convenience, we copy the same file descriptor into all
* three fields of the procinfo struct (ctl_fd, status_fd, and
* as_fd, see NEW_PROC_API above) so that code that uses them
- * doesn't need any #ifdef's.
+ * doesn't need any #ifdef's.
* Pathname for all:
* /proc/<proc-id>
*
* Solaris 2.5 LWP's:
- * Each LWP has an independent file descriptor, but these
+ * Each LWP has an independent file descriptor, but these
* are not obtained via the 'open' system call like the rest:
* instead, they're obtained thru an ioctl call (PIOCOPENLWP)
* to the file descriptor of the parent process.
* In this case, there is only one file descriptor for each procinfo
* (ie. each process or LWP). In fact, only the file descriptor for
* the process can actually be opened by an 'open' system call.
- * The ones for the LWPs have to be obtained thru an IOCTL call
- * on the process's file descriptor.
+ * The ones for the LWPs have to be obtained thru an IOCTL call
+ * on the process's file descriptor.
*
* For convenience, we copy each procinfo's single file descriptor
- * into all of the fields occupied by the several file descriptors
+ * into all of the fields occupied by the several file descriptors
* of the NEW_PROC_API implementation. That way, the code that uses
* them can be written without ifdefs.
*/
load_syscalls (pi);
#endif
+ pi->saved_entryset = sysset_t_alloc (pi);
+ pi->saved_exitset = sysset_t_alloc (pi);
+
/* Chain into list. */
if (tid == 0)
{
/* Step one: unlink the procinfo from its list */
if (pi == *list)
*list = pi->next;
- else
+ else
for (ptr = *list; ptr; ptr = ptr->next)
if (ptr->next == pi)
{
#ifdef DYNAMIC_SYSCALLS
free_syscalls (pi);
#endif
+ xfree (pi->saved_entryset);
+ xfree (pi->saved_exitset);
xfree (pi);
}
kill (pi->pid, SIGKILL);
destroy_procinfo (pi);
- error (msg);
+ error ((msg));
}
/*
}
/* Function: sysset_t_alloc
-
+
Allocate and (partially) initialize a sysset_t struct. */
static sysset_t *
#ifdef DYNAMIC_SYSCALLS
/* Function: load_syscalls
-
+
Extract syscall numbers and names from /proc/<pid>/sysent. Initialize
pi->num_syscalls with the number of syscalls and pi->syscall_names
with the names. (Certain numbers may be skipped in which case the
sysent_fd = open_with_retry (pathname, O_RDONLY);
if (sysent_fd < 0)
{
- error ("load_syscalls: Can't open /proc/%d/sysent", pi->pid);
+ error (_("load_syscalls: Can't open /proc/%d/sysent"), pi->pid);
}
size = sizeof header - sizeof (prsyscall_t);
if (read (sysent_fd, &header, size) != size)
{
- error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid);
+ error (_("load_syscalls: Error reading /proc/%d/sysent"), pi->pid);
}
if (header.pr_nsyscalls == 0)
{
- error ("load_syscalls: /proc/%d/sysent contains no syscalls!", pi->pid);
+ error (_("load_syscalls: /proc/%d/sysent contains no syscalls!"), pi->pid);
}
size = header.pr_nsyscalls * sizeof (prsyscall_t);
if (read (sysent_fd, syscalls, size) != size)
{
xfree (syscalls);
- error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid);
+ error (_("load_syscalls: Error reading /proc/%d/sysent"), pi->pid);
}
/* Find maximum syscall number. This may not be the same as
strncpy (pi->syscall_names[callnum], namebuf, size-1);
pi->syscall_names[callnum][size-1] = '\0';
}
-
+
close (sysent_fd);
xfree (syscalls);
}
/* Function: free_syscalls
-
+
Free the space allocated for the syscall names from the procinfo
structure. */
Given a name, look up (and return) the corresponding syscall number.
If no match is found, return -1. */
-
+
static int
find_syscall (procinfo *pi, char *name)
{
/*
* This "module" is the interface layer between the /proc system API
- * and the gdb target vector functions. This layer consists of
+ * and the gdb target vector functions. This layer consists of
* access functions that encapsulate each of the basic operations
* that we need to use from the /proc API.
*
pi->status_valid = 0; /* fail */
else
{
- /* Sigh... I have to read a different data structure,
+ /* Sigh... I have to read a different data structure,
depending on whether this is a main process or an LWP. */
if (pi->tid)
- pi->status_valid = (read (pi->status_fd,
- (char *) &pi->prstatus.pr_lwp,
+ pi->status_valid = (read (pi->status_fd,
+ (char *) &pi->prstatus.pr_lwp,
sizeof (lwpstatus_t))
== sizeof (lwpstatus_t));
else
{
- pi->status_valid = (read (pi->status_fd,
+ pi->status_valid = (read (pi->status_fd,
(char *) &pi->prstatus,
sizeof (gdb_prstatus_t))
== sizeof (gdb_prstatus_t));
(pi->prstatus.pr_lwp.pr_flags & PR_ISTOP) &&
pi->prstatus.pr_lwp.pr_why == PR_REQUESTED)
/* Unixware peculiarity -- read the damn thing again! */
- pi->status_valid = (read (pi->status_fd,
+ pi->status_valid = (read (pi->status_fd,
(char *) &pi->prstatus,
sizeof (gdb_prstatus_t))
== sizeof (gdb_prstatus_t));
if (pi->tid == 0) /* main process */
{
/* Just read the danged status. Now isn't that simple? */
- pi->status_valid =
+ pi->status_valid =
(ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0);
}
else
win = (ioctl (pi->status_fd, PIOCTSTATUS, &thread_status) >= 0);
if (win)
{
- memcpy (&pi->prstatus, &thread_status.status,
+ memcpy (&pi->prstatus, &thread_status.status,
sizeof (pi->prstatus));
pi->status_valid = 1;
}
if (pi->status_valid)
{
- PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
- proc_what (pi),
+ proc_what (pi),
proc_get_current_thread (pi));
}
/* The status struct includes general regs, so mark them valid too */
pi->gregs_valid = pi->status_valid;
#ifdef NEW_PROC_API
- /* In the read/write multiple-fd model,
+ /* In the read/write multiple-fd model,
the status struct includes the fp regs too, so mark them valid too */
pi->fpregs_valid = pi->status_valid;
#endif
* Function: proc_flags
*
* returns the process flags (pr_flags field).
- */
+ */
long
proc_flags (procinfo *pi)
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
-
+
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_nsysarg;
#else
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
-
+
#ifdef NEW_PROC_API
return (long *) &pi->prstatus.pr_lwp.pr_sysarg;
#else
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
-
+
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_syscall;
#else
}
/*
- * Function: proc_modify_flag
+ * Function: proc_modify_flag
*
- * === I appologize for the messiness of this function.
+ * === I appologize for the messiness of this function.
* === This is an area where the different versions of
* === /proc are more inconsistent than usual. MVS
*
* Note: OSF does not define PR_KLC.
* Note: OSF is the only one that can ONLY use the oldest method.
*
- * Arguments:
+ * Arguments:
* pi -- the procinfo
* flag -- one of PR_FORK, PR_RLC, or PR_ASYNC
* mode -- 1 for set, 0 for reset.
{
long win = 0; /* default to fail */
- /*
- * These operations affect the process as a whole, and applying
- * them to an individual LWP has the same meaning as applying them
- * to the main process. Therefore, if we're ever called with a
- * pointer to an LWP's procinfo, let's substitute the process's
- * procinfo and avoid opening the LWP's file descriptor
- * unnecessarily.
+ /*
+ * These operations affect the process as a whole, and applying
+ * them to an individual LWP has the same meaning as applying them
+ * to the main process. Therefore, if we're ever called with a
+ * pointer to an LWP's procinfo, let's substitute the process's
+ * procinfo and avoid opening the LWP's file descriptor
+ * unnecessarily.
*/
if (pi->pid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API /* Newest method: UnixWare and newer Solarii */
- /* First normalize the PCUNSET/PCRESET command opcode
+ /* First normalize the PCUNSET/PCRESET command opcode
(which for no obvious reason has a different definition
from one operating system to the next...) */
#ifdef PCUNSET
pi->status_valid = 0;
if (!win)
- warning ("procfs: modify_flag failed to turn %s %s",
+ warning (_("procfs: modify_flag failed to turn %s %s"),
flag == PR_FORK ? "PR_FORK" :
flag == PR_RLC ? "PR_RLC" :
#ifdef PR_ASYNC
* Function: proc_unset_kill_on_last_close
*
* Reset the kill_on_last_close flag.
- * Process will NOT be killed when debugger
+ * Process will NOT be killed when debugger
* closes its file handles (or exits or dies).
*
* Returns non-zero for success, zero for failure.
* Function: proc_set_async
*
* Set PR_ASYNC flag.
- * If one LWP stops because of a debug event (signal etc.),
+ * If one LWP stops because of a debug event (signal etc.),
* the remaining LWPs will continue to run.
*
* Returns non-zero for success, zero for failure.
* Function: proc_stop_process
*
* Request the process/LWP to stop. Does not wait.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
if (win)
{
pi->status_valid = 1;
- PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
- proc_what (pi),
+ proc_what (pi),
proc_get_current_thread (pi));
}
#endif
* Function: proc_wait_for_stop
*
* Wait for the process or LWP to stop (block until it does).
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (win)
{
pi->status_valid = 1;
- PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
+ PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
- proc_what (pi),
+ proc_what (pi),
proc_get_current_thread (pi));
}
#endif
* signo if zero, clear the current signal if any.
* if non-zero, set the current signal to this one.
*
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
* We will probably have to apply this operation to individual threads,
* so make sure the control file descriptor is open.
*/
-
+
if (pi->ctl_fd == 0 &&
open_procinfo_files (pi, FD_CTL) == 0)
{
* Function: proc_set_traced_signals
*
* Register to trace signals in the process or LWP.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
pi->status_valid = 0;
if (!win)
- warning ("procfs: set_traced_signals failed");
+ warning (_("procfs: set_traced_signals failed"));
return win;
}
* Function: proc_set_traced_faults
*
* Register to trace hardware faults in the process or LWP.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
* Function: proc_set_traced_sysentry
*
* Register to trace entry to system calls in the process or LWP.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#endif
/* The above operation renders the procinfo's cached pstatus obsolete. */
pi->status_valid = 0;
-
+
return win;
}
* Function: proc_set_traced_sysexit
*
* Register to trace exit from system calls in the process or LWP.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
* Function: proc_set_held_signals
*
* Specify the set of blocked / held signals in the process or LWP.
- * Returns non-zero for success, zero for failure.
+ * Returns non-zero for success, zero for failure.
*/
int
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#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.
+ * it messes up the current signal. Work around the kernel bug.
*/
if (signo > 0 &&
signo == proc_cursig (pi))
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
return win;
}
-/*
- * Function: proc_get_gregs
- *
- * Get the general registers for the process or LWP.
- * Returns non-zero for success, zero for failure.
- */
+/* Return the general-purpose registers for the process or LWP
+ corresponding to PI. Upon failure, return NULL. */
gdb_gregset_t *
proc_get_gregs (procinfo *pi)
if (!proc_get_status (pi))
return NULL;
- /*
- * OK, sorry about the ifdef's.
- * There's three cases instead of two, because
- * in this instance Unixware and Solaris/RW differ.
- */
+ /* OK, sorry about the ifdef's. There's three cases instead of two,
+ because in this case Unixware and Solaris/RW differ. */
#ifdef NEW_PROC_API
-#ifdef UNIXWARE /* ugh, a true architecture dependency */
+# ifdef UNIXWARE /* FIXME: Should be autoconfigured. */
return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs;
-#else /* not Unixware */
+# else
return &pi->prstatus.pr_lwp.pr_reg;
-#endif /* Unixware */
-#else /* not NEW_PROC_API */
+# endif
+#else
return &pi->prstatus.pr_reg;
-#endif /* NEW_PROC_API */
+#endif
}
-/*
- * Function: proc_get_fpregs
- *
- * Get the floating point registers for the process or LWP.
- * Returns non-zero for success, zero for failure.
- */
+/* Return the general-purpose registers for the process or LWP
+ corresponding to PI. Upon failure, return NULL. */
gdb_fpregset_t *
proc_get_fpregs (procinfo *pi)
if (!proc_get_status (pi))
return NULL;
-#ifdef UNIXWARE /* a true architecture dependency */
+# ifdef UNIXWARE /* FIXME: Should be autoconfigured. */
return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs;
-#else
+# else
return &pi->prstatus.pr_lwp.pr_fpreg;
-#endif /* Unixware */
+# endif
-#else /* not NEW_PROC_API */
+#else /* not NEW_PROC_API */
if (pi->fpregs_valid)
- return &pi->fpregset; /* already got 'em */
+ return &pi->fpregset; /* Already got 'em. */
else
{
- if (pi->ctl_fd == 0 &&
- open_procinfo_files (pi, FD_CTL) == 0)
+ if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return NULL;
}
else
{
-#ifdef PIOCTGFPREG
+# ifdef PIOCTGFPREG
struct {
long pr_count;
tid_t pr_error_thread;
thread_fpregs.pr_count = 1;
thread_fpregs.thread_1.tid = pi->tid;
- if (pi->tid == 0 &&
- ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
+ if (pi->tid == 0
+ && ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
{
pi->fpregs_valid = 1;
- return &pi->fpregset; /* got 'em now! */
+ return &pi->fpregset; /* Got 'em now! */
}
- else if (pi->tid != 0 &&
- ioctl (pi->ctl_fd, PIOCTGFPREG, &thread_fpregs) >= 0)
+ else if (pi->tid != 0
+ && ioctl (pi->ctl_fd, PIOCTGFPREG, &thread_fpregs) >= 0)
{
memcpy (&pi->fpregset, &thread_fpregs.thread_1.pr_fpregs,
sizeof (pi->fpregset));
pi->fpregs_valid = 1;
- return &pi->fpregset; /* got 'em now! */
+ return &pi->fpregset; /* Got 'em now! */
}
else
{
return NULL;
}
-#else
+# else
if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
{
pi->fpregs_valid = 1;
- return &pi->fpregset; /* got 'em now! */
+ return &pi->fpregset; /* Got 'em now! */
}
else
{
return NULL;
}
-#endif
+# endif
}
}
-#endif
+#endif /* NEW_PROC_API */
}
-/*
- * Function: proc_set_gregs
- *
- * Write the general registers back to the process or LWP.
- * Returns non-zero for success, zero for failure.
- */
+/* Write the general-purpose registers back to the process or LWP
+ corresponding to PI. Return non-zero for success, zero for
+ failure. */
int
proc_set_gregs (procinfo *pi)
gdb_gregset_t *gregs;
int win;
- if ((gregs = proc_get_gregs (pi)) == NULL)
- return 0; /* get_regs has already warned */
+ gregs = proc_get_gregs (pi);
+ if (gregs == NULL)
+ return 0; /* proc_get_regs has already warned. */
- if (pi->ctl_fd == 0 &&
- open_procinfo_files (pi, FD_CTL) == 0)
+ if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
char gregs[sizeof (gdb_gregset_t)];
} arg;
- arg.cmd = PCSREG;
+ arg.cmd = PCSREG;
memcpy (&arg.gregs, gregs, sizeof (arg.gregs));
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
#else
#endif
}
- /* Policy: writing the regs invalidates our cache. */
+ /* Policy: writing the registers invalidates our cache. */
pi->gregs_valid = 0;
return win;
}
-/*
- * Function: proc_set_fpregs
- *
- * Modify the floating point register set of the process or LWP.
- * Returns non-zero for success, zero for failure.
- */
+/* Write the floating-pointer registers back to the process or LWP
+ corresponding to PI. Return non-zero for success, zero for
+ failure. */
int
proc_set_fpregs (procinfo *pi)
gdb_fpregset_t *fpregs;
int win;
- if ((fpregs = proc_get_fpregs (pi)) == NULL)
- return 0; /* get_fpregs has already warned */
+ fpregs = proc_get_fpregs (pi);
+ if (fpregs == NULL)
+ return 0; /* proc_get_fpregs has already warned. */
- if (pi->ctl_fd == 0 &&
- open_procinfo_files (pi, FD_CTL) == 0)
+ if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
char fpregs[sizeof (gdb_fpregset_t)];
} arg;
- arg.cmd = PCSFPREG;
+ arg.cmd = PCSFPREG;
memcpy (&arg.fpregs, fpregs, sizeof (arg.fpregs));
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
#else
-#ifdef PIOCTSFPREG
+# ifdef PIOCTSFPREG
if (pi->tid == 0)
win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
else
sizeof (*fpregs));
win = (ioctl (pi->ctl_fd, PIOCTSFPREG, &thread_fpregs) >= 0);
}
-#else
+# else
win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
-#endif /* osf PIOCTSFPREG */
-#endif /* NEW_PROC_API */
+# endif
+#endif /* NEW_PROC_API */
}
- /* Policy: writing the regs invalidates our cache. */
+ /* Policy: writing the registers invalidates our cache. */
pi->fpregs_valid = 0;
return win;
}
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
}
+/* Convert a target address (a.k.a. CORE_ADDR) into a host address
+ (a.k.a void pointer)! */
+
+static void *
+procfs_address_to_host_pointer (CORE_ADDR addr)
+{
+ void *ptr;
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ return ptr;
+}
+
/*
* Function: proc_set_watchpoint
*
int
proc_set_watchpoint (procinfo *pi, CORE_ADDR addr, int len, int wflags)
{
-#if !defined (TARGET_HAS_HARDWARE_WATCHPOINTS)
+#if !defined (TARGET_HAS_HARDWARE_WATCHPOINTS)
return 0;
#else
/* Horrible hack! Detect Solaris 2.5, because this doesn't work on 2.5 */
prwatch_t *pwatch;
pwatch = (prwatch_t *) &arg.watch;
- pwatch->pr_vaddr = address_to_host_pointer (addr);
+ /* NOTE: cagney/2003-02-01: Even more horrible hack. Need to
+ convert a target address into something that can be stored in a
+ native data structure. */
+#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */
+ pwatch->pr_vaddr = (uintptr_t) procfs_address_to_host_pointer (addr);
+#else
+ pwatch->pr_vaddr = (caddr_t) procfs_address_to_host_pointer (addr);
+#endif
pwatch->pr_size = len;
pwatch->pr_wflags = wflags;
#if defined(NEW_PROC_API) && defined (PCWATCH)
#endif
}
-/*
- * Function: proc_iterate_over_mappings
- *
- * Given a pointer to a function, call that function once for every
- * mapped address space in the process. The callback function
- * receives an open file descriptor for the file corresponding to
- * that mapped address space (if there is one), and the base address
- * of the mapped space. Quit when the callback function returns a
- * nonzero value, or at teh end of the mappings.
- *
- * Returns: the first non-zero return value of the callback function,
- * or zero.
- */
-
-/* FIXME: it's probably a waste to cache this FD.
- It doesn't get called that often... and if I open it
- every time, I don't need to lseek it. */
-int
-proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
-{
- struct prmap *map;
- procinfo *pi;
-#ifndef NEW_PROC_API /* avoid compiler warning */
- int nmaps = 0;
- int i;
-#else
- int map_fd;
- char pathname[MAX_PROC_NAME_SIZE];
-#endif
- int funcstat = 0;
- int fd;
-
- pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
-
-#ifdef NEW_PROC_API
- /* Open map fd. */
- sprintf (pathname, "/proc/%d/map", pi->pid);
- if ((map_fd = open_with_retry (pathname, O_RDONLY)) < 0)
- proc_error (pi, "proc_iterate_over_mappings (open)", __LINE__);
-
- /* Make sure it gets closed again. */
- make_cleanup_close (map_fd);
-
- /* Allocate space for mapping (lifetime only for this function). */
- map = alloca (sizeof (struct prmap));
-
- /* Now read the mappings from the file,
- open a file descriptor for those that have a name,
- and call the callback function. */
- while (read (map_fd,
- (void *) map,
- sizeof (struct prmap)) == sizeof (struct prmap))
- {
- char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
-
- if (map->pr_vaddr == 0 && map->pr_size == 0)
- break; /* sanity */
-
- if (map->pr_mapname[0] == 0)
- {
- fd = -1; /* no map file */
- }
- else
- {
- sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
- /* Note: caller's responsibility to close this fd! */
- fd = open_with_retry (name, O_RDONLY);
- /* Note: we don't test the above call for failure;
- we just pass the FD on as given. Sometimes there is
- no file, so the ioctl may return failure, but that's
- not a problem. */
- }
-
- /* Stop looping if the callback returns non-zero. */
- if ((funcstat = (*func) (fd, (CORE_ADDR) map->pr_vaddr)) != 0)
- break;
- }
-#else
- /* Get the number of mapping entries. */
- if (ioctl (pi->ctl_fd, PIOCNMAP, &nmaps) < 0)
- proc_error (pi, "proc_iterate_over_mappings (PIOCNMAP)", __LINE__);
-
- /* Allocate space for mappings (lifetime only this function). */
- map = (struct prmap *) alloca ((nmaps + 1) * sizeof (struct prmap));
-
- /* Read in all the mappings. */
- if (ioctl (pi->ctl_fd, PIOCMAP, map) < 0)
- proc_error (pi, "proc_iterate_over_mappings (PIOCMAP)", __LINE__);
-
- /* Now loop through the mappings, open an fd for each, and
- call the callback function. */
- for (i = 0;
- i < nmaps && map[i].pr_size != 0;
- i++)
- {
- /* Note: caller's responsibility to close this fd! */
- fd = ioctl (pi->ctl_fd, PIOCOPENM, &map[i].pr_vaddr);
- /* Note: we don't test the above call for failure;
- we just pass the FD on as given. Sometimes there is
- no file, so the ioctl may return failure, but that's
- not a problem. */
-
- /* Stop looping if the callback returns non-zero. */
- funcstat = (*func) (fd, host_pointer_to_address (map[i].pr_vaddr));
- if (funcstat != 0)
- break;
- }
-#endif
-
- return funcstat;
-}
-
#ifdef TM_I386SOL2_H /* Is it hokey to use this? */
#include <sys/sysi86.h>
/* This alloc has to persist, 'cause we return a pointer to it. */
if (nldt > nalloc)
{
- ldt_entry = (struct ssd *)
+ ldt_entry = (struct ssd *)
xrealloc (ldt_entry, (nldt + 1) * sizeof (struct ssd));
nalloc = nldt;
}
-
+
/* Read the whole table in one gulp. */
if (ioctl (pi->ctl_fd, PIOCLDT, ldt_entry) < 0)
{
since there is a different way to do threads on every OS. */
/*
- * Function: proc_get_nthreads
+ * Function: proc_get_nthreads
*
- * Return the number of threads for the process
+ * Return the number of threads for the process
*/
#if defined (PIOCNTHR) && defined (PIOCTLIST)
/*
* OSF version
*/
-int
+int
proc_get_nthreads (procinfo *pi)
{
int nthreads = 0;
return 0;
/*
- * NEW_PROC_API: only works for the process procinfo,
+ * NEW_PROC_API: only works for the process procinfo,
* because the LWP procinfos do not get prstatus filled in.
*/
-#ifdef NEW_PROC_API
+#ifdef NEW_PROC_API
if (pi->tid != 0) /* find the parent process procinfo */
pi = find_procinfo_or_die (pi->pid, 0);
#endif
/*
* Note: this should be applied to the root procinfo for the process,
* not to the procinfo for an LWP. If applied to the procinfo for
- * an LWP, it will simply return that LWP's ID. In that case,
+ * an LWP, it will simply return that LWP's ID. In that case,
* find the parent process procinfo.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* OSF version
*/
-int
+int
proc_get_current_thread (procinfo *pi)
{
#if 0 /* FIXME: not ready for prime time? */
/*
* Default version
*/
-int
+int
proc_get_current_thread (procinfo *pi)
{
return 0;
#endif
/*
- * Function: proc_update_threads
+ * Function: proc_update_threads
*
* Discover the IDs of all the threads within the process, and
* create a procinfo for each of them (chained to the parent).
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
/*
* Unixware
*
- * Note: this brute-force method is the only way I know of
- * to accomplish this task on Unixware. This method will
+ * Note: this brute-force method is the only way I know of
+ * to accomplish this task on Unixware. This method will
* also work on Solaris 2.6 and 2.7. There is a much simpler
* and more elegant way to do this on Solaris, but the margins
* of this manuscript are too small to write it here... ;-)
/*
* OSF version
*/
-int
+int
proc_update_threads (procinfo *pi)
{
int nthreads, i;
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
return 0; /* nothing to do for 1 or fewer threads */
threads = xmalloc (nthreads * sizeof (tid_t));
-
+
if (ioctl (pi->ctl_fd, PIOCTLIST, threads) < 0)
proc_error (pi, "procfs: update_threads (PIOCTLIST)", __LINE__);
* Note: this function does NOT call update_threads.
* If you want to discover new threads first, you must
* call that function explicitly. This function just makes
- * a quick pass over the currently-known procinfos.
- *
+ * a quick pass over the currently-known procinfos.
+ *
* Arguments:
* pi - parent process procinfo
* func - per-thread function
/*
* We should never have to apply this operation to any procinfo
* except the one for the main process. If that ever changes
- * for any reason, then take out the following clause and
+ * for any reason, then take out the following clause and
* replace it with one that makes sure the ctl_fd is open.
*/
-
+
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
static ptid_t do_attach (ptid_t ptid);
static void do_detach (int signo);
static int register_gdb_signals (procinfo *, gdb_sigset_t *);
+static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum,
+ int entry_or_exit, int mode, int from_tty);
+static int insert_dbx_link_breakpoint (procinfo *pi);
+static void remove_dbx_link_breakpoint (void);
+
+/* On mips-irix, we need to insert a breakpoint at __dbx_link during
+ the startup phase. The following two variables are used to record
+ the address of the breakpoint, and the code that was replaced by
+ a breakpoint. */
+static int dbx_link_bpt_addr = 0;
+static void *dbx_link_bpt;
/*
* Function: procfs_debug_inferior
return 0;
}
-static void
+static void
procfs_attach (char *args, int from_tty)
{
char *exec_file;
int pid;
if (!args)
- error_no_arg ("process-id to attach");
+ error_no_arg (_("process-id to attach"));
pid = atoi (args);
if (pid == getpid ())
- error ("Attaching GDB to itself is not a good idea...");
+ error (_("Attaching GDB to itself is not a good idea..."));
if (from_tty)
{
exec_file = get_exec_file (0);
if (exec_file)
- printf_filtered ("Attaching to program `%s', %s\n",
+ printf_filtered (_("Attaching to program `%s', %s\n"),
exec_file, target_pid_to_str (pid_to_ptid (pid)));
else
- printf_filtered ("Attaching to %s\n",
+ printf_filtered (_("Attaching to %s\n"),
target_pid_to_str (pid_to_ptid (pid)));
fflush (stdout);
push_target (&procfs_ops);
}
-static void
+static void
procfs_detach (char *args, int from_tty)
{
- char *exec_file;
- int signo = 0;
+ int sig = 0;
+
+ if (args)
+ sig = atoi (args);
if (from_tty)
{
+ int pid = PIDGET (inferior_ptid);
+ char *exec_file;
+
exec_file = get_exec_file (0);
- if (exec_file == 0)
+ if (exec_file == NULL)
exec_file = "";
- printf_filtered ("Detaching from program: %s %s\n",
- exec_file, target_pid_to_str (inferior_ptid));
- fflush (stdout);
+
+ printf_filtered (_("Detaching from program: %s, %s\n"), exec_file,
+ target_pid_to_str (pid_to_ptid (pid)));
+ gdb_flush (gdb_stdout);
}
- if (args)
- signo = atoi (args);
-
- do_detach (signo);
+
+ do_detach (sig);
+
inferior_ptid = null_ptid;
- unpush_target (&procfs_ops); /* Pop out of handling an inferior */
+ unpush_target (&procfs_ops);
}
static ptid_t
int fail;
if ((pi = create_procinfo (PIDGET (ptid), 0)) == NULL)
- perror ("procfs: out of memory in 'attach'");
+ perror (_("procfs: out of memory in 'attach'"));
if (!open_procinfo_files (pi, FD_CTL))
{
fprintf_filtered (gdb_stderr, "procfs:%d -- ", __LINE__);
- sprintf (errmsg, "do_attach: couldn't open /proc file for process %d",
+ sprintf (errmsg, "do_attach: couldn't open /proc file for process %d",
PIDGET (ptid));
dead_procinfo (pi, errmsg, NOKILL);
}
dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.",
NOKILL);
if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
- dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
+ dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
NOKILL);
if (!proc_get_held_signals (pi, &pi->saved_sighold))
dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL);
if (signo || (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)))
if (signo || !(pi->was_stopped) ||
- query ("Was stopped when attached, make it runnable again? "))
+ query (_("Was stopped when attached, make it runnable again? ")))
{
/* Clear any pending signal. */
if (!proc_clear_current_fault (pi))
proc_warn (pi, "do_detach, clear_current_fault", __LINE__);
+ if (signo == 0 && !proc_clear_current_signal (pi))
+ proc_warn (pi, "do_detach, clear_current_signal", __LINE__);
+
if (!proc_set_run_on_last_close (pi))
proc_warn (pi, "do_detach, set_rlc", __LINE__);
}
destroy_procinfo (pi);
}
-/*
- * fetch_registers
- *
- * Since the /proc interface cannot give us individual registers,
- * we pay no attention to the (regno) argument, and just fetch them all.
- * This results in the possibility that we will do unnecessarily many
- * fetches, since we may be called repeatedly for individual registers.
- * So we cache the results, and mark the cache invalid when the process
- * is resumed.
- */
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers.
+
+ ??? Is the following note still relevant? We can't get individual
+ registers with the PT_GETREGS ptrace(2) request either, yet we
+ don't bother with caching at all in that case.
+
+ NOTE: Since the /proc interface cannot give us individual
+ registers, we pay no attention to REGNUM, and just fetch them all.
+ This results in the possibility that we will do unnecessarily many
+ fetches, since we may be called repeatedly for individual
+ registers. So we cache the results, and mark the cache invalid
+ when the process is resumed. */
static void
-procfs_fetch_registers (int regno)
+procfs_fetch_registers (int regnum)
{
- gdb_fpregset_t *fpregs;
- gdb_gregset_t *gregs;
- procinfo *pi;
- int pid;
- int tid;
-
- pid = PIDGET (inferior_ptid);
- tid = TIDGET (inferior_ptid);
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid = PIDGET (inferior_ptid);
+ int tid = TIDGET (inferior_ptid);
- /* First look up procinfo for the main process. */
- pi = find_procinfo_or_die (pid, 0);
+ /* First look up procinfo for the main process. */
+ pi = find_procinfo_or_die (pid, 0);
- /* If the event thread is not the same as GDB's requested thread
- (ie. inferior_ptid), then look up procinfo for the requested
+ /* If the event thread is not the same as GDB's requested thread
+ (ie. inferior_ptid), then look up procinfo for the requested
thread. */
- if ((tid != 0) &&
- (tid != proc_get_current_thread (pi)))
+ if (tid != 0 && tid != proc_get_current_thread (pi))
pi = find_procinfo_or_die (pid, tid);
if (pi == NULL)
- error ("procfs: fetch_registers failed to find procinfo for %s",
+ error (_("procfs: fetch_registers failed to find procinfo for %s"),
target_pid_to_str (inferior_ptid));
- if ((gregs = proc_get_gregs (pi)) == NULL)
+ gregs = proc_get_gregs (pi);
+ if (gregs == NULL)
proc_error (pi, "fetch_registers, get_gregs", __LINE__);
supply_gregset (gregs);
- if (FP0_REGNUM >= 0) /* need floating point? */
+ if (FP0_REGNUM >= 0) /* Do we have an FPU? */
{
- if ((regno >= 0 && regno < FP0_REGNUM) ||
- regno == PC_REGNUM ||
- (NPC_REGNUM >= 0 && regno == NPC_REGNUM) ||
- regno == FP_REGNUM ||
- regno == SP_REGNUM)
- return; /* not a floating point register */
-
- if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ gdb_fpregset_t *fpregs;
+
+ if ((regnum >= 0 && regnum < FP0_REGNUM)
+ || regnum == PC_REGNUM
+ || regnum == SP_REGNUM)
+ return; /* Not a floating point register. */
+
+ fpregs = proc_get_fpregs (pi);
+ if (fpregs == NULL)
proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
supply_fpregset (fpregs);
#endif
}
-/*
- * store_registers
- *
- * Since the /proc interface will not read individual registers,
- * we will cache these requests until the process is resumed, and
- * only then write them back to the inferior process.
- *
- * FIXME: is that a really bad idea? Have to think about cases
- * where writing one register might affect the value of others, etc.
- */
+/* Store register REGNUM back into the inferior. If REGNUM is -1, do
+ this for all registers.
+
+ NOTE: Since the /proc interface will not read individual registers,
+ we will cache these requests until the process is resumed, and only
+ then write them back to the inferior process.
+
+ FIXME: is that a really bad idea? Have to think about cases where
+ writing one register might affect the value of others, etc. */
static void
-procfs_store_registers (int regno)
+procfs_store_registers (int regnum)
{
- gdb_fpregset_t *fpregs;
- gdb_gregset_t *gregs;
- procinfo *pi;
- int pid;
- int tid;
-
- pid = PIDGET (inferior_ptid);
- tid = TIDGET (inferior_ptid);
-
- /* First find procinfo for main process */
- pi = find_procinfo_or_die (pid, 0);
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid = PIDGET (inferior_ptid);
+ int tid = TIDGET (inferior_ptid);
- /* If current lwp for process is not the same as requested thread
- (ie. inferior_ptid), then find procinfo for the requested thread. */
+ /* First find procinfo for main process. */
+ pi = find_procinfo_or_die (pid, 0);
- if ((tid != 0) &&
- (tid != proc_get_current_thread (pi)))
+ /* If the event thread is not the same as GDB's requested thread
+ (ie. inferior_ptid), then look up procinfo for the requested
+ thread. */
+ if (tid != 0 && tid != proc_get_current_thread (pi))
pi = find_procinfo_or_die (pid, tid);
if (pi == NULL)
- error ("procfs: store_registers: failed to find procinfo for %s",
+ error (_("procfs: store_registers: failed to find procinfo for %s"),
target_pid_to_str (inferior_ptid));
- if ((gregs = proc_get_gregs (pi)) == NULL)
+ gregs = proc_get_gregs (pi);
+ if (gregs == NULL)
proc_error (pi, "store_registers, get_gregs", __LINE__);
- fill_gregset (gregs, regno);
+ fill_gregset (gregs, regnum);
if (!proc_set_gregs (pi))
proc_error (pi, "store_registers, set_gregs", __LINE__);
- if (FP0_REGNUM >= 0) /* need floating point? */
+ if (FP0_REGNUM >= 0) /* Do we have an FPU? */
{
- if ((regno >= 0 && regno < FP0_REGNUM) ||
- regno == PC_REGNUM ||
- (NPC_REGNUM >= 0 && regno == NPC_REGNUM) ||
- regno == FP_REGNUM ||
- regno == SP_REGNUM)
- return; /* not a floating point register */
-
- if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ gdb_fpregset_t *fpregs;
+
+ if ((regnum >= 0 && regnum < FP0_REGNUM)
+ || regnum == PC_REGNUM
+ || regnum == SP_REGNUM)
+ return; /* Not a floating point register. */
+
+ fpregs = proc_get_fpregs (pi);
+ if (fpregs == NULL)
proc_error (pi, "store_registers, get_fpregs", __LINE__);
- fill_fpregset (fpregs, regno);
+ fill_fpregset (fpregs, regnum);
if (!proc_set_fpregs (pi))
proc_error (pi, "store_registers, set_fpregs", __LINE__);
}
wait_retval = wait (&wstat); /* "wait" for the child's exit */
if (wait_retval != PIDGET (inferior_ptid)) /* wrong child? */
- error ("procfs: couldn't stop process %d: wait returned %d\n",
+ error (_("procfs: couldn't stop process %d: wait returned %d."),
PIDGET (inferior_ptid), wait_retval);
/* FIXME: might I not just use waitpid?
Or try find_procinfo to see if I know about this child? */
into a waitstatus for GDB.
If we actually had to call wait because the /proc file
- is gone (child terminated), then we skip this block,
+ is gone (child terminated), then we skip this block,
because we already have a waitstatus. */
flags = proc_flags (pi);
case PR_SYSENTRY:
if (syscall_is_lwp_exit (pi, what))
{
- printf_filtered ("[%s exited]\n",
+ printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
{
/* Handle SYS_exit call only */
/* Stopped at entry to SYS_exit.
- Make it runnable, resume it, then use
+ Make it runnable, resume it, then use
the wait system call to get its exit code.
- Proc_run_process always clears the current
+ Proc_run_process always clears the current
fault and signal.
Then return its exit status. */
pi->status_valid = 0;
wstat = 0;
- /* FIXME: what we should do is return
+ /* FIXME: what we should do is return
TARGET_WAITKIND_SPURIOUS. */
if (!proc_run_process (pi, 0, 0))
proc_error (pi, "target_wait, run_process", __LINE__);
if (attach_flag)
{
- /* Don't call wait: simulate waiting for exit,
+ /* Don't call wait: simulate waiting for exit,
return a "success" exit code. Bogus: what if
it returns something else? */
wstat = 0;
}
else
{
- printf_filtered ("procfs: trapped on entry to ");
+ printf_filtered (_("procfs: trapped on entry to "));
proc_prettyprint_syscall (proc_what (pi), 0);
printf_filtered ("\n");
#ifndef PIOCSSPCACT
if ((nsysargs = proc_nsysarg (pi)) > 0 &&
(sysargs = proc_sysargs (pi)) != NULL)
{
- printf_filtered ("%ld syscall arguments:\n", nsysargs);
+ printf_filtered (_("%ld syscall arguments:\n"), nsysargs);
for (i = 0; i < nsysargs; i++)
- printf_filtered ("#%ld: 0x%08lx\n",
+ printf_filtered ("#%ld: 0x%08lx\n",
i, sysargs[i]);
}
address. */
wstat = (SIGTRAP << 8) | 0177;
}
+#ifdef SYS_syssgi
+ else if (what == SYS_syssgi)
+ {
+ /* see if we can break on dbx_link(). If yes, then
+ we no longer need the SYS_syssgi notifications. */
+ if (insert_dbx_link_breakpoint (pi))
+ proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT,
+ FLAG_RESET, 0);
+
+ /* This is an internal event and should be transparent
+ to wfi, so resume the execution and wait again. See
+ comment in procfs_init_inferior() for more details. */
+ target_resume (ptid, 0, TARGET_SIGNAL_0);
+ goto wait_again;
+ }
+#endif
else if (syscall_is_lwp_create (pi, what))
{
/*
/* If not in GDB's thread list, add it. */
if (!in_thread_list (temp_ptid))
{
- printf_filtered ("[New %s]\n",
+ printf_filtered (_("[New %s]\n"),
target_pid_to_str (temp_ptid));
add_thread (temp_ptid);
}
}
else if (syscall_is_lwp_exit (pi, what))
{
- printf_filtered ("[%s exited]\n",
+ printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
SYS_fork, or SYS_vfork here? The old procfs
seemed to use this event to handle threads on
older (non-LWP) systems, where I'm assuming
- that threads were actually separate processes.
+ that threads were actually separate processes.
Irix, maybe? Anyway, low priority for now. */
}
else
{
- printf_filtered ("procfs: trapped on exit from ");
+ printf_filtered (_("procfs: trapped on exit from "));
proc_prettyprint_syscall (proc_what (pi), 0);
printf_filtered ("\n");
#ifndef PIOCSSPCACT
if ((nsysargs = proc_nsysarg (pi)) > 0 &&
(sysargs = proc_sysargs (pi)) != NULL)
{
- printf_filtered ("%ld syscall arguments:\n", nsysargs);
+ printf_filtered (_("%ld syscall arguments:\n"), nsysargs);
for (i = 0; i < nsysargs; i++)
- printf_filtered ("#%ld: 0x%08lx\n",
+ printf_filtered ("#%ld: 0x%08lx\n",
i, sysargs[i]);
}
}
#else
if (retry < 5)
{
- printf_filtered ("Retry #%d:\n", retry);
+ printf_filtered (_("Retry #%d:\n"), retry);
pi->status_valid = 0;
goto wait_again;
}
temp_ptid = MERGEPID (pi->pid, temp_tid);
if (!in_thread_list (temp_ptid))
{
- printf_filtered ("[New %s]\n",
+ printf_filtered (_("[New %s]\n"),
target_pid_to_str (temp_ptid));
add_thread (temp_ptid);
}
wstat = (what << 8) | 0177;
break;
case PR_FAULTED:
- switch (what) { /* FIXME: FAULTED_USE_SIGINFO */
+ switch (what) {
#ifdef FLTWATCH
case FLTWATCH:
wstat = (SIGTRAP << 8) | 0177;
#if (FLTTRACE != FLTBPT) /* avoid "duplicate case" error */
case FLTTRACE:
#endif
+ /* If we hit our __dbx_link() internal breakpoint,
+ then remove it. See comments in procfs_init_inferior()
+ for more details. */
+ if (dbx_link_bpt_addr != 0
+ && dbx_link_bpt_addr == read_pc ())
+ remove_dbx_link_breakpoint ();
+
wstat = (SIGTRAP << 8) | 0177;
break;
case FLTSTACK:
default: /* FIXME: use si_signo if possible for fault */
retval = pid_to_ptid (-1);
printf_filtered ("procfs:%d -- ", __LINE__);
- printf_filtered ("child stopped for unknown reason:\n");
+ printf_filtered (_("child stopped for unknown reason:\n"));
proc_prettyprint_why (why, what, 1);
- error ("... giving up...");
+ error (_("... giving up..."));
break;
}
break; /* case PR_FAULTED: */
default: /* switch (why) unmatched */
printf_filtered ("procfs:%d -- ", __LINE__);
- printf_filtered ("child stopped for unknown reason:\n");
+ printf_filtered (_("child stopped for unknown reason:\n"));
proc_prettyprint_why (why, what, 1);
- error ("... giving up...");
+ error (_("... giving up..."));
break;
}
/*
!in_thread_list (retval))
{
/*
- * We have a new thread.
+ * We have a new thread.
* We need to add it both to GDB's list and to our own.
- * If we don't create a procinfo, resume may be unhappy
+ * If we don't create a procinfo, resume may be unhappy
* later.
*/
- printf_filtered ("[New %s]\n", target_pid_to_str (retval));
+ printf_filtered (_("[New %s]\n"), target_pid_to_str (retval));
add_thread (retval);
if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL)
create_procinfo (PIDGET (retval), TIDGET (retval));
/* In addition, it's possible that this is the first
- * new thread we've seen, in which case we may not
+ * new thread we've seen, in which case we may not
* have created entries for inferior_ptid yet.
*/
if (TIDGET (inferior_ptid) != 0)
{
if (!in_thread_list (inferior_ptid))
add_thread (inferior_ptid);
- if (find_procinfo (PIDGET (inferior_ptid),
+ if (find_procinfo (PIDGET (inferior_ptid),
TIDGET (inferior_ptid)) == NULL)
- create_procinfo (PIDGET (inferior_ptid),
+ create_procinfo (PIDGET (inferior_ptid),
TIDGET (inferior_ptid));
}
}
printf_filtered ("procfs:%d -- process not stopped.\n",
__LINE__);
proc_prettyprint_flags (flags, 1);
- error ("procfs: ...giving up...");
+ error (_("procfs: ...giving up..."));
}
}
return retval;
}
-/* Transfer LEN bytes between GDB address MYADDR and target address
- MEMADDR. If DOWRITE is non-zero, transfer them to the target,
- otherwise transfer them from the target. TARGET is unused.
+/* Perform a partial transfer to/from the specified object. For
+ memory transfers, fall back to the old memory xfer functions. */
- The return value is 0 if an error occurred or no bytes were
- transferred. Otherwise, it will be a positive value which
- indicates the number of bytes transferred between gdb and the
- target. (Note that the interface also makes provisions for
+static LONGEST
+procfs_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return (*ops->deprecated_xfer_memory) (offset, readbuf, len,
+ 0/*write*/, NULL, ops);
+ if (writebuf)
+ return (*ops->deprecated_xfer_memory) (offset, writebuf, len,
+ 1/*write*/, NULL, ops);
+ return -1;
+
+#ifdef NEW_PROC_API
+ case TARGET_OBJECT_AUXV:
+ return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
+ offset, len);
+#endif
+
+ default:
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ return -1;
+ }
+}
+
+
+/* Transfer LEN bytes between GDB address MYADDR and target address
+ MEMADDR. If DOWRITE is non-zero, transfer them to the target,
+ otherwise transfer them from the target. TARGET is unused.
+
+ The return value is 0 if an error occurred or no bytes were
+ transferred. Otherwise, it will be a positive value which
+ indicates the number of bytes transferred between gdb and the
+ target. (Note that the interface also makes provisions for
negative values, but this capability isn't implemented here.) */
static int
* If there are "dirty" caches that need to be written back
* to the child process, do that.
*
- * File descriptors are also cached.
+ * File descriptors are also cached.
* As they are a limited resource, we cannot hold onto them indefinitely.
* However, as they are expensive to open, we don't want to throw them
* away indescriminately either. As a compromise, we will keep the
* descriptors we may have accumulated for the threads.
*
* Return value:
- * As this function is called by iterate_over_threads, it always
+ * As this function is called by iterate_over_threads, it always
* returns zero (so that iterate_over_threads will keep iterating).
*/
if (parent == NULL ||
proc_get_current_thread (parent) != pi->tid)
if (!proc_set_fpregs (pi)) /* flush fpregs cache */
- proc_warn (pi, "target_resume, set_fpregs",
+ proc_warn (pi, "target_resume, set_fpregs",
__LINE__);
#endif
if (parent != NULL)
{
/* The presence of a parent indicates that this is an LWP.
- Close any file descriptors that it might have open.
+ Close any file descriptors that it might have open.
We don't do this to the master (parent) procinfo. */
close_procinfo_files (pi);
* procfs_wait and wait for it to stop again (unles gdb is async).
*
* Arguments:
- * step: if true, then arrange for the child to stop again
+ * step: if true, then arrange for the child to stop again
* after executing a single instruction.
* signo: if zero, then cancel any pending signal.
- * If non-zero, then arrange for the indicated signal
+ * If non-zero, then arrange for the indicated signal
* to be delivered to the child when it runs.
* pid: if -1, then allow any child thread to run.
* if non-zero, then allow only the indicated thread to run.
procinfo *pi, *thread;
int native_signo;
- /* 2.1:
+ /* 2.1:
prrun.prflags |= PRSVADDR;
- prrun.pr_vaddr = $PC; set resume address
+ prrun.pr_vaddr = $PC; set resume address
prrun.prflags |= PRSTRACE; trace signals in pr_trace (all)
- prrun.prflags |= PRSFAULT; trace faults in pr_fault (all but PAGE)
+ prrun.prflags |= PRSFAULT; trace faults in pr_fault (all but PAGE)
prrun.prflags |= PRCFAULT; clear current fault.
PRSTRACE and PRSFAULT can be done by other means
/* Running the process voids all cached registers and status. */
/* Void the threads' caches first */
- proc_iterate_over_threads (pi, invalidate_cache, NULL);
+ proc_iterate_over_threads (pi, invalidate_cache, NULL);
/* Void the process procinfo's caches. */
invalidate_cache (NULL, pi, NULL);
{
/* Resume a specific thread, presumably suppressing the others. */
thread = find_procinfo (PIDGET (ptid), TIDGET (ptid));
- if (thread == NULL)
- warning ("procfs: resume can't find thread %ld -- resuming all.",
- TIDGET (ptid));
- else
+ if (thread != NULL)
{
if (thread->tid != 0)
{
proc_error (pi, "target_resume, set_async", __LINE__);
#endif
#if 0
- proc_iterate_over_threads (pi,
+ proc_iterate_over_threads (pi,
make_signal_thread_runnable,
NULL);
#endif
if (!proc_run_process (pi, step, native_signo))
{
if (errno == EBUSY)
- warning ("resume: target already running. Pretend to resume, and hope for the best!\n");
+ warning (_("resume: target already running. Pretend to resume, and hope for the best!"));
else
proc_error (pi, "target_resume", __LINE__);
}
/*
* Function: register_gdb_signals
*
- * Traverse the list of signals that GDB knows about
+ * Traverse the list of signals that GDB knows about
* (see "handle" command), and arrange for the target
* to be stopped or not, according to these settings.
*
static void
procfs_files_info (struct target_ops *ignore)
{
- printf_filtered ("\tUsing the running image of %s %s via /proc.\n",
- attach_flag? "attached": "child",
+ printf_filtered (_("\tUsing the running image of %s %s via /proc.\n"),
+ attach_flag? "attached": "child",
target_pid_to_str (inferior_ptid));
}
static void
procfs_open (char *args, int from_tty)
{
- error ("Use the \"run\" command to start a Unix child process.");
+ error (_("Use the \"run\" command to start a Unix child process."));
}
/*
* Function: target_can_run
*
- * This tells GDB that this target vector can be invoked
+ * This tells GDB that this target vector can be invoked
* for "run" or "attach".
*/
may layer their own process structure atop that provided here.
sol-thread.c does this because of the Solaris two-level thread
model. */
-
+
/* NOTE: possibly obsolete -- use the thread_stratum approach instead. */
return !procfs_suppress_run;
static void
procfs_stop (void)
{
- extern pid_t inferior_process_group;
-
kill (-inferior_process_group, SIGINT);
}
* Function: unconditionally_kill_inferior
*
* Make it die. Wait for it to die. Clean up after it.
- * Note: this should only be applied to the real process,
+ * Note: this should only be applied to the real process,
* not to an LWP, because of the check for parent-process.
* If we need this to work for an LWP, it needs some more logic.
*/
/* If pi is GDB's child, wait for it to die. */
if (parent_pid == getpid ())
- /* FIXME: should we use waitpid to make sure we get the right event?
+ /* FIXME: should we use waitpid to make sure we get the right event?
Should we check the returned event? */
{
#if 0
* Then we want GDB to forget all about it.
*/
-static void
+static void
procfs_kill_inferior (void)
{
if (!ptid_equal (inferior_ptid, null_ptid)) /* ? */
* Forget we ever debugged this thing!
*/
-static void
+static void
procfs_mourn_inferior (void)
{
procinfo *pi;
destroy_procinfo (pi);
}
unpush_target (&procfs_ops);
+
+ if (dbx_link_bpt != NULL)
+ {
+ deprecated_remove_raw_breakpoint (dbx_link_bpt);
+ dbx_link_bpt_addr = 0;
+ dbx_link_bpt = NULL;
+ }
+
generic_mourn_inferior ();
}
/*
* Function: init_inferior
*
- * When GDB forks to create a runnable inferior process,
+ * When GDB forks to create a runnable inferior process,
* this function is called on the parent side of the fork.
* It's job is to do whatever is necessary to make the child
* ready to be debugged, and then wait for the child to synchronize.
*/
-static void
+static void
procfs_init_inferior (int pid)
{
procinfo *pi;
the actual process ID plus the lwp ID. */
inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi));
-#ifdef START_INFERIOR_TRAPS_EXPECTED
+ /* Typically two, one trap to exec the shell, one to exec the
+ program being debugged. Defined by "inferior.h". */
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_INFERIOR_TRAPS_EXPECTED */
+
+#ifdef SYS_syssgi
+ /* On mips-irix, we need to stop the inferior early enough during
+ the startup phase in order to be able to load the shared library
+ symbols and insert the breakpoints that are located in these shared
+ libraries. Stopping at the program entry point is not good enough
+ because the -init code is executed before the execution reaches
+ that point.
+
+ So what we need to do is to insert a breakpoint in the runtime
+ loader (rld), more precisely in __dbx_link(). This procedure is
+ called by rld once all shared libraries have been mapped, but before
+ the -init code is executed. Unfortuantely, this is not straightforward,
+ as rld is not part of the executable we are running, and thus we need
+ the inferior to run until rld itself has been mapped in memory.
+
+ For this, we trace all syssgi() syscall exit events. Each time
+ we detect such an event, we iterate over each text memory maps,
+ get its associated fd, and scan the symbol table for __dbx_link().
+ When found, we know that rld has been mapped, and that we can insert
+ the breakpoint at the symbol address. Once the dbx_link() breakpoint
+ has been inserted, the syssgi() notifications are no longer necessary,
+ so they should be canceled. */
+ proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT, FLAG_SET, 0);
+#endif
}
/*
sysset_t *exitset;
if ((pi = create_procinfo (getpid (), 0)) == NULL)
- perror_with_name ("procfs: create_procinfo failed in child.");
+ perror_with_name (_("procfs: create_procinfo failed in child."));
if (open_procinfo_files (pi, FD_CTL) == 0)
{
if (!proc_unset_run_on_last_close (pi))
proc_warn (pi, "set_exec_trap, unset_RLC", __LINE__);
- /* FIXME: No need to destroy the procinfo --
+ /* FIXME: No need to destroy the procinfo --
we have our own address space, and we're about to do an exec! */
/*destroy_procinfo (pi);*/
}
* Function: create_inferior
*
* This function is called BEFORE gdb forks the inferior process.
- * Its only real responsibility is to set things up for the fork,
+ * Its only real responsibility is to set things up for the fork,
* and tell GDB which two functions to call after the fork (one
* for the parent, and one for the child).
- *
+ *
* This function does a complicated search for a unix shell program,
* which it then uses to parse arguments and environment variables
* to be sent to the child. I wonder whether this code could not
*/
static void
-procfs_create_inferior (char *exec_file, char *allargs, char **env)
+procfs_create_inferior (char *exec_file, char *allargs, char **env,
+ int from_tty)
{
char *shell_file = getenv ("SHELL");
char *tryname;
/* 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 ("procfs:%d -- Can't find shell %s in PATH",
+ error (_("procfs:%d -- Can't find shell %s in PATH"),
__LINE__, shell_file);
shell_file = tryname;
}
- fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
+ fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
procfs_init_inferior, NULL, shell_file);
- /* We are at the first instruction we care about. */
- /* Pedal to the metal... */
-
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+#ifdef SYS_syssgi
+ /* Make sure to cancel the syssgi() syscall-exit notifications.
+ They should normally have been removed by now, but they may still
+ be activated if the inferior doesn't use shared libraries, or if
+ we didn't locate __dbx_link, or if we never stopped in __dbx_link.
+ See procfs_init_inferior() for more details. */
+ proc_trace_syscalls_1 (find_procinfo_or_die (PIDGET (inferior_ptid), 0),
+ SYS_syssgi, PR_SYSEXIT, FLAG_RESET, 0);
+#endif
}
/*
/*
* Function: target_find_new_threads
*
- * Query all the threads that the target knows about,
+ * Query all the threads that the target knows about,
* and give them back to GDB to add to its list.
*/
proc_iterate_over_threads (pi, procfs_notice_thread, NULL);
}
-/*
+/*
* Function: target_thread_alive
*
* Return true if the thread is still 'alive'.
return 1;
}
-/*
- * Function: target_pid_to_str
- *
- * Return a string to be used to identify the thread in
- * the "info threads" display.
- */
+/* Convert PTID to a string. Returns the string in a static buffer. */
char *
procfs_pid_to_str (ptid_t ptid)
{
static char buf[80];
- int proc, thread;
- procinfo *pi;
-
- proc = PIDGET (ptid);
- thread = TIDGET (ptid);
- pi = find_procinfo (proc, thread);
- if (thread == 0)
- sprintf (buf, "Process %d", proc);
+ if (TIDGET (ptid) == 0)
+ sprintf (buf, "process %d", PIDGET (ptid));
else
- sprintf (buf, "LWP %d", thread);
- return &buf[0];
+ sprintf (buf, "LWP %ld", TIDGET (ptid));
+
+ return buf;
}
/*
* Insert a watchpoint
*/
-int
+int
procfs_set_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rwflag,
int after)
{
#ifndef UNIXWARE
#ifndef AIX5
int pflags = 0;
- procinfo *pi;
+ procinfo *pi;
- pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
+ pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
PIDGET (inferior_ptid) : PIDGET (ptid), 0);
/* Translate from GDB's flags to /proc's */
return 0;
}
+/* Return non-zero if we can set a hardware watchpoint of type TYPE. TYPE
+ is one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint,
+ or bp_hardware_watchpoint. CNT is the number of watchpoints used so
+ far.
+
+ Note: procfs_can_use_hw_breakpoint() is not yet used by all
+ procfs.c targets due to the fact that some of them still define
+ TARGET_CAN_USE_HARDWARE_WATCHPOINT. */
+
+static int
+procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
+ return 0;
+#else
+ /* Due to the way that proc_set_watchpoint() is implemented, host
+ and target pointers must be of the same size. If they are not,
+ we can't use hardware watchpoints. This limitation is due to the
+ fact that proc_set_watchpoint() calls
+ procfs_address_to_host_pointer(); a close inspection of
+ procfs_address_to_host_pointer will reveal that an internal error
+ will be generated when the host and target pointer sizes are
+ different. */
+ if (sizeof (void *) != TYPE_LENGTH (builtin_type_void_data_ptr))
+ return 0;
+
+ /* Other tests here??? */
+
+ return 1;
+#endif
+}
+
/*
* Function: stopped_by_watchpoint
*
{
procinfo *pi;
- pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
+ pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
PIDGET (inferior_ptid) : PIDGET (ptid), 0);
if (!pi) /* If no process, then not stopped by watchpoint! */
if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
{
if (proc_why (pi) == PR_FAULTED)
- {
+ {
#ifdef FLTWATCH
if (proc_what (pi) == FLTWATCH)
return 1;
#ifdef TM_I386SOL2_H
/*
- * Function: procfs_find_LDT_entry
+ * Function: procfs_find_LDT_entry
*
* Input:
* ptid_t ptid; // The GDB-style pid-plus-LWP.
/* Find procinfo for the lwp. */
if ((pi = find_procinfo (PIDGET (ptid), TIDGET (ptid))) == NULL)
{
- warning ("procfs_find_LDT_entry: could not find procinfo for %d:%d.",
+ warning (_("procfs_find_LDT_entry: could not find procinfo for %d:%d."),
PIDGET (ptid), TIDGET (ptid));
return NULL;
}
/* get its general registers. */
if ((gregs = proc_get_gregs (pi)) == NULL)
{
- warning ("procfs_find_LDT_entry: could not read gregs for %d:%d.",
+ warning (_("procfs_find_LDT_entry: could not read gregs for %d:%d."),
PIDGET (ptid), TIDGET (ptid));
return NULL;
}
}
#endif /* TM_I386SOL2_H */
+/*
+ * Memory Mappings Functions:
+ */
+
+/*
+ * Function: iterate_over_mappings
+ *
+ * Call a callback function once for each mapping, passing it the mapping,
+ * an optional secondary callback function, and some optional opaque data.
+ * Quit and return the first non-zero value returned from the callback.
+ *
+ * Arguments:
+ * pi -- procinfo struct for the process to be mapped.
+ * func -- callback function to be called by this iterator.
+ * data -- optional opaque data to be passed to the callback function.
+ * child_func -- optional secondary function pointer to be passed
+ * to the child function.
+ *
+ * Return: First non-zero return value from the callback function,
+ * or zero.
+ */
+
+static int
+iterate_over_mappings (procinfo *pi, int (*child_func) (), void *data,
+ int (*func) (struct prmap *map,
+ int (*child_func) (),
+ void *data))
+{
+ char pathname[MAX_PROC_NAME_SIZE];
+ struct prmap *prmaps;
+ struct prmap *prmap;
+ int funcstat;
+ int map_fd;
+ int nmap;
+#ifdef NEW_PROC_API
+ struct stat sbuf;
+#endif
+ /* Get the number of mappings, allocate space,
+ and read the mappings into prmaps. */
+#ifdef NEW_PROC_API
+ /* Open map fd. */
+ sprintf (pathname, "/proc/%d/map", pi->pid);
+ if ((map_fd = open (pathname, O_RDONLY)) < 0)
+ proc_error (pi, "iterate_over_mappings (open)", __LINE__);
+
+ /* Make sure it gets closed again. */
+ make_cleanup_close (map_fd);
+
+ /* Use stat to determine the file size, and compute
+ the number of prmap_t objects it contains. */
+ if (fstat (map_fd, &sbuf) != 0)
+ proc_error (pi, "iterate_over_mappings (fstat)", __LINE__);
+
+ nmap = sbuf.st_size / sizeof (prmap_t);
+ prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+ if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps))
+ != (nmap * sizeof (*prmaps)))
+ proc_error (pi, "iterate_over_mappings (read)", __LINE__);
+#else
+ /* Use ioctl command PIOCNMAP to get number of mappings. */
+ if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0)
+ proc_error (pi, "iterate_over_mappings (PIOCNMAP)", __LINE__);
+
+ prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
+ if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0)
+ proc_error (pi, "iterate_over_mappings (PIOCMAP)", __LINE__);
+#endif
+
+ for (prmap = prmaps; nmap > 0; prmap++, nmap--)
+ if ((funcstat = (*func) (prmap, child_func, data)) != 0)
+ return funcstat;
+
+ return 0;
+}
+
+/*
+ * Function: solib_mappings_callback
+ *
+ * Calls the supplied callback function once for each mapped address
+ * space in the process. The callback function receives an open
+ * file descriptor for the file corresponding to that mapped
+ * address space (if there is one), and the base address of the
+ * mapped space. Quit when the callback function returns a
+ * nonzero value, or at teh end of the mappings.
+ *
+ * Returns: the first non-zero return value of the callback function,
+ * or zero.
+ */
+
+int solib_mappings_callback (struct prmap *map,
+ int (*func) (int, CORE_ADDR),
+ void *data)
+{
+ procinfo *pi = data;
+ int fd;
+
+#ifdef NEW_PROC_API
+ char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
+
+ if (map->pr_vaddr == 0 && map->pr_size == 0)
+ return -1; /* sanity */
+
+ if (map->pr_mapname[0] == 0)
+ {
+ fd = -1; /* no map file */
+ }
+ else
+ {
+ sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
+ /* Note: caller's responsibility to close this fd! */
+ fd = open_with_retry (name, O_RDONLY);
+ /* Note: we don't test the above call for failure;
+ we just pass the FD on as given. Sometimes there is
+ no file, so the open may return failure, but that's
+ not a problem. */
+ }
+#else
+ fd = ioctl (pi->ctl_fd, PIOCOPENM, &map->pr_vaddr);
+ /* Note: we don't test the above call for failure;
+ we just pass the FD on as given. Sometimes there is
+ no file, so the ioctl may return failure, but that's
+ not a problem. */
+#endif
+ return (*func) (fd, (CORE_ADDR) map->pr_vaddr);
+}
+
+/*
+ * Function: proc_iterate_over_mappings
+ *
+ * Uses the unified "iterate_over_mappings" function
+ * to implement the exported interface to solib-svr4.c.
+ *
+ * Given a pointer to a function, call that function once for every
+ * mapped address space in the process. The callback function
+ * receives an open file descriptor for the file corresponding to
+ * that mapped address space (if there is one), and the base address
+ * of the mapped space. Quit when the callback function returns a
+ * nonzero value, or at teh end of the mappings.
+ *
+ * Returns: the first non-zero return value of the callback function,
+ * or zero.
+ */
+
+int
+proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
+{
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+ return iterate_over_mappings (pi, func, pi, solib_mappings_callback);
+}
+
+/*
+ * Function: find_memory_regions_callback
+ *
+ * Implements the to_find_memory_regions method.
+ * Calls an external function for each memory region.
+ * External function will have the signiture:
+ *
+ * int callback (CORE_ADDR vaddr,
+ * unsigned long size,
+ * int read, int write, int execute,
+ * void *data);
+ *
+ * Returns the integer value returned by the callback.
+ */
+
+static int
+find_memory_regions_callback (struct prmap *map,
+ int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ return (*func) ((CORE_ADDR) map->pr_vaddr,
+ map->pr_size,
+ (map->pr_mflags & MA_READ) != 0,
+ (map->pr_mflags & MA_WRITE) != 0,
+ (map->pr_mflags & MA_EXEC) != 0,
+ data);
+}
+
+/*
+ * Function: proc_find_memory_regions
+ *
+ * External interface. Calls a callback function once for each
+ * mapped memory region in the child process, passing as arguments
+ * CORE_ADDR virtual_address,
+ * unsigned long size,
+ * int read, TRUE if region is readable by the child
+ * int write, TRUE if region is writable by the child
+ * int execute TRUE if region is executable by the child.
+ *
+ * Stops iterating and returns the first non-zero value
+ * returned by the callback.
+ */
+
+static int
+proc_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+
+ return iterate_over_mappings (pi, func, data,
+ find_memory_regions_callback);
+}
+
+/* Remove the breakpoint that we inserted in __dbx_link().
+ Does nothing if the breakpoint hasn't been inserted or has already
+ been removed. */
+
+static void
+remove_dbx_link_breakpoint (void)
+{
+ if (dbx_link_bpt_addr == 0)
+ return;
+
+ if (deprecated_remove_raw_breakpoint (dbx_link_bpt) != 0)
+ warning (_("Unable to remove __dbx_link breakpoint."));
+
+ dbx_link_bpt_addr = 0;
+ dbx_link_bpt = NULL;
+}
+
+/* Return the address of the __dbx_link() function in the file
+ refernced by ABFD by scanning its symbol table. Return 0 if
+ the symbol was not found. */
+
+static CORE_ADDR
+dbx_link_addr (bfd *abfd)
+{
+ long storage_needed;
+ asymbol **symbol_table;
+ long number_of_symbols;
+ long i;
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+ if (storage_needed <= 0)
+ return 0;
+
+ symbol_table = (asymbol **) xmalloc (storage_needed);
+ make_cleanup (xfree, symbol_table);
+
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ asymbol *sym = symbol_table[i];
+
+ if ((sym->flags & BSF_GLOBAL)
+ && sym->name != NULL && strcmp (sym->name, "__dbx_link") == 0)
+ return (sym->value + sym->section->vma);
+ }
+
+ /* Symbol not found, return NULL. */
+ return 0;
+}
+
+/* Search the symbol table of the file referenced by FD for a symbol
+ named __dbx_link(). If found, then insert a breakpoint at this location,
+ and return nonzero. Return zero otherwise. */
+
+static int
+insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored)
+{
+ bfd *abfd;
+ long storage_needed;
+ CORE_ADDR sym_addr;
+
+ abfd = bfd_fdopenr ("unamed", 0, fd);
+ if (abfd == NULL)
+ {
+ warning (_("Failed to create a bfd: %s."), bfd_errmsg (bfd_get_error ()));
+ return 0;
+ }
+
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ /* Not the correct format, so we can not possibly find the dbx_link
+ symbol in it. */
+ bfd_close (abfd);
+ return 0;
+ }
+
+ sym_addr = dbx_link_addr (abfd);
+ if (sym_addr != 0)
+ {
+ /* Insert the breakpoint. */
+ dbx_link_bpt_addr = sym_addr;
+ dbx_link_bpt = deprecated_insert_raw_breakpoint (sym_addr);
+ if (dbx_link_bpt == NULL)
+ {
+ warning (_("Failed to insert dbx_link breakpoint."));
+ bfd_close (abfd);
+ return 0;
+ }
+ bfd_close (abfd);
+ return 1;
+ }
+
+ bfd_close (abfd);
+ return 0;
+}
+
+/* If the given memory region MAP contains a symbol named __dbx_link,
+ insert a breakpoint at this location and return nonzero. Return
+ zero otherwise. */
+
+static int
+insert_dbx_link_bpt_in_region (struct prmap *map,
+ int (*child_func) (),
+ void *data)
+{
+ procinfo *pi = (procinfo *) data;
+
+ /* We know the symbol we're looking for is in a text region, so
+ only look for it if the region is a text one. */
+ if (map->pr_mflags & MA_EXEC)
+ return solib_mappings_callback (map, insert_dbx_link_bpt_in_file, pi);
+
+ return 0;
+}
+
+/* Search all memory regions for a symbol named __dbx_link. If found,
+ insert a breakpoint at its location, and return nonzero. Return zero
+ otherwise. */
+
+static int
+insert_dbx_link_breakpoint (procinfo *pi)
+{
+ return iterate_over_mappings (pi, NULL, pi, insert_dbx_link_bpt_in_region);
+}
+
+/*
+ * Function: mappingflags
+ *
+ * Returns an ascii representation of a memory mapping's flags.
+ */
+
+static char *
+mappingflags (long flags)
+{
+ static char asciiflags[8];
+
+ strcpy (asciiflags, "-------");
+#if defined (MA_PHYS)
+ if (flags & MA_PHYS)
+ asciiflags[0] = 'd';
+#endif
+ if (flags & MA_STACK)
+ asciiflags[1] = 's';
+ if (flags & MA_BREAK)
+ asciiflags[2] = 'b';
+ if (flags & MA_SHARED)
+ asciiflags[3] = 's';
+ if (flags & MA_READ)
+ asciiflags[4] = 'r';
+ if (flags & MA_WRITE)
+ asciiflags[5] = 'w';
+ if (flags & MA_EXEC)
+ asciiflags[6] = 'x';
+ return (asciiflags);
+}
+
+/*
+ * Function: info_mappings_callback
+ *
+ * Callback function, does the actual work for 'info proc mappings'.
+ */
+
+static int
+info_mappings_callback (struct prmap *map, int (*ignore) (), void *unused)
+{
+ char *data_fmt_string;
+
+ if (TARGET_ADDR_BIT == 32)
+ data_fmt_string = "\t%#10lx %#10lx %#10x %#10x %7s\n";
+ else
+ data_fmt_string = " %#18lx %#18lx %#10x %#10x %7s\n";
+
+ printf_filtered (data_fmt_string,
+ (unsigned long) map->pr_vaddr,
+ (unsigned long) map->pr_vaddr + map->pr_size - 1,
+ map->pr_size,
+#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */
+ (unsigned int) map->pr_offset,
+#else
+ map->pr_off,
+#endif
+ mappingflags (map->pr_mflags));
+
+ return 0;
+}
+
+/*
+ * Function: info_proc_mappings
+ *
+ * Implement the "info proc mappings" subcommand.
+ */
+
+static void
+info_proc_mappings (procinfo *pi, int summary)
+{
+ char *header_fmt_string;
+
+ if (TARGET_PTR_BIT == 32)
+ header_fmt_string = "\t%10s %10s %10s %10s %7s\n";
+ else
+ header_fmt_string = " %18s %18s %10s %10s %7s\n";
+
+ if (summary)
+ return; /* No output for summary mode. */
+
+ printf_filtered (_("Mapped address spaces:\n\n"));
+ printf_filtered (header_fmt_string,
+ "Start Addr",
+ " End Addr",
+ " Size",
+ " Offset",
+ "Flags");
+
+ iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
+ printf_filtered ("\n");
+}
+
+/*
+ * Function: info_proc_cmd
+ *
+ * Implement the "info proc" command.
+ */
static void
info_proc_cmd (char *args, int from_tty)
{
struct cleanup *old_chain;
- procinfo *process = NULL;
- procinfo *thread = NULL;
- char **argv = NULL;
- char *tmp = NULL;
- int pid = 0;
- int tid = 0;
+ procinfo *process = NULL;
+ procinfo *thread = NULL;
+ char **argv = NULL;
+ char *tmp = NULL;
+ int pid = 0;
+ int tid = 0;
+ int mappings = 0;
old_chain = make_cleanup (null_cleanup, 0);
if (args)
{
tid = strtoul (argv[0] + 1, NULL, 10);
}
+ else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+ {
+ mappings = 1;
+ }
else
{
/* [...] */
if (pid == 0)
pid = PIDGET (inferior_ptid);
if (pid == 0)
- error ("No current process: you must name one.");
+ error (_("No current process: you must name one."));
else
{
/* Have pid, will travel.
process = find_procinfo (pid, 0);
if (process == NULL)
{
- /* No. So open a procinfo for it, but
+ /* No. So open a procinfo for it, but
remember to close it again when finished. */
process = create_procinfo (pid, 0);
make_cleanup (do_destroy_procinfo_cleanup, process);
if (process)
{
- printf_filtered ("process %d flags:\n", process->pid);
+ printf_filtered (_("process %d flags:\n"), process->pid);
proc_prettyprint_flags (proc_flags (process), 1);
if (proc_flags (process) & (PR_STOPPED | PR_ISTOP))
proc_prettyprint_why (proc_why (process), proc_what (process), 1);
if (proc_get_nthreads (process) > 1)
- printf_filtered ("Process has %d threads.\n",
+ printf_filtered ("Process has %d threads.\n",
proc_get_nthreads (process));
}
if (thread)
{
- printf_filtered ("thread %d flags:\n", thread->tid);
+ printf_filtered (_("thread %d flags:\n"), thread->tid);
proc_prettyprint_flags (proc_flags (thread), 1);
if (proc_flags (thread) & (PR_STOPPED | PR_ISTOP))
proc_prettyprint_why (proc_why (thread), proc_what (thread), 1);
}
+ if (mappings)
+ {
+ info_proc_mappings (process, 0);
+ }
+
do_cleanups (old_chain);
}
+/* Modify the status of the system call identified by SYSCALLNUM in
+ the set of syscalls that are currently traced/debugged.
+
+ If ENTRY_OR_EXIT is set to PR_SYSENTRY, then the entry syscalls set
+ will be updated. Otherwise, the exit syscalls set will be updated.
+
+ If MODE is FLAG_SET, then traces will be enabled. Otherwise, they
+ will be disabled. */
+
+static void
+proc_trace_syscalls_1 (procinfo *pi, int syscallnum, int entry_or_exit,
+ int mode, int from_tty)
+{
+ sysset_t *sysset;
+
+ if (entry_or_exit == PR_SYSENTRY)
+ sysset = proc_get_traced_sysentry (pi, NULL);
+ else
+ sysset = proc_get_traced_sysexit (pi, NULL);
+
+ if (sysset == NULL)
+ proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
+
+ if (mode == FLAG_SET)
+ gdb_praddsysset (sysset, syscallnum);
+ else
+ gdb_prdelsysset (sysset, syscallnum);
+
+ if (entry_or_exit == PR_SYSENTRY)
+ {
+ if (!proc_set_traced_sysentry (pi, sysset))
+ proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
+ }
+ else
+ {
+ if (!proc_set_traced_sysexit (pi, sysset))
+ proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
+ }
+}
+
static void
proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode)
{
procinfo *pi;
- sysset_t *sysset;
- int syscallnum = 0;
if (PIDGET (inferior_ptid) <= 0)
- error ("you must be debugging a process to use this command.");
+ error (_("you must be debugging a process to use this command."));
if (args == NULL || args[0] == 0)
- error_no_arg ("system call to trace");
+ error_no_arg (_("system call to trace"));
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
if (isdigit (args[0]))
{
- syscallnum = atoi (args);
- if (entry_or_exit == PR_SYSENTRY)
- sysset = proc_get_traced_sysentry (pi, NULL);
- else
- sysset = proc_get_traced_sysexit (pi, NULL);
-
- if (sysset == NULL)
- proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
-
- if (mode == FLAG_SET)
- gdb_praddsysset (sysset, syscallnum);
- else
- gdb_prdelsysset (sysset, syscallnum);
+ const int syscallnum = atoi (args);
- if (entry_or_exit == PR_SYSENTRY)
- {
- if (!proc_set_traced_sysentry (pi, sysset))
- proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
- }
- else
- {
- if (!proc_set_traced_sysexit (pi, sysset))
- proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
- }
+ proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty);
}
}
-static void
+static void
proc_trace_sysentry_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_SET);
}
-static void
+static void
proc_trace_sysexit_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_SET);
}
-static void
+static void
proc_untrace_sysentry_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_RESET);
}
-static void
+static void
proc_untrace_sysexit_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_RESET);
{
init_procfs_ops ();
add_target (&procfs_ops);
- add_info ("proc", info_proc_cmd,
- "Show /proc process information about any running process.\
-Default is the process being debugged.");
- add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd,
- "Give a trace of entries into the syscall.");
- add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd,
- "Give a trace of exits from the syscall.");
- add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd,
- "Cancel a trace of entries into the syscall.");
- add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd,
- "Cancel a trace of exits from the syscall.");
+ add_info ("proc", info_proc_cmd, _("\
+Show /proc process information about any running process.\n\
+Specify process id, or use the program being debugged by default.\n\
+Specify keyword 'mappings' for detailed info on memory mappings."));
+ add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd,
+ _("Give a trace of entries into the syscall."));
+ add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd,
+ _("Give a trace of exits from the syscall."));
+ add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd,
+ _("Cancel a trace of entries into the syscall."));
+ add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd,
+ _("Cancel a trace of exits from the syscall."));
}
/* =================== END, GDB "MODULE" =================== */
-/* miscelaneous stubs: */
+/* miscellaneous stubs: */
/* The following satisfy a few random symbols mostly created by */
/* the solaris threads implementation, which I will chase down */
/* later. */
{
return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
}
+
+/* =================== GCORE .NOTE "MODULE" =================== */
+#if defined (UNIXWARE) || defined (PIOCOPENLWP) || defined (PCAGENT)
+/* gcore only implemented on solaris and unixware (so far) */
+
+static char *
+procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
+ char *note_data, int *note_size)
+{
+ gdb_gregset_t gregs;
+ gdb_fpregset_t fpregs;
+ unsigned long merged_pid;
+
+ merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
+
+ fill_gregset (&gregs, -1);
+#if defined (UNIXWARE)
+ note_data = (char *) elfcore_write_lwpstatus (obfd,
+ note_data,
+ note_size,
+ merged_pid,
+ stop_signal,
+ &gregs);
+#else
+ note_data = (char *) elfcore_write_prstatus (obfd,
+ note_data,
+ note_size,
+ merged_pid,
+ stop_signal,
+ &gregs);
+#endif
+ fill_fpregset (&fpregs, -1);
+ note_data = (char *) elfcore_write_prfpreg (obfd,
+ note_data,
+ note_size,
+ &fpregs,
+ sizeof (fpregs));
+ return note_data;
+}
+
+struct procfs_corefile_thread_data {
+ bfd *obfd;
+ char *note_data;
+ int *note_size;
+};
+
+static int
+procfs_corefile_thread_callback (procinfo *pi, procinfo *thread, void *data)
+{
+ struct procfs_corefile_thread_data *args = data;
+
+ if (pi != NULL && thread->tid != 0)
+ {
+ ptid_t saved_ptid = inferior_ptid;
+ inferior_ptid = MERGEPID (pi->pid, thread->tid);
+ args->note_data = procfs_do_thread_registers (args->obfd, inferior_ptid,
+ args->note_data,
+ args->note_size);
+ inferior_ptid = saved_ptid;
+ }
+ return 0;
+}
+
+static char *
+procfs_make_note_section (bfd *obfd, int *note_size)
+{
+ struct cleanup *old_chain;
+ gdb_gregset_t gregs;
+ gdb_fpregset_t fpregs;
+ char fname[16] = {'\0'};
+ char psargs[80] = {'\0'};
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ char *note_data = NULL;
+ char *inf_args;
+ struct procfs_corefile_thread_data thread_args;
+ char *auxv;
+ int auxv_len;
+
+ if (get_exec_file (0))
+ {
+ strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+ strncpy (psargs, get_exec_file (0),
+ sizeof (psargs));
+
+ inf_args = get_inferior_args ();
+ if (inf_args && *inf_args &&
+ strlen (inf_args) < ((int) sizeof (psargs) - (int) strlen (psargs)))
+ {
+ strncat (psargs, " ",
+ sizeof (psargs) - strlen (psargs));
+ strncat (psargs, inf_args,
+ sizeof (psargs) - strlen (psargs));
+ }
+ }
+
+ note_data = (char *) elfcore_write_prpsinfo (obfd,
+ note_data,
+ note_size,
+ fname,
+ psargs);
+
+#ifdef UNIXWARE
+ fill_gregset (&gregs, -1);
+ note_data = elfcore_write_pstatus (obfd, note_data, note_size,
+ PIDGET (inferior_ptid),
+ stop_signal, &gregs);
+#endif
+
+ thread_args.obfd = obfd;
+ thread_args.note_data = note_data;
+ thread_args.note_size = note_size;
+ proc_iterate_over_threads (pi, procfs_corefile_thread_callback, &thread_args);
+
+ if (thread_args.note_data == note_data)
+ {
+ /* iterate_over_threads didn't come up with any threads;
+ just use inferior_ptid. */
+ note_data = procfs_do_thread_registers (obfd, inferior_ptid,
+ note_data, note_size);
+ }
+ else
+ {
+ note_data = thread_args.note_data;
+ }
+
+ auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV,
+ NULL, &auxv);
+ if (auxv_len > 0)
+ {
+ note_data = elfcore_write_note (obfd, note_data, note_size,
+ "CORE", NT_AUXV, auxv, auxv_len);
+ xfree (auxv);
+ }
+
+ make_cleanup (xfree, note_data);
+ return note_data;
+}
+#else /* !(Solaris or Unixware) */
+static char *
+procfs_make_note_section (bfd *obfd, int *note_size)
+{
+ error (_("gcore not implemented for this host."));
+ return NULL; /* lint */
+}
+#endif /* Solaris or Unixware */
+/* =================== END GCORE .NOTE "MODULE" =================== */