/* Low-level child interface to ptrace.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1998, 1999, 2000, 2001, 2002, 2004, 2005
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GDB.
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "command.h"
#include "inferior.h"
#include "inflow.h"
#include "gdbcore.h"
-#include "observer.h"
#include "regcache.h"
+#include "gdb_stdint.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "gdb_ptrace.h"
#ifdef PT_GET_PROCESS_STATE
static int
-inf_ptrace_follow_fork (int follow_child)
+inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
{
pid_t pid, fpid;
ptrace_state_t pe;
static void
inf_ptrace_him (int pid)
{
-#ifdef PT_GET_PROCESS_STATE
- {
- ptrace_event_t pe;
-
- /* Set the initial event mask. */
- memset (&pe, 0, sizeof pe);
- pe.pe_set_event |= PTRACE_FORK;
- if (ptrace (PT_SET_EVENT_MASK, pid,
- (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
- perror_with_name (("ptrace"));
- }
-#endif
-
push_target (ptrace_ops_hack);
/* On some targets, there must be some explicit synchronization
{
fork_inferior (exec_file, allargs, env, inf_ptrace_me, inf_ptrace_him,
NULL, NULL);
+}
+
+#ifdef PT_GET_PROCESS_STATE
- /* We are at the first instruction we care about. */
- observer_notify_inferior_created (¤t_target, from_tty);
+static void
+inf_ptrace_post_startup_inferior (ptid_t pid)
+{
+ ptrace_event_t pe;
- /* Pedal to the metal... */
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+ /* Set the initial event mask. */
+ memset (&pe, 0, sizeof pe);
+ pe.pe_set_event |= PTRACE_FORK;
+ if (ptrace (PT_SET_EVENT_MASK, ptid_get_pid (pid),
+ (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+ perror_with_name (("ptrace"));
}
+#endif
+
/* Clean up a rotting corpse of an inferior after it died. */
static void
int status;
/* Wait just one more time to collect the inferior's exit status.
- Don not check whether this succeeds though, since we may be
+ Do not check whether this succeeds though, since we may be
dealing with a process that we attached to. Such a process will
- only report its exit status to its origional parent. */
+ only report its exit status to its original parent. */
waitpid (ptid_get_pid (inferior_ptid), &status, 0);
unpush_target (ptrace_ops_hack);
error (_("This system does not support attaching to a process"));
#endif
-#ifdef PT_GET_PROCESS_STATE
- {
- ptrace_event_t pe;
-
- /* Set the initial event mask. */
- memset (&pe, 0, sizeof pe);
- pe.pe_set_event |= PTRACE_FORK;
- if (ptrace (PT_SET_EVENT_MASK, pid,
- (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
- perror_with_name (("ptrace"));
- }
-#endif
-
inferior_ptid = pid_to_ptid (pid);
push_target (ptrace_ops_hack);
+}
- /* Do this first, before anything has had a chance to query the
- inferior's symbol table or similar. */
- observer_notify_inferior_created (¤t_target, from_tty);
+#ifdef PT_GET_PROCESS_STATE
+
+void
+inf_ptrace_post_attach (int pid)
+{
+ ptrace_event_t pe;
+
+ /* Set the initial event mask. */
+ memset (&pe, 0, sizeof pe);
+ pe.pe_set_event |= PTRACE_FORK;
+ if (ptrace (PT_SET_EVENT_MASK, pid,
+ (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+ perror_with_name (("ptrace"));
}
+#endif
+
/* Detach from the inferior, optionally passing it the signal
- specified ARGS. If FROM_TTY is non-zero, be chatty about it. */
+ specified by ARGS. If FROM_TTY is non-zero, be chatty about it. */
static void
inf_ptrace_detach (char *args, int from_tty)
#ifdef PT_DETACH
/* We'd better not have left any breakpoints in the program or it'll
- die when it hits one. Alsno note that this may only work if we
+ die when it hits one. Also note that this may only work if we
previously attached to the inferior. It *might* work if we
started the process ourselves. */
errno = 0;
struct ptrace_io_desc piod;
/* NOTE: We assume that there are no distinct address spaces
- for instruction and data. */
- piod.piod_op = writebuf ? PIOD_WRITE_D : PIOD_READ_D;
+ for instruction and data. However, on OpenBSD 3.9 and
+ later, PIOD_WRITE_D doesn't allow changing memory that's
+ mapped read-only. Since most code segments will be
+ read-only, using PIOD_WRITE_D will prevent us from
+ inserting breakpoints, so we use PIOD_WRITE_I instead. */
+ piod.piod_op = writebuf ? PIOD_WRITE_I : PIOD_READ_D;
piod.piod_addr = writebuf ? (void *) writebuf : readbuf;
piod.piod_offs = (void *) (long) offset;
piod.piod_len = len;
< rounded_offset + sizeof (PTRACE_TYPE_RET)))
/* Need part of initial word -- fetch it. */
buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+ (PTRACE_TYPE_ARG3)(uintptr_t)
+ rounded_offset, 0);
/* Copy data to be written over corresponding part of
buffer. */
errno = 0;
ptrace (PT_WRITE_D, pid,
- (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+ (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+ buffer.word);
if (errno)
{
/* Using the appropriate one (I or D) is necessary for
Gould NP1, at least. */
errno = 0;
ptrace (PT_WRITE_I, pid,
- (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+ (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+ buffer.word);
if (errno)
return 0;
}
{
errno = 0;
buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+ (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+ 0);
if (errno)
return 0;
/* Copy appropriate bytes out of the buffer. */
t->to_create_inferior = inf_ptrace_create_inferior;
#ifdef PT_GET_PROCESS_STATE
t->to_follow_fork = inf_ptrace_follow_fork;
+ t->to_post_startup_inferior = inf_ptrace_post_startup_inferior;
+ t->to_post_attach = inf_ptrace_post_attach;
#endif
t->to_mourn_inferior = inf_ptrace_mourn_inferior;
t->to_thread_alive = inf_ptrace_thread_alive;
/* Pointer to a function that returns the offset within the user area
where a particular register is stored. */
-static CORE_ADDR (*inf_ptrace_register_u_offset)(int);
+static CORE_ADDR (*inf_ptrace_register_u_offset)(struct gdbarch *, int, int);
/* Fetch register REGNUM from the inferior. */
static void
-inf_ptrace_fetch_register (int regnum)
+inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
{
CORE_ADDR addr;
size_t size;
PTRACE_TYPE_RET *buf;
int pid, i;
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = inf_ptrace_register_u_offset (current_gdbarch, regnum, 0);
+ if (addr == (CORE_ADDR)-1
+ || gdbarch_cannot_fetch_register (current_gdbarch, regnum))
+ {
+ regcache_raw_supply (regcache, regnum, NULL);
+ return;
+ }
+
/* Cater for systems like GNU/Linux, that implement threads as
- seperate processes. */
+ separate processes. */
pid = ptid_get_lwp (inferior_ptid);
if (pid == 0)
pid = ptid_get_pid (inferior_ptid);
- /* This isn't really an address, but ptrace thinks of it as one. */
- addr = inf_ptrace_register_u_offset (regnum);
size = register_size (current_gdbarch, regnum);
-
gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
buf = alloca (size);
- /* Read the register contents from the inferior a chuck at the time. */
+ /* Read the register contents from the inferior a chunk at a time. */
for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
{
errno = 0;
- buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)addr, 0);
+ buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, 0);
if (errno != 0)
error (_("Couldn't read register %s (#%d): %s."),
- REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+ gdbarch_register_name (current_gdbarch, regnum),
+ regnum, safe_strerror (errno));
addr += sizeof (PTRACE_TYPE_RET);
}
- regcache_raw_supply (current_regcache, regnum, buf);
+ regcache_raw_supply (regcache, regnum, buf);
}
/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
for all registers. */
static void
-inf_ptrace_fetch_registers (int regnum)
+inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
{
if (regnum == -1)
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- inf_ptrace_fetch_register (regnum);
+ for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++)
+ inf_ptrace_fetch_register (regcache, regnum);
else
- inf_ptrace_fetch_register (regnum);
+ inf_ptrace_fetch_register (regcache, regnum);
}
/* Store register REGNUM into the inferior. */
static void
-inf_ptrace_store_register (int regnum)
+inf_ptrace_store_register (const struct regcache *regcache, int regnum)
{
CORE_ADDR addr;
size_t size;
PTRACE_TYPE_RET *buf;
int pid, i;
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = inf_ptrace_register_u_offset (current_gdbarch, regnum, 1);
+ if (addr == (CORE_ADDR)-1
+ || gdbarch_cannot_store_register (current_gdbarch, regnum))
+ return;
+
/* Cater for systems like GNU/Linux, that implement threads as
- seperate processes. */
+ separate processes. */
pid = ptid_get_lwp (inferior_ptid);
if (pid == 0)
pid = ptid_get_pid (inferior_ptid);
- /* This isn't really an address, but ptrace thinks of it as one. */
- addr = inf_ptrace_register_u_offset (regnum);
size = register_size (current_gdbarch, regnum);
-
gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
buf = alloca (size);
- /* Write the register contents into the inferior a chunk at the time. */
- regcache_raw_collect (current_regcache, regnum, buf);
+ /* Write the register contents into the inferior a chunk at a time. */
+ regcache_raw_collect (regcache, regnum, buf);
for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
{
errno = 0;
- ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)addr, buf[i]);
+ ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, buf[i]);
if (errno != 0)
error (_("Couldn't write register %s (#%d): %s."),
- REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+ gdbarch_register_name (current_gdbarch, regnum),
+ regnum, safe_strerror (errno));
addr += sizeof (PTRACE_TYPE_RET);
}
this for all registers. */
void
-inf_ptrace_store_registers (int regnum)
+inf_ptrace_store_registers (struct regcache *regcache, int regnum)
{
if (regnum == -1)
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- inf_ptrace_store_register (regnum);
+ for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++)
+ inf_ptrace_store_register (regcache, regnum);
else
- inf_ptrace_store_register (regnum);
+ inf_ptrace_store_register (regcache, regnum);
}
/* Create a "traditional" ptrace target. REGISTER_U_OFFSET should be
particular register is stored. */
struct target_ops *
-inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int))
+inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
+ (struct gdbarch *, int, int))
{
struct target_ops *t = inf_ptrace_target();