X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=cb96bf29fdec8c62ab88861401e88c99444cd6f6;hp=332f74a239952c3134fccf8b2fb18779abcd8c9d;hb=0875e64ddb1cade43c7a56d8cc6e743364b65b58;hpb=4a29a4a86d4ec3e12a9494371c80ace1b8ebedab diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 332f74a239..cb96bf29fd 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -65,15 +65,20 @@ struct gdb_connection { int closed; int busy; int noack_mode; - bool sync; /* set flag to true if you want the next stepi to return immediately. - allowing GDB to pick up a fresh set of register values from the target - without modifying the target state. */ + /* set flag to true if you want the next stepi to return immediately. + * allowing GDB to pick up a fresh set of register values from the target + * without modifying the target state. */ + bool sync; /* We delay reporting memory write errors until next step/continue or memory * write. This improves performance of gdb load significantly as the GDB packet * can be replied immediately and a new GDB packet will be ready without delay - * (ca. 10% or so...). - */ + * (ca. 10% or so...). */ bool mem_write_error; + /* with extended-remote it seems we need to better emulate attach/detach. + * what this means is we reply with a W stop reply after a kill packet, + * normally we reply with a S reply via gdb_last_signal_packet. + * as a side note this behaviour only effects gdb > 6.8 */ + bool attached; }; #if 0 @@ -88,7 +93,6 @@ static enum breakpoint_type gdb_breakpoint_override_type; static int gdb_error(struct connection *connection, int retval); static const char *gdb_port; static const char *gdb_port_next; -static const char DIGITS[16] = "0123456789abcdef"; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); @@ -125,7 +129,7 @@ static int gdb_last_signal(struct target *target) return 0x0; /* no signal... shouldn't happen */ default: LOG_USER("undefined debug reason %d - target needs reset", - target->debug_reason); + target->debug_reason); return 0x0; } } @@ -372,21 +376,16 @@ static int gdb_put_packet_inner(struct connection *connection, char local_buffer[1024]; local_buffer[0] = '$'; if ((size_t)len + 4 <= sizeof(local_buffer)) { - /* performance gain on smaller packets by only a single call to gdb_write() - **/ + /* performance gain on smaller packets by only a single call to gdb_write() */ memcpy(local_buffer + 1, buffer, len++); - local_buffer[len++] = '#'; - local_buffer[len++] = DIGITS[(my_checksum >> 4) & 0xf]; - local_buffer[len++] = DIGITS[my_checksum & 0xf]; + len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, len); if (retval != ERROR_OK) return retval; } else { /* larger packets are transmitted directly from caller supplied buffer - by several calls to gdb_write() to avoid dynamic allocation */ - local_buffer[1] = '#'; - local_buffer[2] = DIGITS[(my_checksum >> 4) & 0xf]; - local_buffer[3] = DIGITS[my_checksum & 0xf]; + * by several calls to gdb_write() to avoid dynamic allocation */ + snprintf(local_buffer + 1, sizeof(local_buffer) - 1, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, 1); if (retval != ERROR_OK) return retval; @@ -427,8 +426,7 @@ static int gdb_put_packet_inner(struct connection *connection, gdb_putback_char(connection, reply); return ERROR_OK; } else { - LOG_ERROR( - "unknown character(1) 0x%2.2x in reply, dropping connection", reply); + LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } @@ -500,8 +498,7 @@ static inline int fetch_packet(struct connection *connection, i++; if (character == '#') { /* Danger! character can be '#' when esc is - * used so we need an explicit boolean for done here. - */ + * used so we need an explicit boolean for done here. */ done = 1; break; } @@ -620,8 +617,7 @@ static int gdb_get_packet_inner(struct connection *connection, int checksum_ok = 0; /* explicit code expansion here to get faster inlined code in -O3 by not - * calculating checksum - */ + * calculating checksum */ if (gdb_con->noack_mode) { retval = fetch_packet(connection, &checksum_ok, 1, len, buffer); if (retval != ERROR_OK) @@ -661,20 +657,17 @@ static int gdb_get_packet(struct connection *connection, char *buffer, int *len) static int gdb_output_con(struct connection *connection, const char *line) { char *hex_buffer; - int i, bin_size; + int bin_size; bin_size = strlen(line); - hex_buffer = malloc(bin_size*2 + 2); + hex_buffer = malloc(bin_size * 2 + 2); if (hex_buffer == NULL) return ERROR_GDB_BUFFER_TOO_SMALL; hex_buffer[0] = 'O'; - for (i = 0; i < bin_size; i++) - snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]); - hex_buffer[bin_size*2 + 1] = 0; - - int retval = gdb_put_packet(connection, hex_buffer, bin_size*2 + 1); + int pkt_len = hexify(hex_buffer + 1, line, bin_size, bin_size * 2 + 1); + int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1); free(hex_buffer); return retval; @@ -735,7 +728,6 @@ static int gdb_target_callback_event_handler(struct target *target, target_call_event_callbacks(target, TARGET_EVENT_GDB_END); break; case TARGET_EVENT_GDB_FLASH_ERASE_START: - target_handle_event(target, TARGET_EVENT_OLD_gdb_program_config); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; @@ -767,6 +759,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->noack_mode = 0; gdb_connection->sync = true; gdb_connection->mem_write_error = false; + gdb_connection->attached = true; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -808,8 +801,8 @@ static int gdb_new_connection(struct connection *connection) struct flash_bank *p; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { - LOG_ERROR( - "Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'."); + LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " \ + "to prepare target for GDB connect, or use 'gdb_memory_map disable'."); return retval; } } @@ -883,9 +876,17 @@ static int gdb_last_signal_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_con = connection->priv; char sig_reply[4]; int signal_var; + if (!gdb_con->attached) { + /* if we are here we have received a kill packet + * reply W stop reply otherwise gdb gets very unhappy */ + gdb_put_packet(connection, "W00", 3); + return ERROR_OK; + } + signal_var = gdb_last_signal(target); snprintf(sig_reply, 4, "S%2.2x", signal_var); @@ -894,7 +895,7 @@ static int gdb_last_signal_packet(struct connection *connection, return ERROR_OK; } -static int gdb_reg_pos(struct target *target, int pos, int len) +static inline int gdb_reg_pos(struct target *target, int pos, int len) { if (target->endianness == TARGET_LITTLE_ENDIAN) return pos; @@ -923,22 +924,10 @@ static void gdb_str_to_target(struct target *target, for (i = 0; i < buf_len; i++) { int j = gdb_reg_pos(target, i, buf_len); - tstr[i*2] = DIGITS[(buf[j]>>4) & 0xf]; - tstr[i*2 + 1] = DIGITS[buf[j]&0xf]; + tstr += sprintf(tstr, "%02x", buf[j]); } } -static int hextoint(int c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - c = toupper(c); - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - LOG_ERROR("BUG: invalid register value %08x", c); - return 0; -} - /* copy over in register buffer */ static void gdb_target_to_reg(struct target *target, char *tstr, int str_len, uint8_t *bin) @@ -950,8 +939,11 @@ static void gdb_target_to_reg(struct target *target, int i; for (i = 0; i < str_len; i += 2) { - uint8_t t = hextoint(tstr[i]) << 4; - t |= hextoint(tstr[i + 1]); + unsigned t; + if (sscanf(tstr + i, "%02x", &t) != 1) { + LOG_ERROR("BUG: unable to convert register value"); + exit(-1); + } int j = gdb_reg_pos(target, i/2, str_len/2); bin[j] = t; @@ -986,7 +978,7 @@ static int gdb_get_registers_packet(struct connection *connection, assert(reg_packet_size > 0); - reg_packet = malloc(reg_packet_size); + reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */ reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { @@ -1032,8 +1024,7 @@ static int gdb_set_registers_packet(struct connection *connection, packet_size--; if (packet_size % 2) { - LOG_WARNING( - "GDB set_registers packet with uneven characters received, dropping connection"); + LOG_WARNING("GDB set_registers packet with uneven characters received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } @@ -1088,13 +1079,13 @@ static int gdb_get_register_packet(struct connection *connection, if (reg_list_size <= reg_num) { LOG_ERROR("gdb requested a non-existing register"); - exit(-1); + return ERROR_SERVER_REMOTE_CLOSED; } if (!reg_list[reg_num]->valid) reg_list[reg_num]->type->get(reg_list[reg_num]); - reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); + reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ gdb_str_to_target(target, reg_packet, reg_list[reg_num]); @@ -1123,7 +1114,7 @@ static int gdb_set_register_packet(struct connection *connection, if (retval != ERROR_OK) return gdb_error(connection, retval); - if (reg_list_size < reg_num) { + if (reg_list_size <= reg_num) { LOG_ERROR("gdb requested a non-existing register"); return ERROR_SERVER_REMOTE_CLOSED; } @@ -1139,6 +1130,7 @@ static int gdb_set_register_packet(struct connection *connection, if ((unsigned int)chars != strlen(separator + 1)) { LOG_ERROR("gdb sent a packet with wrong register size"); + free(bin_buf); return ERROR_SERVER_REMOTE_CLOSED; } @@ -1222,14 +1214,9 @@ static int gdb_read_memory_packet(struct connection *connection, if (retval == ERROR_OK) { hex_buffer = malloc(len * 2 + 1); - uint32_t i; - for (i = 0; i < len; i++) { - uint8_t t = buffer[i]; - hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf]; - hex_buffer[2 * i + 1] = DIGITS[t & 0xf]; - } + int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1); - gdb_put_packet(connection, hex_buffer, len * 2); + gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } else @@ -1249,8 +1236,6 @@ static int gdb_write_memory_packet(struct connection *connection, uint32_t len = 0; uint8_t *buffer; - - uint32_t i; int retval; /* skip command character */ @@ -1274,11 +1259,8 @@ static int gdb_write_memory_packet(struct connection *connection, LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); - for (i = 0; i < len; i++) { - uint32_t tmp; - sscanf(separator + 2*i, "%2" SCNx32, &tmp); - buffer[i] = tmp; - } + if (unhexify((char *)buffer, separator + 2, len) != (int)len) + LOG_ERROR("unable to decode memory packet"); retval = target_write_buffer(target, addr, len, buffer); @@ -1367,11 +1349,8 @@ static int gdb_step_continue_packet(struct connection *connection, if (packet[0] == 'c') { LOG_DEBUG("continue"); - target_handle_event(target, TARGET_EVENT_OLD_pre_resume); - retval = target_resume(target, current, address, 0, 0); /* resume at current - *address, don't handle - *breakpoints, not debugging - **/ + /* resume at current address, don't handle breakpoints, not debugging */ + retval = target_resume(target, current, address, 0, 0); } else if (packet[0] == 's') { LOG_DEBUG("step"); /* step at current or address, don't handle breakpoints */ @@ -1699,17 +1678,12 @@ static int gdb_query_packet(struct connection *connection, struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); - if (strstr(packet, "qRcmd,")) { + if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { char *cmd; - int i; - cmd = malloc((packet_size - 6)/2 + 1); - for (i = 0; i < (packet_size - 6)/2; i++) { - uint32_t tmp; - sscanf(packet + 6 + 2*i, "%2" SCNx32, &tmp); - cmd[i] = tmp; - } - cmd[(packet_size - 6)/2] = 0x0; + cmd = malloc((packet_size - 6) / 2 + 1); + int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2); + cmd[len] = 0; /* We want to print all debug output to GDB connection */ log_add_callback(gdb_log_callback, connection); @@ -1725,7 +1699,7 @@ static int gdb_query_packet(struct connection *connection, } gdb_put_packet(connection, "OK", 2); return ERROR_OK; - } else if (strstr(packet, "qCRC:")) { + } else if (strncmp(packet, "qCRC:", 5) == 0) { if (packet_size > 5) { int retval; char gdb_reply[10]; @@ -1740,8 +1714,7 @@ static int gdb_query_packet(struct connection *connection, addr = strtoul(packet, &separator, 16); if (*separator != ',') { - LOG_ERROR( - "incomplete read memory packet received, dropping connection"); + LOG_ERROR("incomplete read memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } @@ -1760,7 +1733,7 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } - } else if (strstr(packet, "qSupported")) { + } else if (strncmp(packet, "qSupported", 10) == 0) { /* we currently support packet size and qXfer:memory-map:read (if enabled) * disable qXfer:features:read for the moment */ int retval = ERROR_OK; @@ -1785,10 +1758,10 @@ static int gdb_query_packet(struct connection *connection, free(buffer); return ERROR_OK; - } else if (strstr(packet, "qXfer:memory-map:read::") + } else if ((strncmp(packet, "qXfer:memory-map:read::", 23) == 0) && (flash_get_bank_count() > 0)) return gdb_memory_map(connection, packet, packet_size); - else if (strstr(packet, "qXfer:features:read:")) { + else if (strncmp(packet, "qXfer:features:read:", 20) == 0) { char *xml = NULL; int size = 0; int pos = 0; @@ -1826,7 +1799,7 @@ static int gdb_query_packet(struct connection *connection, free(xml); return ERROR_OK; - } else if (strstr(packet, "QStartNoAckMode")) { + } else if (strncmp(packet, "QStartNoAckMode", 15) == 0) { gdb_connection->noack_mode = 1; gdb_put_packet(connection, "OK", 2); return ERROR_OK; @@ -1850,7 +1823,7 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } - if (strstr(packet, "vFlashErase:")) { + if (strncmp(packet, "vFlashErase:", 12) == 0) { unsigned long addr; unsigned long length; @@ -1906,7 +1879,7 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } - if (strstr(packet, "vFlashWrite:")) { + if (strncmp(packet, "vFlashWrite:", 12) == 0) { int retval; unsigned long addr; unsigned long length; @@ -1940,15 +1913,14 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } - if (!strcmp(packet, "vFlashDone")) { + if (strncmp(packet, "vFlashDone", 10) == 0) { uint32_t written; /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ target_call_event_callbacks(gdb_service->target, - TARGET_EVENT_GDB_FLASH_WRITE_START); - result = - flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); + TARGET_EVENT_GDB_FLASH_WRITE_START); + result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) @@ -1975,8 +1947,7 @@ static int gdb_detach(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; - target_call_event_callbacks(gdb_service->target, - TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); return gdb_put_packet(connection, "OK", 2); } @@ -2000,7 +1971,6 @@ static void gdb_sig_halted(struct connection *connection) char sig_reply[4]; snprintf(sig_reply, 4, "T%2.2x", 2); gdb_put_packet(connection, sig_reply, 3); - } static int gdb_input_inner(struct connection *connection) @@ -2055,8 +2025,8 @@ static int gdb_input_inner(struct connection *connection) case 'T': /* Is thread alive? */ gdb_thread_packet(connection, packet, packet_size); break; - case 'H': /* Set current thread ( 'c' for step and continue, 'g' for - * all other operations ) */ + case 'H': /* Set current thread ( 'c' for step and continue, + * 'g' for all other operations ) */ gdb_thread_packet(connection, packet, packet_size); break; case 'q': @@ -2100,7 +2070,7 @@ static int gdb_input_inner(struct connection *connection) LOG_ERROR("Memory write failure!"); /* now that we have reported the memory write error, - *we can clear the condition */ + * we can clear the condition */ gdb_con->mem_write_error = false; } @@ -2151,8 +2121,8 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_step_continue_packet(connection, packet, packet_size); if (retval != ERROR_OK) { /* we'll never receive a halted - *condition... issue a false one.. - **/ + * condition... issue a false one.. + */ gdb_frontend_halted(target, connection); } } @@ -2172,8 +2142,10 @@ static int gdb_input_inner(struct connection *connection) return retval; break; case 'k': - if (extended_protocol != 0) + if (extended_protocol != 0) { + gdb_con->attached = false; break; + } gdb_put_packet(connection, "OK", 2); return ERROR_SERVER_REMOTE_CLOSED; case '!': @@ -2185,24 +2157,24 @@ static int gdb_input_inner(struct connection *connection) /* handle extended restart packet */ breakpoint_clear_target(gdb_service->target); watchpoint_clear_target(gdb_service->target); - command_run_linef(connection->cmd_ctx, - "ocd_gdb_restart %s", - target_name(target)); + command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", + target_name(target)); + /* set connection as attached after reset */ + gdb_con->attached = true; /* info rtos parts */ gdb_thread_packet(connection, packet, packet_size); - gdb_put_packet(connection, "OK", 2); break; case 'j': - /* packet supported only by smp target i.e cortex_a.c*/ + /* packet supported only by smp target i.e cortex_a.c*/ /* handle smp packet replying coreid played to gbd */ gdb_read_smp_packet(connection, packet, packet_size); break; case 'J': - /* packet supported only by smp target i.e cortex_a.c */ - /* handle smp packet setting coreid to be played at next - * resume to gdb */ + /* packet supported only by smp target i.e cortex_a.c */ + /* handle smp packet setting coreid to be played at next + * resume to gdb */ gdb_write_smp_packet(connection, packet, packet_size); break; @@ -2225,8 +2197,7 @@ static int gdb_input_inner(struct connection *connection) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; } else { - LOG_INFO( - "The target is not running when halt was requested, stopping GDB."); + LOG_INFO("The target is not running when halt was requested, stopping GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } }