+/* Return non-zero when the target vector has supplied an xfer_partial
+ method and it, rather than xfer_memory, should be used. */
+static int
+target_xfer_partial_p (void)
+{
+ return (target_stack != NULL
+ && target_stack->to_xfer_partial != default_xfer_partial);
+}
+
+static LONGEST
+target_xfer_partial (struct target_ops *ops,
+ enum target_object object, const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ LONGEST retval;
+
+ gdb_assert (ops->to_xfer_partial != NULL);
+ retval = ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
+ offset, len);
+ if (targetdebug)
+ {
+ const unsigned char *myaddr = NULL;
+
+ fprintf_unfiltered (gdb_stdlog,
+ "%s:target_xfer_partial (%d, %s, 0x%lx, 0x%lx, 0x%s, %s) = %s",
+ ops->to_shortname,
+ (int) object,
+ (annex ? annex : "(null)"),
+ (long) readbuf, (long) writebuf,
+ paddr_nz (offset), paddr_d (len), paddr_d (retval));
+
+ if (readbuf)
+ myaddr = readbuf;
+ if (writebuf)
+ myaddr = writebuf;
+ if (retval > 0 && myaddr != NULL)
+ {
+ int i;
+
+ fputs_unfiltered (", bytes =", gdb_stdlog);
+ for (i = 0; i < retval; i++)
+ {
+ if ((((long) &(myaddr[i])) & 0xf) == 0)
+ {
+ if (targetdebug < 2 && i > 0)
+ {
+ fprintf_unfiltered (gdb_stdlog, " ...");
+ break;
+ }
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ fprintf_unfiltered (gdb_stdlog, " %02x", myaddr[i] & 0xff);
+ }
+ }
+
+ fputc_unfiltered ('\n', gdb_stdlog);
+ }
+ return retval;
+}
+
+/* Attempt a transfer all LEN bytes starting at OFFSET between the
+ inferior's KIND:ANNEX space and GDB's READBUF/WRITEBUF buffer. If
+ the transfer succeeds, return zero, otherwize the host ERRNO is
+ returned.
+
+ The inferior is formed from several layers. In the case of
+ corefiles, inf-corefile is layered above inf-exec and a request for
+ text (corefiles do not include text pages) will be first sent to
+ the core-stratum, fail, and then sent to the object-file where it
+ will succeed.
+
+ NOTE: cagney/2004-09-30:
+
+ The old code tried to use four separate mechanisms for mapping an
+ object:offset:len tuple onto an inferior and its address space: the
+ target stack; the inferior's TO_SECTIONS; solib's SO_LIST;
+ overlays.
+
+ This is stupid.
+
+ The code below is instead using a single mechanism (currently
+ strata). If that mechanism proves insufficient then re-factor it
+ implementing another singluar mechanism (for instance, a generic
+ object:annex onto inferior:object:annex say). */
+
+static LONGEST
+xfer_using_stratum (enum target_object object, const char *annex,
+ ULONGEST offset, LONGEST len, void *readbuf,
+ const void *writebuf)
+{
+ LONGEST xfered;
+ struct target_ops *target;
+
+ /* Always successful. */
+ if (len == 0)
+ return 0;
+ /* Never successful. */
+ if (target_stack == NULL)
+ return EIO;
+
+ target = target_stack;
+ while (1)
+ {
+ xfered = target_xfer_partial (target, object, annex,
+ readbuf, writebuf, offset, len);
+ if (xfered > 0)
+ {
+ /* The partial xfer succeeded, update the counts, check that
+ the xfer hasn't finished and if it hasn't set things up
+ for the next round. */
+ len -= xfered;
+ if (len <= 0)
+ return 0;
+ offset += xfered;
+ if (readbuf != NULL)
+ readbuf = (bfd_byte *) readbuf + xfered;
+ if (writebuf != NULL)
+ writebuf = (bfd_byte *) writebuf + xfered;
+ target = target_stack;
+ }
+ else if (xfered < 0)
+ {
+ /* Something totally screwed up, abandon the attempt to
+ xfer. */
+ if (errno)
+ return errno;
+ else
+ return EIO;
+ }
+ else
+ {
+ /* This "stratum" didn't work, try the next one down. */
+ target = target->beneath;
+ if (target == NULL)
+ return EIO;
+ }
+ }
+}
+