| // SPDX-License-Identifier: GPL-2.0 | |
| #include "libunwind-arch.h" | |
| #include "../debug.h" | |
| #include "../maps.h" | |
| #include <elf.h> | |
| #include <errno.h> | |
| 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; | |
| } | |
| } |