/* Low-level child interface to ptrace.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1998, 1999, 2000, 2001, 2002, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
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
+ 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,
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, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "command.h"
#include "inferior.h"
#include "inflow.h"
+#include "terminal.h"
#include "gdbcore.h"
-#include "observer.h"
#include "regcache.h"
-
-#include "gdb_assert.h"
-#include "gdb_string.h"
-#include "gdb_ptrace.h"
+#include "nat/gdb_ptrace.h"
#include "gdb_wait.h"
#include <signal.h>
+#include "inf-ptrace.h"
#include "inf-child.h"
+#include "gdbthread.h"
-/* HACK: Save the ptrace ops returned by inf_ptrace_target. */
-static struct target_ops *ptrace_ops_hack;
\f
#ifdef PT_GET_PROCESS_STATE
+/* Target hook for follow_fork. On entry and at return inferior_ptid is
+ the ptid of the followed inferior. */
+
static int
-inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
+inf_ptrace_follow_fork (struct target_ops *ops, int follow_child,
+ int detach_fork)
{
- pid_t pid, fpid;
- ptrace_state_t pe;
-
- /* FIXME: kettenis/20050720: This stuff should really be passed as
- an argument by our caller. */
- {
- ptid_t ptid;
- struct target_waitstatus status;
-
- get_last_target_status (&ptid, &status);
- gdb_assert (status.kind == TARGET_WAITKIND_FORKED);
-
- pid = ptid_get_pid (ptid);
- }
-
- if (ptrace (PT_GET_PROCESS_STATE, pid,
- (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
- perror_with_name (("ptrace"));
-
- gdb_assert (pe.pe_report_event == PTRACE_FORK);
- fpid = pe.pe_other_pid;
-
- if (follow_child)
+ if (!follow_child)
{
- inferior_ptid = pid_to_ptid (fpid);
- detach_breakpoints (pid);
+ struct thread_info *tp = inferior_thread ();
+ pid_t child_pid = ptid_get_pid (tp->pending_follow.value.related_pid);
- /* Reset breakpoints in the child as appropriate. */
- follow_inferior_reset_breakpoints ();
+ /* Breakpoints have already been detached from the child by
+ infrun.c. */
- if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
+ if (ptrace (PT_DETACH, child_pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
perror_with_name (("ptrace"));
}
- else
- {
- inferior_ptid = pid_to_ptid (pid);
- detach_breakpoints (fpid);
- if (ptrace (PT_DETACH, fpid, (PTRACE_TYPE_ARG3)1, 0) == -1)
- perror_with_name (("ptrace"));
- }
+ return 0;
+}
+
+static int
+inf_ptrace_insert_fork_catchpoint (struct target_ops *self, int pid)
+{
+ return 0;
+}
+static int
+inf_ptrace_remove_fork_catchpoint (struct target_ops *self, int pid)
+{
return 0;
}
ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3)0, 0);
}
-/* Start tracing PID. */
+/* Start a new inferior Unix child process. EXEC_FILE is the file to
+ run, ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass. If FROM_TTY is non-zero, be
+ chatty about it. */
static void
-inf_ptrace_him (int pid)
+inf_ptrace_create_inferior (struct target_ops *ops,
+ char *exec_file, char *allargs, char **env,
+ int from_tty)
{
- push_target (ptrace_ops_hack);
+ int pid;
+
+ /* Do not change either targets above or the same target if already present.
+ The reason is the target stack is shared across multiple inferiors. */
+ int ops_already_pushed = target_is_pushed (ops);
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+ if (! ops_already_pushed)
+ {
+ /* Clear possible core file with its process_stratum. */
+ push_target (ops);
+ make_cleanup_unpush_target (ops);
+ }
- /* On some targets, there must be some explicit synchronization
- between the parent and child processes after the debugger
- forks, and before the child execs the debuggee program. This
- call basically gives permission for the child to exec. */
+ pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
+ NULL, NULL, NULL);
- target_acknowledge_created_inferior (pid);
+ discard_cleanups (back_to);
- /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
- be 1 or 2 depending on whether we're starting without or with a
- shell. */
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
/* On some targets, there must be some explicit actions taken after
target_post_startup_inferior (pid_to_ptid (pid));
}
-/* Start a new inferior Unix child process. EXEC_FILE is the file to
- run, ALLARGS is a string containing the arguments to the program.
- ENV is the environment vector to pass. If FROM_TTY is non-zero, be
- chatty about it. */
-
-static void
-inf_ptrace_create_inferior (char *exec_file, char *allargs, char **env,
- int from_tty)
-{
- fork_inferior (exec_file, allargs, env, inf_ptrace_me, inf_ptrace_him,
- NULL, NULL);
-
- /* We are at the first instruction we care about. */
- observer_notify_inferior_created (¤t_target, from_tty);
-
- /* Pedal to the metal... */
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
-}
-
#ifdef PT_GET_PROCESS_STATE
static void
-inf_ptrace_post_startup_inferior (ptid_t pid)
+inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid)
{
ptrace_event_t pe;
/* Clean up a rotting corpse of an inferior after it died. */
static void
-inf_ptrace_mourn_inferior (void)
+inf_ptrace_mourn_inferior (struct target_ops *ops)
{
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);
- generic_mourn_inferior ();
+ inf_child_mourn_inferior (ops);
}
/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
be chatty about it. */
static void
-inf_ptrace_attach (char *args, int from_tty)
+inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
{
char *exec_file;
pid_t pid;
- char *dummy;
+ struct inferior *inf;
- if (!args)
- error_no_arg (_("process-id to attach"));
+ /* Do not change either targets above or the same target if already present.
+ The reason is the target stack is shared across multiple inferiors. */
+ int ops_already_pushed = target_is_pushed (ops);
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
- dummy = args;
- pid = strtol (args, &dummy, 0);
- /* Some targets don't set errno on errors, grrr! */
- if (pid == 0 && args == dummy)
- error (_("Illegal process-id: %s."), args);
+ pid = parse_pid_to_attach (args);
if (pid == getpid ()) /* Trying to masturbate? */
error (_("I refuse to debug myself!"));
+ if (! ops_already_pushed)
+ {
+ /* target_pid_to_str already uses the target. Also clear possible core
+ file with its process_stratum. */
+ push_target (ops);
+ make_cleanup_unpush_target (ops);
+ }
+
if (from_tty)
{
exec_file = get_exec_file (0);
ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0);
if (errno != 0)
perror_with_name (("ptrace"));
- attach_flag = 1;
#else
error (_("This system does not support attaching to a process"));
#endif
+ inf = current_inferior ();
+ inferior_appeared (inf, pid);
+ inf->attach_flag = 1;
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);
+ /* Always add a main thread. If some target extends the ptrace
+ target, it should decorate the ptid later with more info. */
+ add_thread_silent (inferior_ptid);
+
+ discard_cleanups (back_to);
}
#ifdef PT_GET_PROCESS_STATE
-void
-inf_ptrace_post_attach (int pid)
+static void
+inf_ptrace_post_attach (struct target_ops *self, int pid)
{
ptrace_event_t pe;
#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)
+inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty)
{
pid_t pid = ptid_get_pid (inferior_ptid);
int sig = 0;
#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;
ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig);
if (errno != 0)
perror_with_name (("ptrace"));
- attach_flag = 0;
#else
error (_("This system does not support detaching from a process"));
#endif
inferior_ptid = null_ptid;
- unpush_target (ptrace_ops_hack);
+ detach_inferior (pid);
+
+ inf_child_maybe_unpush_target (ops);
}
/* Kill the inferior. */
static void
-inf_ptrace_kill (void)
+inf_ptrace_kill (struct target_ops *ops)
{
pid_t pid = ptid_get_pid (inferior_ptid);
int status;
target_mourn_inferior ();
}
-/* Stop the inferior. */
+/* Interrupt the inferior. */
static void
-inf_ptrace_stop (void)
+inf_ptrace_interrupt (struct target_ops *self, ptid_t ptid)
{
/* Send a SIGINT to the process group. This acts just like the user
typed a ^C on the controlling terminal. Note that using a
negative process number in kill() is a System V-ism. The proper
BSD interface is killpg(). However, all modern BSDs support the
System V interface too. */
- kill (-inferior_process_group, SIGINT);
+ kill (-inferior_process_group (), SIGINT);
+}
+
+/* Return which PID to pass to ptrace in order to observe/control the
+ tracee identified by PTID. */
+
+static pid_t
+get_ptrace_pid (ptid_t ptid)
+{
+ pid_t pid;
+
+ /* If we have an LWPID to work with, use it. Otherwise, we're
+ dealing with a non-threaded program/target. */
+ pid = ptid_get_lwp (ptid);
+ if (pid == 0)
+ pid = ptid_get_pid (ptid);
+ return pid;
}
/* Resume execution of thread PTID, or all threads if PTID is -1. If
that signal. */
static void
-inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
+inf_ptrace_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum gdb_signal signal)
{
- pid_t pid = ptid_get_pid (ptid);
- int request = PT_CONTINUE;
+ pid_t pid;
+ int request;
- if (pid == -1)
+ if (ptid_equal (minus_one_ptid, ptid))
/* Resume all threads. Traditionally ptrace() only supports
single-threaded processes, so simply resume the inferior. */
pid = ptid_get_pid (inferior_ptid);
+ else
+ pid = get_ptrace_pid (ptid);
+
+ if (catch_syscall_enabled () > 0)
+ request = PT_SYSCALL;
+ else
+ request = PT_CONTINUE;
if (step)
{
where it was. If GDB wanted it to start some other way, we have
already written a new program counter value to the child. */
errno = 0;
- ptrace (request, pid, (PTRACE_TYPE_ARG3)1, target_signal_to_host (signal));
+ ptrace (request, pid, (PTRACE_TYPE_ARG3)1, gdb_signal_to_host (signal));
if (errno != 0)
perror_with_name (("ptrace"));
}
the status in *OURSTATUS. */
static ptid_t
-inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+inf_ptrace_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
pid_t pid;
int status, save_errno;
do
{
set_sigint_trap ();
- set_sigio_trap ();
do
{
}
while (pid == -1 && errno == EINTR);
- clear_sigio_trap ();
clear_sigint_trap ();
if (pid == -1)
/* Claim it exited with unknown signal. */
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
- return minus_one_ptid;
+ ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
+ return inferior_ptid;
}
/* Ignore terminated detached child processes. */
{
case PTRACE_FORK:
ourstatus->kind = TARGET_WAITKIND_FORKED;
- ourstatus->value.related_pid = pe.pe_other_pid;
+ ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
/* Make sure the other end of the fork is stopped too. */
fpid = waitpid (pe.pe_other_pid, &status, 0);
gdb_assert (pe.pe_other_pid == pid);
if (fpid == ptid_get_pid (inferior_ptid))
{
- ourstatus->value.related_pid = pe.pe_other_pid;
+ ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
return pid_to_ptid (fpid);
}
return pid_to_ptid (pid);
}
-/* Attempt a transfer all LEN bytes starting at OFFSET between the
- inferior's OBJECT:ANNEX space and GDB's READBUF/WRITEBUF buffer.
- Return the number of bytes actually transferred. */
+/* Implement the to_xfer_partial target_ops method. */
-static LONGEST
+static enum target_xfer_status
inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len)
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
{
pid_t pid = ptid_get_pid (inferior_ptid);
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;
errno = 0;
if (ptrace (PT_IO, pid, (caddr_t)&piod, 0) == 0)
- /* Return the actual number of bytes read or written. */
- return piod.piod_len;
+ {
+ /* Return the actual number of bytes read or written. */
+ *xfered_len = piod.piod_len;
+ return (piod.piod_len == 0) ? TARGET_XFER_EOF : TARGET_XFER_OK;
+ }
/* If the PT_IO request is somehow not supported, fallback on
using PT_WRITE_D/PT_READ_D. Otherwise we will return zero
to indicate failure. */
if (errno != EINVAL)
- return 0;
+ return TARGET_XFER_EOF;
}
#endif
{
gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
} buffer;
ULONGEST rounded_offset;
- LONGEST partial_len;
+ ULONGEST partial_len;
/* Round the start offset down to the next long word
boundary. */
< 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;
+ return TARGET_XFER_EOF;
}
}
{
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;
+ return TARGET_XFER_EOF;
/* Copy appropriate bytes out of the buffer. */
memcpy (readbuf, buffer.byte + (offset - rounded_offset),
partial_len);
}
- return partial_len;
+ *xfered_len = partial_len;
+ return TARGET_XFER_OK;
}
case TARGET_OBJECT_UNWIND_TABLE:
- return -1;
+ return TARGET_XFER_E_IO;
case TARGET_OBJECT_AUXV:
- return -1;
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+ /* OpenBSD 4.5 has a new PIOD_READ_AUXV operation for the PT_IO
+ request that allows us to read the auxilliary vector. Other
+ BSD's may follow if they feel the need to support PIE. */
+ {
+ struct ptrace_io_desc piod;
+
+ if (writebuf)
+ return TARGET_XFER_E_IO;
+ piod.piod_op = PIOD_READ_AUXV;
+ piod.piod_addr = readbuf;
+ piod.piod_offs = (void *) (long) offset;
+ piod.piod_len = len;
+
+ errno = 0;
+ if (ptrace (PT_IO, pid, (caddr_t)&piod, 0) == 0)
+ {
+ /* Return the actual number of bytes read or written. */
+ *xfered_len = piod.piod_len;
+ return (piod.piod_len == 0) ? TARGET_XFER_EOF : TARGET_XFER_OK;
+ }
+ }
+#endif
+ return TARGET_XFER_E_IO;
case TARGET_OBJECT_WCOOKIE:
- return -1;
+ return TARGET_XFER_E_IO;
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
}
/* Return non-zero if the thread specified by PTID is alive. */
static int
-inf_ptrace_thread_alive (ptid_t ptid)
+inf_ptrace_thread_alive (struct target_ops *ops, ptid_t ptid)
{
/* ??? Is kill the right way to do this? */
return (kill (ptid_get_pid (ptid), 0) != -1);
static void
inf_ptrace_files_info (struct target_ops *ignore)
{
+ struct inferior *inf = current_inferior ();
+
printf_filtered (_("\tUsing the running image of %s %s.\n"),
- attach_flag ? "attached" : "child",
+ inf->attach_flag ? "attached" : "child",
target_pid_to_str (inferior_ptid));
}
+static char *
+inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+ return normal_pid_to_str (ptid);
+}
+
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+
+/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
+ Return 0 if *READPTR is already at the end of the buffer.
+ Return -1 if there is insufficient buffer for a whole entry.
+ Return 1 if an entry was read into *TYPEP and *VALP. */
+
+static int
+inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
+ gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+{
+ struct type *int_type = builtin_type (target_gdbarch ())->builtin_int;
+ struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+ const int sizeof_auxv_type = TYPE_LENGTH (int_type);
+ const int sizeof_auxv_val = TYPE_LENGTH (ptr_type);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+ gdb_byte *ptr = *readptr;
+
+ if (endptr == ptr)
+ return 0;
+
+ if (endptr - ptr < 2 * sizeof_auxv_val)
+ return -1;
+
+ *typep = extract_unsigned_integer (ptr, sizeof_auxv_type, byte_order);
+ ptr += sizeof_auxv_val; /* Alignment. */
+ *valp = extract_unsigned_integer (ptr, sizeof_auxv_val, byte_order);
+ ptr += sizeof_auxv_val;
+
+ *readptr = ptr;
+ return 1;
+}
+
+#endif
+
/* Create a prototype ptrace target. The client can override it with
local methods. */
t->to_create_inferior = inf_ptrace_create_inferior;
#ifdef PT_GET_PROCESS_STATE
t->to_follow_fork = inf_ptrace_follow_fork;
+ t->to_insert_fork_catchpoint = inf_ptrace_insert_fork_catchpoint;
+ t->to_remove_fork_catchpoint = inf_ptrace_remove_fork_catchpoint;
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;
- t->to_pid_to_str = normal_pid_to_str;
- t->to_stop = inf_ptrace_stop;
+ t->to_pid_to_str = inf_ptrace_pid_to_str;
+ t->to_interrupt = inf_ptrace_interrupt;
t->to_xfer_partial = inf_ptrace_xfer_partial;
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+ t->to_auxv_parse = inf_ptrace_auxv_parse;
+#endif
- ptrace_ops_hack = t;
return t;
}
\f
/* 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)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR addr;
size_t size;
PTRACE_TYPE_RET *buf;
int pid, i;
- if (CANNOT_FETCH_REGISTER (regnum))
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = inf_ptrace_register_u_offset (gdbarch, regnum, 0);
+ if (addr == (CORE_ADDR)-1
+ || gdbarch_cannot_fetch_register (gdbarch, regnum))
{
- regcache_raw_supply (current_regcache, regnum, NULL);
+ regcache_raw_supply (regcache, regnum, NULL);
return;
}
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);
-
+ size = register_size (gdbarch, regnum);
gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
buf = alloca (size);
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 (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 target_ops *ops,
+ 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 (get_regcache_arch (regcache));
+ 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)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR addr;
size_t size;
PTRACE_TYPE_RET *buf;
int pid, i;
- if (CANNOT_STORE_REGISTER (regnum))
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = inf_ptrace_register_u_offset (gdbarch, regnum, 1);
+ if (addr == (CORE_ADDR)-1
+ || gdbarch_cannot_store_register (gdbarch, regnum))
return;
/* Cater for systems like GNU/Linux, that implement threads as
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);
-
+ size = register_size (gdbarch, regnum);
gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
buf = alloca (size);
/* Write the register contents into the inferior a chunk at a time. */
- regcache_raw_collect (current_regcache, regnum, buf);
+ 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 (gdbarch, regnum),
+ regnum, safe_strerror (errno));
addr += sizeof (PTRACE_TYPE_RET);
}
/* Store register REGNUM back into the inferior. If REGNUM is -1, do
this for all registers. */
-void
-inf_ptrace_store_registers (int regnum)
+static void
+inf_ptrace_store_registers (struct target_ops *ops,
+ 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 (get_regcache_arch (regcache));
+ 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();