target: Fix segfault for 'mem2array'
[openocd.git] / src / target / target.c
index a9907b0c3ef92f042dd11d5495084a7fe6419a47..591b9ea2c8ee04bee0962a827aef685e55c5f149 100644 (file)
@@ -54,6 +54,7 @@
 #include "image.h"
 #include "rtos/rtos.h"
 #include "transport/transport.h"
+#include "arm_cti.h"
 
 /* default halt wait timeout (ms) */
 #define DEFAULT_HALT_TIMEOUT 5000
@@ -510,7 +511,9 @@ struct target *get_target_by_num(int num)
 
 struct target *get_current_target(struct command_context *cmd_ctx)
 {
-       struct target *target = get_target_by_num(cmd_ctx->current_target);
+       struct target *target = cmd_ctx->current_target_override
+               ? cmd_ctx->current_target_override
+               : cmd_ctx->current_target;
 
        if (target == NULL) {
                LOG_ERROR("BUG: current_target out of bounds");
@@ -808,8 +811,7 @@ done:
 }
 
 /**
- * Downloads a target-specific native code algorithm to the target,
- * executes and leaves it running.
+ * Executes a target-specific native code algorithm and leaves it running.
  *
  * @param target used to run the algorithm
  * @param arch_info target-specific description of the algorithm.
@@ -882,12 +884,45 @@ done:
 }
 
 /**
- * Executes a target-specific native code algorithm in the target.
- * It differs from target_run_algorithm in that the algorithm is asynchronous.
- * Because of this it requires an compliant algorithm:
- * see contrib/loaders/flash/stm32f1x.S for example.
+ * Streams data to a circular buffer on target intended for consumption by code
+ * running asynchronously on target.
+ *
+ * This is intended for applications where target-specific native code runs
+ * on the target, receives data from the circular buffer, does something with
+ * it (most likely writing it to a flash memory), and advances the circular
+ * buffer pointer.
+ *
+ * This assumes that the helper algorithm has already been loaded to the target,
+ * but has not been started yet. Given memory and register parameters are passed
+ * to the algorithm.
+ *
+ * The buffer is defined by (buffer_start, buffer_size) arguments and has the
+ * following format:
+ *
+ *     [buffer_start + 0, buffer_start + 4):
+ *         Write Pointer address (aka head). Written and updated by this
+ *         routine when new data is written to the circular buffer.
+ *     [buffer_start + 4, buffer_start + 8):
+ *         Read Pointer address (aka tail). Updated by code running on the
+ *         target after it consumes data.
+ *     [buffer_start + 8, buffer_start + buffer_size):
+ *         Circular buffer contents.
+ *
+ * See contrib/loaders/flash/stm32f1x.S for an example.
  *
  * @param target used to run the algorithm
+ * @param buffer address on the host where data to be sent is located
+ * @param count number of blocks to send
+ * @param block_size size in bytes of each block
+ * @param num_mem_params count of memory-based params to pass to algorithm
+ * @param mem_params memory-based params to pass to algorithm
+ * @param num_reg_params count of register-based params to pass to algorithm
+ * @param reg_params memory-based params to pass to algorithm
+ * @param buffer_start address on the target of the circular buffer structure
+ * @param buffer_size size of the circular buffer structure
+ * @param entry_point address on the target to execute to start the algorithm
+ * @param exit_point address at which to set a breakpoint to catch the
+ *     end of the algorithm; can be 0 if target triggers a breakpoint itself
  */
 
 int target_run_flash_async_algorithm(struct target *target,
@@ -1397,7 +1432,6 @@ int target_register_trace_callback(int (*callback)(struct target *target,
 int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv)
 {
        struct target_timer_callback **callbacks_p = &target_timer_callbacks;
-       struct timeval now;
 
        if (callback == NULL)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1414,14 +1448,8 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int
        (*callbacks_p)->time_ms = time_ms;
        (*callbacks_p)->removed = false;
 
-       gettimeofday(&now, NULL);
-       (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000;
-       time_ms -= (time_ms % 1000);
-       (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000);
-       if ((*callbacks_p)->when.tv_usec > 1000000) {
-               (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000;
-               (*callbacks_p)->when.tv_sec += 1;
-       }
+       gettimeofday(&(*callbacks_p)->when, NULL);
+       timeval_add_time(&(*callbacks_p)->when, 0, time_ms * 1000);
 
        (*callbacks_p)->priv = priv;
        (*callbacks_p)->next = NULL;
@@ -1556,14 +1584,8 @@ int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data
 static int target_timer_callback_periodic_restart(
                struct target_timer_callback *cb, struct timeval *now)
 {
-       int time_ms = cb->time_ms;
-       cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000;
-       time_ms -= (time_ms % 1000);
-       cb->when.tv_sec = now->tv_sec + time_ms / 1000;
-       if (cb->when.tv_usec > 1000000) {
-               cb->when.tv_usec = cb->when.tv_usec - 1000000;
-               cb->when.tv_sec += 1;
-       }
+       cb->when = *now;
+       timeval_add_time(&cb->when, 0, cb->time_ms * 1000L);
        return ERROR_OK;
 }
 
@@ -1607,9 +1629,7 @@ static int target_call_timer_callbacks_check_time(int checktime)
 
                bool call_it = (*callback)->callback &&
                        ((!checktime && (*callback)->periodic) ||
-                        now.tv_sec > (*callback)->when.tv_sec ||
-                        (now.tv_sec == (*callback)->when.tv_sec &&
-                         now.tv_usec >= (*callback)->when.tv_usec));
+                        timeval_compare(&now, &(*callback)->when) >= 0);
 
                if (call_it)
                        target_call_timer_callback(*callback, &now);
@@ -1873,8 +1893,41 @@ static void target_destroy(struct target *target)
        if (target->type->deinit_target)
                target->type->deinit_target(target);
 
+       if (target->semihosting)
+               free(target->semihosting);
+
+       jtag_unregister_event_callback(jtag_enable_callback, target);
+
+       struct target_event_action *teap = target->event_action;
+       while (teap) {
+               struct target_event_action *next = teap->next;
+               Jim_DecrRefCount(teap->interp, teap->body);
+               free(teap);
+               teap = next;
+       }
+
+       target_free_all_working_areas(target);
+       /* Now we have none or only one working area marked as free */
+       if (target->working_areas) {
+               free(target->working_areas->backup);
+               free(target->working_areas);
+       }
+
+       /* release the targets SMP list */
+       if (target->smp) {
+               struct target_list *head = target->head;
+               while (head != NULL) {
+                       struct target_list *pos = head->next;
+                       head->target->smp = 0;
+                       free(head);
+                       head = pos;
+               }
+               target->smp = 0;
+       }
+
        free(target->type);
        free(target->trace_info);
+       free(target->fileio_info);
        free(target->cmd_name);
        free(target);
 }
@@ -2028,8 +2081,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
                        break;
 
                gettimeofday(&now, NULL);
-               if ((sample_count >= max_num_samples) ||
-                       ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
+               if ((sample_count >= max_num_samples) || timeval_compare(&now, &timeout) >= 0) {
                        LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
                        break;
                }
@@ -2202,21 +2254,19 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_
        return retval;
 }
 
-int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank,
+int target_blank_check_memory(struct target *target,
+       struct target_memory_check_block *blocks, int num_blocks,
        uint8_t erased_value)
 {
-       int retval;
        if (!target_was_examined(target)) {
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
 
-       if (target->type->blank_check_memory == 0)
+       if (target->type->blank_check_memory == NULL)
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 
-       retval = target->type->blank_check_memory(target, address, size, blank, erased_value);
-
-       return retval;
+       return target->type->blank_check_memory(target, blocks, num_blocks, erased_value);
 }
 
 int target_read_u64(struct target *target, target_addr_t address, uint64_t *value)
@@ -2489,7 +2539,10 @@ static int find_target(struct command_context *cmd_ctx, const char *name)
                return ERROR_FAIL;
        }
 
-       cmd_ctx->current_target = target->target_number;
+       cmd_ctx->current_target = target;
+       if (cmd_ctx->current_target_override)
+               cmd_ctx->current_target_override = target;
+
        return ERROR_OK;
 }
 
@@ -2517,7 +2570,7 @@ COMMAND_HANDLER(handle_targets_command)
                else
                        state = "tap-disabled";
 
-               if (CMD_CTX->current_target == target->target_number)
+               if (CMD_CTX->current_target == target)
                        marker = '*';
 
                /* keep columns lined up to match the headers above */
@@ -2921,6 +2974,9 @@ COMMAND_HANDLER(handle_halt_command)
        LOG_DEBUG("-");
 
        struct target *target = get_current_target(CMD_CTX);
+
+       target->verbose_halt_msg = true;
+
        int retval = target_halt(target);
        if (ERROR_OK != retval)
                return retval;
@@ -3116,6 +3172,10 @@ COMMAND_HANDLER(handle_md_command)
                COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count);
 
        uint8_t *buffer = calloc(count, size);
+       if (buffer == NULL) {
+               LOG_ERROR("Failed to allocate md read buffer");
+               return ERROR_FAIL;
+       }
 
        struct target *target = get_current_target(CMD_CTX);
        int retval = fn(target, address, size, count, buffer);
@@ -3838,7 +3898,7 @@ typedef unsigned char UNIT[2];  /* unit of profiling */
 
 /* Dump a gmon.out histogram file. */
 static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range,
-                       uint32_t start_address, uint32_t end_address, struct target *target)
+                       uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms)
 {
        uint32_t i;
        FILE *f = fopen(filename, "w");
@@ -3906,7 +3966,8 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
        writeLong(f, min, target);                      /* low_pc */
        writeLong(f, max, target);                      /* high_pc */
        writeLong(f, numBuckets, target);       /* # of buckets */
-       writeLong(f, 100, target);                      /* KLUDGE! We lie, ca. 100Hz best case. */
+       float sample_rate = sampleNum / (duration_ms / 1000.0);
+       writeLong(f, sample_rate, target);
        writeString(f, "seconds");
        for (i = 0; i < (15-strlen("seconds")); i++)
                writeData(f, &zero, 1);
@@ -3955,6 +4016,7 @@ COMMAND_HANDLER(handle_profile_command)
                return ERROR_FAIL;
        }
 
+       uint64_t timestart_ms = timeval_ms();
        /**
         * Some cores let us sample the PC without the
         * annoying halt/resume step; for example, ARMv7 PCSR.
@@ -3966,6 +4028,7 @@ COMMAND_HANDLER(handle_profile_command)
                free(samples);
                return retval;
        }
+       uint32_t duration_ms = timeval_ms() - timestart_ms;
 
        assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
 
@@ -3998,7 +4061,7 @@ COMMAND_HANDLER(handle_profile_command)
        }
 
        write_gmon(samples, num_of_samples, CMD_ARGV[1],
-                  with_range, start_address, end_address, target);
+                  with_range, start_address, end_address, target, duration_ms);
        command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
 
        free(samples);
@@ -4068,8 +4131,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
         * argv[3] = memory address
         * argv[4] = count of times to read
         */
+
        if (argc < 4 || argc > 5) {
-               Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]");
+               Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
                return JIM_ERR;
        }
        varname = Jim_GetString(argv[0], &len);
@@ -4418,17 +4482,28 @@ void target_handle_event(struct target *target, enum target_event e)
 
        for (teap = target->event_action; teap != NULL; teap = teap->next) {
                if (teap->event == e) {
-                       LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
+                       LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s",
                                           target->target_number,
                                           target_name(target),
                                           target_type_name(target),
                                           e,
                                           Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
                                           Jim_GetString(teap->body, NULL));
+
+                       /* Override current target by the target an event
+                        * is issued from (lot of scripts need it).
+                        * Return back to previous override as soon
+                        * as the handler processing is done */
+                       struct command_context *cmd_ctx = current_command_context(teap->interp);
+                       struct target *saved_target_override = cmd_ctx->current_target_override;
+                       cmd_ctx->current_target_override = target;
+
                        if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) {
                                Jim_MakeErrorMessage(teap->interp);
                                command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL));
                        }
+
+                       cmd_ctx->current_target_override = saved_target_override;
                }
        }
 }
@@ -4458,7 +4533,6 @@ enum target_cfg_param {
        TCFG_COREID,
        TCFG_CHAIN_POSITION,
        TCFG_DBGBASE,
-       TCFG_CTIBASE,
        TCFG_RTOS,
        TCFG_DEFER_EXAMINE,
 };
@@ -4474,7 +4548,6 @@ static Jim_Nvp nvp_config_opts[] = {
        { .name = "-coreid",           .value = TCFG_COREID },
        { .name = "-chain-position",   .value = TCFG_CHAIN_POSITION },
        { .name = "-dbgbase",          .value = TCFG_DBGBASE },
-       { .name = "-ctibase",          .value = TCFG_CTIBASE },
        { .name = "-rtos",             .value = TCFG_RTOS },
        { .name = "-defer-examine",    .value = TCFG_DEFER_EXAMINE },
        { .name = NULL, .value = -1 }
@@ -4711,6 +4784,13 @@ no_params:
                        if (goi->isconfigure) {
                                Jim_Obj *o_t;
                                struct jtag_tap *tap;
+
+                               if (target->has_dap) {
+                                       Jim_SetResultString(goi->interp,
+                                               "target requires -dap parameter instead of -chain-position!", -1);
+                                       return JIM_ERR;
+                               }
+
                                target_free_all_working_areas(target);
                                e = Jim_GetOpt_Obj(goi, &o_t);
                                if (e != JIM_OK)
@@ -4718,8 +4798,8 @@ no_params:
                                tap = jtag_tap_by_jim_obj(goi->interp, o_t);
                                if (tap == NULL)
                                        return JIM_ERR;
-                               /* make this exactly 1 or 0 */
                                target->tap = tap;
+                               target->tap_configured = true;
                        } else {
                                if (goi->argc != 0)
                                        goto no_params;
@@ -4741,20 +4821,6 @@ no_params:
                        Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase));
                        /* loop for more */
                        break;
-               case TCFG_CTIBASE:
-                       if (goi->isconfigure) {
-                               e = Jim_GetOpt_Wide(goi, &w);
-                               if (e != JIM_OK)
-                                       return e;
-                               target->ctibase = (uint32_t)w;
-                               target->ctibase_set = true;
-                       } else {
-                               if (goi->argc != 0)
-                                       goto no_params;
-                       }
-                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->ctibase));
-                       /* loop for more */
-                       break;
                case TCFG_RTOS:
                        /* RTOS */
                        {
@@ -5371,21 +5437,19 @@ static const struct command_registration target_instance_command_handlers[] = {
                .mode = COMMAND_EXEC,
                .jim_handler = jim_target_examine,
                .help = "used internally for reset processing",
-               .usage = "arp_examine ['allow-defer']",
+               .usage = "['allow-defer']",
        },
        {
                .name = "was_examined",
                .mode = COMMAND_EXEC,
                .jim_handler = jim_target_was_examined,
                .help = "used internally for reset processing",
-               .usage = "was_examined",
        },
        {
                .name = "examine_deferred",
                .mode = COMMAND_EXEC,
                .jim_handler = jim_target_examine_deferred,
                .help = "used internally for reset processing",
-               .usage = "examine_deferred",
        },
        {
                .name = "arp_halt_gdb",
@@ -5506,7 +5570,7 @@ static int target_create(Jim_GetOptInfo *goi)
        target = calloc(1, sizeof(struct target));
        /* set target number */
        target->target_number = new_target_number();
-       cmd_ctx->current_target = target->target_number;
+       cmd_ctx->current_target = target;
 
        /* allocate memory for each unique target type */
        target->type = calloc(1, sizeof(struct target_type));
@@ -5532,7 +5596,7 @@ static int target_create(Jim_GetOptInfo *goi)
        target->next                = NULL;
        target->arch_info           = NULL;
 
-       target->display             = 1;
+       target->verbose_halt_msg        = true;
 
        target->halt_issued                     = false;
 
@@ -5551,9 +5615,21 @@ static int target_create(Jim_GetOptInfo *goi)
        goi->isconfigure = 1;
        e = target_configure(goi, target);
 
-       if (target->tap == NULL) {
-               Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1);
-               e = JIM_ERR;
+       if (e == JIM_OK) {
+               if (target->has_dap) {
+                       if (!target->dap_configured) {
+                               Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1);
+                               e = JIM_ERR;
+                       }
+               } else {
+                       if (!target->tap_configured) {
+                               Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1);
+                               e = JIM_ERR;
+                       }
+               }
+               /* tap must be set after target was configured */
+               if (target->tap == NULL)
+                       e = JIM_ERR;
        }
 
        if (e != JIM_OK) {
@@ -5570,14 +5646,23 @@ static int target_create(Jim_GetOptInfo *goi)
        cp = Jim_GetString(new_cmd, NULL);
        target->cmd_name = strdup(cp);
 
+       if (target->type->target_create) {
+               e = (*(target->type->target_create))(target, goi->interp);
+               if (e != ERROR_OK) {
+                       LOG_DEBUG("target_create failed");
+                       free(target->type);
+                       free(target->cmd_name);
+                       free(target);
+                       return JIM_ERR;
+               }
+       }
+
        /* create the target specific commands */
        if (target->type->commands) {
                e = register_commands(cmd_ctx, NULL, target->type->commands);
                if (ERROR_OK != e)
                        LOG_ERROR("unable to register '%s' commands", cp);
        }
-       if (target->type->target_create)
-               (*(target->type->target_create))(target, goi->interp);
 
        /* append to end of list */
        {
@@ -6331,7 +6416,7 @@ static const struct command_registration target_exec_command_handlers[] = {
                .handler = handle_bp_command,
                .mode = COMMAND_EXEC,
                .help = "list or set hardware or software breakpoint",
-               .usage = "<address> [<asid>]<length> ['hw'|'hw_ctx']",
+               .usage = "<address> [<asid>] <length> ['hw'|'hw_ctx']",
        },
        {
                .name = "rbp",

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)