@@ -14,68 +14,95 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
1414
1515uintptr_t z_riscv_get_sp_before_exc (const struct arch_esf * esf );
1616
17- #if __riscv_xlen == 32
18- #define PR_REG "%08" PRIxPTR
19- #elif __riscv_xlen == 64
20- #define PR_REG "%016" PRIxPTR
21- #endif
22-
23- #define MAX_STACK_FRAMES CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES
17+ #define MAX_STACK_FRAMES \
18+ MAX(CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES, CONFIG_ARCH_STACKWALK_MAX_FRAMES)
2419
2520struct stackframe {
2621 uintptr_t fp ;
2722 uintptr_t ra ;
2823};
2924
30- #ifdef CONFIG_FRAME_POINTER
31- #define SFP_FMT "fp: "
32- #else
33- #define SFP_FMT "sp: "
34- #endif
25+ typedef bool (* stack_verify_fn )(uintptr_t , const struct k_thread * const , const struct arch_esf * );
3526
36- #ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
37- #define LOG_STACK_TRACE (idx , sfp , ra , name , offset ) \
38- LOG_ERR(" %2d: " SFP_FMT PR_REG " ra: " PR_REG " [%s+0x%x]", idx, sfp, ra, name, \
39- offset)
40- #else
41- #define LOG_STACK_TRACE (idx , sfp , ra , name , offset ) \
42- LOG_ERR(" %2d: " SFP_FMT PR_REG " ra: " PR_REG, idx, sfp, ra)
43- #endif
27+ static inline bool in_irq_stack_bound (uintptr_t addr , uint8_t cpu_id )
28+ {
29+ uintptr_t start , end ;
4430
45- static bool in_stack_bound (uintptr_t addr , const struct arch_esf * esf )
31+ start = (uintptr_t )K_KERNEL_STACK_BUFFER (z_interrupt_stacks [cpu_id ]);
32+ end = start + CONFIG_ISR_STACK_SIZE ;
33+
34+ return (addr >= start ) && (addr < end );
35+ }
36+
37+ static inline bool in_kernel_thread_stack_bound (uintptr_t addr , const struct k_thread * const thread )
38+ {
39+ uintptr_t start , end ;
40+
41+ start = thread -> stack_info .start ;
42+ end = Z_STACK_PTR_ALIGN (thread -> stack_info .start + thread -> stack_info .size );
43+
44+ return (addr >= start ) && (addr < end );
45+ }
46+
47+ #ifdef CONFIG_USERSPACE
48+ static inline bool in_user_thread_stack_bound (uintptr_t addr , const struct k_thread * const thread )
4649{
47- #ifdef CONFIG_THREAD_STACK_INFO
4850 uintptr_t start , end ;
4951
52+ /* See: zephyr/include/zephyr/arch/riscv/arch.h */
53+ if (IS_ENABLED (CONFIG_PMP_POWER_OF_TWO_ALIGNMENT )) {
54+ start = thread -> arch .priv_stack_start - CONFIG_PRIVILEGED_STACK_SIZE ;
55+ end = thread -> arch .priv_stack_start ;
56+ } else {
57+ start = thread -> stack_info .start - CONFIG_PRIVILEGED_STACK_SIZE ;
58+ end = thread -> stack_info .start ;
59+ }
60+
61+ return (addr >= start ) && (addr < end );
62+ }
63+ #endif /* CONFIG_USERSPACE */
64+
65+ static bool in_fatal_stack_bound (uintptr_t addr , const struct k_thread * const thread ,
66+ const struct arch_esf * esf )
67+ {
68+ ARG_UNUSED (thread );
69+
70+ if (!IS_ALIGNED (addr , sizeof (uintptr_t ))) {
71+ return false;
72+ }
73+
5074 if (_current == NULL || arch_is_in_isr ()) {
5175 /* We were servicing an interrupt */
5276 uint8_t cpu_id = IS_ENABLED (CONFIG_SMP ) ? arch_curr_cpu ()-> id : 0U ;
5377
54- start = ( uintptr_t ) K_KERNEL_STACK_BUFFER ( z_interrupt_stacks [ cpu_id ] );
55- end = start + CONFIG_ISR_STACK_SIZE ;
78+ return in_irq_stack_bound ( addr , cpu_id );
79+ }
5680#ifdef CONFIG_USERSPACE
57- } else if (((esf -> mstatus & MSTATUS_MPP ) == PRV_U ) &&
58- ((_current -> base .user_options & K_USER ) != 0 )) {
59- /* See: zephyr/include/zephyr/arch/riscv/arch.h */
60- if (IS_ENABLED (CONFIG_PMP_POWER_OF_TWO_ALIGNMENT )) {
61- start = _current -> arch .priv_stack_start - CONFIG_PRIVILEGED_STACK_SIZE ;
62- end = _current -> arch .priv_stack_start ;
63- } else {
64- start = _current -> stack_info .start - CONFIG_PRIVILEGED_STACK_SIZE ;
65- end = _current -> stack_info .start ;
66- }
67- #endif /* CONFIG_USERSPACE */
68- } else {
69- start = _current -> stack_info .start ;
70- end = Z_STACK_PTR_ALIGN (_current -> stack_info .start + _current -> stack_info .size );
81+ if ((esf != NULL ) && ((esf -> mstatus & MSTATUS_MPP ) == PRV_U ) &&
82+ ((_current -> base .user_options & K_USER ) != 0 )) {
83+ return in_user_thread_stack_bound (addr , _current );
7184 }
85+ #endif /* CONFIG_USERSPACE */
7286
73- return (addr >= start ) && (addr < end );
74- #else
75- ARG_UNUSED (addr );
87+ return in_kernel_thread_stack_bound (addr , _current );
88+ }
89+
90+ static bool in_stack_bound (uintptr_t addr , const struct k_thread * const thread ,
91+ const struct arch_esf * esf )
92+ {
7693 ARG_UNUSED (esf );
77- return true;
78- #endif /* CONFIG_THREAD_STACK_INFO */
94+
95+ if (!IS_ALIGNED (addr , sizeof (uintptr_t ))) {
96+ return false;
97+ }
98+
99+ #ifdef CONFIG_USERSPACE
100+ if ((thread -> base .user_options & K_USER ) != 0 ) {
101+ return in_user_thread_stack_bound (addr , thread );
102+ }
103+ #endif /* CONFIG_USERSPACE */
104+
105+ return in_kernel_thread_stack_bound (addr , thread );
79106}
80107
81108static inline bool in_text_region (uintptr_t addr )
@@ -86,61 +113,131 @@ static inline bool in_text_region(uintptr_t addr)
86113}
87114
88115#ifdef CONFIG_FRAME_POINTER
89- void z_riscv_unwind_stack (const struct arch_esf * esf )
116+ static void walk_stackframe (stack_trace_callback_fn cb , void * cookie , const struct k_thread * thread ,
117+ const struct arch_esf * esf , stack_verify_fn vrfy ,
118+ const _callee_saved_t * csf )
90119{
91- uintptr_t fp = esf -> s0 ;
120+ uintptr_t fp , last_fp = 0 ;
92121 uintptr_t ra ;
93122 struct stackframe * frame ;
94123
95- LOG_ERR ("call trace:" );
124+ if (esf != NULL ) {
125+ /* Unwind the provided exception stack frame */
126+ fp = esf -> s0 ;
127+ ra = esf -> mepc ;
128+ } else if ((csf == NULL ) || (csf == & _current -> callee_saved )) {
129+ /* Unwind current thread (default case when nothing is provided ) */
130+ fp = (uintptr_t )__builtin_frame_address (0 );
131+ ra = (uintptr_t )walk_stackframe ;
132+ thread = _current ;
133+ } else {
134+ /* Unwind the provided thread */
135+ fp = csf -> s0 ;
136+ ra = csf -> ra ;
137+ }
96138
97- for (int i = 0 ; (i < MAX_STACK_FRAMES ) && (fp != 0U ) && in_stack_bound (fp , esf );) {
98- frame = (struct stackframe * )fp - 1 ;
99- ra = frame -> ra ;
139+ for (int i = 0 ; (i < MAX_STACK_FRAMES ) && vrfy (fp , thread , esf ) && (fp > last_fp );) {
100140 if (in_text_region (ra )) {
101- #ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
102- uint32_t offset = 0 ;
103- const char * name = symtab_find_symbol_name (ra , & offset );
104- #endif
105- LOG_STACK_TRACE (i , fp , ra , name , offset );
141+ if (!cb (cookie , ra )) {
142+ break ;
143+ }
106144 /*
107145 * Increment the iterator only if `ra` is within the text region to get the
108146 * most out of it
109147 */
110148 i ++ ;
111149 }
150+ last_fp = fp ;
151+ /* Unwind to the previous frame */
152+ frame = (struct stackframe * )fp - 1 ;
153+ ra = frame -> ra ;
112154 fp = frame -> fp ;
113155 }
114-
115- LOG_ERR ("" );
116156}
117- #else /* !CONFIG_FRAME_POINTER */
118- void z_riscv_unwind_stack (const struct arch_esf * esf )
157+ #else /* !CONFIG_FRAME_POINTER */
158+ register uintptr_t current_stack_pointer __asm__("sp" );
159+ static void walk_stackframe (stack_trace_callback_fn cb , void * cookie , const struct k_thread * thread ,
160+ const struct arch_esf * esf , stack_verify_fn vrfy ,
161+ const _callee_saved_t * csf )
119162{
120- uintptr_t sp = z_riscv_get_sp_before_exc ( esf ) ;
163+ uintptr_t sp ;
121164 uintptr_t ra ;
122- uintptr_t * ksp = (uintptr_t * )sp ;
165+ uintptr_t * ksp , last_ksp = 0 ;
166+
167+ if (esf != NULL ) {
168+ /* Unwind the provided exception stack frame */
169+ sp = z_riscv_get_sp_before_exc (esf );
170+ ra = esf -> mepc ;
171+ } else if ((csf == NULL ) || (csf == & _current -> callee_saved )) {
172+ /* Unwind current thread (default case when nothing is provided ) */
173+ sp = current_stack_pointer ;
174+ ra = (uintptr_t )walk_stackframe ;
175+ thread = _current ;
176+ } else {
177+ /* Unwind the provided thread */
178+ sp = csf -> sp ;
179+ ra = csf -> ra ;
123180
124- LOG_ERR ( "call trace:" );
181+ }
125182
126- for (int i = 0 ; (i < MAX_STACK_FRAMES ) && ((uintptr_t )ksp != 0U ) &&
127- in_stack_bound ((uintptr_t )ksp , esf );
128- ksp ++ ) {
129- ra = * ksp ;
183+ ksp = (uintptr_t * )sp ;
184+ for (int i = 0 ; (i < MAX_STACK_FRAMES ) && vrfy ((uintptr_t )ksp , thread , esf ) &&
185+ ((uintptr_t )ksp > last_ksp );) {
130186 if (in_text_region (ra )) {
131- #ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
132- uint32_t offset = 0 ;
133- const char * name = symtab_find_symbol_name (ra , & offset );
134- #endif
135- LOG_STACK_TRACE (i , (uintptr_t )ksp , ra , name , offset );
187+ if (!cb (cookie , ra )) {
188+ break ;
189+ }
136190 /*
137191 * Increment the iterator only if `ra` is within the text region to get the
138192 * most out of it
139193 */
140194 i ++ ;
141195 }
196+ last_ksp = (uintptr_t )ksp ;
197+ /* Unwind to the previous frame */
198+ ra = ((struct arch_esf * )ksp ++ )-> ra ;
142199 }
200+ }
201+ #endif /* CONFIG_FRAME_POINTER */
202+
203+ void arch_stack_walk (stack_trace_callback_fn callback_fn , void * cookie ,
204+ const struct k_thread * thread , const struct arch_esf * esf )
205+ {
206+ walk_stackframe (callback_fn , cookie , thread , esf , in_stack_bound ,
207+ thread != NULL ? & thread -> callee_saved : NULL );
208+ }
209+
210+ #if __riscv_xlen == 32
211+ #define PR_REG "%08" PRIxPTR
212+ #elif __riscv_xlen == 64
213+ #define PR_REG "%016" PRIxPTR
214+ #endif
215+
216+ #ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
217+ #define LOG_STACK_TRACE (idx , ra , name , offset ) \
218+ LOG_ERR(" %2d: ra: " PR_REG " [%s+0x%x]", idx, ra, name, offset)
219+ #else
220+ #define LOG_STACK_TRACE (idx , ra , name , offset ) LOG_ERR(" %2d: ra: " PR_REG, idx, ra)
221+ #endif /* CONFIG_EXCEPTION_STACK_TRACE_SYMTAB */
143222
223+ static bool print_trace_address (void * arg , unsigned long ra )
224+ {
225+ int * i = arg ;
226+ #ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
227+ uint32_t offset = 0 ;
228+ const char * name = symtab_find_symbol_name (ra , & offset );
229+ #endif
230+
231+ LOG_STACK_TRACE ((* i )++ , ra , name , offset );
232+
233+ return true;
234+ }
235+
236+ void z_riscv_unwind_stack (const struct arch_esf * esf , const _callee_saved_t * csf )
237+ {
238+ int i = 0 ;
239+
240+ LOG_ERR ("call trace:" );
241+ walk_stackframe (print_trace_address , & i , NULL , esf , in_fatal_stack_bound , csf );
144242 LOG_ERR ("" );
145243}
146- #endif /* CONFIG_FRAME_POINTER */
0 commit comments