#include "remote-fileio.h"
+/* The size to align memory write packets, when practical. The protocol
+ does not guarantee any alignment, and gdb will generate short
+ writes and unaligned writes, but even as a best-effort attempt this
+ can improve bulk transfers. For instance, if a write is misaligned
+ relative to the target's data bus, the stub may need to make an extra
+ round trip fetching data from the target. This doesn't make a
+ huge difference, but it's easy to do, so we try to be helpful.
+
+ The alignment chosen is arbitrary; usually data bus width is
+ important here, not the possibly larger cache line size. */
+enum { REMOTE_ALIGN_WRITES = 16 };
+
/* Prototypes for local functions. */
static void cleanup_sigint_signal_handler (void *dummy);
static void initialize_sigint_signal_handler (void);
long regnum; /* GDB's internal register number. */
LONGEST pnum; /* Remote protocol register number. */
int in_g_packet; /* Always part of G packet. */
- /* long size in bytes; == register_size (current_gdbarch, regnum);
+ /* long size in bytes; == register_size (current_gdbarch, regnum);
at present. */
/* char *name; == REGISTER_NAME (regnum); at present. */
};
if (rs->buf_size < rsa->remote_packet_size)
{
rs->buf_size = 2 * rsa->remote_packet_size;
- rs->buf = xmalloc (rs->buf_size);
+ rs->buf = xrealloc (rs->buf, rs->buf_size);
}
return rsa;
PACKET_Z2,
PACKET_Z3,
PACKET_Z4,
- PACKET_qPart_auxv,
+ PACKET_qXfer_auxv,
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_MAX
struct gdb_ext_thread_info
{
threadref threadid; /* External form of thread reference. */
- int active; /* Has state interesting to GDB?
+ int active; /* Has state interesting to GDB?
regs, stack. */
- char display[256]; /* Brief state display, name,
+ char display[256]; /* Brief state display, name,
blocked/suspended. */
char shortname[32]; /* To be used to name threads. */
- char more_display[256]; /* Long info, statistics, queue depth,
+ char more_display[256]; /* Long info, statistics, queue depth,
whatever. */
};
static int threadmatch (threadref *dest, threadref *src);
-static char *pack_threadinfo_request (char *pkt, int mode,
+static char *pack_threadinfo_request (char *pkt, int mode,
threadref *id);
static int remote_unpack_thread_info_response (char *pkt,
*info);
-static int remote_get_threadinfo (threadref *threadid,
+static int remote_get_threadinfo (threadref *threadid,
int fieldset, /*TAG mask */
struct gdb_ext_thread_info *info);
static int parse_threadlist_response (char *pkt,
int result_limit,
threadref *original_echo,
- threadref *resultlist,
+ threadref *resultlist,
int *doneflag);
static int remote_get_threadlist (int startflag,
threadref *nextthread,
int result_limit,
int *done,
- int *result_count,
+ int *result_count,
threadref *threadlist);
typedef int (*rmt_thread_action) (threadref *ref, void *context);
ULONGEST *result)
{
int nibble;
- int retval = 0;
+ ULONGEST retval = 0;
while (ishex (*buff, &nibble))
{
if (threadinfo.active)
{
if (*threadinfo.shortname)
- n += xsnprintf (&display_buf[0], sizeof (display_buf) - n,
+ n += xsnprintf (&display_buf[0], sizeof (display_buf) - n,
" Name: %s,", threadinfo.shortname);
if (*threadinfo.display)
- n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
+ n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
" State: %s,", threadinfo.display);
if (*threadinfo.more_display)
- n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
+ n += xsnprintf (&display_buf[n], sizeof (display_buf) - n,
" Priority: %s", threadinfo.more_display);
if (n > 0)
putpkt (rs->buf);
remote_fileio_reset ();
-
+
/* Now query for status so this looks just like we restarted
gdbserver from scratch. */
putpkt ("?");
int packet;
};
-#if 0
static void
remote_supported_packet (const struct protocol_feature *feature,
enum packet_support support,
== PACKET_SUPPORT_UNKNOWN)
remote_protocol_packets[feature->packet].support = support;
}
-#endif
static void
remote_packet_size (const struct protocol_feature *feature,
}
static struct protocol_feature remote_protocol_features[] = {
- { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 }
+ { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
+ { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_auxv }
};
static void
{
signal (SIGINT, handle_sigint);
if (sigint_remote_twice_token)
- delete_async_signal_handler ((struct async_signal_handler **)
+ delete_async_signal_handler ((struct async_signal_handler **)
&sigint_remote_twice_token);
if (sigint_remote_token)
- delete_async_signal_handler ((struct async_signal_handler **)
+ delete_async_signal_handler ((struct async_signal_handler **)
&sigint_remote_token);
}
phex_nz (pnum, 0), p, buf);
fieldsize = hex2bin (p, regs,
- register_size (current_gdbarch,
+ register_size (current_gdbarch,
reg->regnum));
p += 2 * fieldsize;
- if (fieldsize < register_size (current_gdbarch,
+ if (fieldsize < register_size (current_gdbarch,
reg->regnum))
warning (_("Remote reply is too short: %s"), buf);
- regcache_raw_supply (current_regcache,
+ regcache_raw_supply (current_regcache,
reg->regnum, regs);
}
if (*p++ != ';')
- error (_("Remote register badly formatted: %s\nhere: %s"),
+ error (_("Remote register badly formatted: %s\nhere: %s"),
buf, p);
}
}
pnum, p, buf);
fieldsize = hex2bin (p, regs,
- register_size (current_gdbarch,
+ register_size (current_gdbarch,
reg->regnum));
p += 2 * fieldsize;
- if (fieldsize < register_size (current_gdbarch,
+ if (fieldsize < register_size (current_gdbarch,
reg->regnum))
warning (_("Remote reply is too short: %s"), buf);
regcache_raw_supply (current_regcache, reg->regnum, regs);
return addr;
}
+/* Convert BUFFER, binary data at least LEN bytes long, into escaped
+ binary data in OUT_BUF. Set *OUT_LEN to the length of the data
+ encoded in OUT_BUF, and return the number of bytes in OUT_BUF
+ (which may be more than *OUT_LEN due to escape characters). The
+ total number of bytes in the output buffer will be at most
+ OUT_MAXLEN. */
+
+static int
+remote_escape_output (const gdb_byte *buffer, int len,
+ gdb_byte *out_buf, int *out_len,
+ int out_maxlen)
+{
+ int input_index, output_index;
+
+ output_index = 0;
+ for (input_index = 0; input_index < len; input_index++)
+ {
+ gdb_byte b = buffer[input_index];
+
+ if (b == '$' || b == '#' || b == '}')
+ {
+ /* These must be escaped. */
+ if (output_index + 2 > out_maxlen)
+ break;
+ out_buf[output_index++] = '}';
+ out_buf[output_index++] = b ^ 0x20;
+ }
+ else
+ {
+ if (output_index + 1 > out_maxlen)
+ break;
+ out_buf[output_index++] = b;
+ }
+ }
+
+ *out_len = input_index;
+ return output_index;
+}
+
+/* Convert BUFFER, escaped data LEN bytes long, into binary data
+ in OUT_BUF. Return the number of bytes written to OUT_BUF.
+ Raise an error if the total number of bytes exceeds OUT_MAXLEN.
+
+ This function reverses remote_escape_output. It allows more
+ escaped characters than that function does, in particular because
+ '*' must be escaped to avoid the run-length encoding processing
+ in reading packets. */
+
+static int
+remote_unescape_input (const gdb_byte *buffer, int len,
+ gdb_byte *out_buf, int out_maxlen)
+{
+ int input_index, output_index;
+ int escaped;
+
+ output_index = 0;
+ escaped = 0;
+ for (input_index = 0; input_index < len; input_index++)
+ {
+ gdb_byte b = buffer[input_index];
+
+ if (output_index + 1 > out_maxlen)
+ {
+ warning (_("Received too much data from remote target;"
+ " ignoring overflow."));
+ return output_index;
+ }
+
+ if (escaped)
+ {
+ out_buf[output_index++] = b ^ 0x20;
+ escaped = 0;
+ }
+ else if (b == '}')
+ escaped = 1;
+ else
+ out_buf[output_index++] = b;
+ }
+
+ if (escaped)
+ error (_("Unmatched escape character in target response."));
+
+ return output_index;
+}
+
/* Determine whether the remote target supports binary downloading.
This is accomplished by sending a no-op memory write of zero length
to the target at the specified address. It does not suffice to send
error. Only transfer a single packet. */
int
-remote_write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
{
struct remote_state *rs = get_remote_state ();
char *buf;
int todo;
int nr_bytes;
int payload_size;
- char *payload_start;
+ int payload_length;
+
+ /* Should this be the selected frame? */
+ gdbarch_remote_translate_xfer_address (current_gdbarch,
+ current_regcache,
+ memaddr, len,
+ &memaddr, &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. */
buf = rs->buf;
internal_error (__FILE__, __LINE__,
_("minumum packet size too small to write data"));
+ /* If we already need another packet, then try to align the end
+ of this packet to a useful boundary. */
+ if (todo > 2 * REMOTE_ALIGN_WRITES && todo < len)
+ todo = ((memaddr + todo) & ~(REMOTE_ALIGN_WRITES - 1)) - memaddr;
+
/* Append "<memaddr>". */
memaddr = remote_address_masked (memaddr);
p += hexnumstr (p, (ULONGEST) memaddr);
*p = '\0';
/* Append the packet body. */
- payload_start = p;
switch (remote_protocol_packets[PACKET_X].support)
{
case PACKET_ENABLE:
/* Binary mode. Send target system values byte by byte, in
increasing byte addresses. Only escape certain critical
characters. */
- for (nr_bytes = 0;
- (nr_bytes < todo) && (p - payload_start) < payload_size;
- nr_bytes++)
+ payload_length = remote_escape_output (myaddr, todo, p, &nr_bytes,
+ payload_size);
+
+ /* If not all TODO bytes fit, then we'll need another packet. Make
+ a second try to keep the end of the packet aligned. */
+ if (nr_bytes < todo)
{
- switch (myaddr[nr_bytes] & 0xff)
- {
- case '$':
- case '#':
- case 0x7d:
- /* These must be escaped. */
- *p++ = 0x7d;
- *p++ = (myaddr[nr_bytes] & 0xff) ^ 0x20;
- break;
- default:
- *p++ = myaddr[nr_bytes] & 0xff;
- break;
- }
+ int new_nr_bytes;
+
+ new_nr_bytes = (((memaddr + nr_bytes) & ~(REMOTE_ALIGN_WRITES - 1))
+ - memaddr);
+ if (new_nr_bytes != nr_bytes)
+ payload_length = remote_escape_output (myaddr, new_nr_bytes,
+ p, &nr_bytes,
+ payload_size);
}
+
+ p += payload_length;
if (nr_bytes < todo)
{
/* Escape chars have filled up the buffer prematurely,
int max_buf_size; /* Max size of packet output buffer. */
int origlen;
+ /* Should this be the selected frame? */
+ gdbarch_remote_translate_xfer_address (current_gdbarch,
+ current_regcache,
+ memaddr, len,
+ &memaddr, &len);
+
+ if (len <= 0)
+ return 0;
+
max_buf_size = get_memory_read_packet_size ();
/* The packet buffer will be large enough for the payload;
get_memory_packet_size ensures this. */
int should_write, struct mem_attrib *attrib,
struct target_ops *target)
{
- CORE_ADDR targ_addr;
- int targ_len;
int res;
- /* Should this be the selected frame? */
- gdbarch_remote_translate_xfer_address (current_gdbarch,
- current_regcache,
- mem_addr, mem_len,
- &targ_addr, &targ_len);
- if (targ_len <= 0)
- return 0;
-
if (should_write)
- res = remote_write_bytes (targ_addr, buffer, targ_len);
+ res = remote_write_bytes (mem_addr, buffer, mem_len);
else
- res = remote_read_bytes (targ_addr, buffer, targ_len);
+ res = remote_read_bytes (mem_addr, buffer, mem_len);
return res;
}
/* Stuff for dealing with the packets which are part of this protocol.
See comment at top of file for details. */
-/* Read a single character from the remote end, masking it down to 7
- bits. */
+/* Read a single character from the remote end. */
static int
readchar (int timeout)
ch = serial_readchar (remote_desc, timeout);
if (ch >= 0)
- return (ch & 0x7f);
+ return ch;
switch ((enum serial_rc) ch)
{
case '$':
{
if (remote_debug)
- fprintf_unfiltered (gdb_stdlog,
+ fprintf_unfiltered (gdb_stdlog,
"Packet instead of Ack, ignoring it\n");
/* It's probably an old response sent because an ACK
was lost. Gobble up the packet and ack it so it
if (check_0 == SERIAL_TIMEOUT || check_1 == SERIAL_TIMEOUT)
{
if (remote_debug)
- fputs_filtered ("Timeout in checksum, retrying\n",
+ fputs_filtered ("Timeout in checksum, retrying\n",
gdb_stdlog);
return -1;
}
else if (check_0 < 0 || check_1 < 0)
{
if (remote_debug)
- fputs_filtered ("Communication error in checksum\n",
+ fputs_filtered ("Communication error in checksum\n",
gdb_stdlog);
return -1;
}
fprintf_filtered (gdb_stdlog,
"Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
pktcsum, csum);
- fputs_filtered (buf, gdb_stdlog);
+ fputstrn_filtered (buf, bc, 0, gdb_stdlog);
fputs_filtered ("\n", gdb_stdlog);
}
/* Number of characters in buffer ignoring trailing
rather than timing out; this is used (in synchronous mode) to wait
for a target that is is executing user code to stop. If FOREVER ==
0, this function is allowed to time out gracefully and return an
- indication of this to the caller. */
+ indication of this to the caller. Otherwise return the number
+ of bytes read. */
static int
getpkt_sane (char **buf, long *sizeof_buf, int forever)
{
if (remote_debug)
{
fprintf_unfiltered (gdb_stdlog, "Packet received: ");
- fputstr_unfiltered (*buf, 0, gdb_stdlog);
+ fputstrn_unfiltered (*buf, val, 0, gdb_stdlog);
fprintf_unfiltered (gdb_stdlog, "\n");
}
serial_write (remote_desc, "+", 1);
- return 0;
+ return val;
}
/* Try the whole thing again. */
serial_write (remote_desc, "-", 1);
}
- /* We have tried hard enough, and just can't receive the packet.
+ /* We have tried hard enough, and just can't receive the packet.
Give up. */
printf_unfiltered (_("Ignoring packet error, continuing...\n"));
serial_write (remote_desc, "+", 1);
- return 1;
+ return -1;
}
\f
static void
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
return -1;
-
+
*(p++) = 'Z';
*(p++) = '1';
*(p++) = ',';
printf_filtered (_("No loaded section named '%s'.\n"), args);
}
+/* Read OBJECT_NAME/ANNEX from the remote target using a qXfer packet.
+ Data at OFFSET, of up to LEN bytes, is read into READBUF; the
+ number of bytes read is returned, or 0 for EOF, or -1 for error.
+ The number of bytes read may be less than LEN without indicating an
+ EOF. PACKET is checked and updated to indicate whether the remote
+ target supports this object. */
+
+static LONGEST
+remote_read_qxfer (struct target_ops *ops, const char *object_name,
+ const char *annex,
+ gdb_byte *readbuf, ULONGEST offset, LONGEST len,
+ struct packet_config *packet)
+{
+ static char *finished_object;
+ static char *finished_annex;
+ static ULONGEST finished_offset;
+
+ struct remote_state *rs = get_remote_state ();
+ unsigned int total = 0;
+ LONGEST i, n, packet_len;
+
+ if (packet->support == PACKET_DISABLE)
+ return -1;
+
+ /* Check whether we've cached an end-of-object packet that matches
+ this request. */
+ if (finished_object)
+ {
+ if (strcmp (object_name, finished_object) == 0
+ && strcmp (annex ? annex : "", finished_annex) == 0
+ && offset == finished_offset)
+ return 0;
+
+ /* Otherwise, we're now reading something different. Discard
+ the cache. */
+ xfree (finished_object);
+ xfree (finished_annex);
+ finished_object = NULL;
+ finished_annex = NULL;
+ }
+
+ /* Request only enough to fit in a single packet. The actual data
+ may not, since we don't know how much of it will need to be escaped;
+ the target is free to respond with slightly less data. We subtract
+ five to account for the response type and the protocol frame. */
+ n = min (get_remote_packet_size () - 5, len);
+ snprintf (rs->buf, get_remote_packet_size () - 4, "qXfer:%s:read:%s:%s,%s",
+ object_name, annex ? annex : "",
+ phex_nz (offset, sizeof offset),
+ phex_nz (n, sizeof n));
+ i = putpkt (rs->buf);
+ if (i < 0)
+ return -1;
+
+ rs->buf[0] = '\0';
+ packet_len = getpkt_sane (&rs->buf, &rs->buf_size, 0);
+ if (packet_len < 0 || packet_ok (rs->buf, packet) != PACKET_OK)
+ return -1;
+
+ if (rs->buf[0] != 'l' && rs->buf[0] != 'm')
+ error (_("Unknown remote qXfer reply: %s"), rs->buf);
+
+ /* 'm' means there is (or at least might be) more data after this
+ batch. That does not make sense unless there's at least one byte
+ of data in this reply. */
+ if (rs->buf[0] == 'm' && packet_len == 1)
+ error (_("Remote qXfer reply contained no data."));
+
+ /* Got some data. */
+ i = remote_unescape_input (rs->buf + 1, packet_len - 1, readbuf, n);
+
+ /* 'l' is an EOF marker, possibly including a final block of data,
+ or possibly empty. Record it to bypass the next read, if one is
+ issued. */
+ if (rs->buf[0] == 'l')
+ {
+ finished_object = xstrdup (object_name);
+ finished_annex = xstrdup (annex ? annex : "");
+ finished_offset = offset + i;
+ }
+
+ return i;
+}
+
static LONGEST
remote_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
char *p2;
char query_type;
- /* Handle memory using remote_xfer_memory. */
+ /* Handle memory using the standard memory routines. */
if (object == TARGET_OBJECT_MEMORY)
{
int xfered;
errno = 0;
if (writebuf != NULL)
- {
- void *buffer = xmalloc (len);
- struct cleanup *cleanup = make_cleanup (xfree, buffer);
- memcpy (buffer, writebuf, len);
- xfered = remote_xfer_memory (offset, buffer, len, 1, NULL, ops);
- do_cleanups (cleanup);
- }
+ xfered = remote_write_bytes (offset, writebuf, len);
else
- xfered = remote_xfer_memory (offset, readbuf, len, 0, NULL, ops);
+ xfered = remote_read_bytes (offset, readbuf, len);
if (xfered > 0)
return xfered;
objects!!! Instead specify new query packets. */
switch (object)
{
- case TARGET_OBJECT_KOD:
- query_type = 'K';
- break;
case TARGET_OBJECT_AVR:
query_type = 'R';
break;
case TARGET_OBJECT_AUXV:
- if (remote_protocol_packets[PACKET_qPart_auxv].support != PACKET_DISABLE)
- {
- unsigned int total = 0;
- while (len > 0)
- {
- LONGEST n = min ((get_remote_packet_size () - 2) / 2, len);
- snprintf (rs->buf, get_remote_packet_size (),
- "qPart:auxv:read::%s,%s",
- phex_nz (offset, sizeof offset),
- phex_nz (n, sizeof n));
- i = putpkt (rs->buf);
- if (i < 0)
- return total > 0 ? total : i;
- rs->buf[0] = '\0';
- getpkt (&rs->buf, &rs->buf_size, 0);
- if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_qPart_auxv])
- != PACKET_OK)
- return total > 0 ? total : -1;
- if (strcmp (rs->buf, "OK") == 0)
- break; /* Got EOF indicator. */
- /* Got some data. */
- i = hex2bin (rs->buf, readbuf, len);
- if (i > 0)
- {
- readbuf = (void *) ((char *) readbuf + i);
- offset += i;
- len -= i;
- total += i;
- }
- }
- return total;
- }
- return -1;
+ gdb_assert (annex == NULL);
+ return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_auxv]);
default:
return -1;
will be able to delay notifying the client of an event until the
point where an entire packet has been received. */
-static void (*async_client_callback) (enum inferior_event_type event_type,
+static void (*async_client_callback) (enum inferior_event_type event_type,
void *context);
static void *async_client_context;
static serial_event_ftype remote_async_serial_handler;
}
static void
-remote_async (void (*callback) (enum inferior_event_type event_type,
+remote_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context)
{
if (current_target.to_async_mask_value == 0)
init_remote_async_ops (void)
{
remote_async_ops.to_shortname = "async";
- remote_async_ops.to_longname =
+ remote_async_ops.to_longname =
"Remote serial target in async version of the gdb-specific protocol";
remote_async_ops.to_doc =
"Use a remote computer via a serial line, using a gdb-specific protocol.\n\
struct remote_state *rs;
/* architecture specific data */
- remote_gdbarch_data_handle =
+ remote_gdbarch_data_handle =
gdbarch_data_register_post_init (init_remote_state);
/* Old tacky stuff. NOTE: This comes after the remote protocol so
add_packet_config_cmd (&remote_protocol_packets[PACKET_Z4],
"Z4", "access-watchpoint", 0);
- add_packet_config_cmd (&remote_protocol_packets[PACKET_qPart_auxv],
- "qPart:auxv", "read-aux-vector", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
+ "qXfer:auxv:read", "read-aux-vector", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
"qGetTLSAddr", "get-thread-local-storage-address",