1 /*
2 * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "xtensa/corebits.h"
8 #include "xtensa_backtrace.h"
9 #include <zephyr/sys/printk.h>
10 #if defined(CONFIG_SOC_SERIES_ESP32)
11 #include <esp_memory_utils.h>
12 #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP)
13 #include "debug_helpers.h"
14 #elif defined(CONFIG_SOC_XTENSA_DC233C)
15 #include "backtrace_helpers.h"
16 #endif
17
18 #include <xtensa_asm2_context.h>
19 #include <xtensa_stack.h>
20
21 static int mask, cause;
22
xtensa_cpu_process_stack_pc(uint32_t pc)23 static inline uint32_t xtensa_cpu_process_stack_pc(uint32_t pc)
24 {
25 if (pc & 0x80000000) {
26 /* Top two bits of a0 (return address) specify window increment.
27 * Overwrite to map to address space.
28 */
29 if (cause != EXCCAUSE_INSTR_PROHIBITED) {
30 pc = (pc & 0x3fffffff) | mask;
31 } else {
32 pc = (pc & 0x3fffffff) | 0x40000000;
33 }
34 }
35 /* Minus 3 to get PC of previous instruction
36 * (i.e. instruction executed before return address)
37 */
38 return pc - 3;
39 }
40
xtensa_stack_ptr_is_sane(uint32_t sp)41 static inline bool xtensa_stack_ptr_is_sane(uint32_t sp)
42 {
43 bool valid;
44
45 #if defined(CONFIG_SOC_SERIES_ESP32)
46 valid = esp_stack_ptr_is_sane(sp);
47 #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP)
48 valid = intel_adsp_ptr_is_sane(sp);
49 #else
50 /* Platform does not have additional requirements on
51 * whether stack pointer is valid. So use the generic
52 * test below.
53 */
54 valid = true;
55 #endif
56
57 if (valid) {
58 valid = !xtensa_is_outside_stack_bounds(sp, 0, UINT32_MAX);
59 }
60
61 return valid;
62 }
63
xtensa_ptr_executable(const void * p)64 static inline bool xtensa_ptr_executable(const void *p)
65 {
66 #if defined(CONFIG_SOC_SERIES_ESP32)
67 return esp_ptr_executable(p);
68 #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP)
69 return intel_adsp_ptr_executable(p);
70 #elif defined(CONFIG_SOC_XTENSA_DC233C)
71 return xtensa_dc233c_ptr_executable(p);
72 #else
73 #warning "xtensa_ptr_executable is not defined for this platform"
74 #endif
75 }
76
xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t * frame)77 bool xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t *frame)
78 {
79 /* Do not continue backtrace when we encounter an invalid stack
80 * frame pointer.
81 */
82 if (xtensa_is_outside_stack_bounds((uintptr_t)frame->sp, 0, UINT32_MAX)) {
83 return false;
84 }
85
86 /* Use frame(i-1)'s BS area located below frame(i)'s
87 * sp to get frame(i-1)'s sp and frame(i-2)'s pc
88 */
89
90 /* Base save area consists of 4 words under SP */
91 char *base_save = (char *)frame->sp;
92
93 frame->pc = frame->next_pc;
94 /* If next_pc = 0, indicates frame(i-1) is the last
95 * frame on the stack
96 */
97 frame->next_pc = *((uint32_t *)(base_save - 16));
98 frame->sp = *((uint32_t *)(base_save - 12));
99
100 /* Return true if both sp and pc of frame(i-1) are sane,
101 * false otherwise
102 */
103 return (xtensa_stack_ptr_is_sane(frame->sp) &&
104 xtensa_ptr_executable((void *)
105 xtensa_cpu_process_stack_pc(frame->pc)));
106 }
107
xtensa_backtrace_print(int depth,int * interrupted_stack)108 int xtensa_backtrace_print(int depth, int *interrupted_stack)
109 {
110 /* Check arguments */
111 if (depth <= 0) {
112 return -1;
113 }
114
115 _xtensa_irq_stack_frame_raw_t *frame = (void *)interrupted_stack;
116 _xtensa_irq_bsa_t *bsa;
117
118 /* Don't dump stack if the stack pointer is invalid as
119 * any frame elements obtained via de-referencing the
120 * frame pointer are probably also invalid. Or worse,
121 * cause another access violation.
122 */
123 if (!xtensa_is_frame_pointer_valid(frame)) {
124 return -1;
125 }
126
127 bsa = frame->ptr_to_bsa;
128 cause = bsa->exccause;
129
130 /* Initialize stk_frame with first frame of stack */
131 struct xtensa_backtrace_frame_t stk_frame;
132
133 xtensa_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp),
134 &(stk_frame.next_pc), interrupted_stack);
135
136 if (cause != EXCCAUSE_INSTR_PROHIBITED) {
137 mask = stk_frame.pc & 0xc0000000;
138 }
139 printk("\r\n\r\nBacktrace:");
140 printk("0x%08x:0x%08x ",
141 xtensa_cpu_process_stack_pc(stk_frame.pc),
142 stk_frame.sp);
143
144 /* Check if first frame is valid */
145 bool corrupted = !(xtensa_stack_ptr_is_sane(stk_frame.sp) &&
146 (xtensa_ptr_executable((void *)
147 xtensa_cpu_process_stack_pc(stk_frame.pc)) ||
148 /* Ignore the first corrupted PC in case of InstrFetchProhibited */
149 cause == EXCCAUSE_INSTR_PROHIBITED));
150
151 while (depth-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
152 /* Get previous stack frame */
153 if (!xtensa_backtrace_get_next_frame(&stk_frame)) {
154 corrupted = true;
155 }
156 printk("0x%08x:0x%08x ", xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
157 }
158
159 /* Print backtrace termination marker */
160 int ret = 0;
161
162 if (corrupted) {
163 printk(" |<-CORRUPTED");
164 ret = -1;
165 } else if (stk_frame.next_pc != 0) { /* Backtrace continues */
166 printk(" |<-CONTINUES");
167 }
168 printk("\r\n\r\n");
169 return ret;
170 }
171