/src/elfutils/backends/libebl_PERF_FLAGS.h
Line | Count | Source |
1 | | /* Linux perf_events sample_regs_user flags required for unwinding. |
2 | | Internal only; elfutils library users should use ebl_perf_frame_regs_mask(). |
3 | | |
4 | | Copyright (C) 2025-2026 Red Hat, Inc. |
5 | | This file is part of elfutils. |
6 | | |
7 | | This file is free software; you can redistribute it and/or modify |
8 | | it under the terms of either |
9 | | |
10 | | * the GNU Lesser General Public License as published by the Free |
11 | | Software Foundation; either version 3 of the License, or (at |
12 | | your option) any later version |
13 | | |
14 | | or |
15 | | |
16 | | * the GNU General Public License as published by the Free |
17 | | Software Foundation; either version 2 of the License, or (at |
18 | | your option) any later version |
19 | | |
20 | | or both in parallel, as here. |
21 | | |
22 | | elfutils is distributed in the hope that it will be useful, but |
23 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
25 | | General Public License for more details. |
26 | | |
27 | | You should have received copies of the GNU General Public License and |
28 | | the GNU Lesser General Public License along with this program. If |
29 | | not, see <http://www.gnu.org/licenses/>. */ |
30 | | |
31 | | #ifndef _LIBEBL_PERF_FLAGS_H |
32 | | #define _LIBEBL_PERF_FLAGS_H 1 |
33 | | |
34 | | #if defined(__linux__) |
35 | | /* XXX Need to exclude __linux__ arches without perf_regs.h. */ |
36 | | #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__) |
37 | | /* || defined(other_architecture)... */ |
38 | | # include <asm/perf_regs.h> |
39 | | #endif |
40 | | #endif |
41 | | |
42 | | #if defined(_ASM_X86_PERF_REGS_H) |
43 | | /* See the code in x86_initreg_sample.c for list of required regs and |
44 | | linux arch/.../include/asm/ptrace.h for matching pt_regs struct. */ |
45 | 12.3k | #define REG(R) (1ULL << PERF_REG_X86_ ## R) |
46 | | /* FLAGS and segment regs are excluded from the following masks, |
47 | | since they're not needed for unwinding. */ |
48 | 956 | #define PERF_FRAME_REGISTERS_I386 (REG(AX) | REG(BX) | REG(CX) | REG(DX) \ |
49 | 956 | | REG(SI) | REG(DI) | REG(BP) | REG(SP) | REG(IP)) |
50 | 467 | #define PERF_FRAME_REGISTERS_X86_64 (PERF_FRAME_REGISTERS_I386 | REG(R8) \ |
51 | 467 | | REG(R9) | REG(R10) | REG(R11) | REG(R12) | REG(R13) | REG(R14) | REG(R15)) |
52 | | /* Register ordering defined in linux arch/x86/include/uapi/asm/perf_regs.h; |
53 | | see the code in tools/perf/util/intel-pt.c intel_pt_add_gp_regs() |
54 | | and note how regs are added in the same order as the perf_regs.h enum. */ |
55 | | #else |
56 | | /* Since asm/perf_regs.h is absent, or gives the register layout for a |
57 | | different arch, we can't unwind i386 and x86_64 perf sample frames. */ |
58 | | #define PERF_FRAME_REGISTERS_I386 0 |
59 | | #define PERF_FRAME_REGISTERS_X86_64 0 |
60 | | #endif /* _ASM_X86_PERF_REGS_H */ |
61 | | |
62 | | #if defined(_ASM_ARM_PERF_REGS_H) |
63 | | #define REG(R) (1ULL << PERF_REG_ARM_ ## R) |
64 | | /* Proper unwind set: callee-saved R4..R10, then R11 for FP, and SP, |
65 | | LR, PC. Collecting all 16 regs would also be feasible. */ |
66 | | #define PERF_FRAME_REGISTERS_ARM (REG(R0) | REG(R1) | REG(R2) | REG(R3) \ |
67 | | | REG(R4) | REG(R5) | REG(R6) | REG(R7) | REG(R8) | REG(R9) | REG(R10) \ |
68 | | | REG(FP) | REG(IP) | REG(SP) | REG(LR) | REG(PC)) |
69 | | /* Register ordering defined in linux arch/arm/include/uapi/asm/perf_regs.h. */ |
70 | | #elif !defined(_ASM_ARM64_PERF_REGS_H) |
71 | | /* Since asm/perf_regs.h is absent, or gives the register layout for a |
72 | | different arch, we can't unwind 32-bit ARM perf sample frames. */ |
73 | 554 | #define PERF_FRAME_REGISTERS_ARM 0 |
74 | | #endif /* _ASM_ARM_PERF_REGS_H */ |
75 | | |
76 | | #if defined(_ASM_ARM64_PERF_REGS_H) |
77 | | #define REG(R) (1ULL << PERF_REG_ARM64_ ## R) |
78 | | /* Proper unwind set: callee-saved X19..X28, then X29 for FP, |
79 | | LR for return addr, and SP, PC. */ |
80 | | #define PERF_FRAME_REGISTERS_AARCH64 (REG(X19) | REG(X20) | REG(X21) \ |
81 | | | REG(X22) | REG(X23) | REG(X24) | REG(X25) | REG(X26) | REG(X27) \ |
82 | | | REG(X28) | REG(X29) /*FP*/ | REG(LR) | REG(SP) | REG(PC)) |
83 | | /* Register ordering defined in linux arch/arm64/include/uapi/asm/perf_regs.h. */ |
84 | | |
85 | | /* Likewise, for 32bit-on-64bit compat mode: */ |
86 | | #define PERF_FRAME_REGISTERS_ARM (REG(X0) | REG(X1) | REG(X2) | REG(X3) \ |
87 | | | REG(X4) | REG(X5) | REG(X6) | REG(X7) | REG(X8) | REG(X9) | REG(X10) \ |
88 | | | REG(X11) /* FP */ | REG(X12) /* IP */ /* | skip X13..X29 */ | REG(LR) \ |
89 | | | REG(SP) | REG(PC)) |
90 | | /* XXX Then the profiler likely needs to be instructed to request the |
91 | | intersection of these register sets rather than just |
92 | | PERF_FRAME_REGISTERS_AARCH64. Thus, in aarch64_init.c, we have: |
93 | | |
94 | | eh->perf_frame_regs_mask = PERF_FRAME_REGISTERS_AARCH64 |
95 | | | PERF_FRAME_REGISTERS_ARM; |
96 | | */ |
97 | | #else |
98 | | /* Since asm/perf_regs.h is absent, or gives the register layout for a |
99 | | different arch, we can't unwind aarch64 perf sample frames. */ |
100 | 289 | #define PERF_FRAME_REGISTERS_AARCH64 0 |
101 | | #endif /* _ASM_ARM64_PERF_REGS_H */ |
102 | | |
103 | | static inline bool |
104 | | generic_sample_sp_pc (const Dwarf_Word *regs, uint32_t n_regs, |
105 | | const int *regs_mapping, size_t n_regs_mapping, |
106 | | Dwarf_Word *sp, uint sp_index /* into dwarf_regs */, |
107 | | Dwarf_Word *pc, uint pc_index /* into dwarf_regs */) |
108 | 0 | { |
109 | 0 | if (sp != NULL) *sp = 0; |
110 | 0 | if (pc != NULL) *pc = 0; |
111 | | /* TODO: Register locations could be cached and rechecked on a |
112 | | fastpath without needing to loop, though the overhead reduction |
113 | | is minimal. */ |
114 | 0 | int need_sp = (sp != NULL), need_pc = (pc != NULL); |
115 | 0 | for (size_t j = 0; (need_sp || need_pc) && n_regs_mapping > j; j++) |
116 | 0 | { |
117 | 0 | if (n_regs <= (uint32_t)j) break; |
118 | 0 | if (need_sp && regs_mapping[j] == (int)sp_index) |
119 | 0 | { |
120 | 0 | *sp = regs[j]; need_sp = false; |
121 | 0 | } |
122 | 0 | if (need_pc && regs_mapping[j] == (int)pc_index) |
123 | 0 | { |
124 | 0 | *pc = regs[j]; need_pc = false; |
125 | 0 | } |
126 | 0 | } |
127 | 0 | return (!need_sp && !need_pc); |
128 | 0 | } Unexecuted instantiation: i386_init.c:generic_sample_sp_pc Unexecuted instantiation: i386_initreg_sample.c:generic_sample_sp_pc Unexecuted instantiation: x86_64_init.c:generic_sample_sp_pc Unexecuted instantiation: x86_64_initreg_sample.c:generic_sample_sp_pc Unexecuted instantiation: arm_init.c:generic_sample_sp_pc Unexecuted instantiation: arm_initreg_sample.c:generic_sample_sp_pc Unexecuted instantiation: aarch64_init.c:generic_sample_sp_pc Unexecuted instantiation: aarch64_initreg_sample.c:generic_sample_sp_pc |
129 | | |
130 | | #endif /* libebl_PERF_FLAGS.h */ |