1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Core dump port implementation for Xtensa based boards.
10 */
11
12 #include <string.h>
13 #include <stdbool.h>
14 #include "soc/soc_memory_layout.h"
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/task.h"
17 #include "freertos/xtensa_context.h"
18 #include "esp_rom_sys.h"
19 #include "esp_core_dump_common.h"
20 #include "esp_core_dump_port.h"
21 #include "esp_debug_helpers.h"
22
23 const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port";
24
25 #define min(a,b) ((a) < (b) ? (a) : (b))
26
27 #define COREDUMP_EM_XTENSA 0x5E
28 #define COREDUMP_INVALID_CAUSE_VALUE 0xFFFF
29 #define COREDUMP_FAKE_STACK_START 0x20000000
30 #define COREDUMP_FAKE_STACK_LIMIT 0x30000000
31 #define COREDUMP_EXTRA_REG_NUM 16
32
33 #define COREDUMP_GET_REG_PAIR(reg_idx, reg_ptr) { *(uint32_t*)(reg_ptr++) = (uint32_t)reg_idx; \
34 RSR(reg_idx, *(uint32_t*)(reg_ptr++)); \
35 }
36
37 #define COREDUMP_GET_EPC(reg, ptr) \
38 if (reg - EPC_1 + 1 <= XCHAL_NUM_INTLEVELS) COREDUMP_GET_REG_PAIR(reg, ptr)
39
40 #define COREDUMP_GET_EPS(reg, ptr) \
41 if (reg - EPS_2 + 2 <= XCHAL_NUM_INTLEVELS) COREDUMP_GET_REG_PAIR(reg, ptr)
42
43 // Enumeration of registers of exception stack frame
44 // and solicited stack frame
45 typedef enum
46 {
47 // XT_SOL_EXIT = 0,
48 XT_SOL_PC = 1,
49 XT_SOL_PS = 2,
50 // XT_SOL_NEXT = 3,
51 XT_SOL_AR_START = 4,
52 XT_SOL_AR_NUM = 4,
53 // XT_SOL_FRMSZ = 8,
54 XT_STK_EXIT = 0,
55 XT_STK_PC = 1,
56 XT_STK_PS = 2,
57 XT_STK_AR_START = 3,
58 XT_STK_AR_NUM = 16,
59 XT_STK_SAR = 19,
60 XT_STK_EXCCAUSE = 20,
61 XT_STK_EXCVADDR = 21,
62 XT_STK_LBEG = 22,
63 XT_STK_LEND = 23,
64 XT_STK_LCOUNT = 24,
65 //XT_STK_FRMSZ = 25,
66 } stk_frame_t;
67
68 // Xtensa ELF core file register set representation ('.reg' section).
69 // Copied from target-side ELF header <xtensa/elf.h>.
70 typedef struct
71 {
72 uint32_t pc;
73 uint32_t ps;
74 uint32_t lbeg;
75 uint32_t lend;
76 uint32_t lcount;
77 uint32_t sar;
78 uint32_t windowstart;
79 uint32_t windowbase;
80 uint32_t reserved[8+48];
81 uint32_t ar[XCHAL_NUM_AREGS];
82 } __attribute__((packed)) xtensa_gregset_t;
83
84 typedef struct
85 {
86 uint32_t reg_index;
87 uint32_t reg_val;
88 } __attribute__((packed)) core_dump_reg_pair_t;
89
90 typedef struct
91 {
92 uint32_t crashed_task_tcb;
93 core_dump_reg_pair_t exccause;
94 core_dump_reg_pair_t excvaddr;
95 core_dump_reg_pair_t extra_regs[COREDUMP_EXTRA_REG_NUM];
96 } __attribute__((packed)) xtensa_extra_info_t;
97
98 // Xtensa Program Status for GDB
99 typedef struct
100 {
101 uint32_t si_signo;
102 uint32_t si_code;
103 uint32_t si_errno;
104 uint16_t pr_cursig;
105 uint16_t pr_pad0;
106 uint32_t pr_sigpend;
107 uint32_t pr_sighold;
108 uint32_t pr_pid;
109 uint32_t pr_ppid;
110 uint32_t pr_pgrp;
111 uint32_t pr_sid;
112 uint64_t pr_utime;
113 uint64_t pr_stime;
114 uint64_t pr_cutime;
115 uint64_t pr_cstime;
116 } __attribute__((packed)) xtensa_pr_status_t;
117
118 typedef struct
119 {
120 xtensa_pr_status_t pr_status;
121 xtensa_gregset_t regs;
122 // Todo: acc to xtensa_gregset_t number of regs must be 128,
123 // but gdb complains when it less than 129
124 uint32_t reserved;
125 } __attribute__((packed)) xtensa_elf_reg_dump_t;
126
127 #if CONFIG_ESP_COREDUMP_ENABLE
128
129 static XtExcFrame s_fake_stack_frame = {
130 .pc = (UBaseType_t) COREDUMP_FAKE_STACK_START, // task entrypoint fake_ptr
131 .a0 = (UBaseType_t) 0, // to terminate GDB backtrace
132 .a1 = (UBaseType_t) (COREDUMP_FAKE_STACK_START + sizeof(XtExcFrame)), // physical top of stack frame
133 .exit = (UBaseType_t) 0, // user exception exit dispatcher
134 .ps = (PS_UM | PS_EXCM),
135 .exccause = (UBaseType_t) COREDUMP_INVALID_CAUSE_VALUE,
136 };
137
138 /* Keep a track of the number of fake stack distributed. Avoid giving the
139 * same fake address to two different tasks. */
140 static uint32_t s_fake_stacks_num = 0;
141
142 static xtensa_extra_info_t s_extra_info;
143
144 /**
145 * The function creates small fake stack for task as deep as exception frame size
146 * It is required for gdb to take task into account but avoid back trace of stack.
147 * The espcoredump.py script is able to recognize that task is broken
148 */
esp_core_dump_get_fake_stack(uint32_t * stk_len)149 static void *esp_core_dump_get_fake_stack(uint32_t *stk_len)
150 {
151 *stk_len = sizeof(s_fake_stack_frame);
152 return (uint8_t*)COREDUMP_FAKE_STACK_START + sizeof(s_fake_stack_frame)*s_fake_stacks_num++;
153 }
154
155
esp_core_dump_get_epc_regs(core_dump_reg_pair_t * src)156 static core_dump_reg_pair_t *esp_core_dump_get_epc_regs(core_dump_reg_pair_t* src)
157 {
158 uint32_t* reg_ptr = (uint32_t*)src;
159 // get InterruptException program counter registers
160 COREDUMP_GET_EPC(EPC_1, reg_ptr);
161 COREDUMP_GET_EPC(EPC_2, reg_ptr);
162 COREDUMP_GET_EPC(EPC_3, reg_ptr);
163 COREDUMP_GET_EPC(EPC_4, reg_ptr);
164 COREDUMP_GET_EPC(EPC_5, reg_ptr);
165 COREDUMP_GET_EPC(EPC_6, reg_ptr);
166 COREDUMP_GET_EPC(EPC_7, reg_ptr);
167 return (core_dump_reg_pair_t*)reg_ptr;
168 }
169
esp_core_dump_get_eps_regs(core_dump_reg_pair_t * src)170 static core_dump_reg_pair_t *esp_core_dump_get_eps_regs(core_dump_reg_pair_t* src)
171 {
172 uint32_t* reg_ptr = (uint32_t*)src;
173 // get InterruptException processor state registers
174 COREDUMP_GET_EPS(EPS_2, reg_ptr);
175 COREDUMP_GET_EPS(EPS_3, reg_ptr);
176 COREDUMP_GET_EPS(EPS_4, reg_ptr);
177 COREDUMP_GET_EPS(EPS_5, reg_ptr);
178 COREDUMP_GET_EPS(EPS_6, reg_ptr);
179 COREDUMP_GET_EPS(EPS_7, reg_ptr);
180 return (core_dump_reg_pair_t*)reg_ptr;
181 }
182
183 // Returns list of registers (in GDB format) from xtensa stack frame
esp_core_dump_get_regs_from_stack(void * stack_addr,size_t size,xtensa_gregset_t * regs)184 static esp_err_t esp_core_dump_get_regs_from_stack(void* stack_addr,
185 size_t size,
186 xtensa_gregset_t* regs)
187 {
188 XtExcFrame* exc_frame = (XtExcFrame*)stack_addr;
189 uint32_t* stack_arr = (uint32_t*)stack_addr;
190
191 if (size < sizeof(XtExcFrame)) {
192 ESP_COREDUMP_LOGE("Too small stack to keep frame: %d bytes!", size);
193 return ESP_FAIL;
194 }
195
196 // Stack frame type indicator is always the first item
197 uint32_t rc = exc_frame->exit;
198
199 // is this current crashed task?
200 if (rc == COREDUMP_CURR_TASK_MARKER)
201 {
202 s_extra_info.exccause.reg_val = exc_frame->exccause;
203 s_extra_info.exccause.reg_index = EXCCAUSE;
204 s_extra_info.excvaddr.reg_val = exc_frame->excvaddr;
205 s_extra_info.excvaddr.reg_index = EXCVADDR;
206 // get InterruptException registers into extra_info
207 core_dump_reg_pair_t *regs_ptr = esp_core_dump_get_eps_regs(s_extra_info.extra_regs);
208 esp_core_dump_get_epc_regs(regs_ptr);
209 } else {
210 // initialize EXCCAUSE and EXCVADDR members of frames for all the tasks,
211 // except for the crashed one
212 exc_frame->exccause = COREDUMP_INVALID_CAUSE_VALUE;
213 exc_frame->excvaddr = 0;
214 }
215
216 if (rc != 0) {
217 regs->pc = exc_frame->pc;
218 regs->ps = exc_frame->ps;
219 for (int i = 0; i < XT_STK_AR_NUM; i++) {
220 regs->ar[i] = stack_arr[XT_STK_AR_START + i];
221 }
222 regs->sar = exc_frame->sar;
223 #if XCHAL_HAVE_LOOPS
224 regs->lbeg = exc_frame->lbeg;
225 regs->lend = exc_frame->lend;
226 regs->lcount = exc_frame->lcount;
227 #endif
228 // FIXME: crashed and some running tasks (e.g. prvIdleTask) have EXCM bit set
229 // and GDB can not unwind callstack properly (it implies not windowed call0)
230 if (regs->ps & PS_UM) {
231 regs->ps &= ~PS_EXCM;
232 }
233 } else {
234 regs->pc = stack_arr[XT_SOL_PC];
235 regs->ps = stack_arr[XT_SOL_PS];
236 for (int i = 0; i < XT_SOL_AR_NUM; i++) {
237 regs->ar[i] = stack_arr[XT_SOL_AR_START + i];
238 }
239 regs->pc = (regs->pc & 0x3fffffff);
240 if (regs->pc & 0x80000000) {
241 regs->pc = (regs->pc & 0x3fffffff);
242 }
243 if (regs->ar[0] & 0x80000000) {
244 regs->ar[0] = (regs->ar[0] & 0x3fffffff);
245 }
246 }
247 return ESP_OK;
248 }
249
esp_core_dump_port_init(panic_info_t * info)250 inline void esp_core_dump_port_init(panic_info_t *info)
251 {
252 s_extra_info.crashed_task_tcb = COREDUMP_CURR_TASK_MARKER;
253 // Initialize exccause register to default value (required if current task corrupted)
254 s_extra_info.exccause.reg_val = COREDUMP_INVALID_CAUSE_VALUE;
255 s_extra_info.exccause.reg_index = EXCCAUSE;
256
257 XtExcFrame *s_exc_frame = (XtExcFrame *) info->frame;
258 s_exc_frame->exit = COREDUMP_CURR_TASK_MARKER;
259 if (info->pseudo_excause) {
260 s_exc_frame->exccause += XCHAL_EXCCAUSE_NUM;
261 }
262 }
263
264 /**
265 * Get the architecture ID.
266 * Check core dump port interface for more information about this function.
267 */
esp_core_dump_get_arch_id()268 inline uint16_t esp_core_dump_get_arch_id()
269 {
270 return COREDUMP_EM_XTENSA;
271 }
272
esp_core_dump_reset_fake_stacks(void)273 void esp_core_dump_reset_fake_stacks(void)
274 {
275 s_fake_stacks_num = 0;
276 }
277
278 /* Get the top of the ISR stack.
279 * Check core dump port interface for more information about this function.
280 */
esp_core_dump_get_isr_stack_top(void)281 uint8_t* esp_core_dump_get_isr_stack_top(void) {
282 extern uint8_t port_IntStack;
283 return &port_IntStack;
284 }
285
esp_core_dump_get_isr_stack_end(void)286 uint32_t esp_core_dump_get_isr_stack_end(void)
287 {
288 uint8_t* isr_top_stack = esp_core_dump_get_isr_stack_top();
289 return (uint32_t)(isr_top_stack + (xPortGetCoreID()+1)*configISR_STACK_SIZE);
290 }
291
292
esp_core_dump_task_stack_end_is_sane(uint32_t sp)293 static inline bool esp_core_dump_task_stack_end_is_sane(uint32_t sp)
294 {
295 return esp_ptr_in_dram((void *)sp)
296 #if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
297 || esp_stack_ptr_in_extram(sp)
298 #endif
299 #if CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
300 || esp_ptr_in_rtc_dram_fast((void*) sp)
301 #endif
302 ;
303 }
304
305
esp_core_dump_check_stack(core_dump_task_header_t * task)306 bool esp_core_dump_check_stack(core_dump_task_header_t *task)
307 {
308 // Check task's stack
309 if (!esp_stack_ptr_is_sane(task->stack_start) ||
310 !esp_core_dump_task_stack_end_is_sane(task->stack_end) ||
311 (task->stack_start >= task->stack_end) ||
312 ((task->stack_end-task->stack_start) > COREDUMP_MAX_TASK_STACK_SIZE)) {
313 // Check if current task stack is corrupted
314 ESP_COREDUMP_LOG_PROCESS("Invalid stack (%x...%x)!", task->stack_start, task->stack_end);
315 return false;
316 }
317 return true;
318 }
319
320 /**
321 * Check if the memory segment is sane
322 *
323 * Check the header file for more information.
324 */
esp_core_dump_mem_seg_is_sane(uint32_t addr,uint32_t sz)325 bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz)
326 {
327 //TODO: external SRAM not supported yet
328 return (esp_ptr_in_dram((void *)addr) && esp_ptr_in_dram((void *)(addr+sz-1)))
329 || (esp_ptr_in_rtc_slow((void *)addr) && esp_ptr_in_rtc_slow((void *)(addr+sz-1)))
330 || (esp_ptr_in_rtc_dram_fast((void *)addr) && esp_ptr_in_rtc_dram_fast((void *)(addr+sz-1)))
331 || (esp_ptr_in_iram((void *)addr) && esp_ptr_in_iram((void *)(addr+sz-1)));
332 }
333
334 /**
335 * Get the stack of a task.
336 * Check core dump port interface for more information about this function.
337 */
esp_core_dump_get_stack(core_dump_task_header_t * task,uint32_t * stk_vaddr,uint32_t * stk_paddr)338 uint32_t esp_core_dump_get_stack(core_dump_task_header_t *task,
339 uint32_t* stk_vaddr, uint32_t* stk_paddr)
340 {
341 const uint32_t stack_len = abs(task->stack_start - task->stack_end);
342 const uint32_t stack_addr = min(task->stack_start, task->stack_end);
343
344 ESP_COREDUMP_DEBUG_ASSERT(stk_paddr != NULL && stk_vaddr != NULL);
345
346 /* Provide the virtual stack address for any task. */
347 *stk_vaddr = stack_addr;
348
349 if (stack_addr >= COREDUMP_FAKE_STACK_START &&
350 stack_addr < COREDUMP_FAKE_STACK_LIMIT) {
351 /* In this case, the stack address pointed by the task is a fake stack
352 * generated previously. So it doesn't really point to actual data.
353 * Thus, we must provide the address of the fake stack data. */
354 *stk_paddr = (uint32_t) &s_fake_stack_frame;
355 } else {
356 *stk_paddr = stack_addr;
357 }
358
359 return stack_len;
360 }
361
362 /**
363 * Check the task passed as a parameter.
364 * Check core dump port interface for more information about this function.
365 */
esp_core_dump_check_task(core_dump_task_header_t * task)366 bool esp_core_dump_check_task(core_dump_task_header_t *task)
367 {
368 uint32_t stk_size = 0;
369 bool stack_is_valid = false;
370
371 if (!esp_core_dump_tcb_addr_is_sane((uint32_t)task->tcb_addr)) {
372 ESP_COREDUMP_LOG_PROCESS("Bad TCB addr=%x!", task->tcb_addr);
373 return false;
374 }
375
376 stack_is_valid = esp_core_dump_check_stack(task);
377 if (!stack_is_valid) {
378 // Skip saving of invalid task if stack corrupted
379 ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), stack is corrupted (%x, %x)",
380 task->tcb_addr,
381 task->stack_start,
382 task->stack_end);
383 task->stack_start = (uint32_t)esp_core_dump_get_fake_stack(&stk_size);
384 task->stack_end = (uint32_t)(task->stack_start + stk_size);
385 ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), use start, end (%x, %x)",
386 task->tcb_addr,
387 task->stack_start,
388 task->stack_end);
389 } else {
390 /* This shall be done only if the stack was correct, else, stack_start
391 * would point to a fake address. */
392 XtSolFrame *sol_frame = (XtSolFrame *)task->stack_start;
393 if (sol_frame->exit == 0) {
394 ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), EXIT/PC/PS/A0/SP %x %x %x %x %x",
395 task->tcb_addr,
396 sol_frame->exit,
397 sol_frame->pc,
398 sol_frame->ps,
399 sol_frame->a0,
400 sol_frame->a1);
401 } else {
402 // to avoid warning that 'exc_frame' is unused when ESP_COREDUMP_LOG_PROCESS does nothing
403 #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
404 XtExcFrame *exc_frame = (XtExcFrame *)task->stack_start;
405 ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x) EXIT/PC/PS/A0/SP %x %x %x %x %x",
406 task->tcb_addr,
407 exc_frame->exit,
408 exc_frame->pc,
409 exc_frame->ps,
410 exc_frame->a0,
411 exc_frame->a1);
412 #endif
413 }
414 }
415 return true;
416 }
417
418
419 /**
420 * Get a dump of the task's registers.
421 * Check core dump port interface for more information about this function.
422 */
esp_core_dump_get_task_regs_dump(core_dump_task_header_t * task,void ** reg_dump)423 uint32_t esp_core_dump_get_task_regs_dump(core_dump_task_header_t *task, void **reg_dump)
424 {
425 uint32_t stack_vaddr = 0;
426 uint32_t stack_paddr = 0;
427 uint32_t stack_len = 0;
428 static xtensa_elf_reg_dump_t s_reg_dump = { 0 };
429
430 ESP_COREDUMP_DEBUG_ASSERT(task != NULL && reg_dump != NULL);
431
432 stack_len = esp_core_dump_get_stack(task, &stack_vaddr, &stack_paddr);
433
434 ESP_COREDUMP_LOG_PROCESS("Add regs for task 0x%x", task->tcb_addr);
435
436 // initialize program status for the task
437 s_reg_dump.pr_status.pr_cursig = 0;
438 s_reg_dump.pr_status.pr_pid = (uint32_t)task->tcb_addr;
439
440 // fill the gdb registers structure from stack
441 esp_err_t err = esp_core_dump_get_regs_from_stack((void*)stack_paddr,
442 stack_len,
443 &s_reg_dump.regs);
444 if (err != ESP_OK) {
445 ESP_COREDUMP_LOGE("Error while registers processing.");
446 }
447 *reg_dump = &s_reg_dump;
448 return sizeof(s_reg_dump);
449 }
450
451
esp_core_dump_port_set_crashed_tcb(uint32_t handle)452 void esp_core_dump_port_set_crashed_tcb(uint32_t handle) {
453 s_extra_info.crashed_task_tcb = handle;
454 }
455
456 /**
457 * Retrieve the extra information.
458 * Check core dump port interface for more information about this function.
459 */
esp_core_dump_get_extra_info(void ** info)460 uint32_t esp_core_dump_get_extra_info(void **info)
461 {
462 if (info) {
463 *info = &s_extra_info;
464 }
465 return sizeof(s_extra_info);
466 }
467
468 #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
469
esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t * summary,void * ei_data)470 void esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t *summary, void *ei_data)
471 {
472 int i;
473 xtensa_extra_info_t *ei = (xtensa_extra_info_t *) ei_data;
474 summary->exc_tcb = ei->crashed_task_tcb;
475 summary->ex_info.exc_vaddr = ei->excvaddr.reg_val;
476 summary->ex_info.exc_cause = ei->exccause.reg_val;
477 ESP_COREDUMP_LOGD("Crash TCB 0x%x", summary->exc_tcb);
478 ESP_COREDUMP_LOGD("excvaddr 0x%x", summary->ex_info.exc_vaddr);
479 ESP_COREDUMP_LOGD("exccause 0x%x", summary->ex_info.exc_cause);
480
481 memset(summary->ex_info.epcx, 0, sizeof(summary->ex_info.epcx));
482 summary->ex_info.epcx_reg_bits = 0;
483 for (i = 0; i < COREDUMP_EXTRA_REG_NUM; i++ ) {
484 if (ei->extra_regs[i].reg_index >= EPC_1
485 && ei->extra_regs[i].reg_index < (EPC_1 + XCHAL_NUM_INTLEVELS)) {
486 summary->ex_info.epcx[ei->extra_regs[i].reg_index - EPC_1] = ei->extra_regs[i].reg_val;
487 summary->ex_info.epcx_reg_bits |= (1 << (ei->extra_regs[i].reg_index - EPC_1));
488 }
489 }
490 }
491
esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t * summary,void * stack_data)492 void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void *stack_data)
493 {
494 int i;
495 long *a_reg;
496 XtExcFrame *stack = (XtExcFrame *) stack_data;
497 summary->exc_pc = esp_cpu_process_stack_pc(stack->pc);
498 ESP_COREDUMP_LOGD("Crashing PC 0x%x", summary->exc_pc);
499
500 a_reg = &stack->a0;
501 for (i = 0; i < 16; i++) {
502 summary->ex_info.exc_a[i] = a_reg[i];
503 ESP_COREDUMP_LOGD("A[%d] 0x%x", i, summary->ex_info.exc_a[i]);
504 }
505 }
506
esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t * bt_info,const void * vaddr,const void * paddr,uint32_t stack_size)507 void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info, const void *vaddr,
508 const void *paddr, uint32_t stack_size)
509 {
510 if (!vaddr || !paddr || !bt_info) {
511 return;
512 }
513
514 int offset;
515 bool corrupted;
516 esp_backtrace_frame_t frame;
517 XtExcFrame *stack = (XtExcFrame *) paddr;
518 int max_depth = (int) (sizeof(bt_info->bt) / sizeof(bt_info->bt[0]));
519 int index = 0;
520
521 frame.pc = stack->pc;
522 frame.sp = stack->a1;
523 frame.next_pc = stack->a0;
524
525 corrupted = !(esp_stack_ptr_is_sane(frame.sp) &&
526 (esp_ptr_executable((void *)esp_cpu_process_stack_pc(frame.pc)) ||
527 stack->exccause == EXCCAUSE_INSTR_PROHIBITED)); /* Ignore the first corrupted PC in case of InstrFetchProhibited */
528
529 /* vaddr is actual stack address when crash occurred. However that stack is now saved
530 * in the flash at a different location. Hence for each SP, we need to adjust the offset
531 * to point to next frame in the flash */
532 offset = (uint32_t) stack - (uint32_t) vaddr;
533
534 ESP_COREDUMP_LOGD("Crash Backtrace");
535 bt_info->bt[index] = esp_cpu_process_stack_pc(frame.pc);
536 ESP_COREDUMP_LOGD(" 0x%x", bt_info->bt[index]);
537 index++;
538
539 while (max_depth-- > 0 && frame.next_pc && !corrupted) {
540 /* Check if the Stack Pointer is in valid address range */
541 if (!((uint32_t)frame.sp >= (uint32_t)vaddr &&
542 ((uint32_t)frame.sp <= (uint32_t)vaddr + stack_size))) {
543 corrupted = true;
544 break;
545 }
546 /* Adjusting the SP to address in flash than in actual RAM */
547 frame.sp += offset;
548 if (!esp_backtrace_get_next_frame(&frame)) {
549 corrupted = true;
550 }
551 if (corrupted == false) {
552 bt_info->bt[index] = esp_cpu_process_stack_pc(frame.pc);
553 ESP_COREDUMP_LOGD(" 0x%x", bt_info->bt[index]);
554 index++;
555 }
556 }
557 bt_info->depth = index;
558 bt_info->corrupted = corrupted;
559 }
560
561 #endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */
562
563 #endif
564