target, register: allow a register hidden from gdb and 'reg' cmd
[openocd.git] / src / target / target.c
index 8c0fd496ef595846fd0f0a6bed3edcb96d3259a0..3c1a6338e915a561fb1d08f7f4ee79161753dc2c 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[] = {
@@ -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;
 }
@@ -1022,11 +1031,11 @@ int target_run_flash_async_algorithm(struct target *target,
                         * programming. The exact delay shouldn't matter as long as it's
                         * less than buffer size / flash speed. This is very unlikely to
                         * run when using high latency connections such as USB. */
-                       alive_sleep(10);
+                       alive_sleep(2);
 
                        /* to stop an infinite loop on some targets check and increment a timeout
                         * this issue was observed on a stellaris using the new ICDI interface */
-                       if (timeout++ >= 500) {
+                       if (timeout++ >= 2500) {
                                LOG_ERROR("timeout waiting for algorithm, a target reset is recommended");
                                return ERROR_FLASH_OPERATION_FAILED;
                        }
@@ -1040,6 +1049,10 @@ int target_run_flash_async_algorithm(struct target *target,
                if (thisrun_bytes > count * block_size)
                        thisrun_bytes = count * block_size;
 
+               /* Force end of large blocks to be word aligned */
+               if (thisrun_bytes >= 16)
+                       thisrun_bytes -= (rp + thisrun_bytes) & 0x03;
+
                /* Write data to fifo */
                retval = target_write_buffer(target, wp, thisrun_bytes, buffer);
                if (retval != ERROR_OK)
@@ -1089,6 +1102,156 @@ int target_run_flash_async_algorithm(struct target *target,
        return retval;
 }
 
+int target_run_read_async_algorithm(struct target *target,
+               uint8_t *buffer, uint32_t count, int block_size,
+               int num_mem_params, struct mem_param *mem_params,
+               int num_reg_params, struct reg_param *reg_params,
+               uint32_t buffer_start, uint32_t buffer_size,
+               uint32_t entry_point, uint32_t exit_point, void *arch_info)
+{
+       int retval;
+       int timeout = 0;
+
+       const uint8_t *buffer_orig = buffer;
+
+       /* Set up working area. First word is write pointer, second word is read pointer,
+        * rest is fifo data area. */
+       uint32_t wp_addr = buffer_start;
+       uint32_t rp_addr = buffer_start + 4;
+       uint32_t fifo_start_addr = buffer_start + 8;
+       uint32_t fifo_end_addr = buffer_start + buffer_size;
+
+       uint32_t wp = fifo_start_addr;
+       uint32_t rp = fifo_start_addr;
+
+       /* validate block_size is 2^n */
+       assert(!block_size || !(block_size & (block_size - 1)));
+
+       retval = target_write_u32(target, wp_addr, wp);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, rp_addr, rp);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Start up algorithm on target */
+       retval = target_start_algorithm(target, num_mem_params, mem_params,
+                       num_reg_params, reg_params,
+                       entry_point,
+                       exit_point,
+                       arch_info);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("error starting target flash read algorithm");
+               return retval;
+       }
+
+       while (count > 0) {
+               retval = target_read_u32(target, wp_addr, &wp);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("failed to get write pointer");
+                       break;
+               }
+
+               LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
+                       (size_t)(buffer - buffer_orig), count, wp, rp);
+
+               if (wp == 0) {
+                       LOG_ERROR("flash read algorithm aborted by target");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
+               }
+
+               if (((wp - fifo_start_addr) & (block_size - 1)) || wp < fifo_start_addr || wp >= fifo_end_addr) {
+                       LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp);
+                       break;
+               }
+
+               /* Count the number of bytes available in the fifo without
+                * crossing the wrap around. */
+               uint32_t thisrun_bytes;
+               if (wp >= rp)
+                       thisrun_bytes = wp - rp;
+               else
+                       thisrun_bytes = fifo_end_addr - rp;
+
+               if (thisrun_bytes == 0) {
+                       /* Throttle polling a bit if transfer is (much) faster than flash
+                        * reading. The exact delay shouldn't matter as long as it's
+                        * less than buffer size / flash speed. This is very unlikely to
+                        * run when using high latency connections such as USB. */
+                       alive_sleep(2);
+
+                       /* to stop an infinite loop on some targets check and increment a timeout
+                        * this issue was observed on a stellaris using the new ICDI interface */
+                       if (timeout++ >= 2500) {
+                               LOG_ERROR("timeout waiting for algorithm, a target reset is recommended");
+                               return ERROR_FLASH_OPERATION_FAILED;
+                       }
+                       continue;
+               }
+
+               /* Reset our timeout */
+               timeout = 0;
+
+               /* Limit to the amount of data we actually want to read */
+               if (thisrun_bytes > count * block_size)
+                       thisrun_bytes = count * block_size;
+
+               /* Force end of large blocks to be word aligned */
+               if (thisrun_bytes >= 16)
+                       thisrun_bytes -= (rp + thisrun_bytes) & 0x03;
+
+               /* Read data from fifo */
+               retval = target_read_buffer(target, rp, thisrun_bytes, buffer);
+               if (retval != ERROR_OK)
+                       break;
+
+               /* Update counters and wrap write pointer */
+               buffer += thisrun_bytes;
+               count -= thisrun_bytes / block_size;
+               rp += thisrun_bytes;
+               if (rp >= fifo_end_addr)
+                       rp = fifo_start_addr;
+
+               /* Store updated write pointer to target */
+               retval = target_write_u32(target, rp_addr, rp);
+               if (retval != ERROR_OK)
+                       break;
+
+               /* Avoid GDB timeouts */
+               keep_alive();
+
+       }
+
+       if (retval != ERROR_OK) {
+               /* abort flash write algorithm on target */
+               target_write_u32(target, rp_addr, 0);
+       }
+
+       int retval2 = target_wait_algorithm(target, num_mem_params, mem_params,
+                       num_reg_params, reg_params,
+                       exit_point,
+                       10000,
+                       arch_info);
+
+       if (retval2 != ERROR_OK) {
+               LOG_ERROR("error waiting for target flash write algorithm");
+               retval = retval2;
+       }
+
+       if (retval == ERROR_OK) {
+               /* check if algorithm set wp = 0 after fifo writer loop finished */
+               retval = target_read_u32(target, wp_addr, &wp);
+               if (retval == ERROR_OK && wp == 0) {
+                       LOG_ERROR("flash read algorithm aborted by target");
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+               }
+       }
+
+       return retval;
+}
+
 int target_read_memory(struct target *target,
                target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
 {
@@ -1224,8 +1387,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 +1419,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 +1475,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 +1938,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 +1959,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 +2195,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 +2291,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 +2345,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 +2407,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 +2477,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);
@@ -2875,12 +3037,12 @@ COMMAND_HANDLER(handle_reg_command)
                        for (i = 0, reg = cache->reg_list;
                                        i < cache->num_regs;
                                        i++, reg++, count++) {
-                               if (reg->exist == false)
+                               if (reg->exist == false || reg->hidden)
                                        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,
@@ -2947,7 +3109,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 +3124,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 +3560,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 +3587,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 +3604,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 +3623,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 +3737,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 +3760,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 +3775,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 +3886,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 +4251,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 +4282,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 +4455,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 +4487,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 +4661,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 +4710,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);
@@ -4634,6 +4806,7 @@ enum target_cfg_param {
        TCFG_RTOS,
        TCFG_DEFER_EXAMINE,
        TCFG_GDB_PORT,
+       TCFG_GDB_MAX_CONNECTIONS,
 };
 
 static Jim_Nvp nvp_config_opts[] = {
@@ -4650,6 +4823,7 @@ static Jim_Nvp nvp_config_opts[] = {
        { .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 }
 };
 
@@ -4686,7 +4860,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);
@@ -4957,6 +5131,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) */
 
@@ -5478,12 +5671,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));
 
@@ -5512,6 +5714,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;
@@ -5522,6 +5730,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;
@@ -5545,7 +5754,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;
@@ -5558,14 +5769,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;
                }
@@ -5578,15 +5800,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[] = {
                {
@@ -5608,14 +5821,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)
@@ -5627,7 +5853,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;
 }
 
@@ -5674,7 +5902,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] ...
         */
 
@@ -5783,11 +6011,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;
        }
@@ -5800,7 +6025,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;
 
@@ -5826,7 +6050,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)",
@@ -5844,7 +6068,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)) {

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)