1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
50
51
59
60
61
62
63
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
87
88
89
90
96
97
98
99
100
107
108
120
121
122
123
124
125
126
127
128
135
136
137
138
139
140
141
142
143
144
147
148
149
150
151
152
153
154
155
156
157
158
162
163
164
165
166
167
168
169
170
171
172
173
176
177
178
179
180
181
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
209
210
228
229
230
231
232
235
236
237
238
239
240
242
243
244
245
246
247
249
250
251
252
/* ... */
#include "sdkconfig.h"
#include <string.h>
#include <sys/param.h>
#include "soc/soc_memory_layout.h"
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_ipc.h"
#include "esp_debug_helpers.h"
#include "esp_cpu_utils.h"
#include "esp_private/panic_internal.h"
#include "esp_private/freertos_debug.h"
#include "esp_rom_sys.h"
#include "xtensa_context.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"17 includes
const char *DEBUG_HELPER_TAG = "DBG HLPR";
bool IRAM_ATTR esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame)
{
void *base_save = (void *)frame->sp;
frame->pc = frame->next_pc;
frame->next_pc = *((uint32_t *)(base_save - 16));
frame->sp = *((uint32_t *)(base_save - 12));
return (esp_stack_ptr_is_sane(frame->sp) && esp_ptr_executable((void*)esp_cpu_process_stack_pc(frame->pc)));
}{ ... }
static void IRAM_ATTR print_entry(uint32_t pc, uint32_t sp, bool panic)
{
if (panic) {
panic_print_str(" 0x");
panic_print_hex(pc);
panic_print_str(":0x");
panic_print_hex(sp);
}{...} else {
esp_rom_printf(" 0x%08" PRIX32 ":0x%08" PRIX32, pc, sp);
}{...}
}{ ... }
static void IRAM_ATTR print_str(const char* str, bool panic)
{
if (panic) {
panic_print_str(str);
}{...} else {
esp_rom_printf(str);
}{...}
}{ ... }
esp_err_t IRAM_ATTR esp_backtrace_print_from_frame(int depth, const esp_backtrace_frame_t* frame, bool panic)
{
if (depth <= 0) {
return ESP_ERR_INVALID_ARG;
}{...}
esp_backtrace_frame_t stk_frame;
memcpy(&stk_frame, frame, sizeof(esp_backtrace_frame_t));
print_str("\r\n\r\nBacktrace:", panic);
print_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp, panic);
bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
(esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) ||
(stk_frame.exc_frame && ((XtExcFrame *)stk_frame.exc_frame)->exccause == EXCCAUSE_INSTR_PROHIBITED)));
uint32_t i = (depth <= 0) ? INT32_MAX : depth;
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
if (!esp_backtrace_get_next_frame(&stk_frame)) {
corrupted = true;
}{...}
print_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp, panic);
}{...}
esp_err_t ret = ESP_OK;
if (corrupted) {
print_str(" |<-CORRUPTED", panic);
ret = ESP_FAIL;
}{...} else if (stk_frame.next_pc != 0) {
print_str(" |<-CONTINUES", panic);
}{...}
print_str("\r\n\r\n", panic);
return ret;
}{ ... }
esp_err_t IRAM_ATTR esp_backtrace_print(int depth)
{
esp_backtrace_frame_t start = { 0 };
esp_backtrace_get_start(&(start.pc), &(start.sp), &(start.next_pc));
return esp_backtrace_print_from_frame(depth, &start, false);
}{ ... }
typedef struct {
#if !CONFIG_FREERTOS_UNICORE
volatile bool start_tracing;
volatile bool finished_tracing;/* ... */
#endif
struct {
TaskHandle_t task_hdl;
uint32_t starting_pc;
uint32_t starting_sp;
uint32_t next_pc;
}{ ... } cur_tasks[configNUMBER_OF_CORES];
}{ ... } cur_task_backtrace_ctrl_t;
#if !CONFIG_FREERTOS_UNICORE
static void backtrace_other_cores_ipc_func(void *arg)
{
cur_task_backtrace_ctrl_t *ctrl = (cur_task_backtrace_ctrl_t *)arg;
vTaskSuspendAll();
/* ... */
BaseType_t core_id = xPortGetCoreID();
ctrl->cur_tasks[core_id].task_hdl = xTaskGetCurrentTaskHandle();
esp_backtrace_get_start(&ctrl->cur_tasks[core_id].starting_pc,
&ctrl->cur_tasks[core_id].starting_sp,
&ctrl->cur_tasks[core_id].next_pc);
ctrl->start_tracing = true;
while (!ctrl->finished_tracing) {
;
}{...}
xTaskResumeAll();
}{ ... }
/* ... */#endif
esp_err_t IRAM_ATTR esp_backtrace_print_all_tasks(int depth)
{
esp_err_t ret = ESP_OK;
TaskSnapshot_t *task_snapshots;
cur_task_backtrace_ctrl_t ctrl = {0};
/* ... */
const UBaseType_t num_tasks = uxTaskGetNumberOfTasks();
task_snapshots = calloc(num_tasks, sizeof(TaskSnapshot_t));
ESP_GOTO_ON_FALSE(task_snapshots, ESP_ERR_NO_MEM, malloc_err, DEBUG_HELPER_TAG, "Task snapshot alloc failed");
#if !CONFIG_FREERTOS_UNICORE
ESP_GOTO_ON_ERROR(esp_ipc_call(!xPortGetCoreID(), backtrace_other_cores_ipc_func, (void *)&ctrl),
ipc_err,
DEBUG_HELPER_TAG,
"IPC call failed");
while (!ctrl.start_tracing) {
;
}{...}
/* ... */#endif
vTaskSuspendAll();
/* ... */
BaseType_t core_id = xPortGetCoreID();
ctrl.cur_tasks[core_id].task_hdl = xTaskGetCurrentTaskHandle();
esp_backtrace_get_start(&ctrl.cur_tasks[core_id].starting_pc,
&ctrl.cur_tasks[core_id].starting_sp,
&ctrl.cur_tasks[core_id].next_pc);
const UBaseType_t num_snapshots = MIN(num_tasks, uxTaskGetSnapshotAll(task_snapshots, num_tasks, NULL));
for (UBaseType_t task_idx = 0; task_idx < num_snapshots; task_idx++) {
bool cur_running = false;
TaskHandle_t task_hdl = (TaskHandle_t) task_snapshots[task_idx].pxTCB;
esp_backtrace_frame_t stk_frame = {0};
for (BaseType_t core_id = 0; core_id < configNUMBER_OF_CORES; core_id++) {
if (task_hdl == ctrl.cur_tasks[core_id].task_hdl) {
cur_running = true;
break;
}{...}
}{...}
if (cur_running) {
/* ... */
stk_frame.pc = ctrl.cur_tasks[core_id].starting_pc;
stk_frame.sp = ctrl.cur_tasks[core_id].starting_sp;
stk_frame.next_pc = ctrl.cur_tasks[core_id].next_pc;
}{...} else {
XtExcFrame* exc_frame = (XtExcFrame*) task_snapshots[task_idx].pxTopOfStack;
stk_frame.pc = exc_frame->pc;
stk_frame.sp = exc_frame->a1;
stk_frame.next_pc = exc_frame->a0;
}{...}
char* name = pcTaskGetName(task_hdl);
print_str(name ? name : "No Name", false);
esp_err_t bt_ret = esp_backtrace_print_from_frame(depth, &stk_frame, false);
if (bt_ret != ESP_OK) {
ret = bt_ret;
}{...}
}{...}
xTaskResumeAll();
#if !CONFIG_FREERTOS_UNICORE
ctrl.finished_tracing = true;/* ... */
#endif
free(task_snapshots);
return ret;
#if !CONFIG_FREERTOS_UNICORE
ipc_err:
free(task_snapshots);/* ... */
#endif
malloc_err:
return ret;
}{ ... }