X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=34b66050791a6215fd462eef863be04322b2d8c9;hb=ffb51c23fdd753ada2554b8b6283533089153b46;hp=b0c0996119031af4590862443b08d5c69bd5f3da;hpb=d4d36b0a9a778caec77fb8e4ce5b1e406d5a8f50;p=openocd diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b0c09961..34b66050 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -17,7 +17,11 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif + +#include "replacements.h" #include "gdb_server.h" @@ -32,21 +36,6 @@ #include #include -#ifndef HAVE_STRNDUP -#include -char* strndup(const char *s, size_t n) -{ - size_t len = strnlen (s, n); - char *new = (char *) malloc (len + 1); - - if (new == NULL) - return NULL; - - new[len] = '\0'; - return (char *) memcpy (new, s, len); -} -#endif - #if 0 #define _DEBUG_GDB_IO_ #endif @@ -93,11 +82,26 @@ int gdb_get_char(connection_t *connection, int* next_char) return ERROR_OK; } - while ((gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE)) <= 0) + while ((gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE)) <= 0) { if (gdb_con->buf_cnt == 0) return ERROR_SERVER_REMOTE_CLOSED; +#ifdef _WIN32 + errno = WSAGetLastError(); + + switch(errno) + { + case WSAEWOULDBLOCK: + usleep(1000); + break; + case WSAECONNABORTED: + return ERROR_SERVER_REMOTE_CLOSED; + default: + ERROR("read: %d", errno); + exit(-1); + } +#else switch(errno) { case EAGAIN: @@ -111,6 +115,7 @@ int gdb_get_char(connection_t *connection, int* next_char) ERROR("read: %s", strerror(errno)); exit(-1); } +#endif } debug_buffer = malloc(gdb_con->buf_cnt + 1); @@ -133,6 +138,23 @@ int gdb_get_char(connection_t *connection, int* next_char) return ERROR_OK; } +int gdb_putback_char(connection_t *connection, int last_char) +{ + gdb_connection_t *gdb_con = connection->priv; + + if (gdb_con->buf_p > gdb_con->buffer) + { + *(--gdb_con->buf_p) = last_char; + gdb_con->buf_cnt++; + } + else + { + ERROR("BUG: couldn't put character back"); + } + + return ERROR_OK; +} + int gdb_put_packet(connection_t *connection, char *buffer, int len) { int i; @@ -155,14 +177,14 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len) DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); free(debug_buffer); - write(connection->fd, "$", 1); + write_socket(connection->fd, "$", 1); if (len > 0) - write(connection->fd, buffer, len); - write(connection->fd, "#", 1); + write_socket(connection->fd, buffer, len); + write_socket(connection->fd, "#", 1); snprintf(checksum, 3, "%2.2x", my_checksum); - write(connection->fd, checksum, 2); + write_socket(connection->fd, checksum, 2); if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK) return retval; @@ -202,7 +224,7 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) int count = 0; int retval; int first_char = 0; - int packet_type; + int packet_type = '\0'; char checksum[3]; unsigned char my_checksum = 0; gdb_connection_t *gdb_con = connection->priv; @@ -214,6 +236,8 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) if ((retval = gdb_get_char(connection, &character)) != ERROR_OK) return retval; + DEBUG("character: '%c'", character); + switch (character) { case '$': @@ -310,12 +334,12 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len) if (my_checksum == strtoul(checksum, NULL, 16)) { - write (connection->fd, "+", 1); + write_socket(connection->fd, "+", 1); break; } WARNING("checksum error, requesting retransmission"); - write(connection->fd, "-", 1); + write_socket(connection->fd, "-", 1); } return ERROR_OK; @@ -422,6 +446,9 @@ int gdb_new_connection(connection_t *connection) if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK) return retval; + if (initial_ack != '+') + gdb_putback_char(connection, initial_ack); + return ERROR_OK; } @@ -437,6 +464,13 @@ int gdb_connection_closed(connection_t *connection) return ERROR_OK; } +void gdb_send_error(connection_t *connection, u8 the_error) +{ + char err[4]; + snprintf(err, 4, "E%2.2X", the_error ); + gdb_put_packet(connection, err, 3); +} + int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size) { char sig_reply[4]; @@ -450,7 +484,63 @@ int gdb_last_signal_packet(connection_t *connection, target_t *target, char* pac return ERROR_OK; } -void gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size) +void gdb_str_to_target(target_t *target, char *str, char *tstr) +{ + int str_len = strlen(str); + int i; + + if (str_len % 2) + { + ERROR("BUG: gdb value with uneven number of characters encountered: %s", str); + exit(-1); + } + + if (target->endianness == TARGET_LITTLE_ENDIAN) + { + for (i = 0; i < str_len; i+=2) + { + tstr[str_len - i - 1] = str[i + 1]; + tstr[str_len - i - 2] = str[i]; + } + } + else + { + for (i = 0; i < str_len; i++) + { + tstr[i] = str[i]; + } + } +} + +void gdb_target_to_str(target_t *target, char *tstr, char *str) +{ + int str_len = strlen(tstr); + int i; + + if (str_len % 2) + { + ERROR("BUG: gdb value with uneven number of characters encountered"); + exit(-1); + } + + if (target->endianness == TARGET_LITTLE_ENDIAN) + { + for (i = 0; i < str_len; i+=2) + { + str[str_len - i - 1] = tstr[i + 1]; + str[str_len - i - 2] = tstr[i]; + } + } + else + { + for (i = 0; i < str_len; i++) + { + str[i] = tstr[i]; + } + } +} + +int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size) { reg_t **reg_list; int reg_list_size; @@ -460,16 +550,17 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char* char *reg_packet_p; int i; - DEBUG(""); + DEBUG("-"); if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) { switch (retval) { case ERROR_TARGET_NOT_HALTED: - ERROR("gdb requested registers, but we're not halted"); - exit(-1); + ERROR("gdb requested registers but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; default: + /* this is a bug condition - get_gdb_reg_list() may not return any other error */ ERROR("BUG: unexpected error returned by get_gdb_reg_list()"); exit(-1); } @@ -485,14 +576,10 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char* for (i = 0; i < reg_list_size; i++) { - int j; - char *hex_buf = buf_to_char(reg_list[i]->value, reg_list[i]->size); + char *hex_buf = buf_to_str(reg_list[i]->value, reg_list[i]->size, 16); DEBUG("hex_buf: %s", hex_buf); - for (j = CEIL(reg_list[i]->size, 8) * 2; j > 0; j -= 2) - { - *reg_packet_p++ = hex_buf[j - 2]; - *reg_packet_p++ = hex_buf[j - 1]; - } + gdb_str_to_target(target, hex_buf, reg_packet_p); + reg_packet_p += CEIL(reg_list[i]->size, 8) * 2; free(hex_buf); } @@ -503,9 +590,12 @@ void gdb_get_registers_packet(connection_t *connection, target_t *target, char* gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2); free(reg_packet); + free(reg_list); + + return ERROR_OK; } -void gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { int i; reg_t **reg_list; @@ -513,7 +603,7 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char * int retval; char *packet_p; - DEBUG(""); + DEBUG("-"); /* skip command character */ packet++; @@ -521,8 +611,8 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char * if (packet_size % 2) { - WARNING("GDB set_registers packet with uneven characters received"); - return; + WARNING("GDB set_registers packet with uneven characters received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; } if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) @@ -530,9 +620,10 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char * switch (retval) { case ERROR_TARGET_NOT_HALTED: - ERROR("gdb requested registers, but we're not halted"); - exit(-1); + ERROR("gdb tried to registers but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; default: + /* this is a bug condition - get_gdb_reg_list() may not return any other error */ ERROR("BUG: unexpected error returned by get_gdb_reg_list()"); exit(-1); } @@ -541,34 +632,62 @@ void gdb_set_registers_packet(connection_t *connection, target_t *target, char * packet_p = packet; for (i = 0; i < reg_list_size; i++) { - char_to_buf(packet, CEIL(reg_list[i]->size, 8) * 2, reg_list[i]->value, reg_list[i]->size); - reg_list[i]->dirty = 1; + u8 *bin_buf; + char *hex_buf; + reg_arch_type_t *arch_type; + + /* convert from GDB-string (target-endian) to hex-string (big-endian) */ + hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2); + gdb_target_to_str(target, packet_p, hex_buf); + + /* convert hex-string to binary buffer */ + bin_buf = malloc(CEIL(reg_list[i]->size, 8)); + str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16); + + /* get register arch_type, and call set method */ + arch_type = register_get_arch_type(reg_list[i]->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + exit(-1); + } + arch_type->set(reg_list[i], bin_buf); + + /* advance packet pointer */ + packet_p += (CEIL(reg_list[i]->size, 8) * 2); + + free(bin_buf); + free(hex_buf); } + + /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ + free(reg_list); gdb_put_packet(connection, "OK", 2); + + return ERROR_OK; } -void gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { - char *hex_buf; char *reg_packet; - char *reg_packet_p; int reg_num = strtoul(packet + 1, NULL, 16); reg_t **reg_list; int reg_list_size; int retval; - int i; + char *hex_buf; - DEBUG(""); + DEBUG("-"); if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) { switch (retval) { case ERROR_TARGET_NOT_HALTED: - ERROR("gdb requested registers, but we're not halted"); - exit(-1); + ERROR("gdb requested registers but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; default: + /* this is a bug condition - get_gdb_reg_list() may not return any other error */ ERROR("BUG: unexpected error returned by get_gdb_reg_list()"); exit(-1); } @@ -580,40 +699,43 @@ void gdb_get_register_packet(connection_t *connection, target_t *target, char *p exit(-1); } - hex_buf = buf_to_char(reg_list[reg_num]->value, reg_list[reg_num]->size); - reg_packet = reg_packet_p = malloc(CEIL(reg_list[reg_num]->size, 8) * 2); + reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2); + + hex_buf = buf_to_str(reg_list[reg_num]->value, reg_list[reg_num]->size, 16); - for (i = CEIL(reg_list[reg_num]->size, 8) * 2; i > 0; i -= 2) - { - *reg_packet_p++ = hex_buf[i - 2]; - *reg_packet_p++ = hex_buf[i - 1]; - } + gdb_str_to_target(target, hex_buf, reg_packet); gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2); + free(reg_list); free(reg_packet); free(hex_buf); + return ERROR_OK; } -void gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { char *separator; + char *hex_buf; + u8 *bin_buf; int reg_num = strtoul(packet + 1, &separator, 16); reg_t **reg_list; int reg_list_size; int retval; - - DEBUG(""); + reg_arch_type_t *arch_type; + + DEBUG("-"); if ((retval = target->type->get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) { switch (retval) { case ERROR_TARGET_NOT_HALTED: - ERROR("gdb requested registers, but we're not halted"); - exit(-1); + ERROR("gdb tried to set a register but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; default: + /* this is a bug condition - get_gdb_reg_list() may not return any other error */ ERROR("BUG: unexpected error returned by get_gdb_reg_list()"); exit(-1); } @@ -622,23 +744,67 @@ void gdb_set_register_packet(connection_t *connection, target_t *target, char *p if (reg_list_size < reg_num) { ERROR("gdb requested a non-existing register"); - exit(-1); + return ERROR_SERVER_REMOTE_CLOSED; } if (*separator != '=') { - ERROR("GDB set register packet, but no '=' following the register number"); - exit(-1); + ERROR("GDB 'set register packet', but no '=' following the register number"); + return ERROR_SERVER_REMOTE_CLOSED; } - char_to_buf(separator + 1, CEIL(reg_list[reg_num]->size, 8) * 2, reg_list[reg_num]->value, reg_list[reg_num]->size); - reg_list[reg_num]->dirty = 1; + /* convert from GDB-string (target-endian) to hex-string (big-endian) */ + hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2); + gdb_target_to_str(target, separator + 1, hex_buf); + + /* convert hex-string to binary buffer */ + bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8)); + str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16); + + /* get register arch_type, and call set method */ + arch_type = register_get_arch_type(reg_list[reg_num]->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + exit(-1); + } + arch_type->set(reg_list[reg_num], bin_buf); gdb_put_packet(connection, "OK", 2); + free(bin_buf); + free(hex_buf); + free(reg_list); + + return ERROR_OK; } -void gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_memory_packet_error(connection_t *connection, int retval) +{ + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + ERROR("gdb tried to read memory but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + break; + case ERROR_TARGET_DATA_ABORT: + gdb_send_error(connection, EIO); + break; + case ERROR_TARGET_TRANSLATION_FAULT: + gdb_send_error(connection, EFAULT); + break; + case ERROR_TARGET_UNALIGNED_ACCESS: + gdb_send_error(connection, EFAULT); + break; + default: + ERROR("BUG: unexpected error %i", retval); + exit(-1); + } + + return ERROR_OK; +} + +int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { char *separator; u32 addr = 0; @@ -648,6 +814,7 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa char *hex_buffer; int i; + int retval; /* skip command character */ packet++; @@ -655,7 +822,10 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa addr = strtoul(packet, &separator, 16); if (*separator != ',') - return; + { + ERROR("incomplete read memory packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } len = strtoul(separator+1, NULL, 16); @@ -667,35 +837,46 @@ void gdb_read_memory_packet(connection_t *connection, target_t *target, char *pa { case 4: if ((addr % 4) == 0) - target->type->read_memory(target, addr, 4, 1, buffer); + retval = target->type->read_memory(target, addr, 4, 1, buffer); else - target->type->read_memory(target, addr, 1, len, buffer); + retval = target->type->read_memory(target, addr, 1, len, buffer); break; case 2: if ((addr % 2) == 0) - target->type->read_memory(target, addr, 2, 1, buffer); + retval = target->type->read_memory(target, addr, 2, 1, buffer); else - target->type->read_memory(target, addr, 1, len, buffer); + retval = target->type->read_memory(target, addr, 1, len, buffer); break; default: if (((addr % 4) == 0) && ((len % 4) == 0)) - target->type->read_memory(target, addr, 4, len / 4, buffer); + retval = target->type->read_memory(target, addr, 4, len / 4, buffer); else - target->type->read_memory(target, addr, 1, len, buffer); + retval = target->type->read_memory(target, addr, 1, len, buffer); } - hex_buffer = malloc(len * 2 + 1); + if (retval == ERROR_OK) + { + hex_buffer = malloc(len * 2 + 1); + + for (i=0; itype->write_memory(target, addr, 4, 1, buffer); + retval = target->type->write_memory(target, addr, 4, 1, buffer); else - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; case 2: if ((addr % 2) == 0) - target->type->write_memory(target, addr, 2, 1, buffer); + retval = target->type->write_memory(target, addr, 2, 1, buffer); else - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; case 3: case 1: - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; /* handle bulk writes */ default: - target_write_buffer(target, addr, len, buffer); + retval = target_write_buffer(target, addr, len, buffer); break; } - gdb_put_packet(connection, "OK", 2); + if (retval == ERROR_OK) + { + gdb_put_packet(connection, "OK", 2); + } + else + { + if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK) + return retval; + } free(buffer); + + return ERROR_OK; } -void gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { char *separator; u32 addr = 0; u32 len = 0; u8 *buffer; + int retval; /* skip command character */ packet++; @@ -773,13 +973,20 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target, addr = strtoul(packet, &separator, 16); if (*separator != ',') - return; + { + ERROR("incomplete write memory binary packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } len = strtoul(separator+1, &separator, 16); if (*(separator++) != ':') - return; + { + ERROR("incomplete write memory binary packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } + retval = ERROR_OK; if( len ) { buffer = malloc(len); @@ -792,29 +999,39 @@ void gdb_write_memory_binary_packet(connection_t *connection, target_t *target, { case 4: if ((addr % 4) == 0) - target->type->write_memory(target, addr, 4, 1, buffer); + retval = target->type->write_memory(target, addr, 4, 1, buffer); else - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; case 2: if ((addr % 2) == 0) - target->type->write_memory(target, addr, 2, 1, buffer); + retval = target->type->write_memory(target, addr, 2, 1, buffer); else - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; case 3: case 1: - target->type->write_memory(target, addr, 1, len, buffer); + retval = target->type->write_memory(target, addr, 1, len, buffer); break; default: - target_write_buffer(target, addr, len, buffer); + retval = target_write_buffer(target, addr, len, buffer); break; } free(buffer); } - gdb_put_packet(connection, "OK", 2); + if (retval == ERROR_OK) + { + gdb_put_packet(connection, "OK", 2); + } + else + { + if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK) + return retval; + } + + return ERROR_OK; } void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size) @@ -822,11 +1039,10 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char * int current = 0; u32 address = 0x0; - DEBUG(""); + DEBUG("-"); if (packet_size > 1) { - u32 address = 0; packet[packet_size] = 0; address = strtoul(packet + 1, NULL, 16); } @@ -847,17 +1063,36 @@ void gdb_step_continue_packet(connection_t *connection, target_t *target, char * } } -void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size) +int gdb_bp_wp_packet_error(connection_t *connection, int retval) +{ + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + gdb_send_error(connection, EBUSY); + break; + default: + ERROR("BUG: unexpected error %i", retval); + exit(-1); + } + + return ERROR_OK; +} + +int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size) { int type; - enum breakpoint_type bp_type; + enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type; u32 address; u32 size; char *separator; int retval; - DEBUG(""); + DEBUG("-"); type = strtoul(packet + 1, &separator, 16); @@ -873,12 +1108,18 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target wp_type = WPT_ACCESS; if (*separator != ',') - return; + { + ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } address = strtoul(separator+1, &separator, 16); if (*separator != ',') - return; + { + ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); + return ERROR_SERVER_REMOTE_CLOSED; + } size = strtoul(separator+1, &separator, 16); @@ -890,41 +1131,53 @@ void gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target { if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - gdb_put_packet(connection, "E00", 3); - break; - } + if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK) + return retval; + } + else + { + gdb_put_packet(connection, "OK", 2); } } else { breakpoint_remove(target, address); + gdb_put_packet(connection, "OK", 2); } - gdb_put_packet(connection, "OK", 2); break; case 2: case 3: case 4: { if (packet[0] == 'Z') - watchpoint_add(target, address, size, type-2, 0, 0xffffffffu); + { + if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK) + { + if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK) + return retval; + } + else + { + gdb_put_packet(connection, "OK", 2); + } + } else + { watchpoint_remove(target, address); - gdb_put_packet(connection, "OK", 2); + gdb_put_packet(connection, "OK", 2); + } break; } default: break; } + return ERROR_OK; } void gdb_query_packet(connection_t *connection, char *packet, int packet_size) { command_context_t *cmd_ctx = connection->cmd_ctx; - gdb_service_t *gdb_service = connection->service->priv; - target_t *target = gdb_service->target; if (strstr(packet, "qRcmd,")) { @@ -973,7 +1226,7 @@ int gdb_input(connection_t *connection) case ERROR_SERVER_REMOTE_CLOSED: return ERROR_SERVER_REMOTE_CLOSED; default: - ERROR("unexpected error"); + ERROR("BUG: unexpected error"); exit(-1); } } @@ -985,6 +1238,7 @@ int gdb_input(connection_t *connection) if (packet_size > 0) { + retval = ERROR_OK; switch (packet[0]) { case 'H': @@ -996,26 +1250,26 @@ int gdb_input(connection_t *connection) gdb_query_packet(connection, packet, packet_size); break; case 'g': - gdb_get_registers_packet(connection, target, packet, packet_size); + retval = gdb_get_registers_packet(connection, target, packet, packet_size); break; case 'G': - gdb_set_registers_packet(connection, target, packet, packet_size); + retval = gdb_set_registers_packet(connection, target, packet, packet_size); break; case 'p': - gdb_get_register_packet(connection, target, packet, packet_size); + retval = gdb_get_register_packet(connection, target, packet, packet_size); break; case 'P': - gdb_set_register_packet(connection, target, packet, packet_size); + retval = gdb_set_register_packet(connection, target, packet, packet_size); break; case 'm': - gdb_read_memory_packet(connection, target, packet, packet_size); + retval = gdb_read_memory_packet(connection, target, packet, packet_size); break; case 'M': - gdb_write_memory_packet(connection, target, packet, packet_size); + retval = gdb_write_memory_packet(connection, target, packet, packet_size); break; case 'z': case 'Z': - gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size); + retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size); break; case '?': gdb_last_signal_packet(connection, target, packet, packet_size); @@ -1029,7 +1283,8 @@ int gdb_input(connection_t *connection) gdb_put_packet(connection, "OK", 2); break; case 'X': - gdb_write_memory_binary_packet(connection, target, packet, packet_size); + if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK) + return retval; break; case 'k': gdb_put_packet(connection, "OK", 2); @@ -1040,6 +1295,10 @@ int gdb_input(connection_t *connection) gdb_put_packet(connection, NULL, 0); break; } + + /* if a packet handler returned an error, exit input loop */ + if (retval != ERROR_OK) + return retval; } if (gdb_con->ctrl_c) @@ -1087,6 +1346,7 @@ int gdb_init() DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i); + i++; target = target->next; }