unsigned long write_count;
unsigned long data_count;
bfd_size_type total_size;
+
+ /* Per-section data for load_progress. */
+ const char *section_name;
+ ULONGEST section_sent;
+ ULONGEST section_size;
+ CORE_ADDR lma;
+ gdb_byte *buffer;
};
+/* Target write callback routine for load_section_callback. */
+
+static void
+load_progress (ULONGEST bytes, void *untyped_arg)
+{
+ struct load_section_data *args = untyped_arg;
+
+ if (validate_download)
+ {
+ /* Broken memories and broken monitors manifest themselves here
+ when bring new computers to life. This doubles already slow
+ downloads. */
+ /* NOTE: cagney/1999-10-18: A more efficient implementation
+ might add a verify_memory() method to the target vector and
+ then use that. remote.c could implement that method using
+ the ``qCRC'' packet. */
+ gdb_byte *check = xmalloc (bytes);
+ struct cleanup *verify_cleanups = make_cleanup (xfree, check);
+
+ if (target_read_memory (args->lma, check, bytes) != 0)
+ error (_("Download verify read failed at 0x%s"),
+ paddr (args->lma));
+ if (memcmp (args->buffer, check, bytes) != 0)
+ error (_("Download verify compare failed at 0x%s"),
+ paddr (args->lma));
+ do_cleanups (verify_cleanups);
+ }
+ args->data_count += bytes;
+ args->lma += bytes;
+ args->buffer += bytes;
+ args->write_count += 1;
+ args->section_sent += bytes;
+ if (quit_flag
+ || (deprecated_ui_load_progress_hook != NULL
+ && deprecated_ui_load_progress_hook (args->section_name,
+ args->section_sent)))
+ error (_("Canceled the download"));
+
+ if (deprecated_show_load_progress != NULL)
+ deprecated_show_load_progress (args->section_name,
+ args->section_sent,
+ args->section_size,
+ args->data_count,
+ args->total_size);
+}
+
/* Callback service function for generic_load (bfd_map_over_sections). */
static void
load_section_callback (bfd *abfd, asection *asec, void *data)
{
struct load_section_data *args = data;
+ bfd_size_type size = bfd_get_section_size (asec);
+ gdb_byte *buffer;
+ struct cleanup *old_chain;
+ const char *sect_name = bfd_get_section_name (abfd, asec);
+ LONGEST transferred;
- if (bfd_get_section_flags (abfd, asec) & SEC_LOAD)
- {
- bfd_size_type size = bfd_get_section_size (asec);
- if (size > 0)
- {
- gdb_byte *buffer;
- struct cleanup *old_chain;
- CORE_ADDR lma = bfd_section_lma (abfd, asec) + args->load_offset;
- bfd_size_type block_size;
- int err;
- const char *sect_name = bfd_get_section_name (abfd, asec);
- bfd_size_type sent;
-
- buffer = xmalloc (size);
- old_chain = make_cleanup (xfree, buffer);
-
- /* Is this really necessary? I guess it gives the user something
- to look at during a long download. */
- ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
- sect_name, paddr_nz (size), paddr_nz (lma));
-
- bfd_get_section_contents (abfd, asec, buffer, 0, size);
-
- sent = 0;
- do
- {
- int len;
- bfd_size_type this_transfer = size - sent;
-
- len = target_write_memory_partial (lma, buffer,
- this_transfer, &err);
- if (err)
- break;
- if (validate_download)
- {
- /* Broken memories and broken monitors manifest
- themselves here when bring new computers to
- life. This doubles already slow downloads. */
- /* NOTE: cagney/1999-10-18: A more efficient
- implementation might add a verify_memory()
- method to the target vector and then use
- that. remote.c could implement that method
- using the ``qCRC'' packet. */
- gdb_byte *check = xmalloc (len);
- struct cleanup *verify_cleanups =
- make_cleanup (xfree, check);
-
- if (target_read_memory (lma, check, len) != 0)
- error (_("Download verify read failed at 0x%s"),
- paddr (lma));
- if (memcmp (buffer, check, len) != 0)
- error (_("Download verify compare failed at 0x%s"),
- paddr (lma));
- do_cleanups (verify_cleanups);
- }
- args->data_count += len;
- lma += len;
- buffer += len;
- args->write_count += 1;
- sent += len;
- if (quit_flag
- || (deprecated_ui_load_progress_hook != NULL
- && deprecated_ui_load_progress_hook (sect_name, sent)))
- error (_("Canceled the download"));
-
- if (deprecated_show_load_progress != NULL)
- deprecated_show_load_progress (sect_name, sent, size,
- args->data_count,
- args->total_size);
- }
- while (sent < size);
+ if ((bfd_get_section_flags (abfd, asec) & SEC_LOAD) == 0)
+ return;
- if (err != 0)
- error (_("Memory access error while loading section %s."), sect_name);
+ if (size == 0)
+ return;
- do_cleanups (old_chain);
- }
- }
+ buffer = xmalloc (size);
+ old_chain = make_cleanup (xfree, buffer);
+
+ args->section_name = sect_name;
+ args->section_sent = 0;
+ args->section_size = size;
+ args->lma = bfd_section_lma (abfd, asec) + args->load_offset;
+ args->buffer = buffer;
+
+ /* Is this really necessary? I guess it gives the user something
+ to look at during a long download. */
+ ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n",
+ sect_name, paddr_nz (size), paddr_nz (args->lma));
+
+ bfd_get_section_contents (abfd, asec, buffer, 0, size);
+
+ transferred = target_write_with_progress (¤t_target,
+ TARGET_OBJECT_MEMORY,
+ NULL, buffer, args->lma,
+ size, load_progress, args);
+ if (transferred < size)
+ error (_("Memory access error while loading section %s."),
+ sect_name);
+
+ do_cleanups (old_chain);
}
void
const gdb_byte *writebuf,
ULONGEST offset, LONGEST len);
-/* Transfer LEN bytes between target address MEMADDR and GDB address
- MYADDR. Returns 0 for success, errno code for failure (which
- includes partial transfers -- if you want a more useful response to
- partial transfers, try either target_read_memory_partial or
- target_write_memory_partial). */
+static LONGEST current_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len);
-static int target_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
- int write);
+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);
static void init_dummy_target (void);
int attach_flag;
+/* Nonzero if we should trust readonly sections from the
+ executable when reading memory. */
+
+static int trust_readonly = 0;
+
/* Non-zero if we want to see trace of target level stuff. */
static int targetdebug = 0;
de_fault (to_stop,
(void (*) (void))
target_ignore);
- current_target.to_xfer_partial = default_xfer_partial;
+ current_target.to_xfer_partial = current_xfer_partial;
de_fault (to_rcmd,
(void (*) (char *, struct ui_file *))
tcomplain);
return NULL;
}
-/* 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)
+/* Perform a partial memory transfer. The arguments and return
+ value are just as for target_xfer_partial. */
+
+static LONGEST
+memory_xfer_partial (struct target_ops *ops, void *readbuf, const void *writebuf,
+ ULONGEST memaddr, LONGEST len)
{
- return (target_stack != NULL
- && target_stack->to_xfer_partial != default_xfer_partial);
+ LONGEST res;
+ int reg_len;
+ struct mem_region *region;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ return 0;
+
+ /* Try the executable file, if "trust-readonly-sections" is set. */
+ if (readbuf != NULL && trust_readonly)
+ {
+ struct section_table *secp;
+
+ secp = target_section_by_addr (ops, memaddr);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ return xfer_memory (memaddr, readbuf, len, 0, NULL, ops);
+ }
+
+ /* Try GDB's internal data cache. */
+ region = lookup_mem_region (memaddr);
+ if (memaddr + len < region->hi)
+ reg_len = len;
+ else
+ reg_len = region->hi - memaddr;
+
+ switch (region->attrib.mode)
+ {
+ case MEM_RO:
+ if (writebuf != NULL)
+ return -1;
+ break;
+
+ case MEM_WO:
+ if (readbuf != NULL)
+ return -1;
+ break;
+ }
+
+ if (region->attrib.cache)
+ {
+ /* FIXME drow/2006-08-09: This call discards OPS, so the raw
+ memory request will start back at current_target. */
+ if (readbuf != NULL)
+ res = dcache_xfer_memory (target_dcache, memaddr, readbuf,
+ reg_len, 0);
+ else
+ /* FIXME drow/2006-08-09: If we're going to preserve const
+ correctness dcache_xfer_memory should take readbuf and
+ writebuf. */
+ res = dcache_xfer_memory (target_dcache, memaddr,
+ (void *) writebuf,
+ reg_len, 1);
+ if (res <= 0)
+ return -1;
+ else
+ return res;
+ }
+
+ /* If none of those methods found the memory we wanted, fall back
+ to a target partial transfer. Normally a single call to
+ to_xfer_partial is enough; if it doesn't recognize an object
+ it will call the to_xfer_partial of the next target down.
+ But for memory this won't do. Memory is the only target
+ object which can be read from more than one valid target.
+ A core file, for instance, could have some of memory but
+ delegate other bits to the target below it. So, we must
+ manually try all targets. */
+
+ do
+ {
+ res = ops->to_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL,
+ readbuf, writebuf, memaddr, len);
+ if (res > 0)
+ return res;
+
+ ops = ops->beneath;
+ }
+ while (ops != NULL);
+
+ /* If we still haven't got anything, return the last error. We
+ give up. */
+ return res;
}
static LONGEST
LONGEST retval;
gdb_assert (ops->to_xfer_partial != NULL);
- retval = ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
- offset, len);
+
+ /* If this is a memory transfer, let the memory-specific code
+ have a look at it instead. Memory transfers are more
+ complicated. */
+ if (object == TARGET_OBJECT_MEMORY)
+ retval = memory_xfer_partial (ops, readbuf, writebuf, offset, len);
+ else
+ {
+ enum target_object raw_object = object;
+
+ /* If this is a raw memory transfer, request the normal
+ memory object from other layers. */
+ if (raw_object == TARGET_OBJECT_RAW_MEMORY)
+ raw_object = TARGET_OBJECT_MEMORY;
+
+ retval = ops->to_xfer_partial (ops, raw_object, annex, readbuf,
+ writebuf, offset, len);
+ }
+
if (targetdebug)
{
const unsigned char *myaddr = NULL;
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 = (gdb_byte *) readbuf + xfered;
- if (writebuf != NULL)
- writebuf = (gdb_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;
- }
- }
-}
-
/* Read LEN bytes of target memory at address MEMADDR, placing the results in
GDB's memory at MYADDR. Returns either 0 for success or an errno value
if any error occurs.
MYADDR. In particular, the caller should not depend upon partial reads
filling the buffer with good data. There is no way for the caller to know
how much good data might have been transfered anyway. Callers that can
- deal with partial reads should call target_read_memory_partial. */
+ deal with partial reads should call target_read (which will retry until
+ it makes no progress, and then return how much was transferred). */
int
target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
- if (target_xfer_partial_p ())
- return xfer_using_stratum (TARGET_OBJECT_MEMORY, NULL,
- memaddr, len, myaddr, NULL);
+ if (target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
else
- return target_xfer_memory (memaddr, myaddr, len, 0);
+ return EIO;
}
int
target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
{
- gdb_byte *bytes = alloca (len);
- memcpy (bytes, myaddr, len);
- if (target_xfer_partial_p ())
- return xfer_using_stratum (TARGET_OBJECT_MEMORY, NULL,
- memaddr, len, NULL, bytes);
+ if (target_write (¤t_target, TARGET_OBJECT_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
else
- return target_xfer_memory (memaddr, bytes, len, 1);
+ return EIO;
}
#ifndef target_stopped_data_address_p
}
#endif
-static int trust_readonly = 0;
static void
show_trust_readonly (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
value);
}
-/* Move memory to or from the targets. The top target gets priority;
- if it cannot handle it, it is offered to the next one down, etc.
-
- Result is -1 on error, or the number of bytes transfered. */
-
-int
-do_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
- struct mem_attrib *attrib)
-{
- int res;
- int done = 0;
- struct target_ops *t;
-
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- return 0;
-
- /* deprecated_xfer_memory is not guaranteed to set errno, even when
- it returns 0. */
- errno = 0;
-
- if (!write && trust_readonly)
- {
- struct section_table *secp;
- /* User-settable option, "trust-readonly-sections". If true,
- then memory from any SEC_READONLY bfd section may be read
- directly from the bfd file. */
- secp = target_section_by_addr (¤t_target, memaddr);
- if (secp != NULL
- && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
- & SEC_READONLY))
- return xfer_memory (memaddr, myaddr, len, 0, attrib, ¤t_target);
- }
-
- /* The quick case is that the top target can handle the transfer. */
- res = current_target.deprecated_xfer_memory
- (memaddr, myaddr, len, write, attrib, ¤t_target);
-
- /* If res <= 0 then we call it again in the loop. Ah well. */
- if (res <= 0)
- {
- for (t = target_stack; t != NULL; t = t->beneath)
- {
- if (!t->to_has_memory)
- continue;
-
- res = t->deprecated_xfer_memory (memaddr, myaddr, len, write, attrib, t);
- if (res > 0)
- break; /* Handled all or part of xfer */
- if (t->to_has_all_memory)
- break;
- }
-
- if (res <= 0)
- return -1;
- }
-
- return res;
-}
-
-
-/* Perform a memory transfer. Iterate until the entire region has
- been transfered.
-
- Result is 0 or errno value. */
-
-static int
-target_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write)
-{
- int res;
- int reg_len;
- struct mem_region *region;
-
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- {
- return 0;
- }
-
- while (len > 0)
- {
- region = lookup_mem_region(memaddr);
- if (memaddr + len < region->hi)
- reg_len = len;
- else
- reg_len = region->hi - memaddr;
-
- switch (region->attrib.mode)
- {
- case MEM_RO:
- if (write)
- return EIO;
- break;
-
- case MEM_WO:
- if (!write)
- return EIO;
- break;
- }
-
- while (reg_len > 0)
- {
- if (region->attrib.cache)
- res = dcache_xfer_memory (target_dcache, memaddr, myaddr,
- reg_len, write);
- else
- res = do_xfer_memory (memaddr, myaddr, reg_len, write,
- ®ion->attrib);
-
- if (res <= 0)
- {
- /* If this address is for nonexistent memory, read zeros
- if reading, or do nothing if writing. Return
- error. */
- if (!write)
- memset (myaddr, 0, len);
- if (errno == 0)
- return EIO;
- else
- return errno;
- }
-
- memaddr += res;
- myaddr += res;
- len -= res;
- reg_len -= res;
- }
- }
-
- return 0; /* We managed to cover it all somehow. */
-}
-
-
-/* Perform a partial memory transfer.
-
- If we succeed, set *ERR to zero and return the number of bytes transferred.
- If we fail, set *ERR to a non-zero errno value, and return -1. */
-
-static int
-target_xfer_memory_partial (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
- int write_p, int *err)
-{
- int res;
- int reg_len;
- struct mem_region *region;
-
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- {
- *err = 0;
- return 0;
- }
-
- region = lookup_mem_region(memaddr);
- if (memaddr + len < region->hi)
- reg_len = len;
- else
- reg_len = region->hi - memaddr;
-
- switch (region->attrib.mode)
- {
- case MEM_RO:
- if (write_p)
- {
- *err = EIO;
- return -1;
- }
- break;
-
- case MEM_WO:
- if (write_p)
- {
- *err = EIO;
- return -1;
- }
- break;
- }
-
- if (region->attrib.cache)
- res = dcache_xfer_memory (target_dcache, memaddr, myaddr,
- reg_len, write_p);
- else
- res = do_xfer_memory (memaddr, myaddr, reg_len, write_p,
- ®ion->attrib);
-
- if (res <= 0)
- {
- if (errno != 0)
- *err = errno;
- else
- *err = EIO;
-
- return -1;
- }
-
- *err = 0;
- return res;
-}
-
-int
-target_read_memory_partial (CORE_ADDR memaddr, gdb_byte *buf,
- int len, int *err)
-{
- if (target_xfer_partial_p ())
- {
- int retval;
-
- retval = target_xfer_partial (target_stack, TARGET_OBJECT_MEMORY,
- NULL, buf, NULL, memaddr, len);
-
- if (retval <= 0)
- {
- if (errno)
- *err = errno;
- else
- *err = EIO;
- return -1;
- }
- else
- {
- *err = 0;
- return retval;
- }
- }
- else
- return target_xfer_memory_partial (memaddr, buf, len, 0, err);
-}
-
-int
-target_write_memory_partial (CORE_ADDR memaddr, gdb_byte *buf,
- int len, int *err)
-{
- if (target_xfer_partial_p ())
- {
- int retval;
-
- retval = target_xfer_partial (target_stack, TARGET_OBJECT_MEMORY,
- NULL, NULL, buf, memaddr, len);
-
- if (retval <= 0)
- {
- if (errno)
- *err = errno;
- else
- *err = EIO;
- return -1;
- }
- else
- {
- *err = 0;
- return retval;
- }
- }
- else
- return target_xfer_memory_partial (memaddr, buf, len, 1, err);
-}
-
/* More generic transfers. */
static LONGEST
return -1;
}
else if (ops->beneath != NULL)
- return target_xfer_partial (ops->beneath, object, annex,
- readbuf, writebuf, offset, len);
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ else
+ return -1;
+}
+
+/* The xfer_partial handler for the topmost target. Unlike the default,
+ it does not need to handle memory specially; it just passes all
+ requests down the stack. */
+
+static LONGEST
+current_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
else
return -1;
}
return len;
}
+/* An alternative to target_write with progress callbacks. */
+
LONGEST
-target_write (struct target_ops *ops,
- enum target_object object,
- const char *annex, const gdb_byte *buf,
- ULONGEST offset, LONGEST len)
+target_write_with_progress (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const gdb_byte *buf,
+ ULONGEST offset, LONGEST len,
+ void (*progress) (ULONGEST, void *), void *baton)
{
LONGEST xfered = 0;
while (xfered < len)
LONGEST xfer = target_write_partial (ops, object, annex,
(gdb_byte *) buf + xfered,
offset + xfered, len - xfered);
- /* Call an observer, notifying them of the xfer progress? */
+
if (xfer == 0)
return xfered;
if (xfer < 0)
return -1;
+
+ if (progress)
+ (*progress) (xfer, baton);
+
xfered += xfer;
QUIT;
}
return len;
}
+LONGEST
+target_write (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, const gdb_byte *buf,
+ ULONGEST offset, LONGEST len)
+{
+ return target_write_with_progress (ops, object, annex, buf, offset, len,
+ NULL, NULL);
+}
+
/* Read OBJECT/ANNEX using OPS. Store the result in *BUF_P and return
the size of the transferred data. PADDING additional bytes are
available in *BUF_P. This is a helper function for