X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=2acebe83968eb0d224b7e6273a30509d72724967;hp=42ac8a5e2e7a2bfea4798a4109049651fb8796ad;hb=a4cdce0129a6b206a2081d77dd518ce2cae0b71f;hpb=293fb9b25faf8c89a9d06d73b83526b86d4c14d8
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 42ac8a5e2e..2acebe8396 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -961,9 +961,14 @@ static int gdb_new_connection(struct connection *connection)
breakpoint_clear_target(target);
watchpoint_clear_target(target);
- /* clean previous rtos session if supported*/
- if ((target->rtos) && (target->rtos->type->clean))
- target->rtos->type->clean(target);
+ if (target->rtos) {
+ /* clean previous rtos session if supported*/
+ if (target->rtos->type->clean)
+ target->rtos->type->clean(target);
+
+ /* update threads */
+ rtos_update_threads(target);
+ }
/* remove the initial ACK from the incoming buffer */
retval = gdb_get_char(connection, &initial_ack);
@@ -1941,12 +1946,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
return "int"; /* "int" as default value */
}
+static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id,
+ int *num_arch_defined_types)
+{
+ int tbl_sz = *num_arch_defined_types;
+
+ if (type_id != NULL && (strcmp(type_id, ""))) {
+ for (int j = 0; j < (tbl_sz + 1); j++) {
+ if (!((*arch_defined_types_list)[j])) {
+ (*arch_defined_types_list)[tbl_sz++] = type_id;
+ *arch_defined_types_list = realloc(*arch_defined_types_list,
+ sizeof(char *) * (tbl_sz + 1));
+ (*arch_defined_types_list)[tbl_sz] = NULL;
+ *num_arch_defined_types = tbl_sz;
+ return 1;
+ } else {
+ if (!strcmp((*arch_defined_types_list)[j], type_id))
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
static int gdb_generate_reg_type_description(struct target *target,
- char **tdesc, int *pos, int *size, struct reg_data_type *type)
+ char **tdesc, int *pos, int *size, struct reg_data_type *type,
+ char const **arch_defined_types_list[], int * num_arch_defined_types)
{
int retval = ERROR_OK;
if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+ struct reg_data_type *data_type = type->reg_type_vector->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
/* */
xml_printf(&retval, tdesc, pos, size,
"\n",
@@ -1954,6 +1992,20 @@ static int gdb_generate_reg_type_description(struct target *target,
type->reg_type_vector->count);
} else if (type->type_class == REG_TYPE_CLASS_UNION) {
+ struct reg_data_type_union_field *field;
+ field = type->reg_type_union->fields;
+ while (field != NULL) {
+ struct reg_data_type *data_type = field->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
+
+ field = field->next;
+ }
/*
* ...
* */
@@ -1961,7 +2013,6 @@ static int gdb_generate_reg_type_description(struct target *target,
"\n",
type->id);
- struct reg_data_type_union_field *field;
field = type->reg_type_union->fields;
while (field != NULL) {
xml_printf(&retval, tdesc, pos, size,
@@ -1994,6 +2045,17 @@ static int gdb_generate_reg_type_description(struct target *target,
field = field->next;
}
} else {
+ while (field != NULL) {
+ struct reg_data_type *data_type = field->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
+ }
+
/*
* ...
* */
@@ -2086,11 +2148,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
struct reg **reg_list = NULL;
int reg_list_size;
char const **features = NULL;
+ char const **arch_defined_types = NULL;
int feature_list_size = 0;
+ int num_arch_defined_types = 0;
char *tdesc = NULL;
int pos = 0;
int size = 0;
+ arch_defined_types = calloc(1, sizeof(char *));
+
retval = target_get_gdb_reg_list(target, ®_list,
®_list_size, REG_CLASS_ALL);
@@ -2143,8 +2209,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
if (reg_list[i]->reg_data_type != NULL) {
if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
/* generate reg_data_type);
+ if (lookup_add_arch_defined_types(&arch_defined_types,
+ reg_list[i]->reg_data_type->id,
+ &num_arch_defined_types))
+ gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
+ reg_list[i]->reg_data_type,
+ &arch_defined_types,
+ &num_arch_defined_types);
type_str = reg_list[i]->reg_data_type->id;
} else {
@@ -2194,6 +2265,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
error:
free(features);
free(reg_list);
+ free(arch_defined_types);
if (retval == ERROR_OK)
*tdesc_out = tdesc;
@@ -2370,7 +2442,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
else
transfer_type = 'l';
- *chunk = malloc(length + 2);
+ *chunk = malloc(length + 2 + 3);
+ /* Allocating extra 3 bytes prevents false positive valgrind report
+ * of strlen(chunk) word access:
+ * Invalid read of size 4
+ * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */
if (*chunk == NULL) {
LOG_ERROR("Unable to allocate memory");
return ERROR_FAIL;
@@ -2594,18 +2670,32 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
LOG_DEBUG("target %s continue", target_name(target));
log_add_callback(gdb_log_callback, connection);
retval = target_resume(target, 1, 0, 0, 0);
- if (retval == ERROR_OK) {
- gdb_connection->frontend_state = TARGET_RUNNING;
- target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
+ if (retval == ERROR_TARGET_NOT_HALTED)
+ LOG_INFO("target %s was not halted when resume was requested", target_name(target));
+
+ /* poll target in an attempt to make its internal state consistent */
+ if (retval != ERROR_OK) {
+ retval = target_poll(target);
+ if (retval != ERROR_OK)
+ LOG_DEBUG("error polling target %s after failed resume", target_name(target));
}
+
+ /*
+ * We don't report errors to gdb here, move frontend_state to
+ * TARGET_RUNNING to stay in sync with gdb's expectation of the
+ * target state
+ */
+ gdb_connection->frontend_state = TARGET_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
+
return true;
}
/* single-step or step-over-breakpoint */
if (parse[0] == 's') {
if (strncmp(parse, "s:", 2) == 0) {
- int handle_breakpoint = 1;
struct target *ct = target;
+ int current_pc = 1;
int64_t thread_id;
char *endp;
@@ -2629,21 +2719,63 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
parse += 1;
packet_size -= 1;
- handle_breakpoint = 0;
+ /* check if thread-id follows */
+ if (parse[0] == ':') {
+ int64_t tid;
+ parse += 1;
+ packet_size -= 1;
+
+ tid = strtoll(parse, &endp, 16);
+ if (tid == thread_id) {
+ /*
+ * Special case: only step a single thread (core),
+ * keep the other threads halted. Currently, only
+ * aarch64 target understands it. Other target types don't
+ * care (nobody checks the actual value of 'current')
+ * and it doesn't really matter. This deserves
+ * a symbolic constant and a formal interface documentation
+ * at a later time.
+ */
+ LOG_DEBUG("request to step current core only");
+ /* uncomment after checking that indeed other targets are safe */
+ /*current_pc = 2;*/
+ }
+ }
}
}
LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id);
- retval = target_step(ct, 1, 0, handle_breakpoint);
+ log_add_callback(gdb_log_callback, connection);
+ target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
+
+ /* support for gdb_sync command */
+ if (gdb_connection->sync) {
+ gdb_connection->sync = false;
+ if (ct->state == TARGET_HALTED) {
+ LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+ "from the target.");
+ gdb_sig_halted(connection);
+ log_remove_callback(gdb_log_callback, connection);
+ } else
+ gdb_connection->frontend_state = TARGET_RUNNING;
+ return true;
+ }
+
+ retval = target_step(ct, current_pc, 0, 0);
+ if (retval == ERROR_TARGET_NOT_HALTED)
+ LOG_INFO("target %s was not halted when step was requested", target_name(ct));
+
+ /* if step was successful send a reply back to gdb */
if (retval == ERROR_OK) {
- gdb_signal_reply(target, connection);
+ retval = target_poll(ct);
+ if (retval != ERROR_OK)
+ LOG_DEBUG("error polling target %s after successful step", target_name(ct));
+ /* send back signal information */
+ gdb_signal_reply(ct, connection);
/* stop forwarding log packets! */
log_remove_callback(gdb_log_callback, connection);
} else
- if (retval == ERROR_TARGET_TIMEOUT) {
gdb_connection->frontend_state = TARGET_RUNNING;
- target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
- }
} else {
LOG_ERROR("Unknown vCont packet");
return false;
@@ -3119,6 +3251,8 @@ static int gdb_input_inner(struct connection *connection)
if (target->rtos)
target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t);
retval = target_halt(t);
+ if (retval == ERROR_OK)
+ retval = target_poll(t);
if (retval != ERROR_OK)
target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
gdb_con->ctrl_c = 0;
@@ -3442,3 +3576,9 @@ int gdb_register_commands(struct command_context *cmd_ctx)
gdb_port_next = strdup("3333");
return register_commands(cmd_ctx, NULL, gdb_command_handlers);
}
+
+void gdb_service_free(void)
+{
+ free(gdb_port);
+ free(gdb_port_next);
+}