aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/inf-ptrace.c142
2 files changed, 77 insertions, 73 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 63d7441..2658d917 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2017-03-14 Andreas Arnez <arnez@linux.vnet.ibm.com>
+
+ PR gdb/21220
+ * inf-ptrace.c (inf_ptrace_xfer_partial): In "case
+ TARGET_OBJECT_MEMORY", extract the logic for ptrace peek/poke...
+ (inf_ptrace_peek_poke): ...here. New function. Now also loop
+ over ptrace peek/poke until end of buffer or error.
+
2017-03-14 Simon Marchi <simon.marchi@ericsson.com>
* parse.c (length_of_subexp): Make static.
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 21578742..32794ec 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -446,6 +446,72 @@ inf_ptrace_wait (struct target_ops *ops,
return pid_to_ptid (pid);
}
+/* Transfer data via ptrace into process PID's memory from WRITEBUF, or
+ from process PID's memory into READBUF. Start at target address ADDR
+ and transfer up to LEN bytes. Exactly one of READBUF and WRITEBUF must
+ be non-null. Return the number of transferred bytes. */
+
+static ULONGEST
+inf_ptrace_peek_poke (pid_t pid, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST addr, ULONGEST len)
+{
+ ULONGEST n;
+ unsigned int chunk;
+
+ /* We transfer aligned words. Thus align ADDR down to a word
+ boundary and determine how many bytes to skip at the
+ beginning. */
+ unsigned int skip = addr & (sizeof (PTRACE_TYPE_RET) - 1);
+ addr -= skip;
+
+ for (n = 0;
+ n < len;
+ n += chunk, addr += sizeof (PTRACE_TYPE_RET), skip = 0)
+ {
+ /* Restrict to a chunk that fits in the current word. */
+ chunk = std::min (sizeof (PTRACE_TYPE_RET) - skip, len - n);
+
+ /* Use a union for type punning. */
+ union
+ {
+ PTRACE_TYPE_RET word;
+ gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
+ } buf;
+
+ /* Read the word, also when doing a partial word write. */
+ if (readbuf != NULL || chunk < sizeof (PTRACE_TYPE_RET))
+ {
+ errno = 0;
+ buf.word = ptrace (PT_READ_I, pid,
+ (PTRACE_TYPE_ARG3)(uintptr_t) addr, 0);
+ if (errno != 0)
+ break;
+ if (readbuf != NULL)
+ memcpy (readbuf + n, buf.byte + skip, chunk);
+ }
+ if (writebuf != NULL)
+ {
+ memcpy (buf.byte + skip, writebuf + n, chunk);
+ errno = 0;
+ ptrace (PT_WRITE_D, pid, (PTRACE_TYPE_ARG3)(uintptr_t) addr,
+ buf.word);
+ if (errno != 0)
+ {
+ /* Using the appropriate one (I or D) is necessary for
+ Gould NP1, at least. */
+ errno = 0;
+ ptrace (PT_WRITE_I, pid, (PTRACE_TYPE_ARG3)(uintptr_t) addr,
+ buf.word);
+ if (errno != 0)
+ break;
+ }
+ }
+ }
+
+ return n;
+}
+
/* Implement the to_xfer_partial target_ops method. */
static enum target_xfer_status
@@ -491,79 +557,9 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
return TARGET_XFER_EOF;
}
#endif
- {
- union
- {
- PTRACE_TYPE_RET word;
- gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
- } buffer;
- ULONGEST rounded_offset;
- ULONGEST partial_len;
-
- /* Round the start offset down to the next long word
- boundary. */
- rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
-
- /* Since ptrace will transfer a single word starting at that
- rounded_offset the partial_len needs to be adjusted down to
- that (remember this function only does a single transfer).
- Should the required length be even less, adjust it down
- again. */
- partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset;
- if (partial_len > len)
- partial_len = len;
-
- if (writebuf)
- {
- /* If OFFSET:PARTIAL_LEN is smaller than
- ROUNDED_OFFSET:WORDSIZE then a read/modify write will
- be needed. Read in the entire word. */
- if (rounded_offset < offset
- || (offset + partial_len
- < rounded_offset + sizeof (PTRACE_TYPE_RET)))
- /* Need part of initial word -- fetch it. */
- buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)
- rounded_offset, 0);
-
- /* Copy data to be written over corresponding part of
- buffer. */
- memcpy (buffer.byte + (offset - rounded_offset),
- writebuf, partial_len);
-
- errno = 0;
- ptrace (PT_WRITE_D, pid,
- (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)(uintptr_t)rounded_offset,
- buffer.word);
- if (errno)
- return TARGET_XFER_EOF;
- }
- }
-
- if (readbuf)
- {
- errno = 0;
- buffer.word = ptrace (PT_READ_I, pid,
- (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
- 0);
- if (errno)
- return TARGET_XFER_EOF;
- /* Copy appropriate bytes out of the buffer. */
- memcpy (readbuf, buffer.byte + (offset - rounded_offset),
- partial_len);
- }
-
- *xfered_len = partial_len;
- return TARGET_XFER_OK;
- }
+ *xfered_len = inf_ptrace_peek_poke (pid, readbuf, writebuf,
+ offset, len);
+ return *xfered_len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
case TARGET_OBJECT_UNWIND_TABLE:
return TARGET_XFER_E_IO;