X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fetm.c;h=afea12b3b8c898ced9e577eb456b8100b85b8708;hb=0485363c457fd42f38e94ee6b7190c89a4aa762f;hp=dd6e6025d2f9075dc27568d39f443da34026cf79;hpb=3d026ce94393e5e53cccb5d5364f9d500d5b3733;p=openocd.git diff --git a/src/target/etm.c b/src/target/etm.c index dd6e6025d2..afea12b3b8 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -223,7 +223,6 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_co etm_reg_t *arch_info = NULL; int num_regs = sizeof(etm_reg_arch_info)/sizeof(int); int i; - u32 etm_ctrl_value; /* register a register arch-type for etm registers only once */ if (etm_reg_arch_type == -1) @@ -256,21 +255,6 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_co arch_info[i].jtag_info = jtag_info; } - /* initialize some ETM control register settings */ - etm_get_reg(®_list[ETM_CTRL]); - etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); - - /* clear the ETM powerdown bit (0) */ - etm_ctrl_value &= ~0x1; - - /* configure port width (6:4), mode (17:16) and clocking (13) */ - etm_ctrl_value = (etm_ctrl_value & - ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) - | etm_ctx->portmode; - - buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); - etm_store_reg(®_list[ETM_CTRL]); - /* the ETM might have an ETB connected */ if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) { @@ -278,35 +262,64 @@ reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_co if (!etb) { - ERROR("etb selected as etm capture driver, but no ETB configured"); + LOG_ERROR("etb selected as etm capture driver, but no ETB configured"); return ERROR_OK; } reg_cache->next = etb_build_reg_cache(etb); etb->reg_cache = reg_cache->next; - - if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) - { - ERROR("ETM capture driver initialization failed"); - exit(-1); - } } + return reg_cache; } +int etm_setup(target_t *target) +{ + int retval; + u32 etm_ctrl_value; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + etm_context_t *etm_ctx = arm7_9->etm_ctx; + reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + /* initialize some ETM control register settings */ + etm_get_reg(etm_ctrl_reg); + etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size); + + /* clear the ETM powerdown bit (0) */ + etm_ctrl_value &= ~0x1; + + /* configure port width (6:4), mode (17:16) and clocking (13) */ + etm_ctrl_value = (etm_ctrl_value & + ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) + | etm_ctx->portmode; + + buf_set_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size, etm_ctrl_value); + etm_store_reg(etm_ctrl_reg); + + if ((retval=jtag_execute_queue())!=ERROR_OK) + return retval; + + if ((retval=etm_ctx->capture_driver->init(etm_ctx)) != ERROR_OK) + { + LOG_ERROR("ETM capture driver initialization failed"); + return retval; + } + return ERROR_OK; +} + int etm_get_reg(reg_t *reg) { if (etm_read_reg(reg) != ERROR_OK) { - ERROR("BUG: error scheduling etm register read"); + LOG_ERROR("BUG: error scheduling etm register read"); exit(-1); } if (jtag_execute_queue() != ERROR_OK) { - ERROR("register read failed"); + LOG_ERROR("register read failed"); } return ERROR_OK; @@ -318,7 +331,7 @@ int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) u8 reg_addr = etm_reg->addr & 0x7f; scan_field_t fields[3]; - DEBUG("%i", etm_reg->addr); + LOG_DEBUG("%i", etm_reg->addr); jtag_add_end_state(TAP_RTI); arm_jtag_scann(etm_reg->jtag_info, 0x6); @@ -356,13 +369,12 @@ int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) fields[2].in_handler = NULL; fields[2].in_handler_priv = NULL; - jtag_add_dr_scan(3, fields, -1, NULL); + jtag_add_dr_scan(3, fields, -1); fields[0].in_value = reg->value; - fields[0].in_check_value = check_value; - fields[0].in_check_mask = check_mask; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); - jtag_add_dr_scan(3, fields, -1, NULL); + jtag_add_dr_scan(3, fields, -1); free(fields[1].out_value); free(fields[2].out_value); @@ -379,7 +391,7 @@ int etm_set_reg(reg_t *reg, u32 value) { if (etm_write_reg(reg, value) != ERROR_OK) { - ERROR("BUG: error scheduling etm register write"); + LOG_ERROR("BUG: error scheduling etm register write"); exit(-1); } @@ -396,7 +408,7 @@ int etm_set_reg_w_exec(reg_t *reg, u8 *buf) if (jtag_execute_queue() != ERROR_OK) { - ERROR("register write failed"); + LOG_ERROR("register write failed"); exit(-1); } return ERROR_OK; @@ -408,7 +420,7 @@ int etm_write_reg(reg_t *reg, u32 value) u8 reg_addr = etm_reg->addr & 0x7f; scan_field_t fields[3]; - DEBUG("%i: 0x%8.8x", etm_reg->addr, value); + LOG_DEBUG("%i: 0x%8.8x", etm_reg->addr, value); jtag_add_end_state(TAP_RTI); arm_jtag_scann(etm_reg->jtag_info, 0x6); @@ -447,7 +459,7 @@ int etm_write_reg(reg_t *reg, u32 value) fields[2].in_handler = NULL; fields[2].in_handler_priv = NULL; - jtag_add_dr_scan(3, fields, -1, NULL); + jtag_add_dr_scan(3, fields, -1); free(fields[0].out_value); free(fields[1].out_value); @@ -465,10 +477,18 @@ int etm_store_reg(reg_t *reg) * */ extern etm_capture_driver_t etb_capture_driver; +extern etm_capture_driver_t etm_dummy_capture_driver; +#if BUILD_OOCD_TRACE == 1 +extern etm_capture_driver_t oocd_trace_capture_driver; +#endif etm_capture_driver_t *etm_capture_drivers[] = { &etb_capture_driver, + &etm_dummy_capture_driver, +#if BUILD_OOCD_TRACE == 1 + &oocd_trace_capture_driver, +#endif NULL }; @@ -519,7 +539,7 @@ int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) ctx->current_pc - ctx->image->sections[section].base_address, 4, buf, &size_read)) != ERROR_OK) { - ERROR("error while reading instruction: %i", retval); + LOG_ERROR("error while reading instruction: %i", retval); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(ctx->target, buf); @@ -532,7 +552,7 @@ int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) ctx->current_pc - ctx->image->sections[section].base_address, 2, buf, &size_read)) != ERROR_OK) { - ERROR("error while reading instruction: %i", retval); + LOG_ERROR("error while reading instruction: %i", retval); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(ctx->target, buf); @@ -540,12 +560,12 @@ int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) } else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) { - ERROR("BUG: tracing of jazelle code not supported"); + LOG_ERROR("BUG: tracing of jazelle code not supported"); exit(-1); } else { - ERROR("BUG: unknown core state encountered"); + LOG_ERROR("BUG: unknown core state encountered"); exit(-1); } @@ -716,13 +736,18 @@ int etmv1_data(etm_context_t *ctx, int size, u32 *data) } if (size == 8) - ERROR("TODO: add support for 64-bit values"); + { + LOG_ERROR("TODO: add support for 64-bit values"); + return -1; + } else if (size == 4) *data = target_buffer_get_u32(ctx->target, buf); else if (size == 2) *data = target_buffer_get_u16(ctx->target, buf); else if (size == 1) *data = buf[0]; + else + return -1; return 0; } @@ -751,11 +776,19 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) u32 next_pc = ctx->current_pc; u32 old_data_index = ctx->data_index; u32 old_data_half = ctx->data_half; + u32 old_index = ctx->pipe_index; + u32 last_instruction = ctx->last_instruction; + u32 cycles = 0; + int current_pc_ok = ctx->pc_ok; if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) { command_print(cmd_ctx, "--- trigger ---"); } + + /* instructions execute in IE/D or BE/D cycles */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + ctx->last_instruction = ctx->pipe_index; /* if we don't have a valid pc skip until we reach an indirect branch */ if ((!ctx->pc_ok) && (pipestat != STAT_BE)) @@ -775,6 +808,8 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) */ old_data_index = ctx->data_index; old_data_half = ctx->data_half; + + ctx->last_instruction = ctx->pipe_index; if ((retval = etmv1_branch_address(ctx)) != 0) { @@ -786,7 +821,7 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) /* a positive return values means the current branch was abandoned, * and a new branch was encountered in cycle ctx->pipe_index + retval; */ - WARNING("abandoned branch encountered, correctnes of analysis uncertain"); + LOG_WARNING("abandoned branch encountered, correctnes of analysis uncertain"); ctx->pipe_index += retval; continue; } @@ -819,9 +854,19 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) break; case 0x4: /* periodic synchronization point */ next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) + { + command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); + ctx->current_pc = next_pc; + ctx->pipe_index++; + continue; + } break; default: /* reserved */ - ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); + LOG_ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); exit(-1); break; } @@ -866,9 +911,13 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) } else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) { - /* TODO: handle incomplete images */ + /* TODO: handle incomplete images + * for now we just quit the analsysis*/ + return retval; } } + + cycles = old_index - last_instruction; } if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) @@ -891,7 +940,7 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) do { if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) - return -1; + return ERROR_ETM_ANALYSIS_FAILED; ctx->last_ptr &= ~(0x7f << shift); ctx->last_ptr |= (packet & 0x7f) << shift; shift += 7; @@ -917,7 +966,7 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) { u32 data; if (etmv1_data(ctx, 4, &data) != 0) - return -1; + return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd_ctx, "data: 0x%8.8x", data); } } @@ -926,7 +975,7 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) { u32 data; if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) - return -1; + return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd_ctx, "data: 0x%8.8x", data); } } @@ -961,8 +1010,22 @@ int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) { - command_print(cmd_ctx, "%s%s", - instruction.text, (pipestat == STAT_IN) ? " (not executed)" : ""); + char cycles_text[32] = ""; + + /* if the trace was captured with cycle accurate tracing enabled, + * output the number of cycles since the last executed instruction + */ + if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + { + snprintf(cycles_text, 32, " (%i %s)", + cycles, + (cycles == 1) ? "cycle" : "cycles"); + } + + command_print(cmd_ctx, "%s%s%s", + instruction.text, + (pipestat == STAT_IN) ? " (not executed)" : "", + cycles_text); ctx->current_pc = next_pc; @@ -1005,7 +1068,7 @@ int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, c tracemode = arm7_9->etm_ctx->tracemode; - if (argc == 3) + if (argc == 4) { if (strcmp(args[0], "none") == 0) { @@ -1061,10 +1124,24 @@ int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, c command_print(cmd_ctx, "invalid option '%s'", args[2]); return ERROR_OK; } + + if (strcmp(args[3], "enable") == 0) + { + tracemode |= ETMV1_BRANCH_OUTPUT; + } + else if (strcmp(args[3], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } } else if (argc != 0) { - command_print(cmd_ctx, "usage: configure trace mode "); + command_print(cmd_ctx, "usage: configure trace mode "); return ERROR_OK; } @@ -1110,6 +1187,15 @@ int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, c { command_print(cmd_ctx, "cycle-accurate tracing disabled"); } + + if (tracemode & ETMV1_BRANCH_OUTPUT) + { + command_print(cmd_ctx, "full branch address output enabled"); + } + else + { + command_print(cmd_ctx, "full branch address output disabled"); + } /* only update ETM_CTRL register if tracemode changed */ if (arm7_9->etm_ctx->tracemode != tracemode) @@ -1121,7 +1207,7 @@ int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, c buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); - + buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); etm_store_reg(etm_ctrl_reg); arm7_9->etm_ctx->tracemode = tracemode; @@ -1131,6 +1217,7 @@ int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, c if (arm7_9->etm_ctx->trace_depth > 0) { free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; } arm7_9->etm_ctx->trace_depth = 0; } @@ -1149,7 +1236,7 @@ int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char if (argc != 5) { - ERROR("incomplete 'etm config ' command"); + LOG_ERROR("incomplete 'etm config ' command"); exit(-1); } @@ -1157,7 +1244,7 @@ int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char if (!target) { - ERROR("target number '%s' not defined", args[0]); + LOG_ERROR("target number '%s' not defined", args[0]); exit(-1); } @@ -1231,7 +1318,16 @@ int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char } } + if (!etm_capture_drivers[i]) + { + /* no supported capture driver found, don't register an ETM */ + free(etm_ctx); + LOG_ERROR("trace capture driver '%s' not found", args[4]); + return ERROR_OK; + } + etm_ctx->target = target; + etm_ctx->trigger_percent = 50; etm_ctx->trace_data = NULL; etm_ctx->trace_depth = 0; etm_ctx->portmode = portmode; @@ -1247,6 +1343,7 @@ int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char etm_ctx->last_ptr = 0x0; etm_ctx->ptr_ok = 0x0; etm_ctx->context_id = 0x0; + etm_ctx->last_instruction = 0; arm7_9->etm_ctx = etm_ctx; @@ -1255,6 +1352,81 @@ int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char return ERROR_OK; } +int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + reg_t *etm_config_reg; + reg_t *etm_sys_config_reg; + + int max_port_size; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; + etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; + + etm_get_reg(etm_config_reg); + command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); + command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); + command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); + command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); + command_print(cmd_ctx, "sequencer %spresent", + (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); + command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); + command_print(cmd_ctx, "FIFO full %spresent", + (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); + + etm_get_reg(etm_sys_config_reg); + + switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) + { + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + default: + LOG_ERROR("Illegal max_port_size"); + exit(-1); + } + command_print(cmd_ctx, "max. port size: %i", max_port_size); + + command_print(cmd_ctx, "half-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "full-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "normal trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "multiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "demultiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "FIFO full %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); + + return ERROR_OK; +} + int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { target_t *target; @@ -1309,7 +1481,6 @@ int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char armv4_5_common_t *armv4_5; arm7_9_common_t *arm7_9; etm_context_t *etm_ctx; - int i; if (argc < 1) { @@ -1355,7 +1526,6 @@ int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) { - command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); free(etm_ctx->image); etm_ctx->image = NULL; return ERROR_OK; @@ -1412,7 +1582,6 @@ int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char * if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) { - command_print(cmd_ctx, "file open error: %s", file.error_str); return ERROR_OK; } @@ -1470,19 +1639,20 @@ int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char * if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) { - command_print(cmd_ctx, "file open error: %s", file.error_str); return ERROR_OK; } if (file.size % 4) { command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + fileio_close(&file); return ERROR_OK; } if (etm_ctx->trace_depth > 0) { free(etm_ctx->trace_data); + etm_ctx->trace_data = NULL; } fileio_read_u32(&file, &etm_ctx->capture_status); @@ -1491,12 +1661,22 @@ int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char * fileio_read_u32(&file, &etm_ctx->trace_depth); etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + if(etm_ctx->trace_data == NULL) + { + command_print(cmd_ctx, "not enough memory to perform operation"); + fileio_close(&file); + return ERROR_OK; + } for (i = 0; i < etm_ctx->trace_depth; i++) { - fileio_read_u32(&file, &etm_ctx->trace_data[i].pipestat); - fileio_read_u32(&file, &etm_ctx->trace_data[i].packet); - fileio_read_u32(&file, &etm_ctx->trace_data[i].flags); + u32 pipestat, packet, flags; + fileio_read_u32(&file, &pipestat); + fileio_read_u32(&file, &packet); + fileio_read_u32(&file, &flags); + etm_ctx->trace_data[i].pipestat = pipestat & 0xff; + etm_ctx->trace_data[i].packet = packet & 0xffff; + etm_ctx->trace_data[i].flags = flags; } fileio_close(&file); @@ -1504,6 +1684,46 @@ int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char * return ERROR_OK; } +int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (argc > 0) + { + u32 new_value = strtoul(args[0], NULL, 0); + + if ((new_value < 2) || (new_value > 100)) + { + command_print(cmd_ctx, "valid settings are 2% to 100%"); + } + else + { + etm_ctx->trigger_percent = new_value; + } + } + + command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); + + return ERROR_OK; +} + int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { target_t *target; @@ -1531,6 +1751,7 @@ int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char if (arm7_9->etm_ctx->trace_depth > 0) { free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; } arm7_9->etm_ctx->trace_depth = 0; @@ -1590,6 +1811,7 @@ int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, cha armv4_5_common_t *armv4_5; arm7_9_common_t *arm7_9; etm_context_t *etm_ctx; + int retval; target = get_current_target(cmd_ctx); @@ -1605,7 +1827,23 @@ int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, cha return ERROR_OK; } - etmv1_analyze_trace(etm_ctx, cmd_ctx); + if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) + { + switch(retval) + { + case ERROR_ETM_ANALYSIS_FAILED: + command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(cmd_ctx, "no image available for trace analysis"); + break; + default: + command_print(cmd_ctx, "unknown error: %i", retval); + } + } return ERROR_OK; } @@ -1622,8 +1860,13 @@ int etm_register_commands(struct command_context_s *cmd_ctx) int etm_register_user_commands(struct command_context_s *cmd_ctx) { register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, - COMMAND_EXEC, "configure trace mode "); + COMMAND_EXEC, "configure trace mode ", handle_etm_trigger_percent_command, + COMMAND_EXEC, "amount () of trace buffer to be filled after the trigger occured"); register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, COMMAND_EXEC, "display current target's ETM status"); register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command,