+ 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. */
+ ULONGEST 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. */
+
+enum target_xfer_status
+inf_ptrace_target::xfer_partial (enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
+{
+ pid_t pid = get_ptrace_pid (inferior_ptid);