This is an automated email from Gerrit.

"Alexandra Kulyatskaya <[email protected]>" just uploaded a new patch 
set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9579

-- gerrit

commit ef486bfd76b58a400f46045cf9d8f9afd73f3c36
Author: Kulyatskaya Alexandra <[email protected]>
Date:   Fri Apr 10 13:20:21 2026 +0300

    [src/server] Support x packet
    
    Implement the binary memory read GDB packet 'x addr,length'.
    
    Change-Id: I7e4aab1c5e9fd26bb03f19f133b9d94aee7f22a1
    Signed-off-by: Kulyatskaya Alexandra <[email protected]>

diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index f59eb5029e..a06133bf31 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -1532,42 +1532,37 @@ static int gdb_error(struct connection *connection, int 
retval)
        return ERROR_OK;
 }
 
-static int gdb_read_memory_packet(struct connection *connection,
-               char const *packet, int packet_size)
+static bool parse_packet_addr_len(char const *packet, uint64_t *addr, uint32_t 
*len)
 {
-       struct target *target = 
get_available_target_from_connection(connection);
        char *separator;
-       uint64_t addr = 0;
-       uint32_t len = 0;
-
-       uint8_t *buffer;
-       char *hex_buffer;
-
-       int retval = ERROR_OK;
 
        /* skip command character */
        packet++;
 
-       addr = strtoull(packet, &separator, 16);
+       *addr = strtoull(packet, &separator, 16);
 
-       if (*separator != ',') {
-               LOG_ERROR("incomplete read memory packet received, dropping 
connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
+       if (*separator != ',')
+               return false;
+
+       errno = 0;
+       long signed_len = strtol(separator + 1, NULL, 16);
+       if (errno == ERANGE || signed_len < 0 || (unsigned long)signed_len > 
UINT32_MAX) {
+               return false;
        }
 
-       len = strtoul(separator + 1, NULL, 16);
+       *len = (uint32_t)signed_len;
 
-       if (!len) {
-               LOG_WARNING("invalid read memory packet received (len == 0)");
-               gdb_put_packet(connection, "", 0);
-               return ERROR_OK;
-       }
+       return true;
+}
 
-       buffer = malloc(len);
+static int gdb_read_memory(const struct connection *connection,
+               uint8_t *buffer, uint64_t addr, uint32_t len)
+{
+       struct target *target = 
get_available_target_from_connection(connection);
 
        LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32, addr, len);
 
-       retval = ERROR_NOT_IMPLEMENTED;
+       int retval = ERROR_NOT_IMPLEMENTED;
        if (target->rtos)
                retval = rtos_read_buffer(target, addr, len, buffer);
        if (retval == ERROR_NOT_IMPLEMENTED)
@@ -1591,8 +1586,47 @@ static int gdb_read_memory_packet(struct connection 
*connection,
                retval = ERROR_OK;
        }
 
+       return retval;
+}
+
+static int gdb_read_memory_packet(struct connection *connection,
+               char const *packet, int packet_size)
+{
+       uint64_t addr;
+       uint32_t len;
+
+       uint8_t *buffer;
+       char *hex_buffer;
+
+       int retval;
+
+       if (!parse_packet_addr_len(packet, &addr, &len)) {
+               LOG_ERROR("incomplete read memory packet received, dropping 
connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+       if (!len) {
+               LOG_WARNING("invalid read memory packet received (len == 0)");
+               gdb_put_packet(connection, "", 0);
+               return ERROR_OK;
+       }
+
+       buffer = malloc(len);
+       if (!buffer) {
+               LOG_ERROR("Unable to allocate memory");
+               gdb_send_error(connection, 01);
+               return ERROR_OK;
+       }
+
+       retval = gdb_read_memory(connection, buffer, addr, len);
+
        if (retval == ERROR_OK) {
                hex_buffer = malloc(len * 2 + 1);
+               if (!hex_buffer) {
+                       LOG_ERROR("Unable to allocate memory for hex buffer");
+                       gdb_send_error(connection, 01);
+                       free(buffer);
+                       return ERROR_OK;
+               }
 
                size_t pkt_len = hexify(hex_buffer, buffer, len, len * 2 + 1);
 
@@ -1607,6 +1641,83 @@ static int gdb_read_memory_packet(struct connection 
*connection,
        return retval;
 }
 
+static size_t escape_binary_data(const uint8_t *data, char *out, size_t 
data_len)
+{
+       assert(out);
+
+       size_t out_pos = 1;
+       out[0] = 'b';
+
+       for (size_t i = 0; i < data_len; ++i) {
+               uint8_t c = data[i];
+               /* See the logic for escaping binary data here:
+                * 
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Overview.html#Binary-Data
 */
+               if (c == 0x23 || c == 0x24 || c == 0x7d || c == 0x2a) {
+                       out[out_pos++] = 0x7d;
+                       out[out_pos++] = c ^ 0x20;
+               } else {
+                       out[out_pos++] = c;
+               }
+       }
+
+       return out_pos;
+}
+
+static int gdb_read_memory_packet_binary(struct connection *connection,
+               char const *packet, int packet_size)
+{
+       uint64_t addr;
+       uint32_t len;
+
+       if (!parse_packet_addr_len(packet, &addr, &len)) {
+               LOG_ERROR("incomplete read memory packet received, dropping 
connection");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+       if (!len) {
+               LOG_WARNING("invalid read memory packet received (len == 0)");
+               gdb_put_packet(connection, "", 0);
+               return ERROR_OK;
+       }
+
+       char *out_buffer = NULL;
+       uint8_t *buffer = malloc(len);
+       if (!buffer) {
+               LOG_ERROR("Unable to allocate memory");
+               gdb_send_error(connection, 01);
+               return ERROR_OK;
+       }
+
+       int retval = gdb_read_memory(connection, buffer, addr, len);
+       if (retval != ERROR_OK) {
+               retval = gdb_error(connection, retval);
+               goto cleanup;
+       }
+
+       /* len * 2 : each byte may need escaping → 2 bytes max per input byte
+       * +1 : for 'b' prefix
+       * +1 : for null terminator */
+       out_buffer = malloc(len * 2 + 1 + 1);
+       if (!out_buffer) {
+               LOG_ERROR("Unable to allocate memory for output buffer");
+               gdb_send_error(connection, 01);
+               goto cleanup;
+       }
+       size_t pkt_len = escape_binary_data(buffer, out_buffer, len);
+       if (pkt_len < len || INT_MAX <= pkt_len) {
+               LOG_ERROR("Escape binary data failed: invalid output length %zu 
"
+                               "(input: %" PRIu32 ", max: %d)", pkt_len, len, 
INT_MAX);
+               gdb_send_error(connection, ERANGE);
+       } else {
+               retval = gdb_put_packet(connection, out_buffer, pkt_len);
+       }
+
+cleanup:
+       free(out_buffer);
+       free(buffer);
+
+       return retval;
+}
+
 static int gdb_write_memory_packet(struct connection *connection,
                char const *packet, int packet_size)
 {
@@ -2942,7 +3053,7 @@ static int gdb_query_packet(struct connection *connection,
                        &buffer,
                        &pos,
                        &size,
-                       
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+",
+                       
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+;binary-upload+",
                        GDB_BUFFER_SIZE,
                        (gdb_use_memory_map && (flash_get_bank_count() > 0)) ? 
'+' : '-',
                        gdb_target_desc_supported ? '+' : '-');
@@ -3735,6 +3846,11 @@ static int gdb_input_inner(struct connection *connection)
                                        retval = 
gdb_write_memory_binary_packet(connection, packet, packet_size);
                                        gdb_con->output_flag = GDB_OUTPUT_NO;
                                        break;
+                               case 'x':
+                                       gdb_con->output_flag = GDB_OUTPUT_NOTIF;
+                                       retval = 
gdb_read_memory_packet_binary(connection, packet, packet_size);
+                                       gdb_con->output_flag = GDB_OUTPUT_NO;
+                                       break;
                                case 'k':
                                        if (gdb_con->extended_protocol) {
                                                gdb_con->attached = false;

-- 

Reply via email to