1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * ESP32xx application tracing module for OpenOCD *
5 * Copyright (C) 2017 Espressif Systems Ltd. *
6 ***************************************************************************/
12 #ifdef HAVE_ARPA_INET_H
13 #include <arpa/inet.h>
21 #include <netinet/tcp.h>
22 #include <sys/ioctl.h>
25 #include <helper/list.h>
26 #include <helper/time_support.h>
27 #include <target/target.h>
28 #include <target/target_type.h>
29 #include <target/smp.h>
30 #include <server/server.h>
31 #include "esp_xtensa.h"
32 #include "esp_xtensa_smp.h"
33 #include "esp_xtensa_apptrace.h"
34 #include "esp32_apptrace.h"
36 #define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
37 #define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
39 #define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4
41 #define ESP_APPTRACE_CMD_MODE_GEN 0
42 #define ESP_APPTRACE_CMD_MODE_SYSVIEW 1
43 #define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2
44 #define ESP_APPTRACE_CMD_MODE_SYNC 3
46 #define ESP32_APPTRACE_TGT_STATE_TMO 5000
47 #define ESP_APPTRACE_BLOCKS_POOL_SZ 10
49 struct esp32_apptrace_dest_file_data
{
53 struct esp32_apptrace_dest_tcp_data
{
57 struct esp32_apptrace_target_state
{
63 struct esp_apptrace_target2host_hdr
{
67 #define APPTRACE_BLOCK_SIZE_OFFSET 0
68 #define APPTRACE_WR_SIZE_OFFSET 2
70 struct esp32_apptrace_block
{
71 struct list_head node
;
76 static int esp32_apptrace_data_processor(void *priv
);
77 static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx
*ctx
,
78 struct esp32_apptrace_target_state
*target_state
,
79 uint32_t *fired_target_num
);
80 static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx
*ctx
,
81 struct esp32_apptrace_target_state
*targets
);
82 static struct esp32_apptrace_block
*esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx
*ctx
);
83 static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx
*ctx
,
84 struct esp32_apptrace_block
*block
);
86 static const bool s_time_stats_enable
= true;
88 /*********************************************************************
89 * Trace destination API
90 **********************************************************************/
92 static int esp32_apptrace_file_dest_write(void *priv
, uint8_t *data
, int size
)
94 struct esp32_apptrace_dest_file_data
*dest_data
= (struct esp32_apptrace_dest_file_data
*)priv
;
96 int wr_sz
= write(dest_data
->fout
, data
, size
);
98 LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size
, errno
, wr_sz
);
104 static int esp32_apptrace_file_dest_cleanup(void *priv
)
106 struct esp32_apptrace_dest_file_data
*dest_data
= (struct esp32_apptrace_dest_file_data
*)priv
;
108 if (dest_data
->fout
> 0)
109 close(dest_data
->fout
);
114 static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest
*dest
, const char *dest_name
)
116 struct esp32_apptrace_dest_file_data
*dest_data
= calloc(1, sizeof(*dest_data
));
118 LOG_ERROR("Failed to alloc mem for file dest!");
122 LOG_INFO("Open file %s", dest_name
);
123 dest_data
->fout
= open(dest_name
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0666);
124 if (dest_data
->fout
<= 0) {
125 LOG_ERROR("Failed to open file %s", dest_name
);
130 dest
->priv
= dest_data
;
131 dest
->write
= esp32_apptrace_file_dest_write
;
132 dest
->clean
= esp32_apptrace_file_dest_cleanup
;
133 dest
->log_progress
= true;
138 static int esp32_apptrace_console_dest_write(void *priv
, uint8_t *data
, int size
)
140 LOG_USER_N("%.*s", size
, data
);
144 static int esp32_apptrace_console_dest_cleanup(void *priv
)
149 static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest
*dest
, const char *dest_name
)
152 dest
->write
= esp32_apptrace_console_dest_write
;
153 dest
->clean
= esp32_apptrace_console_dest_cleanup
;
154 dest
->log_progress
= false;
159 static int esp32_apptrace_tcp_dest_write(void *priv
, uint8_t *data
, int size
)
161 struct esp32_apptrace_dest_tcp_data
*dest_data
= (struct esp32_apptrace_dest_tcp_data
*)priv
;
162 int wr_sz
= write_socket(dest_data
->sockfd
, data
, size
);
164 LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size
, errno
, wr_sz
);
170 static int esp32_apptrace_tcp_dest_cleanup(void *priv
)
172 struct esp32_apptrace_dest_tcp_data
*dest_data
= (struct esp32_apptrace_dest_tcp_data
*)priv
;
174 if (dest_data
->sockfd
> 0)
175 close_socket(dest_data
->sockfd
);
180 static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest
*dest
, const char *dest_name
)
182 const char *port_sep
= strchr(dest_name
, ':');
183 /* separator not found, or was the first or the last character */
184 if (!port_sep
|| port_sep
== dest_name
|| port_sep
== dest_name
+ strlen(dest_name
) - 1) {
185 LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port");
186 return ERROR_COMMAND_ARGUMENT_INVALID
;
188 size_t hostname_len
= port_sep
- dest_name
;
190 char hostname
[64] = { 0 };
191 if (hostname_len
>= sizeof(hostname
)) {
192 LOG_ERROR("apptrace: Hostname too long");
193 return ERROR_COMMAND_ARGUMENT_INVALID
;
195 memcpy(hostname
, dest_name
, hostname_len
);
197 const char *port_str
= port_sep
+ 1;
200 #ifdef AI_NUMERICSERV
201 flags
|= AI_NUMERICSERV
;
202 #endif /* AI_NUMERICSERV */
203 struct addrinfo hint
= {
204 .ai_family
= AF_UNSPEC
,
205 .ai_socktype
= SOCK_STREAM
,
209 int res
= getaddrinfo(hostname
, port_str
, &hint
, &ai
);
211 LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname
);
215 for (struct addrinfo
*ai_it
= ai
; ai_it
; ai_it
= ai_it
->ai_next
) {
216 sockfd
= socket(ai_it
->ai_family
, ai_it
->ai_socktype
, ai_it
->ai_protocol
);
218 LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)",
226 char cur_hostname
[NI_MAXHOST
];
227 char cur_portname
[NI_MAXSERV
];
229 getnameinfo(ai_it
->ai_addr
, ai_it
->ai_addrlen
, cur_hostname
,
230 sizeof(cur_hostname
),
231 cur_portname
, sizeof(cur_portname
),
232 NI_NUMERICHOST
| NI_NUMERICSERV
);
236 LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname
, cur_portname
);
237 if (connect(sockfd
, ai_it
->ai_addr
, ai_it
->ai_addrlen
) < 0) {
238 close_socket(sockfd
);
240 LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno
));
247 LOG_ERROR("apptrace: Could not connect to %s:%s", hostname
, port_str
);
250 LOG_INFO("apptrace: Connected!");
252 struct esp32_apptrace_dest_tcp_data
*dest_data
= calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data
));
254 LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!");
255 close_socket(sockfd
);
259 dest_data
->sockfd
= sockfd
;
260 dest
->priv
= dest_data
;
261 dest
->write
= esp32_apptrace_tcp_dest_write
;
262 dest
->clean
= esp32_apptrace_tcp_dest_cleanup
;
263 dest
->log_progress
= true;
268 int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest
[], const char *dest_paths
[], unsigned int max_dests
)
273 for (i
= 0; i
< max_dests
; i
++) {
274 if (strncmp(dest_paths
[i
], "file://", 7) == 0)
275 res
= esp32_apptrace_file_dest_init(&dest
[i
], &dest_paths
[i
][7]);
276 else if (strncmp(dest_paths
[i
], "con:", 4) == 0)
277 res
= esp32_apptrace_console_dest_init(&dest
[i
], NULL
);
278 else if (strncmp(dest_paths
[i
], "tcp://", 6) == 0)
279 res
= esp32_apptrace_tcp_dest_init(&dest
[i
], &dest_paths
[i
][6]);
283 if (res
!= ERROR_OK
) {
284 LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths
[i
]);
292 int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest
[], unsigned int max_dests
)
294 for (unsigned int i
= 0; i
< max_dests
; i
++) {
295 if (dest
[i
].clean
&& dest
[i
].priv
) {
296 int res
= dest
[i
].clean(dest
[i
].priv
);
304 /*********************************************************************
305 * Trace data blocks management API
306 **********************************************************************/
307 static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx
*ctx
)
309 struct esp32_apptrace_block
*cur
;
310 struct list_head
*head
= &ctx
->free_trace_blocks
;
311 struct list_head
*tmp
, *pos
;
313 list_for_each_safe(pos
, tmp
, head
) {
314 cur
= list_entry(pos
, struct esp32_apptrace_block
, node
);
316 list_del(&cur
->node
);
322 head
= &ctx
->ready_trace_blocks
;
324 list_for_each_safe(pos
, tmp
, head
) {
325 cur
= list_entry(pos
, struct esp32_apptrace_block
, node
);
327 list_del(&cur
->node
);
334 struct esp32_apptrace_block
*esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx
*ctx
)
336 struct esp32_apptrace_block
*block
= NULL
;
338 if (!list_empty(&ctx
->free_trace_blocks
)) {
340 block
= list_first_entry(&ctx
->free_trace_blocks
, struct esp32_apptrace_block
, node
);
341 list_del(&block
->node
);
347 static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx
*ctx
, struct esp32_apptrace_block
*block
)
349 LOG_DEBUG("esp32_apptrace_ready_block_put");
350 /* add to ready blocks list */
351 INIT_LIST_HEAD(&block
->node
);
352 list_add(&block
->node
, &ctx
->ready_trace_blocks
);
357 static struct esp32_apptrace_block
*esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx
*ctx
)
359 if (list_empty(&ctx
->ready_trace_blocks
))
362 struct esp32_apptrace_block
*block
=
363 list_last_entry(&ctx
->ready_trace_blocks
, struct esp32_apptrace_block
, node
);
365 /* remove it from ready list */
366 list_del(&block
->node
);
371 static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx
*ctx
, struct esp32_apptrace_block
*block
)
373 /* add to free blocks list */
374 INIT_LIST_HEAD(&block
->node
);
375 list_add(&block
->node
, &ctx
->free_trace_blocks
);
380 static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx
*ctx
)
382 int64_t timeout
= timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG
) ? 70000 : 5000);
383 while (!list_empty(&ctx
->ready_trace_blocks
)) {
385 if (timeval_ms() >= timeout
) {
386 LOG_ERROR("Failed to wait for pended trace blocks!");
390 /* signal timer callback to stop */
392 target_unregister_timer_callback(esp32_apptrace_data_processor
, ctx
);
396 /*********************************************************************
398 **********************************************************************/
400 int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx
*cmd_ctx
, struct command_invocation
*cmd
, int mode
)
402 struct target
*target
= get_current_target(CMD_CTX
);
404 memset(cmd_ctx
, 0, sizeof(struct esp32_apptrace_cmd_ctx
));
405 cmd_ctx
->target
= target
;
406 cmd_ctx
->mode
= mode
;
407 cmd_ctx
->target_state
= target
->state
;
411 struct target_list
*head
;
414 cmd_ctx
->cores_num
= 0;
415 foreach_smp_target(head
, target
->smp_targets
) {
417 if (i
== ESP32_APPTRACE_MAX_CORES_NUM
) {
418 command_print(cmd
, "Too many cores configured! Max %d cores are supported.",
419 ESP32_APPTRACE_MAX_CORES_NUM
);
422 if (!target_was_examined(curr
))
424 cmd_ctx
->cores_num
++;
425 cmd_ctx
->cpus
[i
++] = curr
;
428 cmd_ctx
->cores_num
= 1;
429 cmd_ctx
->cpus
[0] = target
;
431 /* some relies on ESP32_APPTRACE_MAX_CORES_NUM
432 * TODO: remove that dependency */
433 assert(cmd_ctx
->cores_num
<= ESP32_APPTRACE_MAX_CORES_NUM
&& "Too many cores number!");
435 struct xtensa
*xtensa
= target
->arch_info
;
436 if (xtensa
->common_magic
== XTENSA_COMMON_MAGIC
) {
437 cmd_ctx
->hw
= target_to_esp_xtensa(target
)->apptrace
.hw
;
438 } else { /* TODO: riscv is not supported yet */
439 command_print(cmd
, "Unsupported target arch 0x%X", xtensa
->common_magic
);
443 cmd_ctx
->max_trace_block_sz
= cmd_ctx
->hw
->max_block_size_get(cmd_ctx
->cpus
[0]);
444 if (cmd_ctx
->max_trace_block_sz
== 0) {
445 command_print(cmd
, "Failed to get max trace block size!");
448 LOG_INFO("Total trace memory: %" PRIu32
" bytes", cmd_ctx
->max_trace_block_sz
);
450 INIT_LIST_HEAD(&cmd_ctx
->ready_trace_blocks
);
451 INIT_LIST_HEAD(&cmd_ctx
->free_trace_blocks
);
452 for (unsigned int i
= 0; i
< ESP_APPTRACE_BLOCKS_POOL_SZ
; i
++) {
453 struct esp32_apptrace_block
*block
= calloc(1, sizeof(struct esp32_apptrace_block
));
455 command_print(cmd
, "Failed to alloc trace buffer entry!");
456 esp32_apptrace_blocks_pool_cleanup(cmd_ctx
);
459 block
->data
= malloc(cmd_ctx
->max_trace_block_sz
);
462 command_print(cmd
, "Failed to alloc trace buffer %" PRIu32
" bytes!", cmd_ctx
->max_trace_block_sz
);
463 esp32_apptrace_blocks_pool_cleanup(cmd_ctx
);
466 INIT_LIST_HEAD(&block
->node
);
467 list_add(&block
->node
, &cmd_ctx
->free_trace_blocks
);
470 cmd_ctx
->running
= 1;
471 if (cmd_ctx
->mode
!= ESP_APPTRACE_CMD_MODE_SYNC
) {
472 int res
= target_register_timer_callback(esp32_apptrace_data_processor
,
474 TARGET_TIMER_TYPE_PERIODIC
,
476 if (res
!= ERROR_OK
) {
477 command_print(cmd
, "Failed to start trace data timer callback (%d)!", res
);
478 esp32_apptrace_blocks_pool_cleanup(cmd_ctx
);
483 if (s_time_stats_enable
) {
484 cmd_ctx
->stats
.min_blk_read_time
= 1000000.0;
485 cmd_ctx
->stats
.min_blk_proc_time
= 1000000.0;
487 if (duration_start(&cmd_ctx
->idle_time
) != 0) {
488 command_print(cmd
, "Failed to start idle time measurement!");
489 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx
);
496 int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx
*cmd_ctx
)
498 esp32_apptrace_blocks_pool_cleanup(cmd_ctx
);
502 #define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \
504 if ((_arg_) == 0 && (_start_) == (_end_)) { \
505 command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \
510 void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx
*cmd_ctx
,
511 struct esp32_apptrace_cmd_data
*cmd_data
,
517 cmd_data
->poll_period
= strtoul(argv
[0], &end
, 10);
518 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx
->cmd
, cmd_data
->poll_period
, argv
[0], end
);
520 cmd_data
->max_len
= strtoul(argv
[1], &end
, 10);
521 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx
->cmd
, cmd_data
->max_len
, argv
[1], end
);
523 int32_t tmo
= strtol(argv
[2], &end
, 10);
524 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx
->cmd
, tmo
, argv
[2], end
);
525 cmd_ctx
->stop_tmo
= 1.0 * tmo
;
527 cmd_data
->wait4halt
= strtoul(argv
[3], &end
, 10);
528 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx
->cmd
, cmd_data
->wait4halt
, argv
[3], end
);
530 cmd_data
->skip_len
= strtoul(argv
[4], &end
, 10);
531 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx
->cmd
, cmd_data
->skip_len
, argv
[4], end
);
538 static int esp32_apptrace_core_id_get(struct target
*target
, uint8_t *hdr_buf
)
540 return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target
, hdr_buf
+ APPTRACE_BLOCK_SIZE_OFFSET
));
543 static uint32_t esp32_apptrace_usr_block_len_get(struct target
*target
, uint8_t *hdr_buf
, uint32_t *wr_len
)
545 *wr_len
= ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target
, hdr_buf
+ APPTRACE_WR_SIZE_OFFSET
));
546 return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target
, hdr_buf
+ APPTRACE_BLOCK_SIZE_OFFSET
));
549 static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx
*cmd_ctx
,
550 struct command_invocation
*cmd
,
555 struct esp32_apptrace_cmd_data
*cmd_data
;
558 command_print(cmd
, "Not enough args! Need trace data destination!");
562 int res
= esp32_apptrace_cmd_ctx_init(cmd_ctx
, cmd
, mode
);
566 cmd_data
= calloc(1, sizeof(*cmd_data
));
567 assert(cmd_data
&& "No memory for command data!");
568 cmd_ctx
->cmd_priv
= cmd_data
;
570 /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
571 res
= esp32_apptrace_dest_init(&cmd_data
->data_dest
, argv
, 1);
572 if (res
!= 1) { /* only one destination needs to be initialized */
573 command_print(cmd
, "Wrong args! Needs a trace data destination!");
577 cmd_ctx
->stop_tmo
= -1.0; /* infinite */
578 cmd_data
->max_len
= UINT32_MAX
;
579 cmd_data
->poll_period
= 0 /*ms*/;
581 /* parse remaining args */
582 esp32_apptrace_cmd_args_parse(cmd_ctx
, cmd_data
, &argv
[1], argc
- 1);
584 LOG_USER("App trace params: from %d cores, size %" PRId32
" bytes, stop_tmo %g s, poll period %" PRId32
585 " ms, wait_rst %d, skip %" PRId32
" bytes", cmd_ctx
->cores_num
,
588 cmd_data
->poll_period
,
592 cmd_ctx
->trace_format
.hdr_sz
= ESP32_APPTRACE_USER_BLOCK_HDR_SZ
;
593 cmd_ctx
->trace_format
.core_id_get
= esp32_apptrace_core_id_get
;
594 cmd_ctx
->trace_format
.usr_block_len_get
= esp32_apptrace_usr_block_len_get
;
597 command_print(cmd
, "Not enough args! Need %d trace data destinations!", cmd_ctx
->cores_num
);
598 cmd_ctx
->running
= 0;
599 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx
);
603 static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx
*cmd_ctx
)
605 struct esp32_apptrace_cmd_data
*cmd_data
= cmd_ctx
->cmd_priv
;
607 esp32_apptrace_dest_cleanup(&cmd_data
->data_dest
, 1);
609 cmd_ctx
->cmd_priv
= NULL
;
610 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx
);
614 static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx
*ctx
)
616 struct esp32_apptrace_cmd_data
*cmd_data
= ctx
->cmd_priv
;
617 uint32_t trace_sz
= 0;
620 trace_sz
= ctx
->tot_len
> cmd_data
->skip_len
? ctx
->tot_len
- cmd_data
->skip_len
: 0;
621 LOG_USER("Tracing is %s. Size is %" PRId32
" of %" PRId32
" @ %f (%f) KiB/s",
622 !ctx
->running
? "STOPPED" : "RUNNING",
624 cmd_data
? cmd_data
->max_len
: 0,
625 duration_kbps(&ctx
->read_time
, ctx
->tot_len
),
626 duration_kbps(&ctx
->read_time
, ctx
->raw_tot_len
));
627 LOG_USER("Data: blocks incomplete %" PRId32
", lost bytes: %" PRId32
,
628 ctx
->stats
.incompl_blocks
,
629 ctx
->stats
.lost_bytes
);
630 if (s_time_stats_enable
) {
631 LOG_USER("Block read time [%f..%f] ms",
632 1000 * ctx
->stats
.min_blk_read_time
,
633 1000 * ctx
->stats
.max_blk_read_time
);
634 LOG_USER("Block proc time [%f..%f] ms",
635 1000 * ctx
->stats
.min_blk_proc_time
,
636 1000 * ctx
->stats
.max_blk_proc_time
);
640 static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx
*ctx
, struct target
*target
)
642 LOG_USER("Wait for halt...");
643 while (!openocd_is_shutdown_pending()) {
644 int res
= target_poll(target
);
647 if (target
->state
== TARGET_HALTED
) {
648 LOG_USER("%s: HALTED", target
->cmd_name
);
656 int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx
*ctx
,
657 struct esp32_apptrace_target_state
*targets
)
661 memset(targets
, 0, ctx
->cores_num
* sizeof(struct esp32_apptrace_target_state
));
663 LOG_DEBUG("Halt all targets!");
664 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++) {
665 if (!target_was_examined(ctx
->cpus
[k
]))
667 if (ctx
->cpus
[k
]->state
== TARGET_HALTED
)
669 res
= target_halt(ctx
->cpus
[k
]);
670 if (res
!= ERROR_OK
) {
671 LOG_ERROR("Failed to halt target (%d)!", res
);
674 res
= target_wait_state(ctx
->cpus
[k
], TARGET_HALTED
, ESP32_APPTRACE_TGT_STATE_TMO
);
675 if (res
!= ERROR_OK
) {
676 LOG_ERROR("Failed to wait halt target %s / %d (%d)!",
677 target_name(ctx
->cpus
[k
]),
683 /* read current block statuses from CPUs */
684 LOG_DEBUG("Read current block statuses");
685 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++) {
687 res
= ctx
->hw
->status_reg_read(ctx
->cpus
[k
], &stat
);
688 if (res
!= ERROR_OK
) {
689 LOG_ERROR("Failed to read trace status (%d)!", res
);
692 /* check if some CPU stopped inside tracing regs update critical section */
694 if (ctx
->hw
->leave_trace_crit_section_start
) {
695 res
= ctx
->hw
->leave_trace_crit_section_start(ctx
->cpus
[k
]);
699 uint32_t bp_addr
= stat
;
700 res
= breakpoint_add(ctx
->cpus
[k
], bp_addr
, 1, BKPT_HARD
);
701 if (res
!= ERROR_OK
) {
702 LOG_ERROR("Failed to set breakpoint (%d)!", res
);
706 /* allow this CPU to leave ERI write critical section */
707 res
= target_resume(ctx
->cpus
[k
], 1, 0, 1, 0);
708 if (res
!= ERROR_OK
) {
709 LOG_ERROR("Failed to resume target (%d)!", res
);
710 breakpoint_remove(ctx
->cpus
[k
], bp_addr
);
713 /* wait for CPU to be halted on BP */
714 enum target_debug_reason debug_reason
= DBG_REASON_UNDEFINED
;
715 while (debug_reason
!= DBG_REASON_BREAKPOINT
) {
716 res
= target_wait_state(ctx
->cpus
[k
], TARGET_HALTED
,
717 ESP32_APPTRACE_TGT_STATE_TMO
);
718 if (res
!= ERROR_OK
) {
719 LOG_ERROR("Failed to wait halt on bp (%d)!", res
);
720 breakpoint_remove(ctx
->cpus
[k
], bp_addr
);
723 debug_reason
= ctx
->cpus
[k
]->debug_reason
;
725 res
= ctx
->hw
->status_reg_read(ctx
->cpus
[k
], &stat
);
726 if (res
!= ERROR_OK
) {
727 LOG_ERROR("Failed to read trace status (%d)!", res
);
728 breakpoint_remove(ctx
->cpus
[k
], bp_addr
);
732 breakpoint_remove(ctx
->cpus
[k
], bp_addr
);
733 if (ctx
->hw
->leave_trace_crit_section_stop
) {
734 res
= ctx
->hw
->leave_trace_crit_section_stop(ctx
->cpus
[k
]);
739 res
= ctx
->hw
->data_len_read(ctx
->cpus
[k
], &targets
[k
].block_id
, &targets
[k
].data_len
);
740 if (res
!= ERROR_OK
) {
741 LOG_ERROR("Failed to read trace status (%d)!", res
);
749 static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx
*ctx
,
753 struct esp32_apptrace_target_state target_to_connect
[ESP32_APPTRACE_MAX_CORES_NUM
];
756 LOG_USER("Connect targets...");
758 LOG_USER("Disconnect targets...");
760 int res
= esp32_apptrace_safe_halt_targets(ctx
, target_to_connect
);
761 if (res
!= ERROR_OK
) {
762 command_print(ctx
->cmd
, "Failed to halt targets (%d)!", res
);
765 if (ctx
->cores_num
> 1) {
766 /* set block ids to the highest value */
768 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++) {
769 if (target_to_connect
[k
].block_id
> max_id
)
770 max_id
= target_to_connect
[k
].block_id
;
772 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++)
773 target_to_connect
[k
].block_id
= max_id
;
775 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++) {
776 /* update host connected status */
777 res
= ctx
->hw
->ctrl_reg_write(ctx
->cpus
[k
],
778 target_to_connect
[k
].block_id
,
779 0 /*ack target data*/,
781 false /*no host data*/);
782 if (res
!= ERROR_OK
) {
783 command_print(ctx
->cmd
, "Failed to read trace status (%d)!", res
);
788 LOG_DEBUG("Resume targets");
789 bool smp_resumed
= false;
790 for (unsigned int k
= 0; k
< ctx
->cores_num
; k
++) {
791 if (smp_resumed
&& ctx
->cpus
[k
]->smp
) {
792 /* in SMP mode we need to call target_resume for one core only */
795 res
= target_resume(ctx
->cpus
[k
], 1, 0, 1, 0);
796 if (res
!= ERROR_OK
) {
797 command_print(ctx
->cmd
, "Failed to resume target (%d)!", res
);
800 if (ctx
->cpus
[k
]->smp
)
805 LOG_INFO("Targets connected.");
807 LOG_INFO("Targets disconnected.");
811 int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw
*hw
, struct target
*target
,
816 struct esp_apptrace_host2target_hdr hdr
= { .block_sz
= size
};
817 uint32_t buf_sz
[2] = { sizeof(hdr
), size
};
818 const uint8_t *bufs
[2] = { (const uint8_t *)&hdr
, data
};
820 if (size
> hw
->usr_block_max_size_get(target
)) {
821 LOG_ERROR("Too large user block %" PRId32
, size
);
825 return hw
->buffs_write(target
,
830 true /*ack target data*/,
834 static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx
*ctx
, uint8_t *hdr_buf
)
837 uint32_t usr_len
= ctx
->trace_format
.usr_block_len_get(ctx
->target
, hdr_buf
, &wr_len
);
838 if (usr_len
!= wr_len
) {
839 LOG_ERROR("Incomplete block sz %" PRId32
", wr %" PRId32
, usr_len
, wr_len
);
840 ctx
->stats
.incompl_blocks
++;
841 ctx
->stats
.lost_bytes
+= usr_len
- wr_len
;
846 int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx
*ctx
,
847 struct esp32_apptrace_target_state
*target_state
,
848 uint32_t *fired_target_num
)
850 if (fired_target_num
)
851 *fired_target_num
= UINT32_MAX
;
853 for (unsigned int i
= 0; i
< ctx
->cores_num
; i
++) {
854 int res
= ctx
->hw
->data_len_read(ctx
->cpus
[i
], &target_state
[i
].block_id
, &target_state
[i
].data_len
);
855 if (res
!= ERROR_OK
) {
856 LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx
->cpus
[i
]));
859 if (target_state
[i
].data_len
) {
860 LOG_TARGET_DEBUG(ctx
->cpus
[i
], "Block %" PRId32
", len %" PRId32
" bytes on fired",
861 target_state
[i
].block_id
, target_state
[i
].data_len
);
862 if (fired_target_num
)
863 *fired_target_num
= i
;
870 static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx
*ctx
,
871 unsigned int core_id
,
875 struct esp32_apptrace_cmd_data
*cmd_data
= ctx
->cmd_priv
;
877 LOG_DEBUG("Got block %" PRId32
" bytes [%x %x...%x %x]", data_len
, data
[12], data
[13],
878 data
[data_len
- 2], data
[data_len
- 1]);
879 if (ctx
->tot_len
+ data_len
> cmd_data
->skip_len
) {
880 uint32_t wr_idx
= 0, wr_chunk_len
= data_len
;
881 if (ctx
->tot_len
< cmd_data
->skip_len
) {
882 wr_chunk_len
= (ctx
->tot_len
+ wr_chunk_len
) - cmd_data
->skip_len
;
883 wr_idx
= cmd_data
->skip_len
- ctx
->tot_len
;
885 if (ctx
->tot_len
+ wr_chunk_len
> cmd_data
->max_len
)
886 wr_chunk_len
-= (ctx
->tot_len
+ wr_chunk_len
- cmd_data
->skip_len
) - cmd_data
->max_len
;
887 if (wr_chunk_len
> 0) {
888 int res
= cmd_data
->data_dest
.write(cmd_data
->data_dest
.priv
, data
+ wr_idx
, wr_chunk_len
);
889 if (res
!= ERROR_OK
) {
890 LOG_ERROR("Failed to write %" PRId32
" bytes to dest 0!", data_len
);
894 ctx
->tot_len
+= wr_chunk_len
;
896 ctx
->tot_len
+= data_len
;
899 if (cmd_data
->data_dest
.log_progress
)
900 LOG_USER("%" PRId32
" ", ctx
->tot_len
);
901 /* check for stop condition */
902 if (ctx
->tot_len
> cmd_data
->skip_len
&& (ctx
->tot_len
- cmd_data
->skip_len
>= cmd_data
->max_len
)) {
904 if (duration_measure(&ctx
->read_time
) != 0) {
905 LOG_ERROR("Failed to stop trace read time measure!");
912 static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx
*ctx
,
913 struct esp32_apptrace_block
*block
)
915 uint32_t processed
= 0;
916 uint32_t hdr_sz
= ctx
->trace_format
.hdr_sz
;
918 LOG_DEBUG("Got block %" PRId32
" bytes", block
->data_len
);
919 /* process user blocks one by one */
920 while (processed
< block
->data_len
) {
921 LOG_DEBUG("Process usr block %" PRId32
"/%" PRId32
, processed
, block
->data_len
);
922 /* process user block */
923 uint32_t usr_len
= esp32_apptrace_usr_block_check(ctx
, block
->data
+ processed
);
924 int core_id
= ctx
->trace_format
.core_id_get(ctx
->target
, block
->data
+ processed
);
925 /* process user data */
926 int res
= ctx
->process_data(ctx
, core_id
, block
->data
+ processed
+ hdr_sz
, usr_len
);
927 if (res
!= ERROR_OK
) {
928 LOG_ERROR("Failed to process %" PRId32
" bytes!", usr_len
);
931 processed
+= usr_len
+ hdr_sz
;
936 static int esp32_apptrace_data_processor(void *priv
)
938 struct esp32_apptrace_cmd_ctx
*ctx
= (struct esp32_apptrace_cmd_ctx
*)priv
;
943 struct esp32_apptrace_block
*block
= esp32_apptrace_ready_block_get(ctx
);
947 int res
= esp32_apptrace_handle_trace_block(ctx
, block
);
948 if (res
!= ERROR_OK
) {
950 LOG_ERROR("Failed to process trace block %" PRId32
" bytes!", block
->data_len
);
953 res
= esp32_apptrace_block_free(ctx
, block
);
954 if (res
!= ERROR_OK
) {
956 LOG_ERROR("Failed to free ready block!");
963 static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx
*ctx
)
968 unsigned int busy_target_num
= 0;
970 for (unsigned int i
= 0; i
< ctx
->cores_num
; i
++) {
972 int res
= ctx
->hw
->ctrl_reg_read(ctx
->cpus
[i
], NULL
, NULL
, &conn
);
973 if (res
!= ERROR_OK
) {
974 LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i
, res
);
979 LOG_TARGET_WARNING(ctx
->cpus
[i
], "apptrace connection is lost. Re-connect.");
980 res
= ctx
->hw
->status_reg_read(ctx
->cpus
[i
], &stat
);
981 if (res
!= ERROR_OK
) {
982 LOG_ERROR("Failed to read trace status (%d)!", res
);
986 LOG_TARGET_WARNING(ctx
->cpus
[i
], "in critical state. Retry in next poll");
987 if (++busy_target_num
== ctx
->cores_num
) {
988 LOG_WARNING("No available core");
993 res
= ctx
->hw
->ctrl_reg_write(ctx
->cpus
[i
],
996 true /*host connected*/,
997 false /*no host data*/);
998 if (res
!= ERROR_OK
) {
999 LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i
, res
);
1002 if (ctx
->stop_tmo
!= -1.0) {
1003 /* re-start idle time measurement */
1004 if (duration_start(&ctx
->idle_time
) != 0) {
1005 LOG_ERROR("Failed to re-start idle time measure!");
1015 static int esp32_apptrace_poll(void *priv
)
1017 struct esp32_apptrace_cmd_ctx
*ctx
= (struct esp32_apptrace_cmd_ctx
*)priv
;
1019 uint32_t fired_target_num
= 0;
1020 struct esp32_apptrace_target_state target_state
[ESP32_APPTRACE_MAX_CORES_NUM
];
1021 struct duration blk_proc_time
;
1023 if (!ctx
->running
) {
1024 if (ctx
->auto_clean
)
1025 ctx
->auto_clean(ctx
);
1029 /* Check for connection is alive.For some reason target and therefore host_connected flag
1030 * might have been reset */
1031 res
= esp32_apptrace_check_connection(ctx
);
1032 if (res
!= ERROR_OK
) {
1033 if (res
!= ERROR_WAIT
)
1038 /* check for data from target */
1039 res
= esp32_apptrace_get_data_info(ctx
, target_state
, &fired_target_num
);
1040 if (res
!= ERROR_OK
) {
1042 LOG_ERROR("Failed to read data len!");
1045 /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id,
1046 * target_state[0].data_len, target_name(ctx->cpus[0])); */
1047 if (fired_target_num
== UINT32_MAX
) {
1048 /* no data has been received, but block could be switched due to the data transferred
1049 * from host to target */
1050 if (ctx
->cores_num
> 1) {
1051 uint32_t max_block_id
= 0, min_block_id
= ctx
->hw
->max_block_id
;
1052 /* find maximum block ID and set the same ID in control reg for both cores
1054 for (unsigned int i
= 0; i
< ctx
->cores_num
; i
++) {
1055 if (max_block_id
< target_state
[i
].block_id
)
1056 max_block_id
= target_state
[i
].block_id
;
1057 if (min_block_id
> target_state
[i
].block_id
)
1058 min_block_id
= target_state
[i
].block_id
;
1060 /* handle block ID overflow */
1061 if (max_block_id
== ctx
->hw
->max_block_id
&& min_block_id
== 0)
1063 for (unsigned int i
= 0; i
< ctx
->cores_num
; i
++) {
1064 if (max_block_id
!= target_state
[i
].block_id
) {
1065 LOG_TARGET_DEBUG(ctx
->cpus
[i
], "Ack empty block %" PRId32
"!", max_block_id
);
1066 res
= ctx
->hw
->ctrl_reg_write(ctx
->cpus
[i
],
1069 true /*host connected*/,
1070 false /*no host data*/);
1071 if (res
!= ERROR_OK
) {
1073 LOG_TARGET_ERROR(ctx
->cpus
[i
], "Failed to ack empty data block!");
1078 ctx
->last_blk_id
= max_block_id
;
1080 if (ctx
->stop_tmo
!= -1.0) {
1081 if (duration_measure(&ctx
->idle_time
) != 0) {
1083 LOG_ERROR("Failed to measure idle time!");
1086 if (duration_elapsed(&ctx
->idle_time
) >= ctx
->stop_tmo
) {
1088 LOG_ERROR("Data timeout!");
1092 return ERROR_OK
;/* no data */
1095 if (target_state
[fired_target_num
].data_len
> ctx
->max_trace_block_sz
) {
1097 LOG_ERROR("Too large block size %" PRId32
"!", target_state
[fired_target_num
].data_len
);
1100 if (ctx
->tot_len
== 0) {
1101 if (duration_start(&ctx
->read_time
) != 0) {
1103 LOG_ERROR("Failed to start trace read time measurement!");
1107 struct esp32_apptrace_block
*block
= esp32_apptrace_free_block_get(ctx
);
1110 LOG_TARGET_ERROR(ctx
->cpus
[fired_target_num
], "Failed to get free block for data!");
1113 if (s_time_stats_enable
) {
1115 if (duration_start(&blk_proc_time
) != 0) {
1117 LOG_ERROR("Failed to start block read time measurement!");
1122 ctx
->hw
->data_read(ctx
->cpus
[fired_target_num
],
1123 target_state
[fired_target_num
].data_len
,
1125 target_state
[fired_target_num
].block_id
,
1126 /* do not ack target data in sync mode,
1127 esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
1128 ctx
->mode
!= ESP_APPTRACE_CMD_MODE_SYNC
);
1129 if (res
!= ERROR_OK
) {
1131 LOG_TARGET_ERROR(ctx
->cpus
[fired_target_num
], "Failed to read data!");
1134 ctx
->last_blk_id
= target_state
[fired_target_num
].block_id
;
1135 block
->data_len
= target_state
[fired_target_num
].data_len
;
1136 ctx
->raw_tot_len
+= block
->data_len
;
1137 if (s_time_stats_enable
) {
1138 if (duration_measure(&blk_proc_time
) != 0) {
1140 LOG_ERROR("Failed to measure block read time!");
1144 float brt
= duration_elapsed(&blk_proc_time
);
1145 if (brt
> ctx
->stats
.max_blk_read_time
)
1146 ctx
->stats
.max_blk_read_time
= brt
;
1147 if (brt
< ctx
->stats
.min_blk_read_time
)
1148 ctx
->stats
.min_blk_read_time
= brt
;
1150 if (duration_start(&blk_proc_time
) != 0) {
1152 LOG_ERROR("Failed to start block proc time measurement!");
1156 /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response
1157 * data and will do ack thereafter */
1158 if (ctx
->mode
!= ESP_APPTRACE_CMD_MODE_SYNC
) {
1159 for (unsigned int i
= 0; i
< ctx
->cores_num
; i
++) {
1160 if (i
== fired_target_num
)
1162 res
= ctx
->hw
->ctrl_reg_write(ctx
->cpus
[i
],
1165 true /*host connected*/,
1166 false /*no host data*/);
1167 if (res
!= ERROR_OK
) {
1169 LOG_TARGET_ERROR(ctx
->cpus
[i
], "Failed to ack data!");
1172 LOG_TARGET_DEBUG(ctx
->cpus
[i
], "Ack block %" PRId32
, ctx
->last_blk_id
);
1174 res
= esp32_apptrace_ready_block_put(ctx
, block
);
1175 if (res
!= ERROR_OK
) {
1177 LOG_TARGET_ERROR(ctx
->cpus
[fired_target_num
], "Failed to put ready block of data!");
1181 res
= esp32_apptrace_handle_trace_block(ctx
, block
);
1182 if (res
!= ERROR_OK
) {
1184 LOG_ERROR("Failed to process trace block %" PRId32
" bytes!", block
->data_len
);
1187 res
= esp32_apptrace_block_free(ctx
, block
);
1188 if (res
!= ERROR_OK
) {
1190 LOG_ERROR("Failed to free ready block!");
1194 if (ctx
->stop_tmo
!= -1.0) {
1195 /* start idle time measurement */
1196 if (duration_start(&ctx
->idle_time
) != 0) {
1198 LOG_ERROR("Failed to start idle time measure!");
1202 if (s_time_stats_enable
) {
1203 if (duration_measure(&blk_proc_time
) != 0) {
1205 LOG_ERROR("Failed to stop block proc time measure!");
1209 float bt
= duration_elapsed(&blk_proc_time
);
1210 if (bt
> ctx
->stats
.max_blk_proc_time
)
1211 ctx
->stats
.max_blk_proc_time
= bt
;
1212 if (bt
< ctx
->stats
.min_blk_proc_time
)
1213 ctx
->stats
.min_blk_proc_time
= bt
;
1218 static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx
*ctx
)
1220 if (duration_measure(&ctx
->read_time
) != 0)
1221 LOG_ERROR("Failed to stop trace read time measurement!");
1222 int res
= target_unregister_timer_callback(esp32_apptrace_poll
, ctx
);
1223 if (res
!= ERROR_OK
)
1224 LOG_ERROR("Failed to unregister target timer handler (%d)!", res
);
1226 /* data processor is alive, so wait for all received blocks to be processed */
1227 res
= esp32_apptrace_wait_tracing_finished(ctx
);
1228 if (res
!= ERROR_OK
)
1229 LOG_ERROR("Failed to wait for pended blocks (%d)!", res
);
1230 res
= esp32_apptrace_connect_targets(ctx
, false, ctx
->target_state
== TARGET_RUNNING
);
1231 if (res
!= ERROR_OK
)
1232 LOG_ERROR("Failed to disconnect targets (%d)!", res
);
1233 esp32_apptrace_print_stats(ctx
);
1234 res
= esp32_apptrace_cmd_cleanup(ctx
);
1235 if (res
!= ERROR_OK
)
1236 LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res
);
1239 int esp32_cmd_apptrace_generic(struct command_invocation
*cmd
, int mode
, const char **argv
, int argc
)
1241 static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx
;
1242 struct esp32_apptrace_cmd_data
*cmd_data
;
1243 int res
= ERROR_FAIL
;
1244 enum target_state old_state
;
1245 struct target
*target
= get_current_target(CMD_CTX
);
1248 return ERROR_COMMAND_SYNTAX_ERROR
;
1250 /* command can be invoked on unexamined core, if so find examined one */
1251 if (target
->smp
&& !target_was_examined(target
)) {
1252 struct target_list
*head
;
1253 struct target
*curr
;
1254 LOG_WARNING("Current target '%s' was not examined!", target_name(target
));
1255 foreach_smp_target(head
, target
->smp_targets
) {
1256 curr
= head
->target
;
1257 if (target_was_examined(curr
)) {
1259 LOG_WARNING("Run command on target '%s'", target_name(target
));
1264 old_state
= target
->state
;
1266 if (strcmp(argv
[0], "start") == 0) {
1267 res
= esp32_apptrace_cmd_init(&s_at_cmd_ctx
,
1272 if (res
!= ERROR_OK
) {
1273 command_print(cmd
, "Failed to init cmd ctx (%d)!", res
);
1276 cmd_data
= s_at_cmd_ctx
.cmd_priv
;
1277 s_at_cmd_ctx
.process_data
= esp32_apptrace_process_data
;
1278 s_at_cmd_ctx
.auto_clean
= esp32_apptrace_cmd_stop
;
1279 if (cmd_data
->wait4halt
) {
1280 res
= esp32_apptrace_wait4halt(&s_at_cmd_ctx
, target
);
1281 if (res
!= ERROR_OK
) {
1282 command_print(cmd
, "Failed to wait for halt target (%d)!", res
);
1283 goto _on_start_error
;
1286 res
= esp32_apptrace_connect_targets(&s_at_cmd_ctx
, true, old_state
== TARGET_RUNNING
);
1287 if (res
!= ERROR_OK
) {
1288 command_print(cmd
, "Failed to connect to targets (%d)!", res
);
1289 goto _on_start_error
;
1291 res
= target_register_timer_callback(esp32_apptrace_poll
,
1292 cmd_data
->poll_period
,
1293 TARGET_TIMER_TYPE_PERIODIC
,
1295 if (res
!= ERROR_OK
) {
1296 command_print(cmd
, "Failed to register target timer handler (%d)!", res
);
1297 goto _on_start_error
;
1299 } else if (strcmp(argv
[0], "stop") == 0) {
1300 if (!s_at_cmd_ctx
.running
) {
1301 command_print(cmd
, "Tracing is not running!");
1304 esp32_apptrace_cmd_stop(&s_at_cmd_ctx
);
1306 } else if (strcmp(argv
[0], "status") == 0) {
1307 if (s_at_cmd_ctx
.running
&& duration_measure(&s_at_cmd_ctx
.read_time
) != 0)
1308 LOG_ERROR("Failed to measure trace read time!");
1309 esp32_apptrace_print_stats(&s_at_cmd_ctx
);
1311 } else if (strcmp(argv
[0], "dump") == 0) {
1312 /* [dump outfile] - post-mortem dump without connection to targets */
1313 res
= esp32_apptrace_cmd_init(&s_at_cmd_ctx
,
1318 if (res
!= ERROR_OK
) {
1319 command_print(cmd
, "Failed to init cmd ctx (%d)!", res
);
1322 s_at_cmd_ctx
.stop_tmo
= 0.01; /* use small stop tmo */
1323 s_at_cmd_ctx
.process_data
= esp32_apptrace_process_data
;
1324 /* check for exit signal and command completion */
1325 while (!openocd_is_shutdown_pending() && s_at_cmd_ctx
.running
) {
1326 res
= esp32_apptrace_poll(&s_at_cmd_ctx
);
1327 if (res
!= ERROR_OK
) {
1328 LOG_ERROR("Failed to poll target for trace data (%d)!", res
);
1331 /* let registered timer callbacks to run */
1332 target_call_timer_callbacks();
1334 if (s_at_cmd_ctx
.running
) {
1335 /* data processor is alive, so wait for all received blocks to be processed */
1336 res
= esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx
);
1337 if (res
!= ERROR_OK
)
1338 LOG_ERROR("Failed to wait for pended blocks (%d)!", res
);
1340 esp32_apptrace_print_stats(&s_at_cmd_ctx
);
1341 res
= esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx
);
1342 if (res
!= ERROR_OK
)
1343 command_print(cmd
, "Failed to cleanup cmd ctx (%d)!", res
);
1345 command_print(cmd
, "Invalid action '%s'!", argv
[0]);
1351 s_at_cmd_ctx
.running
= 0;
1352 esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx
);
1356 COMMAND_HANDLER(esp32_cmd_apptrace
)
1358 return esp32_cmd_apptrace_generic(CMD
, ESP_APPTRACE_CMD_MODE_GEN
, CMD_ARGV
, CMD_ARGC
);
1361 const struct command_registration esp32_apptrace_command_handlers
[] = {
1364 .handler
= esp32_cmd_apptrace
,
1365 .mode
= COMMAND_EXEC
,
1367 "App Tracing: application level trace control. Starts, stops or queries tracing process status.",
1369 "[start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
1371 COMMAND_REGISTRATION_DONE
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)