aboutsummaryrefslogtreecommitdiff
path: root/gdb/remote.c
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2006-09-21 14:00:53 +0000
committerDaniel Jacobowitz <drow@false.org>2006-09-21 14:00:53 +0000
commita76d924dffcb040b44a2bb5be026f0c974590c30 (patch)
treea347bcb3680f48f5316b790bae5ff8a4105ccf96 /gdb/remote.c
parentfd79eceebf094938376c671ea3538a31d4f63eac (diff)
downloadgdb-a76d924dffcb040b44a2bb5be026f0c974590c30.zip
gdb-a76d924dffcb040b44a2bb5be026f0c974590c30.tar.gz
gdb-a76d924dffcb040b44a2bb5be026f0c974590c30.tar.bz2
* Makefile.in (SFILES): Add target-memory.c.
(COMMON_OBS): Add target-memory.o. * memattr.c (lookup_mem_region): Adjust handling for the top of memory. Improve comments. * remote.c (packet_check_result): New function, split out from packet_ok. Recognize "E." as an error prefix. (packet_ok): Use it. (remote_write_bytes_aux): New function, renamed from remote_write_bytes. Take packet header, packet format, and length flag as arguments. (remote_write_bytes): Rewrite to use remote_write_bytes_aux. (remote_send_printf, restore_remote_timeout) (remote_flash_timeout, remote_flash_erase, remote_flash_write) (remote_flash_done): New. (remote_xfer_partial): Handle flash writes. (init_remote_ops, init_remote_async_ops): Set to_flash_erase and to_flash_done. * symfile.c (struct load_section_data): Include a pointer to the cumulative stats and a request queue. Move most members to other types. (struct load_progress_data, struct load_progress_section_data): New types. (load_progress): Handle a NULL baton and zero bytes. Update for type changes. (load_section_callback): Create memory write requests instead of writing to memory. Don't print the progress message here. (clear_memory_write_data): New function. (generic_load): Use target_write_memory_blocks. * target-memory.c: New file. * target.c (update_current_target): Mention new uninherited methods. (memory_xfer_partial): Issue an error for flash writes. (target_flash_erase, target_flash_done): New functions. (target_write_with_progress): Call the progress callback at the start also. * target.h (enum target_object): Add TARGET_OBJECT_FLASH. (target_write_with_progress): Update comment. (struct target_ops): Add to_flash_erase and to_flash_done. (target_flash_erase, target_flash_done, struct memory_write_request) (memory_write_request_s, enum flash_preserve_mode) (target_write_memory_blocks): New, including a vector type for memory_write_request_s.
Diffstat (limited to 'gdb/remote.c')
-rw-r--r--gdb/remote.c324
1 files changed, 262 insertions, 62 deletions
diff --git a/gdb/remote.c b/gdb/remote.c
index e2716b5..d05be84 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -753,12 +753,42 @@ add_packet_config_cmd (struct packet_config *config, const char *name,
}
static enum packet_result
-packet_ok (const char *buf, struct packet_config *config)
+packet_check_result (const char *buf)
{
if (buf[0] != '\0')
{
/* The stub recognized the packet request. Check that the
operation succeeded. */
+ if (buf[0] == 'E'
+ && isxdigit (buf[1]) && isxdigit (buf[2])
+ && buf[3] == '\0')
+ /* "Enn" - definitly an error. */
+ return PACKET_ERROR;
+
+ /* Always treat "E." as an error. This will be used for
+ more verbose error messages, such as E.memtypes. */
+ if (buf[0] == 'E' && buf[1] == '.')
+ return PACKET_ERROR;
+
+ /* The packet may or may not be OK. Just assume it is. */
+ return PACKET_OK;
+ }
+ else
+ /* The stub does not support the packet. */
+ return PACKET_UNKNOWN;
+}
+
+static enum packet_result
+packet_ok (const char *buf, struct packet_config *config)
+{
+ enum packet_result result;
+
+ result = packet_check_result (buf);
+ switch (result)
+ {
+ case PACKET_OK:
+ case PACKET_ERROR:
+ /* The stub recognized the packet request. */
switch (config->support)
{
case PACKET_SUPPORT_UNKNOWN:
@@ -775,19 +805,8 @@ packet_ok (const char *buf, struct packet_config *config)
case PACKET_ENABLE:
break;
}
- if (buf[0] == 'O' && buf[1] == 'K' && buf[2] == '\0')
- /* "OK" - definitly OK. */
- return PACKET_OK;
- if (buf[0] == 'E'
- && isxdigit (buf[1]) && isxdigit (buf[2])
- && buf[3] == '\0')
- /* "Enn" - definitly an error. */
- return PACKET_ERROR;
- /* The packet may or may not be OK. Just assume it is. */
- return PACKET_OK;
- }
- else
- {
+ break;
+ case PACKET_UNKNOWN:
/* The stub does not support the packet. */
switch (config->support)
{
@@ -812,8 +831,10 @@ packet_ok (const char *buf, struct packet_config *config)
case PACKET_DISABLE:
break;
}
- return PACKET_UNKNOWN;
+ break;
}
+
+ return result;
}
enum {
@@ -3852,24 +3873,44 @@ check_binary_download (CORE_ADDR addr)
/* Write memory data directly to the remote machine.
This does not inform the data cache; the data cache uses this.
+ HEADER is the starting part of the packet.
MEMADDR is the address in the remote memory space.
MYADDR is the address of the buffer in our space.
LEN is the number of bytes.
+ PACKET_FORMAT should be either 'X' or 'M', and indicates if we
+ should send data as binary ('X'), or hex-encoded ('M').
+
+ The function creates packet of the form
+ <HEADER><ADDRESS>,<LENGTH>:<DATA>
+
+ where encoding of <DATA> is termined by PACKET_FORMAT.
+
+ If USE_LENGTH is 0, then the <LENGTH> field and the preceding comma
+ are omitted.
+
+ Returns the number of bytes transferred, or 0 (setting errno) for
Returns number of bytes transferred, or 0 (setting errno) for
error. Only transfer a single packet. */
-int
-remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+static int
+remote_write_bytes_aux (const char *header, CORE_ADDR memaddr,
+ const gdb_byte *myaddr, int len,
+ char packet_format, int use_length)
{
struct remote_state *rs = get_remote_state ();
char *p;
- char *plen;
- int plenlen;
+ char *plen = NULL;
+ int plenlen = 0;
int todo;
int nr_bytes;
int payload_size;
int payload_length;
+ int header_length;
+
+ if (packet_format != 'X' && packet_format != 'M')
+ internal_error (__FILE__, __LINE__,
+ "remote_write_bytes_aux: bad packet format");
/* Should this be the selected frame? */
gdbarch_remote_translate_xfer_address (current_gdbarch,
@@ -3880,47 +3921,46 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
if (len <= 0)
return 0;
- /* Verify that the target can support a binary download. */
- check_binary_download (memaddr);
-
payload_size = get_memory_write_packet_size ();
/* The packet buffer will be large enough for the payload;
get_memory_packet_size ensures this. */
+ rs->buf[0] = '\0';
/* Compute the size of the actual payload by subtracting out the
packet header and footer overhead: "$M<memaddr>,<len>:...#nn".
*/
- payload_size -= strlen ("$M,:#NN");
+ payload_size -= strlen ("$,:#NN");
+ if (!use_length)
+ /* The comma won't be used. */
+ payload_size += 1;
+ header_length = strlen (header);
+ payload_size -= header_length;
payload_size -= hexnumlen (memaddr);
- /* Construct the packet header: "[MX]<memaddr>,<len>:". */
+ /* Construct the packet excluding the data: "<header><memaddr>,<len>:". */
- /* Append "[XM]". Compute a best guess of the number of bytes
- actually transfered. */
- p = rs->buf;
- switch (remote_protocol_packets[PACKET_X].support)
+ strcat (rs->buf, header);
+ p = rs->buf + strlen (header);
+
+ /* Compute a best guess of the number of bytes actually transfered. */
+ if (packet_format == 'X')
{
- case PACKET_ENABLE:
- *p++ = 'X';
/* Best guess at number of bytes that will fit. */
todo = min (len, payload_size);
- payload_size -= hexnumlen (todo);
+ if (use_length)
+ payload_size -= hexnumlen (todo);
todo = min (todo, payload_size);
- break;
- case PACKET_DISABLE:
- *p++ = 'M';
+ }
+ else
+ {
/* Num bytes that will fit. */
todo = min (len, payload_size / 2);
- payload_size -= hexnumlen (todo);
+ if (use_length)
+ payload_size -= hexnumlen (todo);
todo = min (todo, payload_size / 2);
- break;
- case PACKET_SUPPORT_UNKNOWN:
- internal_error (__FILE__, __LINE__,
- _("remote_write_bytes: bad internal state"));
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
}
+
if (todo <= 0)
internal_error (__FILE__, __LINE__,
_("minumum packet size too small to write data"));
@@ -3934,23 +3974,25 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
memaddr = remote_address_masked (memaddr);
p += hexnumstr (p, (ULONGEST) memaddr);
- /* Append ",". */
- *p++ = ',';
+ if (use_length)
+ {
+ /* Append ",". */
+ *p++ = ',';
- /* Append <len>. Retain the location/size of <len>. It may need to
- be adjusted once the packet body has been created. */
- plen = p;
- plenlen = hexnumstr (p, (ULONGEST) todo);
- p += plenlen;
+ /* Append <len>. Retain the location/size of <len>. It may need to
+ be adjusted once the packet body has been created. */
+ plen = p;
+ plenlen = hexnumstr (p, (ULONGEST) todo);
+ p += plenlen;
+ }
/* Append ":". */
*p++ = ':';
*p = '\0';
/* Append the packet body. */
- switch (remote_protocol_packets[PACKET_X].support)
+ if (packet_format == 'X')
{
- case PACKET_ENABLE:
/* Binary mode. Send target system values byte by byte, in
increasing byte addresses. Only escape certain critical
characters. */
@@ -3972,7 +4014,7 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
}
p += payload_length;
- if (nr_bytes < todo)
+ if (use_length && nr_bytes < todo)
{
/* Escape chars have filled up the buffer prematurely,
and we have actually sent fewer bytes than planned.
@@ -3981,19 +4023,14 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
plen += hexnumnstr (plen, (ULONGEST) nr_bytes, plenlen);
*plen = ':'; /* overwrite \0 from hexnumnstr() */
}
- break;
- case PACKET_DISABLE:
+ }
+ else
+ {
/* Normal mode: Send target system values byte by byte, in
increasing byte addresses. Each byte is encoded as a two hex
value. */
nr_bytes = bin2hex (myaddr, p, todo);
p += 2 * nr_bytes;
- break;
- case PACKET_SUPPORT_UNKNOWN:
- internal_error (__FILE__, __LINE__,
- _("remote_write_bytes: bad internal state"));
- default:
- internal_error (__FILE__, __LINE__, _("bad switch"));
}
putpkt_binary (rs->buf, (int) (p - rs->buf));
@@ -4014,6 +4051,42 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
return nr_bytes;
}
+/* Write memory data directly to the remote machine.
+ This does not inform the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 (setting errno) for
+ error. Only transfer a single packet. */
+
+int
+remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+{
+ char *packet_format = 0;
+
+ /* Check whether the target supports binary download. */
+ check_binary_download (memaddr);
+
+ switch (remote_protocol_packets[PACKET_X].support)
+ {
+ case PACKET_ENABLE:
+ packet_format = "X";
+ break;
+ case PACKET_DISABLE:
+ packet_format = "M";
+ break;
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error (__FILE__, __LINE__,
+ _("remote_write_bytes: bad internal state"));
+ default:
+ internal_error (__FILE__, __LINE__, _("bad switch"));
+ }
+
+ return remote_write_bytes_aux (packet_format,
+ memaddr, myaddr, len, packet_format[0], 1);
+}
+
/* Read memory data directly from the remote machine.
This does not use the data cache; the data cache uses this.
MEMADDR is the address in the remote memory space.
@@ -4121,6 +4194,111 @@ remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
return res;
}
+/* Sends a packet with content determined by the printf format string
+ FORMAT and the remaining arguments, then gets the reply. Returns
+ whether the packet was a success, a failure, or unknown. */
+
+enum packet_result
+remote_send_printf (const char *format, ...)
+{
+ struct remote_state *rs = get_remote_state ();
+ int max_size = get_remote_packet_size ();
+
+ va_list ap;
+ va_start (ap, format);
+
+ rs->buf[0] = '\0';
+ if (vsnprintf (rs->buf, max_size, format, ap) >= max_size)
+ internal_error (__FILE__, __LINE__, "Too long remote packet.");
+
+ if (putpkt (rs->buf) < 0)
+ error (_("Communication problem with target."));
+
+ rs->buf[0] = '\0';
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ return packet_check_result (rs->buf);
+}
+
+static void
+restore_remote_timeout (void *p)
+{
+ int value = *(int *)p;
+ remote_timeout = value;
+}
+
+/* Flash writing can take quite some time. We'll set
+ effectively infinite timeout for flash operations.
+ In future, we'll need to decide on a better approach. */
+static const int remote_flash_timeout = 1000;
+
+static void
+remote_flash_erase (struct target_ops *ops,
+ ULONGEST address, LONGEST length)
+{
+ int saved_remote_timeout = remote_timeout;
+ enum packet_result ret;
+
+ struct cleanup *back_to = make_cleanup (restore_remote_timeout,
+ &saved_remote_timeout);
+ remote_timeout = remote_flash_timeout;
+
+ ret = remote_send_printf ("vFlashErase:%s,%s",
+ paddr (address),
+ phex (length, 4));
+ switch (ret)
+ {
+ case PACKET_UNKNOWN:
+ error (_("Remote target does not support flash erase"));
+ case PACKET_ERROR:
+ error (_("Error erasing flash with vFlashErase packet"));
+ default:
+ break;
+ }
+
+ do_cleanups (back_to);
+}
+
+static LONGEST
+remote_flash_write (struct target_ops *ops,
+ ULONGEST address, LONGEST length,
+ const gdb_byte *data)
+{
+ int saved_remote_timeout = remote_timeout;
+ int ret;
+ struct cleanup *back_to = make_cleanup (restore_remote_timeout,
+ &saved_remote_timeout);
+
+ remote_timeout = remote_flash_timeout;
+ ret = remote_write_bytes_aux ("vFlashWrite:", address, data, length, 'X', 0);
+ do_cleanups (back_to);
+
+ return ret;
+}
+
+static void
+remote_flash_done (struct target_ops *ops)
+{
+ int saved_remote_timeout = remote_timeout;
+ int ret;
+ struct cleanup *back_to = make_cleanup (restore_remote_timeout,
+ &saved_remote_timeout);
+
+ remote_timeout = remote_flash_timeout;
+ ret = remote_send_printf ("vFlashDone");
+ do_cleanups (back_to);
+
+ switch (ret)
+ {
+ case PACKET_UNKNOWN:
+ error (_("Remote target does not support vFlashDone"));
+ case PACKET_ERROR:
+ error (_("Error finishing flash operation"));
+ default:
+ break;
+ }
+}
+
static void
remote_files_info (struct target_ops *ignore)
{
@@ -5300,9 +5478,27 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
return -1;
}
- /* Only handle reads. */
- if (writebuf != NULL || readbuf == NULL)
- return -1;
+ /* Only handle flash writes. */
+ if (writebuf != NULL)
+ {
+ LONGEST xfered;
+
+ switch (object)
+ {
+ case TARGET_OBJECT_FLASH:
+ xfered = remote_flash_write (ops, offset, len, writebuf);
+
+ if (xfered > 0)
+ return xfered;
+ else if (xfered == 0 && errno == 0)
+ return 0;
+ else
+ return -1;
+
+ default:
+ return -1;
+ }
+ }
/* Map pre-existing objects onto letters. DO NOT do this for new
objects!!! Instead specify new query packets. */
@@ -5722,6 +5918,8 @@ Specify the serial device it is connected to\n\
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
remote_ops.to_magic = OPS_MAGIC;
remote_ops.to_memory_map = remote_memory_map;
+ remote_ops.to_flash_erase = remote_flash_erase;
+ remote_ops.to_flash_done = remote_flash_done;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -5852,6 +6050,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
remote_async_ops.to_async_mask_value = 1;
remote_async_ops.to_magic = OPS_MAGIC;
remote_async_ops.to_memory_map = remote_memory_map;
+ remote_async_ops.to_flash_erase = remote_flash_erase;
+ remote_async_ops.to_flash_done = remote_flash_done;
}
/* Set up the async extended remote vector by making a copy of the standard