diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 67dfb9c28..edea5f5b0 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -154,6 +154,29 @@ static int gdb_use_target_description = 1; /* current processing free-run type, used by file-I/O */ static char gdb_running_type; +/* Find an available target in the SMP group that gdb is connected to. For + * commands that affect an entire SMP group (like memory access and run control) + * this will give better results than returning the unavailable target and having + * the command fail. If gdb was aware that targets can be unavailable we + * wouldn't need this logic. + */ +struct target *get_available_target_from_connection(struct connection *connection) +{ + struct gdb_service *gdb_service = connection->service->priv; + struct target *target = gdb_service->target; + if (target->state == TARGET_UNAVAILABLE && target->smp) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (t->state != TARGET_UNAVAILABLE) + return t; + } + /* If we can't find an available target, just return the + * original. */ + } + return target; +} + static int gdb_last_signal(struct target *target) { switch (target->debug_reason) { @@ -976,9 +999,9 @@ static int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { struct connection *connection = priv; - struct gdb_service *gdb_service = connection->service->priv; + struct target *gdb_target = get_available_target_from_connection(connection); - if (gdb_service->target != target) + if (gdb_target != target) return ERROR_OK; switch (event) { @@ -1503,7 +1526,7 @@ static int gdb_error(struct connection *connection, int retval) static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1578,7 +1601,7 @@ static int gdb_read_memory_packet(struct connection *connection, static int gdb_write_memory_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1629,7 +1652,7 @@ static int gdb_write_memory_packet(struct connection *connection, static int gdb_write_memory_binary_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1708,7 +1731,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, static int gdb_step_continue_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); int current = 0; uint64_t address = 0x0; int retval = ERROR_OK; @@ -1736,7 +1759,7 @@ static int gdb_step_continue_packet(struct connection *connection, static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; @@ -1918,7 +1941,7 @@ static int gdb_memory_map(struct connection *connection, * have to regenerate it a couple of times. */ - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); struct flash_bank *p; char *xml = NULL; int size = 0; @@ -2988,7 +3011,7 @@ static int gdb_query_packet(struct connection *connection, static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); const char *parse = packet; int retval; @@ -3227,7 +3250,7 @@ static void gdb_restart_inferior(struct connection *connection, const char *pack static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); const char *parse = packet; /* Skip "vRun" */ @@ -3273,7 +3296,7 @@ static int gdb_v_packet(struct connection *connection, struct gdb_connection *gdb_connection = connection->priv; int result; - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); if (strncmp(packet, "vCont", 5) == 0) { bool handled; @@ -3444,7 +3467,7 @@ static int gdb_detach(struct connection *connection) static int gdb_fileio_response_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; char *parsing_point; int fileio_retcode = strtoul(packet + 1, &separator, 16); @@ -3731,10 +3754,11 @@ static int gdb_input_inner(struct connection *connection) } if (gdb_con->ctrl_c) { - if (target->state == TARGET_RUNNING) { - struct target *t = target; - if (target->rtos) - target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); + struct target *available_target = get_available_target_from_connection(connection); + if (available_target->state == TARGET_RUNNING) { + struct target *t = available_target; + if (available_target->rtos) + available_target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); retval = target_halt(t); if (retval == ERROR_OK) retval = target_poll(t);