/* Low-level child interface to ptrace.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
1998, 1999, 2000, 2001, 2002, 2004, 2005
Free Software Foundation, Inc.
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"
static struct target_ops *ptrace_ops_hack;
\f
+#ifdef PT_GET_PROCESS_STATE
+
+static int
+inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
+{
+ 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)
+ {
+ inferior_ptid = pid_to_ptid (fpid);
+ detach_breakpoints (pid);
+
+ /* Reset breakpoints in the child as appropriate. */
+ follow_inferior_reset_breakpoints ();
+
+ if (ptrace (PT_DETACH, 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;
+}
+
+#endif /* PT_GET_PROCESS_STATE */
+\f
+
/* Prepare to be traced. */
static void
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
}
+#ifdef PT_GET_PROCESS_STATE
+
+static void
+inf_ptrace_post_startup_inferior (ptid_t 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, 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);
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;
}
while (pid == -1);
+#ifdef PT_GET_PROCESS_STATE
+ if (WIFSTOPPED (status))
+ {
+ ptrace_state_t pe;
+ pid_t fpid;
+
+ if (ptrace (PT_GET_PROCESS_STATE, pid,
+ (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+ perror_with_name (("ptrace"));
+
+ switch (pe.pe_report_event)
+ {
+ case PTRACE_FORK:
+ ourstatus->kind = TARGET_WAITKIND_FORKED;
+ ourstatus->value.related_pid = pe.pe_other_pid;
+
+ /* Make sure the other end of the fork is stopped too. */
+ fpid = waitpid (pe.pe_other_pid, &status, 0);
+ if (fpid == -1)
+ perror_with_name (("waitpid"));
+
+ if (ptrace (PT_GET_PROCESS_STATE, fpid,
+ (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+ perror_with_name (("ptrace"));
+
+ gdb_assert (pe.pe_report_event == PTRACE_FORK);
+ gdb_assert (pe.pe_other_pid == pid);
+ if (fpid == ptid_get_pid (inferior_ptid))
+ {
+ ourstatus->value.related_pid = pe.pe_other_pid;
+ return pid_to_ptid (fpid);
+ }
+
+ return pid_to_ptid (pid);
+ }
+ }
+#endif
+
store_waitstatus (ourstatus, status);
return pid_to_ptid (pid);
}
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;
t->to_files_info = inf_ptrace_files_info;
t->to_kill = inf_ptrace_kill;
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;
t->to_pid_to_str = normal_pid_to_str;
PTRACE_TYPE_RET *buf;
int pid, i;
+ if (CANNOT_FETCH_REGISTER (regnum))
+ {
+ regcache_raw_supply (current_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);
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;
PTRACE_TYPE_RET *buf;
int pid, i;
+ if (CANNOT_STORE_REGISTER (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);
gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
buf = alloca (size);
- /* Write the register contents into the inferior a chunk at the time. */
+ /* Write the register contents into the inferior a chunk at a time. */
regcache_raw_collect (current_regcache, regnum, buf);
for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
{