// SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" #include #include int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum) { switch (e_machine) { case EM_ARM: return __get_perf_regnum_for_unw_regnum_arm(unw_regnum); case EM_AARCH64: return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum); case EM_LOONGARCH: return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum); case EM_MIPS: return __get_perf_regnum_for_unw_regnum_mips(unw_regnum); case EM_PPC: return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); case EM_PPC64: return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); case EM_RISCV: return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum); case EM_S390: return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); case EM_386: return __get_perf_regnum_for_unw_regnum_i386(unw_regnum); case EM_X86_64: return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum); default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); return -EINVAL; } } void libunwind_arch__flush_access(struct maps *maps) { unsigned int e_machine = maps__e_machine(maps); switch (e_machine) { case EM_NONE: break; // No libunwind info on the maps. case EM_ARM: __libunwind_arch__flush_access_arm(maps); break; case EM_AARCH64: __libunwind_arch__flush_access_arm64(maps); break; case EM_LOONGARCH: __libunwind_arch__flush_access_loongarch(maps); break; case EM_MIPS: __libunwind_arch__flush_access_mips(maps); break; case EM_PPC: __libunwind_arch__flush_access_ppc32(maps); break; case EM_PPC64: __libunwind_arch__flush_access_ppc64(maps); break; case EM_RISCV: __libunwind_arch__flush_access_riscv(maps); break; case EM_S390: __libunwind_arch__flush_access_s390(maps); break; case EM_386: __libunwind_arch__flush_access_i386(maps); break; case EM_X86_64: __libunwind_arch__flush_access_x86_64(maps); break; default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); break; } } void libunwind_arch__finish_access(struct maps *maps) { unsigned int e_machine = maps__e_machine(maps); switch (e_machine) { case EM_NONE: break; // No libunwind info on the maps. case EM_ARM: __libunwind_arch__finish_access_arm(maps); break; case EM_AARCH64: __libunwind_arch__finish_access_arm64(maps); break; case EM_LOONGARCH: __libunwind_arch__finish_access_loongarch(maps); break; case EM_MIPS: __libunwind_arch__finish_access_mips(maps); break; case EM_PPC: __libunwind_arch__finish_access_ppc32(maps); break; case EM_PPC64: __libunwind_arch__finish_access_ppc64(maps); break; case EM_RISCV: __libunwind_arch__finish_access_riscv(maps); break; case EM_S390: __libunwind_arch__finish_access_s390(maps); break; case EM_386: __libunwind_arch__finish_access_i386(maps); break; case EM_X86_64: __libunwind_arch__finish_access_x86_64(maps); break; default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); break; } } void *libunwind_arch__create_addr_space(unsigned int e_machine) { switch (e_machine) { case EM_ARM: return __libunwind_arch__create_addr_space_arm(); case EM_AARCH64: return __libunwind_arch__create_addr_space_arm64(); case EM_LOONGARCH: return __libunwind_arch__create_addr_space_loongarch(); case EM_MIPS: return __libunwind_arch__create_addr_space_mips(); case EM_PPC: return __libunwind_arch__create_addr_space_ppc32(); case EM_PPC64: return __libunwind_arch__create_addr_space_ppc64(); case EM_RISCV: return __libunwind_arch__create_addr_space_riscv(); case EM_S390: return __libunwind_arch__create_addr_space_s390(); case EM_386: return __libunwind_arch__create_addr_space_i386(); case EM_X86_64: return __libunwind_arch__create_addr_space_x86_64(); default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); return NULL; } } int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, void *as, uint64_t ip, struct libarch_unwind__dyn_info *di, void *pi, int need_unwind_info, void *arg) { switch (e_machine) { case EM_ARM: return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi, need_unwind_info, arg); case EM_AARCH64: return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi, need_unwind_info, arg); case EM_LOONGARCH: return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di, pi, need_unwind_info, arg); case EM_MIPS: return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi, need_unwind_info, arg); case EM_PPC: return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi, need_unwind_info, arg); case EM_PPC64: return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, need_unwind_info, arg); case EM_RISCV: return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi, need_unwind_info, arg); case EM_S390: return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, need_unwind_info, arg); case EM_386: return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi, need_unwind_info, arg); case EM_X86_64: return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi, need_unwind_info, arg); default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); return -EINVAL; } } int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, int found, struct libarch_unwind__dyn_info *di_debug, uint64_t ip, uint64_t segbase, const char *obj_name, uint64_t start, uint64_t end) { switch (e_machine) { case EM_ARM: return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip, segbase, obj_name, start, end); case EM_AARCH64: return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, ip, segbase, obj_name, start, end); case EM_LOONGARCH: return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debug, ip, segbase, obj_name, start, end); case EM_MIPS: return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip, segbase, obj_name, start, end); case EM_PPC: return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, ip, segbase, obj_name, start, end); case EM_PPC64: return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, ip, segbase, obj_name, start, end); case EM_RISCV: return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, ip, segbase, obj_name, start, end); case EM_S390: return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip, segbase, obj_name, start, end); case EM_386: return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip, segbase, obj_name, start, end); case EM_X86_64: return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, ip, segbase, obj_name, start, end); default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); return -EINVAL; } } struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, struct perf_sample *sample, int max_stack, bool best_effort, uint16_t e_machine, uint64_t first_ip) { switch (e_machine) { case EM_ARM: return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack, best_effort, first_ip); case EM_AARCH64: return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack, best_effort, first_ip); case EM_LOONGARCH: return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_stack, best_effort, first_ip); case EM_MIPS: return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack, best_effort, first_ip); case EM_PPC: return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack, best_effort, first_ip); case EM_PPC64: return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, best_effort, first_ip); case EM_RISCV: return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack, best_effort, first_ip); case EM_S390: return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, best_effort, first_ip); case EM_386: return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack, best_effort, first_ip); case EM_X86_64: return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stack, best_effort, first_ip); default: pr_err("ELF MACHINE %x is not supported.\n", e_machine); return NULL; } } void libunwind_arch_unwind_info__delete(struct unwind_info *ui) { free(ui); } int libunwind_arch__unwind_step(struct unwind_info *ui) { switch (ui->e_machine) { case EM_ARM: return __libunwind_arch__unwind_step_arm(ui); case EM_AARCH64: return __libunwind_arch__unwind_step_arm64(ui); case EM_LOONGARCH: return __libunwind_arch__unwind_step_loongarch(ui); case EM_MIPS: return __libunwind_arch__unwind_step_mips(ui); case EM_PPC: return __libunwind_arch__unwind_step_ppc32(ui); case EM_PPC64: return __libunwind_arch__unwind_step_ppc64(ui); case EM_RISCV: return __libunwind_arch__unwind_step_riscv(ui); case EM_S390: return __libunwind_arch__unwind_step_s390(ui); case EM_386: return __libunwind_arch__unwind_step_i386(ui); case EM_X86_64: return __libunwind_arch__unwind_step_x86_64(ui); default: pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine); return -EINVAL; } }