target: Examine subsequent targets after failure
[fw/openocd] / src / target / target.c
index c0953a3f1ca666eebc4deec6bf75f6eb0308579a..3b1c666e5e0d8ec6c5ef06c624c5453ef0be7eb1 100644 (file)
@@ -72,8 +72,6 @@ static int target_get_gdb_fileio_info_default(struct target *target,
                struct gdb_fileio_info *fileio_info);
 static int target_gdb_fileio_end_default(struct target *target, int retcode,
                int fileio_errno, bool ctrl_c);
-static int target_profiling_default(struct target *target, uint32_t *samples,
-               uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
 
 /* targets */
 extern struct target_type arm7tdmi_target;
@@ -156,8 +154,8 @@ static struct target_type *target_types[] = {
 struct target *all_targets;
 static struct target_event_callback *target_event_callbacks;
 static struct target_timer_callback *target_timer_callbacks;
-LIST_HEAD(target_reset_callback_list);
-LIST_HEAD(target_trace_callback_list);
+static LIST_HEAD(target_reset_callback_list);
+static LIST_HEAD(target_trace_callback_list);
 static const int polling_interval = 100;
 
 static const Jim_Nvp nvp_assert[] = {
@@ -176,10 +174,10 @@ static const Jim_Nvp nvp_error_target[] = {
        { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" },
        { .value = ERROR_TARGET_NOT_HALTED, .name = "err-not-halted" },
        { .value = ERROR_TARGET_FAILURE, .name = "err-failure" },
-       { .value = ERROR_TARGET_UNALIGNED_ACCESS   , .name = "err-unaligned-access" },
-       { .value = ERROR_TARGET_DATA_ABORT , .name = "err-data-abort" },
-       { .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE , .name = "err-resource-not-available" },
-       { .value = ERROR_TARGET_TRANSLATION_FAULT  , .name = "err-translation-fault" },
+       { .value = ERROR_TARGET_UNALIGNED_ACCESS, .name = "err-unaligned-access" },
+       { .value = ERROR_TARGET_DATA_ABORT, .name = "err-data-abort" },
+       { .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE, .name = "err-resource-not-available" },
+       { .value = ERROR_TARGET_TRANSLATION_FAULT, .name = "err-translation-fault" },
        { .value = ERROR_TARGET_NOT_RUNNING, .name = "err-not-running" },
        { .value = ERROR_TARGET_NOT_EXAMINED, .name = "err-not-examined" },
        { .value = -1, .name = NULL }
@@ -229,10 +227,10 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" },
 
        { .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" },
-       { .value = TARGET_EVENT_GDB_FLASH_WRITE_END  , .name = "gdb-flash-write-end"   },
+       { .value = TARGET_EVENT_GDB_FLASH_WRITE_END,   .name = "gdb-flash-write-end"   },
 
        { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" },
-       { .value = TARGET_EVENT_GDB_FLASH_ERASE_END  , .name = "gdb-flash-erase-end" },
+       { .value = TARGET_EVENT_GDB_FLASH_ERASE_END,   .name = "gdb-flash-erase-end" },
 
        { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
 
@@ -249,15 +247,15 @@ static const Jim_Nvp nvp_target_state[] = {
 };
 
 static const Jim_Nvp nvp_target_debug_reason[] = {
-       { .name = "debug-request"            , .value = DBG_REASON_DBGRQ },
-       { .name = "breakpoint"               , .value = DBG_REASON_BREAKPOINT },
-       { .name = "watchpoint"               , .value = DBG_REASON_WATCHPOINT },
+       { .name = "debug-request",             .value = DBG_REASON_DBGRQ },
+       { .name = "breakpoint",                .value = DBG_REASON_BREAKPOINT },
+       { .name = "watchpoint",                .value = DBG_REASON_WATCHPOINT },
        { .name = "watchpoint-and-breakpoint", .value = DBG_REASON_WPTANDBKPT },
-       { .name = "single-step"              , .value = DBG_REASON_SINGLESTEP },
-       { .name = "target-not-halted"        , .value = DBG_REASON_NOTHALTED  },
-       { .name = "program-exit"             , .value = DBG_REASON_EXIT },
-       { .name = "exception-catch"          , .value = DBG_REASON_EXC_CATCH },
-       { .name = "undefined"                , .value = DBG_REASON_UNDEFINED },
+       { .name = "single-step",               .value = DBG_REASON_SINGLESTEP },
+       { .name = "target-not-halted",         .value = DBG_REASON_NOTHALTED  },
+       { .name = "program-exit",              .value = DBG_REASON_EXIT },
+       { .name = "exception-catch",           .value = DBG_REASON_EXC_CATCH },
+       { .name = "undefined",                 .value = DBG_REASON_UNDEFINED },
        { .name = NULL, .value = -1 },
 };
 
@@ -271,10 +269,10 @@ static const Jim_Nvp nvp_target_endian[] = {
 
 static const Jim_Nvp nvp_reset_modes[] = {
        { .name = "unknown", .value = RESET_UNKNOWN },
-       { .name = "run"    , .value = RESET_RUN },
-       { .name = "halt"   , .value = RESET_HALT },
-       { .name = "init"   , .value = RESET_INIT },
-       { .name = NULL     , .value = -1 },
+       { .name = "run",     .value = RESET_RUN },
+       { .name = "halt",    .value = RESET_HALT },
+       { .name = "init",    .value = RESET_INIT },
+       { .name = NULL,      .value = -1 },
 };
 
 const char *debug_reason_name(struct target *t)
@@ -344,6 +342,15 @@ static int new_target_number(void)
        return x + 1;
 }
 
+static void append_to_list_all_targets(struct target *target)
+{
+       struct target **t = &all_targets;
+
+       while (*t)
+               t = &((*t)->next);
+       *t = target;
+}
+
 /* read a uint64_t from a buffer in target memory endianness */
 uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer)
 {
@@ -593,7 +600,7 @@ int target_halt(struct target *target)
  * @param address Optionally used as the program counter.
  * @param handle_breakpoints True iff breakpoints at the resumption PC
  *     should be skipped.  (For example, maybe execution was stopped by
- *     such a breakpoint, in which case it would be counterprodutive to
+ *     such a breakpoint, in which case it would be counterproductive to
  *     let it re-trigger.
  * @param debug_execution False if all working areas allocated by OpenOCD
  *     should be released and/or restored to their original contents.
@@ -709,7 +716,7 @@ static int default_check_reset(struct target *target)
        return ERROR_OK;
 }
 
-/* Equvivalent Tcl code arp_examine_one is in src/target/startup.tcl
+/* Equivalent Tcl code arp_examine_one is in src/target/startup.tcl
  * Keep in sync */
 int target_examine_one(struct target *target)
 {
@@ -759,9 +766,11 @@ int target_examine(void)
                if (target->defer_examine)
                        continue;
 
-               retval = target_examine_one(target);
-               if (retval != ERROR_OK)
-                       return retval;
+               int retval2 = target_examine_one(target);
+               if (retval2 != ERROR_OK) {
+                       LOG_WARNING("target %s examination failed", target_name(target));
+                       retval = retval2;
+               }
        }
        return retval;
 }
@@ -1224,8 +1233,17 @@ int target_get_gdb_reg_list(struct target *target,
                struct reg **reg_list[], int *reg_list_size,
                enum target_register_class reg_class)
 {
-       int result = target->type->get_gdb_reg_list(target, reg_list,
+       int result = ERROR_FAIL;
+
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               goto done;
+       }
+
+       result = target->type->get_gdb_reg_list(target, reg_list,
                        reg_list_size, reg_class);
+
+done:
        if (result != ERROR_OK) {
                *reg_list = NULL;
                *reg_list_size = 0;
@@ -1247,10 +1265,10 @@ int target_get_gdb_reg_list_noread(struct target *target,
 bool target_supports_gdb_connection(struct target *target)
 {
        /*
-        * based on current code, we can simply exclude all the targets that
-        * don't provide get_gdb_reg_list; this could change with new targets.
+        * exclude all the targets that don't provide get_gdb_reg_list
+        * or that have explicit gdb_max_connection == 0
         */
-       return !!target->type->get_gdb_reg_list;
+       return !!target->type->get_gdb_reg_list && !!target->gdb_max_connections;
 }
 
 int target_step(struct target *target,
@@ -1303,13 +1321,9 @@ unsigned target_address_bits(struct target *target)
        return 32;
 }
 
-int target_profiling(struct target *target, uint32_t *samples,
+static int target_profiling(struct target *target, uint32_t *samples,
                        uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
 {
-       if (target->state != TARGET_HALTED) {
-               LOG_WARNING("target %s is not halted (profiling)", target->cmd_name);
-               return ERROR_TARGET_NOT_HALTED;
-       }
        return target->type->profiling(target, samples, max_num_samples,
                        num_samples, seconds);
 }
@@ -1770,10 +1784,8 @@ static void target_split_working_area(struct working_area *area, uint32_t size)
 
                /* If backup memory was allocated to this area, it has the wrong size
                 * now so free it and it will be reallocated if/when needed */
-               if (area->backup) {
-                       free(area->backup);
-                       area->backup = NULL;
-               }
+               free(area->backup);
+               area->backup = NULL;
        }
 }
 
@@ -1793,16 +1805,13 @@ static void target_merge_working_areas(struct target *target)
                        /* Remove the last */
                        struct working_area *to_be_freed = c->next;
                        c->next = c->next->next;
-                       if (to_be_freed->backup)
-                               free(to_be_freed->backup);
+                       free(to_be_freed->backup);
                        free(to_be_freed);
 
                        /* If backup memory was allocated to the remaining area, it's has
                         * the wrong size now */
-                       if (c->backup) {
-                               free(c->backup);
-                               c->backup = NULL;
-                       }
+                       free(c->backup);
+                       c->backup = NULL;
                } else {
                        c = c->next;
                }
@@ -2032,8 +2041,7 @@ static void target_destroy(struct target *target)
        if (target->type->deinit_target)
                target->type->deinit_target(target);
 
-       if (target->semihosting)
-               free(target->semihosting);
+       free(target->semihosting);
 
        jtag_unregister_event_callback(jtag_enable_callback, target);
 
@@ -2129,7 +2137,7 @@ static int target_gdb_fileio_end_default(struct target *target,
        return ERROR_OK;
 }
 
-static int target_profiling_default(struct target *target, uint32_t *samples,
+int target_profiling_default(struct target *target, uint32_t *samples,
                uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
 {
        struct timeval timeout, now;
@@ -2183,7 +2191,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
  */
 int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
 {
-       LOG_DEBUG("writing buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT,
+       LOG_DEBUG("writing buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT,
                          size, address);
 
        if (!target_was_examined(target)) {
@@ -2245,7 +2253,7 @@ static int target_write_buffer_default(struct target *target,
  */
 int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
 {
-       LOG_DEBUG("reading buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT,
+       LOG_DEBUG("reading buffer of %" PRIu32 " byte at " TARGET_ADDR_FMT,
                          size, address);
 
        if (!target_was_examined(target)) {
@@ -2315,7 +2323,7 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_
        if (retval != ERROR_OK) {
                buffer = malloc(size);
                if (buffer == NULL) {
-                       LOG_ERROR("error allocating buffer for section (%" PRId32 " bytes)", size);
+                       LOG_ERROR("error allocating buffer for section (%" PRIu32 " bytes)", size);
                        return ERROR_COMMAND_SYNTAX_ERROR;
                }
                retval = target_read_buffer(target, address, size, buffer);
@@ -2879,8 +2887,8 @@ COMMAND_HANDLER(handle_reg_command)
                                        continue;
                                /* only print cached values if they are valid */
                                if (reg->valid) {
-                                       value = buf_to_str(reg->value,
-                                                       reg->size, 16);
+                                       value = buf_to_hex_str(reg->value,
+                                                       reg->size);
                                        command_print(CMD,
                                                        "(%i) %s (/%" PRIu32 "): 0x%s%s",
                                                        count, reg->name,
@@ -2892,7 +2900,7 @@ COMMAND_HANDLER(handle_reg_command)
                                } else {
                                        command_print(CMD, "(%i) %s (/%" PRIu32 ")",
                                                          count, reg->name,
-                                                         reg->size) ;
+                                                         reg->size);
                                }
                        }
                        cache = cache->next;
@@ -2947,7 +2955,7 @@ COMMAND_HANDLER(handle_reg_command)
 
                if (reg->valid == 0)
                        reg->type->get(reg);
-               value = buf_to_str(reg->value, reg->size, 16);
+               value = buf_to_hex_str(reg->value, reg->size);
                command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value);
                free(value);
                return ERROR_OK;
@@ -2962,7 +2970,7 @@ COMMAND_HANDLER(handle_reg_command)
 
                reg->type->set(reg, buf);
 
-               value = buf_to_str(reg->value, reg->size, 16);
+               value = buf_to_hex_str(reg->value, reg->size);
                command_print(CMD, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value);
                free(value);
 
@@ -3398,11 +3406,11 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image,
                target_addr_t addr;
                COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr);
                image->base_address = addr;
-               image->base_address_set = 1;
+               image->base_address_set = true;
        } else
-               image->base_address_set = 0;
+               image->base_address_set = false;
 
-       image->start_address_set = 0;
+       image->start_address_set = false;
 
        if (CMD_ARGC >= 4)
                COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address);
@@ -3425,7 +3433,6 @@ COMMAND_HANDLER(handle_load_image_command)
        uint32_t image_size;
        target_addr_t min_address = 0;
        target_addr_t max_address = -1;
-       int i;
        struct image image;
 
        int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV,
@@ -3443,7 +3450,7 @@ COMMAND_HANDLER(handle_load_image_command)
 
        image_size = 0x0;
        retval = ERROR_OK;
-       for (i = 0; i < image.num_sections; i++) {
+       for (unsigned int i = 0; i < image.num_sections; i++) {
                buffer = malloc(image.sections[i].size);
                if (buffer == NULL) {
                        command_print(CMD,
@@ -3462,7 +3469,7 @@ COMMAND_HANDLER(handle_load_image_command)
                uint32_t offset = 0;
                uint32_t length = buf_cnt;
 
-               /* DANGER!!! beware of unsigned comparision here!!! */
+               /* DANGER!!! beware of unsigned comparison here!!! */
 
                if ((image.sections[i].base_address + buf_cnt >= min_address) &&
                                (image.sections[i].base_address < max_address)) {
@@ -3576,7 +3583,6 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver
        uint8_t *buffer;
        size_t buf_cnt;
        uint32_t image_size;
-       int i;
        int retval;
        uint32_t checksum = 0;
        uint32_t mem_checksum = 0;
@@ -3600,13 +3606,13 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver
                target_addr_t addr;
                COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr);
                image.base_address = addr;
-               image.base_address_set = 1;
+               image.base_address_set = true;
        } else {
-               image.base_address_set = 0;
+               image.base_address_set = false;
                image.base_address = 0x0;
        }
 
-       image.start_address_set = 0;
+       image.start_address_set = false;
 
        retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL);
        if (retval != ERROR_OK)
@@ -3615,12 +3621,12 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver
        image_size = 0x0;
        int diffs = 0;
        retval = ERROR_OK;
-       for (i = 0; i < image.num_sections; i++) {
+       for (unsigned int i = 0; i < image.num_sections; i++) {
                buffer = malloc(image.sections[i].size);
                if (buffer == NULL) {
                        command_print(CMD,
-                                       "error allocating buffer for section (%d bytes)",
-                                       (int)(image.sections[i].size));
+                                       "error allocating buffer for section (%" PRIu32 " bytes)",
+                                       image.sections[i].size);
                        break;
                }
                retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt);
@@ -3726,8 +3732,8 @@ static int handle_bp_command_list(struct command_invocation *cmd)
        struct breakpoint *breakpoint = target->breakpoints;
        while (breakpoint) {
                if (breakpoint->type == BKPT_SOFT) {
-                       char *buf = buf_to_str(breakpoint->orig_instr,
-                                       breakpoint->length, 16);
+                       char *buf = buf_to_hex_str(breakpoint->orig_instr,
+                                       breakpoint->length);
                        command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s",
                                        breakpoint->address,
                                        breakpoint->length,
@@ -4091,6 +4097,7 @@ COMMAND_HANDLER(handle_profile_command)
        uint32_t offset;
        uint32_t num_of_samples;
        int retval = ERROR_OK;
+       bool halted_before_profiling = target->state == TARGET_HALTED;
 
        COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset);
 
@@ -4121,12 +4128,23 @@ COMMAND_HANDLER(handle_profile_command)
                free(samples);
                return retval;
        }
-       if (target->state == TARGET_RUNNING) {
+
+       if (target->state == TARGET_RUNNING && halted_before_profiling) {
+               /* The target was halted before we started and is running now. Halt it,
+                * for consistency. */
                retval = target_halt(target);
                if (retval != ERROR_OK) {
                        free(samples);
                        return retval;
                }
+       } else if (target->state == TARGET_HALTED && !halted_before_profiling) {
+               /* The target was running before we started and is halted now. Resume
+                * it, for consistency. */
+               retval = target_resume(target, 1, 0, 0, 0);
+               if (retval != ERROR_OK) {
+                       free(samples);
+                       return retval;
+               }
        }
 
        retval = target_poll(target);
@@ -4283,7 +4301,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
        } else {
                char buf[100];
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-               sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
+               sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRIu32 " byte reads",
                                addr,
                                width);
                Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
@@ -4315,7 +4333,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
                        retval = target_read_memory(target, addr, width, count, buffer);
                if (retval != ERROR_OK) {
                        /* BOO !*/
-                       LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
+                       LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
                                          addr,
                                          width,
                                          count);
@@ -4489,7 +4507,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
        } else {
                char buf[100];
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-               sprintf(buf, "array2mem address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
+               sprintf(buf, "array2mem address: 0x%08" PRIx32 " is not aligned for %" PRIu32 " byte reads",
                                addr,
                                width);
                Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
@@ -4538,7 +4556,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
                        retval = target_write_memory(target, addr, width, count, buffer);
                if (retval != ERROR_OK) {
                        /* BOO !*/
-                       LOG_ERROR("array2mem: Write @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
+                       LOG_ERROR("array2mem: Write @ 0x%08" PRIx32 ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
                                          addr,
                                          width,
                                          count);
@@ -4582,8 +4600,14 @@ void target_handle_event(struct target *target, enum target_event e)
                        struct command_context *cmd_ctx = current_command_context(teap->interp);
                        struct target *saved_target_override = cmd_ctx->current_target_override;
                        cmd_ctx->current_target_override = target;
+
                        retval = Jim_EvalObj(teap->interp, teap->body);
 
+                       cmd_ctx->current_target_override = saved_target_override;
+
+                       if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
+                               return;
+
                        if (retval == JIM_RETURN)
                                retval = teap->interp->returnCode;
 
@@ -4596,8 +4620,6 @@ void target_handle_event(struct target *target, enum target_event e)
                                /* clean both error code and stacktrace before return */
                                Jim_Eval(teap->interp, "error \"\" \"\"");
                        }
-
-                       cmd_ctx->current_target_override = saved_target_override;
                }
        }
 }
@@ -4630,6 +4652,7 @@ enum target_cfg_param {
        TCFG_RTOS,
        TCFG_DEFER_EXAMINE,
        TCFG_GDB_PORT,
+       TCFG_GDB_MAX_CONNECTIONS,
 };
 
 static Jim_Nvp nvp_config_opts[] = {
@@ -4639,13 +4662,14 @@ static Jim_Nvp nvp_config_opts[] = {
        { .name = "-work-area-phys",   .value = TCFG_WORK_AREA_PHYS },
        { .name = "-work-area-size",   .value = TCFG_WORK_AREA_SIZE },
        { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
-       { .name = "-endian" ,          .value = TCFG_ENDIAN },
+       { .name = "-endian"          .value = TCFG_ENDIAN },
        { .name = "-coreid",           .value = TCFG_COREID },
        { .name = "-chain-position",   .value = TCFG_CHAIN_POSITION },
        { .name = "-dbgbase",          .value = TCFG_DBGBASE },
        { .name = "-rtos",             .value = TCFG_RTOS },
        { .name = "-defer-examine",    .value = TCFG_DEFER_EXAMINE },
        { .name = "-gdb-port",         .value = TCFG_GDB_PORT },
+       { .name = "-gdb-max-connections",   .value = TCFG_GDB_MAX_CONNECTIONS },
        { .name = NULL, .value = -1 }
 };
 
@@ -4682,7 +4706,7 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target)
                }
                switch (n->value) {
                case TCFG_TYPE:
-                       /* not setable */
+                       /* not settable */
                        if (goi->isconfigure) {
                                Jim_SetResultFormatted(goi->interp,
                                                "not settable: %s", n->name);
@@ -4953,6 +4977,25 @@ no_params:
                        Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1);
                        /* loop for more */
                        break;
+
+               case TCFG_GDB_MAX_CONNECTIONS:
+                       if (goi->isconfigure) {
+                               struct command_context *cmd_ctx = current_command_context(goi->interp);
+                               if (cmd_ctx->mode != COMMAND_CONFIG) {
+                                       Jim_SetResultString(goi->interp, "-gdb-max-conenctions must be configured before 'init'", -1);
+                                       return JIM_ERR;
+                               }
+
+                               e = Jim_GetOpt_Wide(goi, &w);
+                               if (e != JIM_OK)
+                                       return e;
+                               target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w;
+                       } else {
+                               if (goi->argc != 0)
+                                       goto no_params;
+                       }
+                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections));
+                       break;
                }
        } /* while (goi->argc) */
 
@@ -5474,12 +5517,21 @@ static int target_create(Jim_GetOptInfo *goi)
 
        /* Create it */
        target = calloc(1, sizeof(struct target));
+       if (!target) {
+               LOG_ERROR("Out of memory");
+               return JIM_ERR;
+       }
+
        /* set target number */
        target->target_number = new_target_number();
-       cmd_ctx->current_target = target;
 
        /* allocate memory for each unique target type */
-       target->type = calloc(1, sizeof(struct target_type));
+       target->type = malloc(sizeof(struct target_type));
+       if (!target->type) {
+               LOG_ERROR("Out of memory");
+               free(target);
+               return JIM_ERR;
+       }
 
        memcpy(target->type, target_types[x], sizeof(struct target_type));
 
@@ -5508,6 +5560,12 @@ static int target_create(Jim_GetOptInfo *goi)
 
        /* initialize trace information */
        target->trace_info = calloc(1, sizeof(struct trace));
+       if (!target->trace_info) {
+               LOG_ERROR("Out of memory");
+               free(target->type);
+               free(target);
+               return JIM_ERR;
+       }
 
        target->dbgmsg          = NULL;
        target->dbg_msg_enabled = 0;
@@ -5518,6 +5576,7 @@ static int target_create(Jim_GetOptInfo *goi)
        target->rtos_auto_detect = false;
 
        target->gdb_port_override = NULL;
+       target->gdb_max_connections = 1;
 
        /* Do the rest as "configure" options */
        goi->isconfigure = 1;
@@ -5541,7 +5600,9 @@ static int target_create(Jim_GetOptInfo *goi)
        }
 
        if (e != JIM_OK) {
+               rtos_destroy(target);
                free(target->gdb_port_override);
+               free(target->trace_info);
                free(target->type);
                free(target);
                return e;
@@ -5554,14 +5615,25 @@ static int target_create(Jim_GetOptInfo *goi)
 
        cp = Jim_GetString(new_cmd, NULL);
        target->cmd_name = strdup(cp);
+       if (!target->cmd_name) {
+               LOG_ERROR("Out of memory");
+               rtos_destroy(target);
+               free(target->gdb_port_override);
+               free(target->trace_info);
+               free(target->type);
+               free(target);
+               return JIM_ERR;
+       }
 
        if (target->type->target_create) {
                e = (*(target->type->target_create))(target, goi->interp);
                if (e != ERROR_OK) {
                        LOG_DEBUG("target_create failed");
+                       free(target->cmd_name);
+                       rtos_destroy(target);
                        free(target->gdb_port_override);
+                       free(target->trace_info);
                        free(target->type);
-                       free(target->cmd_name);
                        free(target);
                        return JIM_ERR;
                }
@@ -5574,15 +5646,6 @@ static int target_create(Jim_GetOptInfo *goi)
                        LOG_ERROR("unable to register '%s' commands", cp);
        }
 
-       /* append to end of list */
-       {
-               struct target **tpp;
-               tpp = &(all_targets);
-               while (*tpp)
-                       tpp = &((*tpp)->next);
-               *tpp = target;
-       }
-
        /* now - create the new target name command */
        const struct command_registration target_subcommands[] = {
                {
@@ -5604,14 +5667,27 @@ static int target_create(Jim_GetOptInfo *goi)
                COMMAND_REGISTRATION_DONE
        };
        e = register_commands(cmd_ctx, NULL, target_commands);
-       if (ERROR_OK != e)
+       if (e != ERROR_OK) {
+               if (target->type->deinit_target)
+                       target->type->deinit_target(target);
+               free(target->cmd_name);
+               rtos_destroy(target);
+               free(target->gdb_port_override);
+               free(target->trace_info);
+               free(target->type);
+               free(target);
                return JIM_ERR;
+       }
 
        struct command *c = command_find_in_context(cmd_ctx, cp);
        assert(c);
        command_set_handler_data(c, target);
 
-       return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
+       /* append to end of list */
+       append_to_list_all_targets(target);
+
+       cmd_ctx->current_target = target;
+       return JIM_OK;
 }
 
 static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -5623,7 +5699,9 @@ static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv
        struct command_context *cmd_ctx = current_command_context(interp);
        assert(cmd_ctx != NULL);
 
-       Jim_SetResultString(interp, target_name(get_current_target(cmd_ctx)), -1);
+       struct target *target = get_current_target_or_null(cmd_ctx);
+       if (target)
+               Jim_SetResultString(interp, target_name(target), -1);
        return JIM_OK;
 }
 
@@ -5670,7 +5748,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        retval = 0;
        LOG_DEBUG("%d", argc);
        /* argv[1] = target to associate in smp
-        * argv[2] = target to assoicate in smp
+        * argv[2] = target to associate in smp
         * argv[3] ...
         */
 
@@ -5779,11 +5857,8 @@ static struct FastLoad *fastload;
 static void free_fastload(void)
 {
        if (fastload != NULL) {
-               int i;
-               for (i = 0; i < fastload_num; i++) {
-                       if (fastload[i].data)
-                               free(fastload[i].data);
-               }
+               for (int i = 0; i < fastload_num; i++)
+                       free(fastload[i].data);
                free(fastload);
                fastload = NULL;
        }
@@ -5796,7 +5871,6 @@ COMMAND_HANDLER(handle_fast_load_image_command)
        uint32_t image_size;
        target_addr_t min_address = 0;
        target_addr_t max_address = -1;
-       int i;
 
        struct image image;
 
@@ -5822,7 +5896,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
                return ERROR_FAIL;
        }
        memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections);
-       for (i = 0; i < image.num_sections; i++) {
+       for (unsigned int i = 0; i < image.num_sections; i++) {
                buffer = malloc(image.sections[i].size);
                if (buffer == NULL) {
                        command_print(CMD, "error allocating buffer for section (%d bytes)",
@@ -5840,7 +5914,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
                uint32_t offset = 0;
                uint32_t length = buf_cnt;
 
-               /* DANGER!!! beware of unsigned comparision here!!! */
+               /* DANGER!!! beware of unsigned comparison here!!! */
 
                if ((image.sections[i].base_address + buf_cnt >= min_address) &&
                                (image.sections[i].base_address < max_address)) {