Select one of the symbols to view example projects that use it.
 
Outline
#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"
DEBUG_HELPER_TAG
esp_backtrace_get_next_frame(esp_backtrace_frame_t *)
print_entry(uint32_t, uint32_t, bool)
print_str(const char *, bool)
esp_backtrace_print_from_frame(int, const esp_backtrace_frame_t *, bool)
esp_backtrace_print(int)
cur_task_backtrace_ctrl_t
backtrace_other_cores_ipc_func(void *)
esp_backtrace_print_all_tasks(int)
Files
loading...
SourceVuESP-IDF Framework and ExamplesESP-IDFcomponents/esp_system/port/arch/xtensa/debug_helpers.c
 
1
2
3
4
5
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #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) { //Use frame(i-1)'s BS area located below frame(i)'s sp to get frame(i-1)'s sp and frame(i-2)'s pc void *base_save = (void *)frame->sp; //Base save area consists of 4 words under SP frame->pc = frame->next_pc; frame->next_pc = *((uint32_t *)(base_save - 16)); //If next_pc = 0, indicates frame(i-1) is the last frame on the stack frame->sp = *((uint32_t *)(base_save - 12)); //Return true if both sp and pc of frame(i-1) are sane, false otherwise 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) { //Check arguments if (depth <= 0) { return ESP_ERR_INVALID_ARG; }{...} //Initialize stk_frame with first frame of stack 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); //Check if first frame is valid bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) && (esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) || /* Ignore the first corrupted PC in case of InstrFetchProhibited */ (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)) { //Get previous stack frame corrupted = true; }{...} print_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp, panic); }{...} //Print backtrace termination marker esp_err_t ret = ESP_OK; if (corrupted) { print_str(" |<-CORRUPTED", panic); ret = ESP_FAIL; }{...} else if (stk_frame.next_pc != 0) { //Backtrace continues print_str(" |<-CONTINUES", panic); }{...} print_str("\r\n\r\n", panic); return ret; }{ ... } esp_err_t IRAM_ATTR esp_backtrace_print(int depth) { //Initialize stk_frame with first frame of stack 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 // !CONFIG_FREERTOS_UNICORE 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; // Suspend the scheduler to prevent task switching vTaskSuspendAll(); /* Initialize backtracing for this core: - Flush current core's register windows back onto current task's stack using esp_backtrace_get_start() - Get starting frame for backtracing (starting frame is the caller of this function) using esp_backtrace_get_start() - Save the starting frame details into the control block *//* ... */ BaseType_t core_id = xPortGetCoreID(); // Get core ID now that task switching is disabled 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); // Indicate to backtracing core that this core is ready for backtracing ctrl->start_tracing = true; // Wait for backtracing core to indicate completion while (!ctrl->finished_tracing) { ; }{...} // Resume the scheduler to allow task switching again xTaskResumeAll(); }{ ... } /* ... */#endif // !CONFIG_FREERTOS_UNICORE 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}; /* Allocate array to store task snapshots. Users are responsible for ensuring tasks don't get created/deleted while backtracing. *//* ... */ 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 // Use IPC call to prepare other core for backtracing ESP_GOTO_ON_ERROR(esp_ipc_call(!xPortGetCoreID(), backtrace_other_cores_ipc_func, (void *)&ctrl), ipc_err, DEBUG_HELPER_TAG, "IPC call failed"); // Wait for other core to confirm its ready for backtracing while (!ctrl.start_tracing) { ; }{...} /* ... */#endif // !CONFIG_FREERTOS_UNICORE // Suspend the scheduler to prevent task switching vTaskSuspendAll(); /* Initialize backtracing for this core: - Flush current core's register windows back onto current task's stack using esp_backtrace_get_start() - Get starting frame for backtracing (starting frame is the caller of this function) using esp_backtrace_get_start() - Save the starting frame details into the control block *//* ... */ BaseType_t core_id = xPortGetCoreID(); // Get core ID now that task switching is disabled 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); // Get snapshot of all tasks in the system const UBaseType_t num_snapshots = MIN(num_tasks, uxTaskGetSnapshotAll(task_snapshots, num_tasks, NULL)); // Print the backtrace of every task in the system 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}; // Check if the task is one of the currently running tasks 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; }{...} }{...} // Initialize the starting backtrace frame of the task if (cur_running) { /* Setting the starting backtrace frame for currently running tasks is different. We cannot use the current frame of each running task as the starting frame (due to the possibility of the SP changing). Thus, each currently running task will have initialized their callers as the starting frame for backtracing, which is saved inside the cur_task_backtrace_ctrl_t block. *//* ... */ 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 { // Set the starting backtrace frame using the task's saved stack pointer 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; }{...} // Print backtrace 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; }{...} }{...} // Resume the scheduler to allow task switching again xTaskResumeAll(); #if !CONFIG_FREERTOS_UNICORE // Indicate to the other core that backtracing is complete ctrl.finished_tracing = true;/* ... */ #endif // !CONFIG_FREERTOS_UNICORE free(task_snapshots); return ret; #if !CONFIG_FREERTOS_UNICORE ipc_err: free(task_snapshots);/* ... */ #endif // !CONFIG_FREERTOS_UNICORE malloc_err: return ret; }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.