Skip to content

Commit 7343350

Browse files
Mikhail Kushnerovnashif
authored andcommitted
arch: x86: intel64: make perf stack thrace func
Implement stack trace function for x86_64 arch, that get required thread register values and unwind stack with it. Originally-by: Yonatan Goldschmidt <[email protected]> Signed-off-by: Mikhail Kushnerov <[email protected]>
1 parent 13156ad commit 7343350

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

arch/x86/core/intel64.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD intel64/irq_offload.c)
2020
zephyr_library_sources_ifdef(CONFIG_USERSPACE intel64/userspace.S)
2121
zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE intel64/tls.c)
2222
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP intel64/coredump.c)
23+
zephyr_library_sources_ifdef(CONFIG_PROFILING_PERF intel64/perf.c)

arch/x86/core/intel64/perf.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2023 KNS Group LLC (YADRO)
3+
* Copyright (c) 2020 Yonatan Goldschmidt <[email protected]>
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/kernel.h>
9+
10+
static bool valid_stack(uintptr_t addr, k_tid_t current)
11+
{
12+
return current->stack_info.start <= addr &&
13+
addr < current->stack_info.start + current->stack_info.size;
14+
}
15+
16+
/*
17+
* This function use frame pointers to unwind stack and get trace of return addresses.
18+
* Return addresses are translated in corresponding function's names using .elf file.
19+
* So we get function call trace
20+
*/
21+
size_t arch_perf_current_stack_trace(uintptr_t *buf, size_t size)
22+
{
23+
if (size < 1U)
24+
return 0;
25+
26+
size_t idx = 0;
27+
28+
/*
29+
* In x86_64 (arch/x86/core/intel64/locore.S) %rip and %rbp
30+
* are always saved in _current->callee_saved before calling
31+
* handler function if interrupt is not nested
32+
*
33+
* %rip points the location where interrupt was occurred
34+
*/
35+
buf[idx++] = (uintptr_t)_current->callee_saved.rip;
36+
void **fp = (void **)_current->callee_saved.rbp;
37+
38+
/*
39+
* %rbp is frame pointer.
40+
*
41+
* stack frame in memory:
42+
* (addresses growth up)
43+
* ....
44+
* ra
45+
* %rbp (next) <- %rbp (curr)
46+
* ....
47+
*/
48+
while (valid_stack((uintptr_t)fp, _current)) {
49+
if (idx >= size)
50+
return 0;
51+
52+
buf[idx++] = (uintptr_t)fp[1];
53+
void **new_fp = (void **)fp[0];
54+
55+
/*
56+
* anti-infinity-loop if
57+
* new_fp can't be smaller than fp, cause the stack is growing down
58+
* and trace moves deeper into the stack
59+
*/
60+
if (new_fp <= fp) {
61+
break;
62+
}
63+
fp = new_fp;
64+
}
65+
66+
return idx;
67+
}

0 commit comments

Comments
 (0)