/* Machine independent support for SVR4 /proc (process file system) for GDB.
- Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
- Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2006, 2007, 2008
+ Free Software Foundation, Inc.
Written by Michael Snyder at Cygnus Solutions.
Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
-This file is part of GDB.
+ This file is part of GDB.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "inferior.h"
#include "elf-bfd.h" /* for elfcore_write_* */
#include "gdbcmd.h"
#include "gdbthread.h"
+#include "regcache.h"
#if defined (NEW_PROC_API)
#define _STRUCTURED_PROC 1 /* Should be done by configure script. */
*/
static void procfs_open (char *, int);
-static void procfs_attach (char *, int);
-static void procfs_detach (char *, int);
+static void procfs_attach (struct target_ops *, char *, int);
+static void procfs_detach (struct target_ops *, char *, int);
static void procfs_resume (ptid_t, int, enum target_signal);
static int procfs_can_run (void);
-static void procfs_stop (void);
+static void procfs_stop (ptid_t);
static void procfs_files_info (struct target_ops *);
-static void procfs_fetch_registers (int);
-static void procfs_store_registers (int);
+static void procfs_fetch_registers (struct regcache *, int);
+static void procfs_store_registers (struct regcache *, int);
static void procfs_notice_signals (ptid_t);
-static void procfs_prepare_to_store (void);
+static void procfs_prepare_to_store (struct regcache *);
static void procfs_kill_inferior (void);
-static void procfs_mourn_inferior (void);
-static void procfs_create_inferior (char *, char *, char **, int);
+static void procfs_mourn_inferior (struct target_ops *ops);
+static void procfs_create_inferior (struct target_ops *, char *,
+ char *, char **, int);
static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
-static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
+static int procfs_xfer_memory (CORE_ADDR, gdb_byte *, 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,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len);
static int procfs_thread_alive (ptid_t);
struct target_ops procfs_ops; /* the target vector */
+#if defined (PR_MODEL_NATIVE) && (PR_MODEL_NATIVE == PR_MODEL_LP64)
+/* When GDB is built as 64-bit application on Solaris, the auxv data is
+ presented in 64-bit format. We need to provide a custom parser to handle
+ that. */
+static int
+procfs_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
+ gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+{
+ gdb_byte *ptr = *readptr;
+
+ if (endptr == ptr)
+ return 0;
+
+ if (endptr - ptr < 8 * 2)
+ return -1;
+
+ *typep = extract_unsigned_integer (ptr, 4);
+ ptr += 8;
+ /* The size of data is always 64-bit. If the application is 32-bit,
+ it will be zero extended, as expected. */
+ *valp = extract_unsigned_integer (ptr, 8);
+ ptr += 8;
+
+ *readptr = ptr;
+ return 1;
+}
+#endif
+
static void
init_procfs_ops (void)
{
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.to_xfer_memory = procfs_xfer_memory;
+ 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_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;
+
+#if defined(PR_MODEL_NATIVE) && (PR_MODEL_NATIVE == PR_MODEL_LP64)
+ procfs_ops.to_auxv_parse = procfs_auxv_parse;
+#endif
+
procfs_ops.to_magic = OPS_MAGIC;
}
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;
}
static procinfo *
create_procinfo (int pid, int tid)
{
- procinfo *pi, *parent;
+ procinfo *pi, *parent = NULL;
if ((pi = find_procinfo (pid, tid)))
return pi; /* Already exists, nothing to do. */
kill (pi->pid, SIGKILL);
destroy_procinfo (pi);
- error (msg);
+ error ("%s", msg);
}
/*
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
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
pi->status_valid = 0;
if (!win)
- warning ("procfs: set_traced_signals failed");
+ warning (_("procfs: set_traced_signals failed"));
return win;
}
char sinfo[sizeof (gdb_siginfo_t)];
} arg;
gdb_siginfo_t *mysinfo;
+ ptid_t wait_ptid;
+ struct target_waitstatus wait_status;
/*
* We should never have to apply this operation to any procinfo
/* The pointer is just a type alias. */
mysinfo = (gdb_siginfo_t *) &arg.sinfo;
- mysinfo->si_signo = signo;
- mysinfo->si_code = 0;
- mysinfo->si_pid = getpid (); /* ?why? */
- mysinfo->si_uid = getuid (); /* ?why? */
+ get_last_target_status (&wait_ptid, &wait_status);
+ if (ptid_equal (wait_ptid, inferior_ptid)
+ && wait_status.kind == TARGET_WAITKIND_STOPPED
+ && wait_status.value.sig == target_signal_from_host (signo)
+ && proc_get_status (pi)
+#ifdef NEW_PROC_API
+ && pi->prstatus.pr_lwp.pr_info.si_signo == signo
+#else
+ && pi->prstatus.pr_info.si_signo == signo
+#endif
+ )
+ /* Use the siginfo associated with the signal being
+ redelivered. */
+#ifdef NEW_PROC_API
+ memcpy (mysinfo, &pi->prstatus.pr_lwp.pr_info, sizeof (gdb_siginfo_t));
+#else
+ memcpy (mysinfo, &pi->prstatus.pr_info, sizeof (gdb_siginfo_t));
+#endif
+ else
+ {
+ mysinfo->si_signo = signo;
+ mysinfo->si_code = 0;
+ mysinfo->si_pid = getpid (); /* ?why? */
+ mysinfo->si_uid = getuid (); /* ?why? */
+ }
#ifdef NEW_PROC_API
arg.cmd = PCSSIG;
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;
}
static void *
procfs_address_to_host_pointer (CORE_ADDR addr)
{
+ struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
void *ptr;
- gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
- ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (ptr_type));
+ gdbarch_address_to_pointer (target_gdbarch, ptr_type,
+ (gdb_byte *) &ptr, addr);
return ptr;
}
#endif
}
-#ifdef TM_I386SOL2_H /* Is it hokey to use this? */
+#if (defined(__i386__) || defined(__x86_64__)) && defined (sun)
#include <sys/sysi86.h>
#endif
}
-#endif /* TM_I386SOL2_H */
+/*
+ * Function: procfs_find_LDT_entry
+ *
+ * Input:
+ * ptid_t ptid; // The GDB-style pid-plus-LWP.
+ *
+ * Return:
+ * pointer to the corresponding LDT entry.
+ */
+
+struct ssd *
+procfs_find_LDT_entry (ptid_t ptid)
+{
+ gdb_gregset_t *gregs;
+ int key;
+ procinfo *pi;
+
+ /* 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:%ld."),
+ 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:%ld."),
+ PIDGET (ptid), TIDGET (ptid));
+ return NULL;
+ }
+ /* Now extract the GS register's lower 16 bits. */
+ key = (*gregs)[GS] & 0xffff;
+
+ /* Find the matching entry and return it. */
+ return proc_get_LDT_entry (pi, key);
+}
+
+#endif
/* =============== END, non-thread part of /proc "MODULE" =============== */
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
}
static void
-procfs_attach (char *args, int from_tty)
+procfs_attach (struct target_ops *ops, 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);
}
static void
-procfs_detach (char *args, int from_tty)
+procfs_detach (struct target_ops *ops, char *args, int from_tty)
{
- char *exec_file;
- int signo = 0;
+ int sig = 0;
+ int pid = PIDGET (inferior_ptid);
+
+ if (args)
+ sig = atoi (args);
if (from_tty)
{
+ 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 */
+ detach_inferior (pid);
+ unpush_target (&procfs_ops);
}
static ptid_t
do_attach (ptid_t ptid)
{
procinfo *pi;
+ struct inferior *inf;
int fail;
+ int lwpid;
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))
{
if ((fail = procfs_debug_inferior (pi)) != 0)
dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
+ inf = add_inferior (pi->pid);
/* Let GDB know that the inferior was attached. */
- attach_flag = 1;
- return MERGEPID (pi->pid, proc_get_current_thread (pi));
+ inf->attach_flag = 1;
+
+ /* Create a procinfo for the current lwp. */
+ lwpid = proc_get_current_thread (pi);
+ create_procinfo (pi->pid, lwpid);
+
+ /* Add it to gdb's thread list. */
+ ptid = MERGEPID (pi->pid, lwpid);
+ add_thread (ptid);
+
+ return ptid;
}
static void
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, set_rlc", __LINE__);
}
- attach_flag = 0;
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.
-static void
-procfs_fetch_registers (int regno)
-{
- gdb_fpregset_t *fpregs;
- gdb_gregset_t *gregs;
- procinfo *pi;
- int pid;
- int tid;
+ ??? 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.
- pid = PIDGET (inferior_ptid);
- tid = TIDGET (inferior_ptid);
+ 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. */
- /* First look up procinfo for the main process. */
- pi = find_procinfo_or_die (pid, 0);
+static void
+procfs_fetch_registers (struct regcache *regcache, int regnum)
+{
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid = PIDGET (inferior_ptid);
+ int tid = TIDGET (inferior_ptid);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
- /* 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);
+ 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);
+ supply_gregset (regcache, (const gdb_gregset_t *) gregs);
- if (FP0_REGNUM >= 0) /* need floating point? */
+ if (gdbarch_fp0_regnum (gdbarch) >= 0) /* Do we have an FPU? */
{
- if ((regno >= 0 && regno < FP0_REGNUM)
- || regno == PC_REGNUM
- || regno == DEPRECATED_FP_REGNUM
- || regno == SP_REGNUM)
- return; /* not a floating point register */
+ gdb_fpregset_t *fpregs;
+
+ if ((regnum >= 0 && regnum < gdbarch_fp0_regnum (gdbarch))
+ || regnum == gdbarch_pc_regnum (gdbarch)
+ || regnum == gdbarch_sp_regnum (gdbarch))
+ return; /* Not a floating point register. */
- if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ fpregs = proc_get_fpregs (pi);
+ if (fpregs == NULL)
proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
- supply_fpregset (fpregs);
+ supply_fpregset (regcache, (const gdb_fpregset_t *) fpregs);
}
}
from the program being debugged. */
static void
-procfs_prepare_to_store (void)
+procfs_prepare_to_store (struct regcache *regcache)
{
-#ifdef CHILD_PREPARE_TO_STORE
- CHILD_PREPARE_TO_STORE ();
-#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 (struct regcache *regcache, 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);
-
- /* If current lwp for process is not the same as requested thread
- (ie. inferior_ptid), then find procinfo for the requested thread. */
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid = PIDGET (inferior_ptid);
+ int tid = TIDGET (inferior_ptid);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
- if ((tid != 0) &&
- (tid != proc_get_current_thread (pi)))
- pi = find_procinfo_or_die (pid, tid);
+ 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 (regcache, gregs, regnum);
if (!proc_set_gregs (pi))
proc_error (pi, "store_registers, set_gregs", __LINE__);
- if (FP0_REGNUM >= 0) /* need floating point? */
+ if (gdbarch_fp0_regnum (gdbarch) >= 0) /* Do we have an FPU? */
{
- if ((regno >= 0 && regno < FP0_REGNUM)
- || regno == PC_REGNUM
- || regno == DEPRECATED_FP_REGNUM
- || regno == SP_REGNUM)
- return; /* not a floating point register */
+ gdb_fpregset_t *fpregs;
+
+ if ((regnum >= 0 && regnum < gdbarch_fp0_regnum (gdbarch))
+ || regnum == gdbarch_pc_regnum (gdbarch)
+ || regnum == gdbarch_sp_regnum (gdbarch))
+ return; /* Not a floating point register. */
- if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ fpregs = proc_get_fpregs (pi);
+ if (fpregs == NULL)
proc_error (pi, "store_registers, get_fpregs", __LINE__);
- fill_fpregset (fpregs, regno);
+ fill_fpregset (regcache, 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? */
case PR_SYSENTRY:
if (syscall_is_lwp_exit (pi, what))
{
- printf_filtered ("[%s exited]\n",
- target_pid_to_str (retval));
+ if (print_thread_events)
+ printf_unfiltered (_("[%s exited]\n"),
+ target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
else if (syscall_is_exit (pi, what))
{
+ struct inferior *inf;
+
/* Handle SYS_exit call only */
/* Stopped at entry to SYS_exit.
Make it runnable, resume it, then use
TARGET_WAITKIND_SPURIOUS. */
if (!proc_run_process (pi, 0, 0))
proc_error (pi, "target_wait, run_process", __LINE__);
- if (attach_flag)
+
+ inf = find_inferior_pid (pi->pid);
+ if (inf->attach_flag)
{
/* Don't call wait: simulate waiting for exit,
return a "success" exit code. Bogus: what if
}
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",
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))
{
/*
temp_ptid = MERGEPID (pi->pid, temp_tid);
/* If not in GDB's thread list, add it. */
if (!in_thread_list (temp_ptid))
- {
- printf_filtered ("[New %s]\n",
- target_pid_to_str (temp_ptid));
- add_thread (temp_ptid);
- }
+ add_thread (temp_ptid);
+
/* Return to WFI, but tell it to immediately resume. */
status->kind = TARGET_WAITKIND_SPURIOUS;
return inferior_ptid;
}
else if (syscall_is_lwp_exit (pi, what))
{
- printf_filtered ("[%s exited]\n",
- target_pid_to_str (retval));
+ if (print_thread_events)
+ printf_unfiltered (_("[%s exited]\n"),
+ target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
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",
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;
}
/* If not in GDB's thread list, add it. */
temp_ptid = MERGEPID (pi->pid, temp_tid);
if (!in_thread_list (temp_ptid))
- {
- printf_filtered ("[New %s]\n",
- target_pid_to_str (temp_ptid));
- add_thread (temp_ptid);
- }
+ add_thread (temp_ptid);
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = 0;
#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;
}
/*
* If we don't create a procinfo, resume may be unhappy
* later.
*/
- 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
- * 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),
- TIDGET (inferior_ptid)) == NULL)
- create_procinfo (PIDGET (inferior_ptid),
- TIDGET (inferior_ptid));
- }
}
}
else /* flags do not indicate STOPPED */
printf_filtered ("procfs:%d -- process not stopped.\n",
__LINE__);
proc_prettyprint_flags (flags, 1);
- error ("procfs: ...giving up...");
+ error (_("procfs: ...giving up..."));
}
}
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)
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
switch (object)
{
case TARGET_OBJECT_MEMORY:
if (readbuf)
- return (*ops->to_xfer_memory) (offset, readbuf, len, 0/*write*/,
- NULL, ops);
+ return (*ops->deprecated_xfer_memory) (offset, readbuf,
+ len, 0/*read*/, NULL, ops);
if (writebuf)
- return (*ops->to_xfer_memory) (offset, readbuf, len, 1/*write*/,
- NULL, ops);
+ return (*ops->deprecated_xfer_memory) (offset, (gdb_byte *) writebuf,
+ len, 1/*write*/, NULL, ops);
return -1;
#ifdef NEW_PROC_API
negative values, but this capability isn't implemented here.) */
static int
-procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
+procfs_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int dowrite,
struct mem_attrib *attrib, struct target_ops *target)
{
procinfo *pi;
if (!proc_set_gregs (pi)) /* flush gregs cache */
proc_warn (pi, "target_resume, set_gregs",
__LINE__);
- if (FP0_REGNUM >= 0)
+ if (gdbarch_fp0_regnum (current_gdbarch) >= 0)
if (pi->fpregs_dirty)
if (parent == NULL ||
proc_get_current_thread (parent) != pi->tid)
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__);
}
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",
+ struct inferior *inf = current_inferior ();
+ printf_filtered (_("\tUsing the running image of %s %s via /proc.\n"),
+ inf->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."));
}
/*
*/
static void
-procfs_stop (void)
+procfs_stop (ptid_t ptid)
{
kill (-inferior_process_group, SIGINT);
}
*/
static void
-procfs_mourn_inferior (void)
+procfs_mourn_inferior (struct target_ops *ops)
{
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 ();
}
procinfo *pi;
gdb_sigset_t signals;
int fail;
+ int lwpid;
/* This routine called on the parent side (GDB side)
after GDB forks the inferior. */
if (!proc_set_run_on_last_close (pi))
proc_error (pi, "init_inferior, set_RLC", __LINE__);
- /* The 'process ID' we return to GDB is composed of
- the actual process ID plus the lwp ID. */
- inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi));
+ /* We now have have access to the lwpid of the main thread/lwp. */
+ lwpid = proc_get_current_thread (pi);
+
+ /* Create a procinfo for the main lwp. */
+ create_procinfo (pid, lwpid);
+
+ /* We already have a main thread registered in the thread table at
+ this point, but it didn't have any lwp info yet. Notify the core
+ about it. This changes inferior_ptid as well. */
+ thread_change_ptid (pid_to_ptid (pid),
+ MERGEPID (pid, lwpid));
/* 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);
+
+#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)
{
*/
static void
-procfs_create_inferior (char *exec_file, char *allargs, char **env,
- int from_tty)
+procfs_create_inferior (struct target_ops *ops, 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,
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
}
/*
{
ptid_t gdb_threadid = MERGEPID (pi->pid, thread->tid);
- if (!in_thread_list (gdb_threadid))
+ if (!in_thread_list (gdb_threadid) || is_exited (gdb_threadid))
add_thread (gdb_threadid);
return 0;
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;
}
/*
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))
+ struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+ if (sizeof (void *) != TYPE_LENGTH (ptr_type))
return 0;
/* Other tests here??? */
return 0;
}
-#ifdef TM_I386SOL2_H
-/*
- * Function: procfs_find_LDT_entry
- *
- * Input:
- * ptid_t ptid; // The GDB-style pid-plus-LWP.
- *
- * Return:
- * pointer to the corresponding LDT entry.
- */
-
-struct ssd *
-procfs_find_LDT_entry (ptid_t ptid)
-{
- gdb_gregset_t *gregs;
- int key;
- procinfo *pi;
-
- /* 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.",
- 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.",
- PIDGET (ptid), TIDGET (ptid));
- return NULL;
- }
- /* Now extract the GS register's lower 16 bits. */
- key = (*gregs)[GS] & 0xffff;
-
- /* Find the matching entry and return it. */
- return proc_get_LDT_entry (pi, key);
-}
-#endif /* TM_I386SOL2_H */
-
/*
* Memory Mappings Functions:
*/
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
*
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";
+ unsigned int pr_off;
- 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,
+ pr_off = (unsigned int) map->pr_offset;
#else
- map->pr_off,
+ pr_off = map->pr_off;
#endif
- mappingflags (map->pr_mflags));
+
+ if (gdbarch_addr_bit (current_gdbarch) == 32)
+ printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
+ (unsigned long) map->pr_vaddr,
+ (unsigned long) map->pr_vaddr + map->pr_size - 1,
+ map->pr_size,
+ pr_off,
+ mappingflags (map->pr_mflags));
+ else
+ printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n",
+ (unsigned long) map->pr_vaddr,
+ (unsigned long) map->pr_vaddr + map->pr_size - 1,
+ map->pr_size,
+ pr_off,
+ mappingflags (map->pr_mflags));
return 0;
}
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");
+ printf_filtered (_("Mapped address spaces:\n\n"));
+ if (gdbarch_ptr_bit (current_gdbarch) == 32)
+ printf_filtered ("\t%10s %10s %10s %10s %7s\n",
+ "Start Addr",
+ " End Addr",
+ " Size",
+ " Offset",
+ "Flags");
+ else
+ printf_filtered (" %18s %18s %10s %10s %7s\n",
+ "Start Addr",
+ " End Addr",
+ " Size",
+ " Offset",
+ "Flags");
iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
printf_filtered ("\n");
old_chain = make_cleanup (null_cleanup, 0);
if (args)
{
- if ((argv = buildargv (args)) == NULL)
- nomem (0);
- else
- make_cleanup_freeargv (argv);
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
}
while (argv != NULL && *argv != NULL)
{
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.
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 (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);
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);
+ const int syscallnum = atoi (args);
- 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__);
- }
+ proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty);
}
}
{
init_procfs_ops ();
add_target (&procfs_ops);
- add_info ("proc", info_proc_cmd,
- "Show /proc process information about any running process.\n\
+ 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.");
+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.");
+ _("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.");
+ _("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.");
+ _("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.");
+ _("Cancel a trace of exits from the syscall."));
}
/* =================== END, GDB "MODULE" =================== */
return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
}
+static int
+find_signalled_thread (struct thread_info *info, void *data)
+{
+ if (info->stop_signal != TARGET_SIGNAL_0
+ && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
+ return 1;
+
+ return 0;
+}
+
+static enum target_signal
+find_stop_signal (void)
+{
+ struct thread_info *info =
+ iterate_over_threads (find_signalled_thread, NULL);
+
+ if (info)
+ return info->stop_signal;
+ else
+ return TARGET_SIGNAL_0;
+}
+
/* =================== 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)
+ char *note_data, int *note_size,
+ enum target_signal stop_signal)
{
+ struct regcache *regcache = get_thread_regcache (ptid);
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
unsigned long merged_pid;
merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
- fill_gregset (&gregs, -1);
+ fill_gregset (regcache, &gregs, -1);
#if defined (UNIXWARE)
note_data = (char *) elfcore_write_lwpstatus (obfd,
note_data,
stop_signal,
&gregs);
#endif
- fill_fpregset (&fpregs, -1);
+ fill_fpregset (regcache, &fpregs, -1);
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
bfd *obfd;
char *note_data;
int *note_size;
+ enum target_signal stop_signal;
};
static int
{
struct procfs_corefile_thread_data *args = data;
- if (pi != NULL && thread->tid != 0)
+ if (pi != NULL)
{
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);
+ args->note_size,
+ args->stop_signal);
inferior_ptid = saved_ptid;
}
return 0;
char *note_data = NULL;
char *inf_args;
struct procfs_corefile_thread_data thread_args;
- char *auxv;
+ gdb_byte *auxv;
int auxv_len;
if (get_exec_file (0))
psargs);
#ifdef UNIXWARE
- fill_gregset (&gregs, -1);
+ fill_gregset (get_current_regcache (), &gregs, -1);
note_data = elfcore_write_pstatus (obfd, note_data, note_size,
PIDGET (inferior_ptid),
stop_signal, &gregs);
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
+ thread_args.stop_signal = find_stop_signal ();
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;
- }
+ /* There should be always at least one thread. */
+ gdb_assert (thread_args.note_data != note_data);
+ note_data = thread_args.note_data;
- auxv_len = target_auxv_read (¤t_target, &auxv);
+ 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,
static char *
procfs_make_note_section (bfd *obfd, int *note_size)
{
- error ("gcore not implemented for this host.");
+ error (_("gcore not implemented for this host."));
return NULL; /* lint */
}
#endif /* Solaris or Unixware */