/* Low-level child interface to ptrace.
- Copyright (C) 1988-2013 Free Software Foundation, Inc.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "regcache.h"
#include "gdb_assert.h"
-#include "gdb_string.h"
+#include <string.h>
#include "gdb_ptrace.h"
#include "gdb_wait.h"
#include <signal.h>
#ifdef PT_GET_PROCESS_STATE
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;
/* 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 = NULL;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
if (! ops_already_pushed)
{
/* Clear possible core file with its process_stratum. */
push_target (ops);
- back_to = make_cleanup_unpush_target (ops);
+ make_cleanup_unpush_target (ops);
}
pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
NULL, NULL, NULL);
- if (! ops_already_pushed)
- discard_cleanups (back_to);
+ 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
#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;
only report its exit status to its original parent. */
waitpid (ptid_get_pid (inferior_ptid), &status, 0);
- generic_mourn_inferior ();
-
- if (!have_inferiors ())
- unpush_target (ops);
+ 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 (struct target_ops *ops, char *args, int from_tty)
+inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
{
char *exec_file;
pid_t 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 = NULL;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
pid = parse_pid_to_attach (args);
/* target_pid_to_str already uses the target. Also clear possible core
file with its process_stratum. */
push_target (ops);
- back_to = make_cleanup_unpush_target (ops);
+ make_cleanup_unpush_target (ops);
}
if (from_tty)
target, it should decorate the ptid later with more info. */
add_thread_silent (inferior_ptid);
- if (! ops_already_pushed)
- discard_cleanups (back_to);
+ discard_cleanups (back_to);
}
#ifdef PT_GET_PROCESS_STATE
static void
-inf_ptrace_post_attach (int pid)
+inf_ptrace_post_attach (struct target_ops *self, int pid)
{
ptrace_event_t pe;
specified by ARGS. If FROM_TTY is non-zero, be chatty about it. */
static void
-inf_ptrace_detach (struct target_ops *ops, 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;
inferior_ptid = null_ptid;
detach_inferior (pid);
- if (!have_inferiors ())
- unpush_target (ops);
+ inf_child_maybe_unpush_target (ops);
}
/* Kill the inferior. */
/* Stop the inferior. */
static void
-inf_ptrace_stop (ptid_t ptid)
+inf_ptrace_stop (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
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);
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. */
(PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
buffer.word);
if (errno)
- return 0;
+ return TARGET_XFER_EOF;
}
}
(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:
#if defined (PT_IO) && defined (PIOD_READ_AUXV)
struct ptrace_io_desc piod;
if (writebuf)
- return -1;
+ return TARGET_XFER_E_IO;
piod.piod_op = PIOD_READ_AUXV;
piod.piod_addr = readbuf;
piod.piod_offs = (void *) (long) offset;
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;
+ }
}
#endif
- return -1;
+ return TARGET_XFER_E_IO;
case TARGET_OBJECT_WCOOKIE:
- return -1;
+ return TARGET_XFER_E_IO;
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
}