xref: /linux/tools/perf/util/libunwind-arch/libunwind-arch.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1fdf08e4bSIan Rogers // SPDX-License-Identifier: GPL-2.0
2fdf08e4bSIan Rogers #include "libunwind-arch.h"
3fdf08e4bSIan Rogers #include "../debug.h"
42723e9f8SIan Rogers #include "../maps.h"
5fdf08e4bSIan Rogers #include <elf.h>
6fdf08e4bSIan Rogers #include <errno.h>
7fdf08e4bSIan Rogers 
8fdf08e4bSIan Rogers int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum)
9fdf08e4bSIan Rogers {
10fdf08e4bSIan Rogers 	switch (e_machine) {
11fdf08e4bSIan Rogers 	case EM_ARM:
12fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_arm(unw_regnum);
13fdf08e4bSIan Rogers 	case EM_AARCH64:
14fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum);
15fdf08e4bSIan Rogers 	case EM_LOONGARCH:
16fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum);
17fdf08e4bSIan Rogers 	case EM_MIPS:
18fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_mips(unw_regnum);
19fdf08e4bSIan Rogers 	case EM_PPC:
20fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum);
21fdf08e4bSIan Rogers 	case EM_PPC64:
22fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum);
23*834c5571SIan Rogers 	case EM_RISCV:
24*834c5571SIan Rogers 		return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum);
25fdf08e4bSIan Rogers 	case EM_S390:
26fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_s390(unw_regnum);
27fdf08e4bSIan Rogers 	case EM_386:
28fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_i386(unw_regnum);
29fdf08e4bSIan Rogers 	case EM_X86_64:
30fdf08e4bSIan Rogers 		return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum);
31fdf08e4bSIan Rogers 	default:
32fdf08e4bSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
33fdf08e4bSIan Rogers 		return -EINVAL;
34fdf08e4bSIan Rogers 	}
35fdf08e4bSIan Rogers }
362723e9f8SIan Rogers 
372723e9f8SIan Rogers 
382723e9f8SIan Rogers void libunwind_arch__flush_access(struct maps *maps)
392723e9f8SIan Rogers {
402723e9f8SIan Rogers 	unsigned int e_machine = maps__e_machine(maps);
412723e9f8SIan Rogers 
422723e9f8SIan Rogers 	switch (e_machine) {
432723e9f8SIan Rogers 	case EM_NONE:
442723e9f8SIan Rogers 		break;  // No libunwind info on the maps.
452723e9f8SIan Rogers 	case EM_ARM:
462723e9f8SIan Rogers 		__libunwind_arch__flush_access_arm(maps);
472723e9f8SIan Rogers 		break;
482723e9f8SIan Rogers 	case EM_AARCH64:
492723e9f8SIan Rogers 		__libunwind_arch__flush_access_arm64(maps);
502723e9f8SIan Rogers 		break;
512723e9f8SIan Rogers 	case EM_LOONGARCH:
522723e9f8SIan Rogers 		__libunwind_arch__flush_access_loongarch(maps);
532723e9f8SIan Rogers 		break;
542723e9f8SIan Rogers 	case EM_MIPS:
552723e9f8SIan Rogers 		__libunwind_arch__flush_access_mips(maps);
562723e9f8SIan Rogers 		break;
572723e9f8SIan Rogers 	case EM_PPC:
582723e9f8SIan Rogers 		__libunwind_arch__flush_access_ppc32(maps);
592723e9f8SIan Rogers 		break;
602723e9f8SIan Rogers 	case EM_PPC64:
612723e9f8SIan Rogers 		__libunwind_arch__flush_access_ppc64(maps);
622723e9f8SIan Rogers 		break;
63*834c5571SIan Rogers 	case EM_RISCV:
64*834c5571SIan Rogers 		__libunwind_arch__flush_access_riscv(maps);
65*834c5571SIan Rogers 		break;
662723e9f8SIan Rogers 	case EM_S390:
672723e9f8SIan Rogers 		__libunwind_arch__flush_access_s390(maps);
682723e9f8SIan Rogers 		break;
692723e9f8SIan Rogers 	case EM_386:
702723e9f8SIan Rogers 		__libunwind_arch__flush_access_i386(maps);
712723e9f8SIan Rogers 		break;
722723e9f8SIan Rogers 	case EM_X86_64:
732723e9f8SIan Rogers 		__libunwind_arch__flush_access_x86_64(maps);
742723e9f8SIan Rogers 		break;
752723e9f8SIan Rogers 	default:
762723e9f8SIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
772723e9f8SIan Rogers 		break;
782723e9f8SIan Rogers 	}
792723e9f8SIan Rogers }
802723e9f8SIan Rogers 
812723e9f8SIan Rogers void libunwind_arch__finish_access(struct maps *maps)
822723e9f8SIan Rogers {
832723e9f8SIan Rogers 	unsigned int e_machine = maps__e_machine(maps);
842723e9f8SIan Rogers 
852723e9f8SIan Rogers 	switch (e_machine) {
862723e9f8SIan Rogers 	case EM_NONE:
872723e9f8SIan Rogers 		break;  // No libunwind info on the maps.
882723e9f8SIan Rogers 	case EM_ARM:
892723e9f8SIan Rogers 		__libunwind_arch__finish_access_arm(maps);
902723e9f8SIan Rogers 		break;
912723e9f8SIan Rogers 	case EM_AARCH64:
922723e9f8SIan Rogers 		__libunwind_arch__finish_access_arm64(maps);
932723e9f8SIan Rogers 		break;
942723e9f8SIan Rogers 	case EM_LOONGARCH:
952723e9f8SIan Rogers 		__libunwind_arch__finish_access_loongarch(maps);
962723e9f8SIan Rogers 		break;
972723e9f8SIan Rogers 	case EM_MIPS:
982723e9f8SIan Rogers 		__libunwind_arch__finish_access_mips(maps);
992723e9f8SIan Rogers 		break;
1002723e9f8SIan Rogers 	case EM_PPC:
1012723e9f8SIan Rogers 		__libunwind_arch__finish_access_ppc32(maps);
1022723e9f8SIan Rogers 		break;
1032723e9f8SIan Rogers 	case EM_PPC64:
1042723e9f8SIan Rogers 		__libunwind_arch__finish_access_ppc64(maps);
1052723e9f8SIan Rogers 		break;
106*834c5571SIan Rogers 	case EM_RISCV:
107*834c5571SIan Rogers 		__libunwind_arch__finish_access_riscv(maps);
108*834c5571SIan Rogers 		break;
1092723e9f8SIan Rogers 	case EM_S390:
1102723e9f8SIan Rogers 		__libunwind_arch__finish_access_s390(maps);
1112723e9f8SIan Rogers 		break;
1122723e9f8SIan Rogers 	case EM_386:
1132723e9f8SIan Rogers 		__libunwind_arch__finish_access_i386(maps);
1142723e9f8SIan Rogers 		break;
1152723e9f8SIan Rogers 	case EM_X86_64:
1162723e9f8SIan Rogers 		__libunwind_arch__finish_access_x86_64(maps);
1172723e9f8SIan Rogers 		break;
1182723e9f8SIan Rogers 	default:
1192723e9f8SIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
1202723e9f8SIan Rogers 		break;
1212723e9f8SIan Rogers 	}
1222723e9f8SIan Rogers }
12388b4275fSIan Rogers 
12488b4275fSIan Rogers void *libunwind_arch__create_addr_space(unsigned int e_machine)
12588b4275fSIan Rogers {
12688b4275fSIan Rogers 	switch (e_machine) {
12788b4275fSIan Rogers 	case EM_ARM:
12888b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_arm();
12988b4275fSIan Rogers 	case EM_AARCH64:
13088b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_arm64();
13188b4275fSIan Rogers 	case EM_LOONGARCH:
13288b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_loongarch();
13388b4275fSIan Rogers 	case EM_MIPS:
13488b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_mips();
13588b4275fSIan Rogers 	case EM_PPC:
13688b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_ppc32();
13788b4275fSIan Rogers 	case EM_PPC64:
13888b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_ppc64();
139*834c5571SIan Rogers 	case EM_RISCV:
140*834c5571SIan Rogers 		return __libunwind_arch__create_addr_space_riscv();
14188b4275fSIan Rogers 	case EM_S390:
14288b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_s390();
14388b4275fSIan Rogers 	case EM_386:
14488b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_i386();
14588b4275fSIan Rogers 	case EM_X86_64:
14688b4275fSIan Rogers 		return __libunwind_arch__create_addr_space_x86_64();
14788b4275fSIan Rogers 	default:
14888b4275fSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
14988b4275fSIan Rogers 		return NULL;
15088b4275fSIan Rogers 	}
15188b4275fSIan Rogers }
15288b4275fSIan Rogers 
15388b4275fSIan Rogers int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine,
15488b4275fSIan Rogers 					      void *as,
15588b4275fSIan Rogers 					      uint64_t ip,
15688b4275fSIan Rogers 					      struct libarch_unwind__dyn_info *di,
15788b4275fSIan Rogers 					      void *pi,
15888b4275fSIan Rogers 					      int need_unwind_info,
15988b4275fSIan Rogers 					      void *arg)
16088b4275fSIan Rogers {
16188b4275fSIan Rogers 	switch (e_machine) {
16288b4275fSIan Rogers 	case EM_ARM:
16388b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi,
16488b4275fSIan Rogers 								       need_unwind_info, arg);
16588b4275fSIan Rogers 	case EM_AARCH64:
16688b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi,
16788b4275fSIan Rogers 									 need_unwind_info, arg);
16888b4275fSIan Rogers 	case EM_LOONGARCH:
16988b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di, pi,
17088b4275fSIan Rogers 									     need_unwind_info, arg);
17188b4275fSIan Rogers 	case EM_MIPS:
17288b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi,
17388b4275fSIan Rogers 									need_unwind_info, arg);
17488b4275fSIan Rogers 	case EM_PPC:
17588b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi,
17688b4275fSIan Rogers 									 need_unwind_info, arg);
17788b4275fSIan Rogers 	case EM_PPC64:
17888b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi,
17988b4275fSIan Rogers 									 need_unwind_info, arg);
180*834c5571SIan Rogers 	case EM_RISCV:
181*834c5571SIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi,
182*834c5571SIan Rogers 									need_unwind_info, arg);
18388b4275fSIan Rogers 	case EM_S390:
18488b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi,
18588b4275fSIan Rogers 									need_unwind_info, arg);
18688b4275fSIan Rogers 	case EM_386:
18788b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi,
18888b4275fSIan Rogers 									need_unwind_info, arg);
18988b4275fSIan Rogers 	case EM_X86_64:
19088b4275fSIan Rogers 		return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi,
19188b4275fSIan Rogers 									  need_unwind_info, arg);
19288b4275fSIan Rogers 	default:
19388b4275fSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
19488b4275fSIan Rogers 		return -EINVAL;
19588b4275fSIan Rogers 	}
19688b4275fSIan Rogers }
19788b4275fSIan Rogers 
19888b4275fSIan Rogers int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine,
19988b4275fSIan Rogers 					   int found,
20088b4275fSIan Rogers 					   struct libarch_unwind__dyn_info *di_debug,
20188b4275fSIan Rogers 					   uint64_t ip,
20288b4275fSIan Rogers 					   uint64_t segbase,
20388b4275fSIan Rogers 					   const char *obj_name,
20488b4275fSIan Rogers 					   uint64_t start,
20588b4275fSIan Rogers 					   uint64_t end)
20688b4275fSIan Rogers {
20788b4275fSIan Rogers 	switch (e_machine) {
20888b4275fSIan Rogers 	case EM_ARM:
20988b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip, segbase,
21088b4275fSIan Rogers 								    obj_name, start, end);
21188b4275fSIan Rogers 	case EM_AARCH64:
21288b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, ip, segbase,
21388b4275fSIan Rogers 								      obj_name, start, end);
21488b4275fSIan Rogers 	case EM_LOONGARCH:
21588b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debug, ip,
21688b4275fSIan Rogers 									  segbase, obj_name,
21788b4275fSIan Rogers 									  start, end);
21888b4275fSIan Rogers 	case EM_MIPS:
21988b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip, segbase,
22088b4275fSIan Rogers 								     obj_name, start, end);
22188b4275fSIan Rogers 	case EM_PPC:
22288b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, ip, segbase,
22388b4275fSIan Rogers 								      obj_name, start, end);
22488b4275fSIan Rogers 	case EM_PPC64:
22588b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, ip, segbase,
22688b4275fSIan Rogers 								      obj_name, start, end);
227*834c5571SIan Rogers 	case EM_RISCV:
228*834c5571SIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, ip, segbase,
229*834c5571SIan Rogers 								     obj_name, start, end);
23088b4275fSIan Rogers 	case EM_S390:
23188b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip, segbase,
23288b4275fSIan Rogers 								     obj_name, start, end);
23388b4275fSIan Rogers 	case EM_386:
23488b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip, segbase,
23588b4275fSIan Rogers 								     obj_name, start, end);
23688b4275fSIan Rogers 	case EM_X86_64:
23788b4275fSIan Rogers 		return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, ip, segbase,
23888b4275fSIan Rogers 								       obj_name, start, end);
23988b4275fSIan Rogers 	default:
24088b4275fSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
24188b4275fSIan Rogers 		return -EINVAL;
24288b4275fSIan Rogers 	}
24388b4275fSIan Rogers }
24488b4275fSIan Rogers 
24588b4275fSIan Rogers struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread,
24688b4275fSIan Rogers 						    struct perf_sample *sample, int max_stack,
24788b4275fSIan Rogers 						    bool best_effort, uint16_t e_machine,
24888b4275fSIan Rogers 						    uint64_t first_ip)
24988b4275fSIan Rogers {
25088b4275fSIan Rogers 	switch (e_machine) {
25188b4275fSIan Rogers 	case EM_ARM:
25288b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack,
25388b4275fSIan Rogers 							     best_effort, first_ip);
25488b4275fSIan Rogers 	case EM_AARCH64:
25588b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack,
25688b4275fSIan Rogers 							       best_effort, first_ip);
25788b4275fSIan Rogers 	case EM_LOONGARCH:
25888b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_stack,
25988b4275fSIan Rogers 								   best_effort, first_ip);
26088b4275fSIan Rogers 	case EM_MIPS:
26188b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack,
26288b4275fSIan Rogers 							      best_effort, first_ip);
26388b4275fSIan Rogers 	case EM_PPC:
26488b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack,
26588b4275fSIan Rogers 							       best_effort, first_ip);
26688b4275fSIan Rogers 	case EM_PPC64:
26788b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack,
26888b4275fSIan Rogers 							       best_effort, first_ip);
269*834c5571SIan Rogers 	case EM_RISCV:
270*834c5571SIan Rogers 		return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack,
271*834c5571SIan Rogers 							      best_effort, first_ip);
27288b4275fSIan Rogers 	case EM_S390:
27388b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack,
27488b4275fSIan Rogers 							      best_effort, first_ip);
27588b4275fSIan Rogers 	case EM_386:
27688b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack,
27788b4275fSIan Rogers 							      best_effort, first_ip);
27888b4275fSIan Rogers 	case EM_X86_64:
27988b4275fSIan Rogers 		return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stack,
28088b4275fSIan Rogers 								best_effort, first_ip);
28188b4275fSIan Rogers 	default:
28288b4275fSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", e_machine);
28388b4275fSIan Rogers 		return NULL;
28488b4275fSIan Rogers 	}
28588b4275fSIan Rogers }
28688b4275fSIan Rogers 
28788b4275fSIan Rogers void libunwind_arch_unwind_info__delete(struct unwind_info *ui)
28888b4275fSIan Rogers {
28988b4275fSIan Rogers 	free(ui);
29088b4275fSIan Rogers }
29188b4275fSIan Rogers 
29288b4275fSIan Rogers int libunwind_arch__unwind_step(struct unwind_info *ui)
29388b4275fSIan Rogers {
29488b4275fSIan Rogers 	switch (ui->e_machine) {
29588b4275fSIan Rogers 	case EM_ARM:
29688b4275fSIan Rogers 		return __libunwind_arch__unwind_step_arm(ui);
29788b4275fSIan Rogers 	case EM_AARCH64:
29888b4275fSIan Rogers 		return __libunwind_arch__unwind_step_arm64(ui);
29988b4275fSIan Rogers 	case EM_LOONGARCH:
30088b4275fSIan Rogers 		return __libunwind_arch__unwind_step_loongarch(ui);
30188b4275fSIan Rogers 	case EM_MIPS:
30288b4275fSIan Rogers 		return __libunwind_arch__unwind_step_mips(ui);
30388b4275fSIan Rogers 	case EM_PPC:
30488b4275fSIan Rogers 		return __libunwind_arch__unwind_step_ppc32(ui);
30588b4275fSIan Rogers 	case EM_PPC64:
30688b4275fSIan Rogers 		return __libunwind_arch__unwind_step_ppc64(ui);
307*834c5571SIan Rogers 	case EM_RISCV:
308*834c5571SIan Rogers 		return __libunwind_arch__unwind_step_riscv(ui);
30988b4275fSIan Rogers 	case EM_S390:
31088b4275fSIan Rogers 		return __libunwind_arch__unwind_step_s390(ui);
31188b4275fSIan Rogers 	case EM_386:
31288b4275fSIan Rogers 		return __libunwind_arch__unwind_step_i386(ui);
31388b4275fSIan Rogers 	case EM_X86_64:
31488b4275fSIan Rogers 		return __libunwind_arch__unwind_step_x86_64(ui);
31588b4275fSIan Rogers 	default:
31688b4275fSIan Rogers 		pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine);
31788b4275fSIan Rogers 		return -EINVAL;
31888b4275fSIan Rogers 	}
31988b4275fSIan Rogers }
320