xref: /linux/tools/perf/util/libunwind-arch/libunwind-arch.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "libunwind-arch.h"
3 #include "../debug.h"
4 #include "../maps.h"
5 #include <elf.h>
6 #include <errno.h>
7 
8 int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum)
9 {
10 	switch (e_machine) {
11 	case EM_ARM:
12 		return __get_perf_regnum_for_unw_regnum_arm(unw_regnum);
13 	case EM_AARCH64:
14 		return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum);
15 	case EM_LOONGARCH:
16 		return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum);
17 	case EM_MIPS:
18 		return __get_perf_regnum_for_unw_regnum_mips(unw_regnum);
19 	case EM_PPC:
20 		return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum);
21 	case EM_PPC64:
22 		return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum);
23 	case EM_RISCV:
24 		return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum);
25 	case EM_S390:
26 		return __get_perf_regnum_for_unw_regnum_s390(unw_regnum);
27 	case EM_386:
28 		return __get_perf_regnum_for_unw_regnum_i386(unw_regnum);
29 	case EM_X86_64:
30 		return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum);
31 	default:
32 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
33 		return -EINVAL;
34 	}
35 }
36 
37 
38 void libunwind_arch__flush_access(struct maps *maps)
39 {
40 	unsigned int e_machine = maps__e_machine(maps);
41 
42 	switch (e_machine) {
43 	case EM_NONE:
44 		break;  // No libunwind info on the maps.
45 	case EM_ARM:
46 		__libunwind_arch__flush_access_arm(maps);
47 		break;
48 	case EM_AARCH64:
49 		__libunwind_arch__flush_access_arm64(maps);
50 		break;
51 	case EM_LOONGARCH:
52 		__libunwind_arch__flush_access_loongarch(maps);
53 		break;
54 	case EM_MIPS:
55 		__libunwind_arch__flush_access_mips(maps);
56 		break;
57 	case EM_PPC:
58 		__libunwind_arch__flush_access_ppc32(maps);
59 		break;
60 	case EM_PPC64:
61 		__libunwind_arch__flush_access_ppc64(maps);
62 		break;
63 	case EM_RISCV:
64 		__libunwind_arch__flush_access_riscv(maps);
65 		break;
66 	case EM_S390:
67 		__libunwind_arch__flush_access_s390(maps);
68 		break;
69 	case EM_386:
70 		__libunwind_arch__flush_access_i386(maps);
71 		break;
72 	case EM_X86_64:
73 		__libunwind_arch__flush_access_x86_64(maps);
74 		break;
75 	default:
76 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
77 		break;
78 	}
79 }
80 
81 void libunwind_arch__finish_access(struct maps *maps)
82 {
83 	unsigned int e_machine = maps__e_machine(maps);
84 
85 	switch (e_machine) {
86 	case EM_NONE:
87 		break;  // No libunwind info on the maps.
88 	case EM_ARM:
89 		__libunwind_arch__finish_access_arm(maps);
90 		break;
91 	case EM_AARCH64:
92 		__libunwind_arch__finish_access_arm64(maps);
93 		break;
94 	case EM_LOONGARCH:
95 		__libunwind_arch__finish_access_loongarch(maps);
96 		break;
97 	case EM_MIPS:
98 		__libunwind_arch__finish_access_mips(maps);
99 		break;
100 	case EM_PPC:
101 		__libunwind_arch__finish_access_ppc32(maps);
102 		break;
103 	case EM_PPC64:
104 		__libunwind_arch__finish_access_ppc64(maps);
105 		break;
106 	case EM_RISCV:
107 		__libunwind_arch__finish_access_riscv(maps);
108 		break;
109 	case EM_S390:
110 		__libunwind_arch__finish_access_s390(maps);
111 		break;
112 	case EM_386:
113 		__libunwind_arch__finish_access_i386(maps);
114 		break;
115 	case EM_X86_64:
116 		__libunwind_arch__finish_access_x86_64(maps);
117 		break;
118 	default:
119 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
120 		break;
121 	}
122 }
123 
124 void *libunwind_arch__create_addr_space(unsigned int e_machine)
125 {
126 	switch (e_machine) {
127 	case EM_ARM:
128 		return __libunwind_arch__create_addr_space_arm();
129 	case EM_AARCH64:
130 		return __libunwind_arch__create_addr_space_arm64();
131 	case EM_LOONGARCH:
132 		return __libunwind_arch__create_addr_space_loongarch();
133 	case EM_MIPS:
134 		return __libunwind_arch__create_addr_space_mips();
135 	case EM_PPC:
136 		return __libunwind_arch__create_addr_space_ppc32();
137 	case EM_PPC64:
138 		return __libunwind_arch__create_addr_space_ppc64();
139 	case EM_RISCV:
140 		return __libunwind_arch__create_addr_space_riscv();
141 	case EM_S390:
142 		return __libunwind_arch__create_addr_space_s390();
143 	case EM_386:
144 		return __libunwind_arch__create_addr_space_i386();
145 	case EM_X86_64:
146 		return __libunwind_arch__create_addr_space_x86_64();
147 	default:
148 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
149 		return NULL;
150 	}
151 }
152 
153 int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine,
154 					      void *as,
155 					      uint64_t ip,
156 					      struct libarch_unwind__dyn_info *di,
157 					      void *pi,
158 					      int need_unwind_info,
159 					      void *arg)
160 {
161 	switch (e_machine) {
162 	case EM_ARM:
163 		return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi,
164 								       need_unwind_info, arg);
165 	case EM_AARCH64:
166 		return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi,
167 									 need_unwind_info, arg);
168 	case EM_LOONGARCH:
169 		return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di, pi,
170 									     need_unwind_info, arg);
171 	case EM_MIPS:
172 		return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi,
173 									need_unwind_info, arg);
174 	case EM_PPC:
175 		return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi,
176 									 need_unwind_info, arg);
177 	case EM_PPC64:
178 		return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi,
179 									 need_unwind_info, arg);
180 	case EM_RISCV:
181 		return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi,
182 									need_unwind_info, arg);
183 	case EM_S390:
184 		return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi,
185 									need_unwind_info, arg);
186 	case EM_386:
187 		return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi,
188 									need_unwind_info, arg);
189 	case EM_X86_64:
190 		return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi,
191 									  need_unwind_info, arg);
192 	default:
193 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
194 		return -EINVAL;
195 	}
196 }
197 
198 int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine,
199 					   int found,
200 					   struct libarch_unwind__dyn_info *di_debug,
201 					   uint64_t ip,
202 					   uint64_t segbase,
203 					   const char *obj_name,
204 					   uint64_t start,
205 					   uint64_t end)
206 {
207 	switch (e_machine) {
208 	case EM_ARM:
209 		return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip, segbase,
210 								    obj_name, start, end);
211 	case EM_AARCH64:
212 		return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, ip, segbase,
213 								      obj_name, start, end);
214 	case EM_LOONGARCH:
215 		return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debug, ip,
216 									  segbase, obj_name,
217 									  start, end);
218 	case EM_MIPS:
219 		return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip, segbase,
220 								     obj_name, start, end);
221 	case EM_PPC:
222 		return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, ip, segbase,
223 								      obj_name, start, end);
224 	case EM_PPC64:
225 		return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, ip, segbase,
226 								      obj_name, start, end);
227 	case EM_RISCV:
228 		return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, ip, segbase,
229 								     obj_name, start, end);
230 	case EM_S390:
231 		return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip, segbase,
232 								     obj_name, start, end);
233 	case EM_386:
234 		return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip, segbase,
235 								     obj_name, start, end);
236 	case EM_X86_64:
237 		return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, ip, segbase,
238 								       obj_name, start, end);
239 	default:
240 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
241 		return -EINVAL;
242 	}
243 }
244 
245 struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread,
246 						    struct perf_sample *sample, int max_stack,
247 						    bool best_effort, uint16_t e_machine,
248 						    uint64_t first_ip)
249 {
250 	switch (e_machine) {
251 	case EM_ARM:
252 		return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack,
253 							     best_effort, first_ip);
254 	case EM_AARCH64:
255 		return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack,
256 							       best_effort, first_ip);
257 	case EM_LOONGARCH:
258 		return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_stack,
259 								   best_effort, first_ip);
260 	case EM_MIPS:
261 		return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack,
262 							      best_effort, first_ip);
263 	case EM_PPC:
264 		return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack,
265 							       best_effort, first_ip);
266 	case EM_PPC64:
267 		return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack,
268 							       best_effort, first_ip);
269 	case EM_RISCV:
270 		return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack,
271 							      best_effort, first_ip);
272 	case EM_S390:
273 		return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack,
274 							      best_effort, first_ip);
275 	case EM_386:
276 		return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack,
277 							      best_effort, first_ip);
278 	case EM_X86_64:
279 		return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stack,
280 								best_effort, first_ip);
281 	default:
282 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
283 		return NULL;
284 	}
285 }
286 
287 void libunwind_arch_unwind_info__delete(struct unwind_info *ui)
288 {
289 	free(ui);
290 }
291 
292 int libunwind_arch__unwind_step(struct unwind_info *ui)
293 {
294 	switch (ui->e_machine) {
295 	case EM_ARM:
296 		return __libunwind_arch__unwind_step_arm(ui);
297 	case EM_AARCH64:
298 		return __libunwind_arch__unwind_step_arm64(ui);
299 	case EM_LOONGARCH:
300 		return __libunwind_arch__unwind_step_loongarch(ui);
301 	case EM_MIPS:
302 		return __libunwind_arch__unwind_step_mips(ui);
303 	case EM_PPC:
304 		return __libunwind_arch__unwind_step_ppc32(ui);
305 	case EM_PPC64:
306 		return __libunwind_arch__unwind_step_ppc64(ui);
307 	case EM_RISCV:
308 		return __libunwind_arch__unwind_step_riscv(ui);
309 	case EM_S390:
310 		return __libunwind_arch__unwind_step_s390(ui);
311 	case EM_386:
312 		return __libunwind_arch__unwind_step_i386(ui);
313 	case EM_X86_64:
314 		return __libunwind_arch__unwind_step_x86_64(ui);
315 	default:
316 		pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine);
317 		return -EINVAL;
318 	}
319 }
320