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; --
