1 /* 2 * Copyright (c) 2023 KNS Group LLC (YADRO) 3 * Copyright (c) 2020 Yonatan Goldschmidt <yon.goldschmidt@gmail.com> 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 #include <zephyr/kernel.h> 9 #include <zephyr/linker/linker-defs.h> 10 valid_stack(uintptr_t addr,k_tid_t current)11static bool valid_stack(uintptr_t addr, k_tid_t current) 12 { 13 return current->stack_info.start <= addr && 14 addr < current->stack_info.start + current->stack_info.size; 15 } 16 in_text_region(uintptr_t addr)17static inline bool in_text_region(uintptr_t addr) 18 { 19 return (addr >= (uintptr_t)__text_region_start) && (addr < (uintptr_t)__text_region_end); 20 } 21 22 /* interruption stack frame */ 23 struct isf { 24 uint32_t ebp; 25 uint32_t ecx; 26 uint32_t edx; 27 uint32_t eax; 28 uint32_t eip; 29 }; 30 31 /* 32 * This function use frame pointers to unwind stack and get trace of return addresses. 33 * Return addresses are translated in corresponding function's names using .elf file. 34 * So we get function call trace 35 */ arch_perf_current_stack_trace(uintptr_t * buf,size_t size)36size_t arch_perf_current_stack_trace(uintptr_t *buf, size_t size) 37 { 38 if (size < 1U) { 39 return 0; 40 } 41 42 size_t idx = 0; 43 44 const struct isf * const isf = 45 *((struct isf **)(((void **)_current_cpu->irq_stack)-1)); 46 /* 47 * In x86 (arch/x86/core/ia32/intstub.S) %eip and %ebp 48 * are saved at the beginning of _interrupt_enter in order, that described 49 * in struct esf. Core switch %esp to 50 * _current_cpu->irq_stack and push %esp on irq stack 51 * 52 * The following lines lines do the reverse things to get %eip and %ebp 53 * from thread stack 54 */ 55 void **fp = (void **)isf->ebp; 56 57 /* 58 * %ebp is frame pointer. 59 * 60 * stack frame in memory: 61 * (addresses growth up) 62 * .... 63 * ra 64 * %ebp (next) <- %ebp (curr) 65 * .... 66 */ 67 68 buf[idx++] = (uintptr_t)isf->eip; 69 while (valid_stack((uintptr_t)fp, _current)) { 70 if (idx >= size) { 71 return 0; 72 } 73 74 if (!in_text_region((uintptr_t)fp[1])) { 75 break; 76 } 77 78 buf[idx++] = (uintptr_t)fp[1]; 79 void **new_fp = (void **)fp[0]; 80 81 /* 82 * anti-infinity-loop if 83 * new_fp can't be smaller than fp, cause the stack is growing down 84 * and trace moves deeper into the stack 85 */ 86 if (new_fp <= fp) { 87 break; 88 } 89 fp = new_fp; 90 } 91 92 return idx; 93 } 94