gdb_server: fix GDB_BUFFER_SIZE usage, fix unaligned access during bulk transfers
authorBohdan Tymkiv <bhdt@cypress.com>
Tue, 16 Apr 2019 14:28:29 +0000 (17:28 +0300)
committerTomas Vanek <vanekt@fbl.cz>
Tue, 4 Jun 2019 20:37:41 +0000 (21:37 +0100)
Currently size of the GDB buffer is 16384 bytes but it is treated as
nul-terminated string in most of the code, so effective size of the
buffer is actually 16383 bytes. OpenOCD responds with `PacketSize=3fff`
to qSupported request. Result of GDB's `m` command is encoded in hex so
each data byte uses two bytes in the buffer. As a result GDB will split
bulk read requests into chunks 0x1fff bytes each. This causes troubles
on targets (or memory regions) which support only aligned, word-sized
access (such as MMIO buffers).

Steps to reproduce (psoc6 target):
gdb> dump binary memory dump.bin 0x040320000 (0x040320000 + 65536)

OpenOCD:
Error: Failed to read memory at 0x40321ffe
Error: Failed to read memory at 0x40321000
Error: Failed to read memory at 0x40323000
Error: Failed to read memory at 0x40325ffe
Error: Failed to read memory at 0x40329ffa
Error: Failed to read memory at 0x40329ffc
Error: Failed to read memory at 0x4032bffc
Error: Failed to read memory at 0x4032dffa

Consolidate GDB_BUFFER_SIZE usage: ensure size of each buffer is
(GDB_BUFFER_SIZE + 1), add explicit comment that additional byte is used
for nul-termination. Report correct size of the buffer to GDB (0x4000)
as recommended in GDB's docummentation: `if the stub stores packets in a
NUL-terminated format, it should allow an extra byte in its buffer for
the NUL`

Checked with clang-asan, clang-analyzer, valgrind - no new errors.

Change-Id: I909e8a2c6b010c5d4a304641808d4a807a4ec18d
Signed-off-by: Bohdan Tymkiv <bhdt@cypress.com>
Reviewed-on: http://openocd.zylin.com/5109
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
src/rtos/nuttx.c
src/rtos/rtos.c
src/server/gdb_server.c

index 61fd9aa6ca1b366ef0894b8f6f002fad6d4d996c..8c3076e161d9151cd221641f221f2bae2b589714 100644 (file)
@@ -174,7 +174,7 @@ static int rcmd_offset(const char *cmd, const char *name)
 static int nuttx_thread_packet(struct connection *connection,
        char const *packet, int packet_size)
 {
-       char cmd[GDB_BUFFER_SIZE / 2] = "";
+       char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for nul-termination */
 
        if (!strncmp(packet, "qRcmd", 5)) {
                size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
index da0a5036295bdbc3f12d9ca2e44d86b225bf64b9..20e875d8b850098a7a64037438532b445a774300 100644 (file)
@@ -223,7 +223,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
        int rtos_detected = 0;
        uint64_t addr = 0;
        size_t reply_len;
-       char reply[GDB_BUFFER_SIZE], cur_sym[GDB_BUFFER_SIZE / 2] = "";
+       char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for nul-termination */
        symbol_table_elem_t *next_sym = NULL;
        struct target *target = get_target_from_connection(connection);
        struct rtos *os = target->rtos;
index c6cf7d350e076d438832d4de9bb038ec2f48218b..60ed4ce0426082753206011ba5c0506cbf7ed865 100644 (file)
@@ -67,7 +67,7 @@ struct target_desc_format {
 
 /* private connection data for GDB */
 struct gdb_connection {
-       char buffer[GDB_BUFFER_SIZE];
+       char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */
        char *buf_p;
        int buf_cnt;
        int ctrl_c;
@@ -1407,8 +1407,6 @@ static int gdb_error(struct connection *connection, int retval)
 
 /* We don't have to worry about the default 2 second timeout for GDB packets,
  * because GDB breaks up large memory reads into smaller reads.
- *
- * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
 static int gdb_read_memory_packet(struct connection *connection,
                char const *packet, int packet_size)
@@ -2614,7 +2612,7 @@ static int gdb_query_packet(struct connection *connection,
                        &pos,
                        &size,
                        "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+",
-                       (GDB_BUFFER_SIZE - 1),
+                       GDB_BUFFER_SIZE,
                        ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
                        (gdb_target_desc_supported == 1) ? '+' : '-');
 
@@ -3117,7 +3115,7 @@ static void gdb_sig_halted(struct connection *connection)
 static int gdb_input_inner(struct connection *connection)
 {
        /* Do not allocate this on the stack */
-       static char gdb_packet_buffer[GDB_BUFFER_SIZE];
+       static char gdb_packet_buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */
 
        struct target *target;
        char const *packet = gdb_packet_buffer;
@@ -3140,7 +3138,7 @@ static int gdb_input_inner(struct connection *connection)
         * drain the rest of the buffer.
         */
        do {
-               packet_size = GDB_BUFFER_SIZE-1;
+               packet_size = GDB_BUFFER_SIZE;
                retval = gdb_get_packet(connection, gdb_packet_buffer, &packet_size);
                if (retval != ERROR_OK)
                        return retval;