target: handle command 'target current' when no target is present
[openocd.git] / src / target / target.c
index 1e42c5eea92a951e7133968c6d8635319796733e..e2e614ffa315bb424ea39d0d5ebb96745874958e 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;
@@ -94,6 +92,7 @@ extern struct target_type cortexr4_target;
 extern struct target_type arm11_target;
 extern struct target_type ls1_sap_target;
 extern struct target_type mips_m4k_target;
+extern struct target_type mips_mips64_target;
 extern struct target_type avr_target;
 extern struct target_type dsp563xx_target;
 extern struct target_type dsp5680xx_target;
@@ -110,6 +109,7 @@ extern struct target_type stm8_target;
 extern struct target_type riscv_target;
 extern struct target_type mem_ap_target;
 extern struct target_type esirisc_target;
+extern struct target_type arcv2_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -145,9 +145,9 @@ static struct target_type *target_types[] = {
        &riscv_target,
        &mem_ap_target,
        &esirisc_target,
-#if BUILD_TARGET64
+       &arcv2_target,
        &aarch64_target,
-#endif
+       &mips_mips64_target,
        NULL,
 };
 
@@ -174,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 }
@@ -201,6 +201,8 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_RESUMED, .name = "resumed" },
        { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" },
        { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" },
+       { .value = TARGET_EVENT_STEP_START, .name = "step-start" },
+       { .value = TARGET_EVENT_STEP_END, .name = "step-end" },
 
        { .name = "gdb-start", .value = TARGET_EVENT_GDB_START },
        { .name = "gdb-end", .value = TARGET_EVENT_GDB_END },
@@ -215,6 +217,7 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_RESET_END,           .name = "reset-end" },
 
        { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" },
+       { .value = TARGET_EVENT_EXAMINE_FAIL, .name = "examine-fail" },
        { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" },
 
        { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" },
@@ -224,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" },
 
@@ -244,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 },
 };
 
@@ -266,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)
@@ -339,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)
 {
@@ -588,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.
@@ -704,13 +716,17 @@ static int default_check_reset(struct target *target)
        return ERROR_OK;
 }
 
+/* Equivalent Tcl code arp_examine_one is in src/target/startup.tcl
+ * Keep in sync */
 int target_examine_one(struct target *target)
 {
        target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START);
 
        int retval = target->type->examine(target);
-       if (retval != ERROR_OK)
+       if (retval != ERROR_OK) {
+               target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL);
                return retval;
+       }
 
        target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
 
@@ -1215,22 +1231,58 @@ int target_get_gdb_reg_list(struct target *target,
                struct reg **reg_list[], int *reg_list_size,
                enum target_register_class reg_class)
 {
-       return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
+       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;
+       }
+       return result;
+}
+
+int target_get_gdb_reg_list_noread(struct target *target,
+               struct reg **reg_list[], int *reg_list_size,
+               enum target_register_class reg_class)
+{
+       if (target->type->get_gdb_reg_list_noread &&
+                       target->type->get_gdb_reg_list_noread(target, reg_list,
+                               reg_list_size, reg_class) == ERROR_OK)
+               return ERROR_OK;
+       return target_get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
 }
 
 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,
                int current, target_addr_t address, int handle_breakpoints)
 {
-       return target->type->step(target, current, address, handle_breakpoints);
+       int retval;
+
+       target_call_event_callbacks(target, TARGET_EVENT_STEP_START);
+
+       retval = target->type->step(target, current, address, handle_breakpoints);
+       if (retval != ERROR_OK)
+               return retval;
+
+       target_call_event_callbacks(target, TARGET_EVENT_STEP_END);
+
+       return retval;
 }
 
 int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
@@ -1270,10 +1322,6 @@ unsigned target_address_bits(struct target *target)
 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);
 }
@@ -1587,8 +1635,9 @@ int target_call_event_callbacks(struct target *target, enum target_event event)
                target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
        }
 
-       LOG_DEBUG("target event %i (%s)", event,
-                       Jim_Nvp_value2name_simple(nvp_target_event, event)->name);
+       LOG_DEBUG("target event %i (%s) for core %s", event,
+                       Jim_Nvp_value2name_simple(nvp_target_event, event)->name,
+                       target_name(target));
 
        target_handle_event(target, event);
 
@@ -1662,7 +1711,7 @@ static int target_call_timer_callbacks_check_time(int checktime)
         * next item; initially, that's a standalone "root of the
         * list" variable. */
        struct target_timer_callback **callback = &target_timer_callbacks;
-       while (*callback) {
+       while (callback && *callback) {
                if ((*callback)->removed) {
                        struct target_timer_callback *p = *callback;
                        *callback = (*callback)->next;
@@ -1733,10 +1782,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;
        }
 }
 
@@ -1756,16 +1803,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;
                }
@@ -1995,8 +2039,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);
 
@@ -2022,6 +2065,8 @@ static void target_destroy(struct target *target)
                target->smp = 0;
        }
 
+       rtos_destroy(target);
+
        free(target->gdb_port_override);
        free(target->type);
        free(target->trace_info);
@@ -2090,7 +2135,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;
@@ -2144,7 +2189,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)) {
@@ -2206,7 +2251,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)) {
@@ -2261,7 +2306,7 @@ static int target_read_buffer_default(struct target *target, target_addr_t addre
        return ERROR_OK;
 }
 
-int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_tcrc)
+int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t *crc)
 {
        uint8_t *buffer;
        int retval;
@@ -2276,7 +2321,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);
@@ -2840,8 +2885,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,
@@ -2853,7 +2898,7 @@ COMMAND_HANDLER(handle_reg_command)
                                } else {
                                        command_print(CMD, "(%i) %s (/%" PRIu32 ")",
                                                          count, reg->name,
-                                                         reg->size) ;
+                                                         reg->size);
                                }
                        }
                        cache = cache->next;
@@ -2908,7 +2953,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;
@@ -2923,7 +2968,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);
 
@@ -3116,7 +3161,7 @@ COMMAND_HANDLER(handle_step_command)
 
        struct target *target = get_current_target(CMD_CTX);
 
-       return target->type->step(target, current_pc, addr, 1);
+       return target_step(target, current_pc, addr, 1);
 }
 
 void target_handle_md_output(struct command_invocation *cmd,
@@ -3318,8 +3363,8 @@ COMMAND_HANDLER(handle_mw_command)
        target_addr_t address;
        COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
 
-       target_addr_t value;
-       COMMAND_PARSE_ADDRESS(CMD_ARGV[1], value);
+       uint64_t value;
+       COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], value);
 
        unsigned count = 1;
        if (CMD_ARGC == 3)
@@ -3423,7 +3468,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)) {
@@ -3618,14 +3663,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver
 
                                data = malloc(buf_cnt);
 
-                               /* Can we use 32bit word accesses? */
-                               int size = 1;
-                               int count = buf_cnt;
-                               if ((count % 4) == 0) {
-                                       size *= 4;
-                                       count /= 4;
-                               }
-                               retval = target_read_memory(target, image.sections[i].base_address, size, count, data);
+                               retval = target_read_buffer(target, image.sections[i].base_address, buf_cnt, data);
                                if (retval == ERROR_OK) {
                                        uint32_t t;
                                        for (t = 0; t < buf_cnt; t++) {
@@ -3694,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,
@@ -3807,11 +3845,16 @@ COMMAND_HANDLER(handle_rbp_command)
        if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       target_addr_t addr;
-       COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
-
        struct target *target = get_current_target(CMD_CTX);
-       breakpoint_remove(target, addr);
+
+       if (!strcmp(CMD_ARGV[0], "all")) {
+               breakpoint_remove_all(target);
+       } else {
+               target_addr_t addr;
+               COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
+
+               breakpoint_remove(target, addr);
+       }
 
        return ERROR_OK;
 }
@@ -4054,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);
 
@@ -4084,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);
@@ -4246,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);
@@ -4278,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);
@@ -4452,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);
@@ -4501,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);
@@ -4526,6 +4581,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
 void target_handle_event(struct target *target, enum target_event e)
 {
        struct target_event_action *teap;
+       int retval;
 
        for (teap = target->event_action; teap != NULL; teap = teap->next) {
                if (teap->event == e) {
@@ -4545,7 +4601,17 @@ void target_handle_event(struct target *target, enum target_event e)
                        struct target *saved_target_override = cmd_ctx->current_target_override;
                        cmd_ctx->current_target_override = target;
 
-                       if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) {
+                       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;
+
+                       if (retval != JIM_OK) {
                                Jim_MakeErrorMessage(teap->interp);
                                LOG_USER("Error executing event %s on target %s:\n%s",
                                                  Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
@@ -4554,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;
                }
        }
 }
@@ -4588,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[] = {
@@ -4597,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 }
 };
 
@@ -4640,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);
@@ -4893,6 +4959,12 @@ no_params:
 
                case TCFG_GDB_PORT:
                        if (goi->isconfigure) {
+                               struct command_context *cmd_ctx = current_command_context(goi->interp);
+                               if (cmd_ctx->mode != COMMAND_CONFIG) {
+                                       Jim_SetResultString(goi->interp, "-gdb-port must be configured before 'init'", -1);
+                                       return JIM_ERR;
+                               }
+
                                const char *s;
                                e = Jim_GetOpt_String(goi, &s, NULL);
                                if (e != JIM_OK)
@@ -4905,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) */
 
@@ -4963,7 +5054,7 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv
        if (goi.argc > 0 &&
            strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) {
                /* consume it */
-               struct Jim_Obj *obj;
+               Jim_Obj *obj;
                int e = Jim_GetOpt_Obj(&goi, &obj);
                if (e != JIM_OK)
                        return e;
@@ -5133,7 +5224,6 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a
                                "target: %s wait %s fails (%#s) %s",
                                target_name(target), n->name,
                                eObj, target_strerror_safe(e));
-               Jim_FreeNewObj(interp, eObj);
                return JIM_ERR;
        }
        return JIM_OK;
@@ -5194,7 +5284,7 @@ static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const
 static const struct command_registration target_instance_command_handlers[] = {
        {
                .name = "configure",
-               .mode = COMMAND_CONFIG,
+               .mode = COMMAND_ANY,
                .jim_handler = jim_target_configure,
                .help  = "configure a new target for use",
                .usage = "[target_attribute ...]",
@@ -5427,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));
 
@@ -5461,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;
@@ -5471,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;
@@ -5494,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;
@@ -5507,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;
                }
@@ -5527,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[] = {
                {
@@ -5557,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)
@@ -5576,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;
 }
 
@@ -5623,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] ...
         */
 
@@ -5732,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;
        }
@@ -5793,7 +5915,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)) {
@@ -6185,7 +6307,7 @@ static const struct command_registration target_exec_command_handlers[] = {
                .name = "halt",
                .handler = handle_halt_command,
                .mode = COMMAND_EXEC,
-               .help = "request target to halt, then wait up to the specified"
+               .help = "request target to halt, then wait up to the specified "
                        "number of milliseconds (default 5000) for it to complete",
                .usage = "[milliseconds]",
        },
@@ -6201,7 +6323,7 @@ static const struct command_registration target_exec_command_handlers[] = {
                .handler = handle_reset_command,
                .mode = COMMAND_EXEC,
                .usage = "[run|halt|init]",
-               .help = "Reset all targets into the specified mode."
+               .help = "Reset all targets into the specified mode. "
                        "Default reset mode is run, if not given.",
        },
        {
@@ -6286,7 +6408,7 @@ static const struct command_registration target_exec_command_handlers[] = {
                .handler = handle_rbp_command,
                .mode = COMMAND_EXEC,
                .help = "remove breakpoint",
-               .usage = "address",
+               .usage = "'all' | address",
        },
        {
                .name = "wp",

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)