X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=e2e614ffa315bb424ea39d0d5ebb96745874958e;hb=65de0d3bfa14c59c2fea31a2974dd3492ac3320d;hp=1e42c5eea92a951e7133968c6d8635319796733e;hpb=51ef02a5d161820f6d0be8f7984c3dc057b395a9;p=openocd.git diff --git a/src/target/target.c b/src/target/target.c index 1e42c5eea9..e2e614ffa3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -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_t* crc) +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",