xref: /linux/tools/perf/util/perf_regs.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <elf.h>
3 #include <errno.h>
4 #include <string.h>
5 #include "dwarf-regs.h"
6 #include "perf_regs.h"
7 #include "util/sample.h"
8 #include "debug.h"
9 
10 int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op)
11 {
12 	int ret = SDT_ARG_SKIP;
13 
14 	switch (e_machine) {
15 	case EM_AARCH64:
16 		ret = __perf_sdt_arg_parse_op_arm64(old_op, new_op);
17 		break;
18 	case EM_PPC:
19 	case EM_PPC64:
20 		ret = __perf_sdt_arg_parse_op_powerpc(old_op, new_op);
21 		break;
22 	case EM_386:
23 	case EM_X86_64:
24 		ret = __perf_sdt_arg_parse_op_x86(old_op, new_op);
25 		break;
26 	default:
27 		pr_debug("Unknown ELF machine %d, standard arguments parse will be skipped.\n",
28 			 e_machine);
29 		break;
30 	}
31 
32 	return ret;
33 }
34 
35 uint64_t perf_intr_reg_mask(uint16_t e_machine)
36 {
37 	uint64_t mask = 0;
38 
39 	switch (e_machine) {
40 	case EM_ARM:
41 		mask = __perf_reg_mask_arm(/*intr=*/true);
42 		break;
43 	case EM_AARCH64:
44 		mask = __perf_reg_mask_arm64(/*intr=*/true);
45 		break;
46 	case EM_CSKY:
47 		mask = __perf_reg_mask_csky(/*intr=*/true);
48 		break;
49 	case EM_LOONGARCH:
50 		mask = __perf_reg_mask_loongarch(/*intr=*/true);
51 		break;
52 	case EM_MIPS:
53 		mask = __perf_reg_mask_mips(/*intr=*/true);
54 		break;
55 	case EM_PPC:
56 	case EM_PPC64:
57 		mask = __perf_reg_mask_powerpc(/*intr=*/true);
58 		break;
59 	case EM_RISCV:
60 		mask = __perf_reg_mask_riscv(/*intr=*/true);
61 		break;
62 	case EM_S390:
63 		mask = __perf_reg_mask_s390(/*intr=*/true);
64 		break;
65 	case EM_386:
66 	case EM_X86_64:
67 		mask = __perf_reg_mask_x86(/*intr=*/true);
68 		break;
69 	default:
70 		pr_debug("Unknown ELF machine %d, interrupt sampling register mask will be empty.\n",
71 			 e_machine);
72 		break;
73 	}
74 
75 	return mask;
76 }
77 
78 uint64_t perf_user_reg_mask(uint16_t e_machine)
79 {
80 	uint64_t mask = 0;
81 
82 	switch (e_machine) {
83 	case EM_ARM:
84 		mask = __perf_reg_mask_arm(/*intr=*/false);
85 		break;
86 	case EM_AARCH64:
87 		mask = __perf_reg_mask_arm64(/*intr=*/false);
88 		break;
89 	case EM_CSKY:
90 		mask = __perf_reg_mask_csky(/*intr=*/false);
91 		break;
92 	case EM_LOONGARCH:
93 		mask = __perf_reg_mask_loongarch(/*intr=*/false);
94 		break;
95 	case EM_MIPS:
96 		mask = __perf_reg_mask_mips(/*intr=*/false);
97 		break;
98 	case EM_PPC:
99 	case EM_PPC64:
100 		mask = __perf_reg_mask_powerpc(/*intr=*/false);
101 		break;
102 	case EM_RISCV:
103 		mask = __perf_reg_mask_riscv(/*intr=*/false);
104 		break;
105 	case EM_S390:
106 		mask = __perf_reg_mask_s390(/*intr=*/false);
107 		break;
108 	case EM_386:
109 	case EM_X86_64:
110 		mask = __perf_reg_mask_x86(/*intr=*/false);
111 		break;
112 	default:
113 		pr_debug("Unknown ELF machine %d, user sampling register mask will be empty.\n",
114 			 e_machine);
115 		break;
116 	}
117 
118 	return mask;
119 }
120 
121 const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags)
122 {
123 	const char *reg_name = NULL;
124 
125 	switch (e_machine) {
126 	case EM_ARM:
127 		reg_name = __perf_reg_name_arm(id);
128 		break;
129 	case EM_AARCH64:
130 		reg_name = __perf_reg_name_arm64(id);
131 		break;
132 	case EM_CSKY:
133 		reg_name = __perf_reg_name_csky(id, e_flags);
134 		break;
135 	case EM_LOONGARCH:
136 		reg_name = __perf_reg_name_loongarch(id);
137 		break;
138 	case EM_MIPS:
139 		reg_name = __perf_reg_name_mips(id);
140 		break;
141 	case EM_PPC:
142 	case EM_PPC64:
143 		reg_name = __perf_reg_name_powerpc(id);
144 		break;
145 	case EM_RISCV:
146 		reg_name = __perf_reg_name_riscv(id);
147 		break;
148 	case EM_S390:
149 		reg_name = __perf_reg_name_s390(id);
150 		break;
151 	case EM_386:
152 	case EM_X86_64:
153 		reg_name = __perf_reg_name_x86(id);
154 		break;
155 	default:
156 		break;
157 	}
158 	if (reg_name)
159 		return reg_name;
160 
161 	pr_debug("Failed to find register %d for ELF machine type %u\n", id, e_machine);
162 	return "unknown";
163 }
164 
165 int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
166 {
167 	int i, idx = 0;
168 	u64 mask = regs->mask;
169 
170 	if ((u64)id >= PERF_SAMPLE_REGS_CACHE_SIZE)
171 		return -EINVAL;
172 
173 	if (regs->cache_mask & (1ULL << id))
174 		goto out;
175 
176 	if (!(mask & (1ULL << id)))
177 		return -EINVAL;
178 
179 	for (i = 0; i < id; i++) {
180 		if (mask & (1ULL << i))
181 			idx++;
182 	}
183 
184 	regs->cache_mask |= (1ULL << id);
185 	regs->cache_regs[id] = regs->regs[idx];
186 
187 out:
188 	*valp = regs->cache_regs[id];
189 	return 0;
190 }
191 
192 uint64_t perf_arch_reg_ip(uint16_t e_machine)
193 {
194 	switch (e_machine) {
195 	case EM_ARM:
196 		return __perf_reg_ip_arm();
197 	case EM_AARCH64:
198 		return __perf_reg_ip_arm64();
199 	case EM_CSKY:
200 		return __perf_reg_ip_csky();
201 	case EM_LOONGARCH:
202 		return __perf_reg_ip_loongarch();
203 	case EM_MIPS:
204 		return __perf_reg_ip_mips();
205 	case EM_PPC:
206 	case EM_PPC64:
207 		return __perf_reg_ip_powerpc();
208 	case EM_RISCV:
209 		return __perf_reg_ip_riscv();
210 	case EM_S390:
211 		return __perf_reg_ip_s390();
212 	case EM_386:
213 	case EM_X86_64:
214 		return __perf_reg_ip_x86();
215 	default:
216 		pr_err("Failed to find IP register for ELF machine type %u\n", e_machine);
217 		return 0;
218 	}
219 }
220 
221 uint64_t perf_arch_reg_sp(uint16_t e_machine)
222 {
223 	switch (e_machine) {
224 	case EM_ARM:
225 		return __perf_reg_sp_arm();
226 	case EM_AARCH64:
227 		return __perf_reg_sp_arm64();
228 	case EM_CSKY:
229 		return __perf_reg_sp_csky();
230 	case EM_LOONGARCH:
231 		return __perf_reg_sp_loongarch();
232 	case EM_MIPS:
233 		return __perf_reg_sp_mips();
234 	case EM_PPC:
235 	case EM_PPC64:
236 		return __perf_reg_sp_powerpc();
237 	case EM_RISCV:
238 		return __perf_reg_sp_riscv();
239 	case EM_S390:
240 		return __perf_reg_sp_s390();
241 	case EM_386:
242 	case EM_X86_64:
243 		return __perf_reg_sp_x86();
244 	default:
245 		pr_err("Failed to find SP register for ELF machine type %u\n", e_machine);
246 		return 0;
247 	}
248 }
249