@@ -152,6 +152,12 @@ QThreadOptions in qSupported
QThreadOptions packet, and the qSupported response can contain the
set of thread options the remote stub supports.
+x addr,length
+ Given ADDR and LENGTH, fetch LENGTH units from the memory at address
+ ADDR and send the fetched data in binary format. This packet is
+ equivalent to 'm', except that the data in the response are in
+ binary format.
+
*** Changes in GDB 14
* GDB now supports the AArch64 Scalable Matrix Extension 2 (SME2), which
@@ -43122,6 +43122,35 @@ for success (@pxref{Stop Reply Packets})
@cindex @samp{vStopped} packet
@xref{Notification Packets}.
+@item x @var{addr},@var{length}
+@anchor{x packet}
+@cindex @samp{x} packet
+Read @var{length} addressable memory units starting at address @var{addr}
+(@pxref{addressable memory unit}). Note that @var{addr} does not have to
+be aligned to any particular boundary.
+
+@cindex alignment of remote memory accesses
+@cindex size of remote memory accesses
+@cindex memory, alignment and size of remote accesses
+The stub need not use any particular size or alignment when gathering
+data from memory for the response; even if @var{addr} is word-aligned
+and @var{length} is a multiple of the word size, the stub is free to
+use byte accesses, or not. For this reason, this packet may not be
+suitable for accessing memory-mapped I/O devices.
+
+This packet is used only if the stub announces support for it using
+@samp{qSupported}.
+
+Reply:
+@table @samp
+@item @var{XX@dots{}}
+Memory contents as binary data (@pxref{Binary Data}).
+The reply may contain fewer addressable memory units than requested if the
+server was able to read only part of the region of memory.
+@item E @var{NN}
+for an error
+@end table
+
@item X @var{addr},@var{length}:@var{XX@dots{}}
@anchor{X packet}
@cindex @samp{X} packet
@@ -194,6 +194,7 @@ struct packet_result
enum {
PACKET_vCont = 0,
PACKET_X,
+ PACKET_x,
PACKET_qSymbol,
PACKET_P,
PACKET_p,
@@ -5763,6 +5764,7 @@ static const struct protocol_feature remote_protocol_features[] = {
{ "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
{ "memory-tagging", PACKET_DISABLE, remote_supported_packet,
PACKET_memory_tagging_feature },
+ { "x", PACKET_DISABLE, remote_supported_packet, PACKET_x },
};
static char *remote_support_xml;
@@ -9582,24 +9584,56 @@ remote_target::remote_read_bytes_1 (CORE_ADDR memaddr, gdb_byte *myaddr,
todo_units = std::min (len_units,
(ULONGEST) (buf_size_bytes / unit_size) / 2);
- /* Construct "m"<memaddr>","<len>". */
+ /* Determine which packet format to use. */
+ char packet_format = 'm';
+ switch (m_features.packet_support (PACKET_x))
+ {
+ case PACKET_ENABLE:
+ packet_format = 'x';
+ break;
+
+ case PACKET_DISABLE:
+ packet_format = 'm';
+ break;
+
+ case PACKET_SUPPORT_UNKNOWN:
+ internal_error (_("remote_read_bytes_1: bad internal state"));
+
+ default:
+ /* This is unexpected but we can still continue with 'm'. */
+ break;
+ }
+
+ /* Construct "m/x"<memaddr>","<len>". */
memaddr = remote_address_masked (memaddr);
p = rs->buf.data ();
- *p++ = 'm';
+ *p++ = packet_format;
p += hexnumstr (p, (ULONGEST) memaddr);
*p++ = ',';
p += hexnumstr (p, (ULONGEST) todo_units);
*p = '\0';
putpkt (rs->buf);
- getpkt (&rs->buf);
+ int packet_len = getpkt (&rs->buf);
+ if (packet_len < 0)
+ return TARGET_XFER_E_IO;
+
if (rs->buf[0] == 'E'
&& isxdigit (rs->buf[1]) && isxdigit (rs->buf[2])
&& rs->buf[3] == '\0')
return TARGET_XFER_E_IO;
- /* Reply describes memory byte by byte, each byte encoded as two hex
- characters. */
+
p = rs->buf.data ();
- decoded_bytes = hex2bin (p, myaddr, todo_units * unit_size);
+ if (packet_format == 'x')
+ decoded_bytes = remote_unescape_input ((const gdb_byte *) p,
+ packet_len, myaddr,
+ todo_units * unit_size);
+ else
+ {
+ /* Reply describes memory byte by byte, each byte encoded as two hex
+ characters. */
+ decoded_bytes = hex2bin (p, myaddr, todo_units * unit_size);
+ }
+
/* Return what we have. Let higher layers handle partial reads. */
*xfered_len_units = (ULONGEST) (decoded_bytes / unit_size);
return (*xfered_len_units != 0) ? TARGET_XFER_OK : TARGET_XFER_EOF;
@@ -15839,6 +15873,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (PACKET_X, "X", "binary-download", 1);
+ add_packet_config_cmd (PACKET_x, "x", "binary-read", 0);
+
add_packet_config_cmd (PACKET_vCont, "vCont", "verbose-resume", 0);
add_packet_config_cmd (PACKET_QPassSignals, "QPassSignals", "pass-signals",
@@ -1334,6 +1334,13 @@ decode_M_packet (const char *from, CORE_ADDR *mem_addr_ptr,
hex2bin (from, *to_p, *len_ptr);
}
+void
+decode_x_packet (const char *from, CORE_ADDR *mem_addr_ptr,
+ unsigned int *len_ptr)
+{
+ decode_m_packet_params (from, mem_addr_ptr, len_ptr, '\0');
+}
+
int
decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
unsigned int *len_ptr, unsigned char **to_p)
@@ -1478,25 +1485,45 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
while it figures out the address of the symbol. */
while (1)
{
- if (cs.own_buf[0] == 'm')
+ int new_len = -1;
+ if (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'x')
{
CORE_ADDR mem_addr;
unsigned char *mem_buf;
unsigned int mem_len;
- decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+ if (cs.own_buf[0] == 'm')
+ decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+ else
+ decode_x_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+
mem_buf = (unsigned char *) xmalloc (mem_len);
if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
- bin2hex (mem_buf, cs.own_buf, mem_len);
+ {
+ if (cs.own_buf[0] == 'm')
+ bin2hex (mem_buf, cs.own_buf, mem_len);
+ else
+ {
+ int out_len_units;
+ new_len
+ = remote_escape_output (mem_buf, mem_len, 1,
+ (gdb_byte *) cs.own_buf,
+ &out_len_units, PBUFSIZ);
+ suppress_next_putpkt_log ();
+ }
+ }
else
write_enn (cs.own_buf);
free (mem_buf);
- if (putpkt (cs.own_buf) < 0)
+
+ int res = ((new_len == -1)
+ ? putpkt (cs.own_buf)
+ : putpkt_binary (cs.own_buf, new_len));
+ if (res < 0)
return -1;
}
else if (cs.own_buf[0] == 'v')
{
- int new_len = -1;
handle_v_requests (cs.own_buf, len, &new_len);
if (new_len != -1)
putpkt_binary (cs.own_buf, new_len);
@@ -1571,18 +1598,36 @@ relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
wait for the qRelocInsn "response". That requires re-entering
the main loop. For now, this is an adequate approximation; allow
GDB to access memory. */
- while (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'M' || cs.own_buf[0] == 'X')
+ while (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'M'
+ || cs.own_buf[0] == 'X' || cs.own_buf[0] == 'x')
{
CORE_ADDR mem_addr;
unsigned char *mem_buf = NULL;
unsigned int mem_len;
+ int new_packet_len = -1;
- if (cs.own_buf[0] == 'm')
+ if (cs.own_buf[0] == 'm' || cs.own_buf[0] == 'x')
{
- decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+ if (cs.own_buf[0] == 'm')
+ decode_m_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+ else
+ decode_x_packet (&cs.own_buf[1], &mem_addr, &mem_len);
+
mem_buf = (unsigned char *) xmalloc (mem_len);
if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
- bin2hex (mem_buf, cs.own_buf, mem_len);
+ {
+ if (cs.own_buf[0] == 'm')
+ bin2hex (mem_buf, cs.own_buf, mem_len);
+ else
+ {
+ int out_len_units;
+ new_packet_len
+ = remote_escape_output (mem_buf, mem_len, 1,
+ (gdb_byte *) cs.own_buf,
+ &out_len_units, PBUFSIZ);
+ suppress_next_putpkt_log ();
+ }
+ }
else
write_enn (cs.own_buf);
}
@@ -1604,7 +1649,11 @@ relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
write_enn (cs.own_buf);
}
free (mem_buf);
- if (putpkt (cs.own_buf) < 0)
+
+ int res = ((new_packet_len == -1)
+ ? putpkt (cs.own_buf)
+ : putpkt_binary (cs.own_buf, new_packet_len));
+ if (res < 0)
return -1;
len = getpkt (cs.own_buf);
if (len < 0)
@@ -57,6 +57,8 @@ void decode_m_packet (const char *from, CORE_ADDR * mem_addr_ptr,
unsigned int *len_ptr);
void decode_M_packet (const char *from, CORE_ADDR * mem_addr_ptr,
unsigned int *len_ptr, unsigned char **to_p);
+void decode_x_packet (const char *from, CORE_ADDR *mem_addr_ptr,
+ unsigned int *len_ptr);
int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
unsigned int *len_ptr, unsigned char **to_p);
int decode_xfer_write (char *buf, int packet_len,
@@ -2840,6 +2840,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_memory_tagging ())
strcat (own_buf, ";memory-tagging+");
+ /* Binary memory read support. */
+ strcat (own_buf, ";x+");
+
/* Reinitialize components as needed for the new connection. */
hostio_handle_new_gdb_connection ();
target_handle_new_gdb_connection ();
@@ -4690,6 +4693,24 @@ process_serial_event (void)
else
write_enn (cs.own_buf);
break;
+ case 'x':
+ {
+ require_running_or_break (cs.own_buf);
+ decode_x_packet (&cs.own_buf[1], &mem_addr, &len);
+ int res = gdb_read_memory (mem_addr, mem_buf, len);
+ if (res < 0)
+ write_enn (cs.own_buf);
+ else
+ {
+ int out_len_units;
+ new_packet_len
+ = remote_escape_output (mem_buf, res, 1,
+ (gdb_byte *) cs.own_buf,
+ &out_len_units, PBUFSIZ);
+ suppress_next_putpkt_log ();
+ }
+ }
+ break;
case 'X':
require_running_or_break (cs.own_buf);
if (decode_X_packet (&cs.own_buf[1], packet_len - 1,