mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Add a RISC-V implementation for unwinding. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexandre Ghiti <alex@ghiti.fr> Cc: Andrew Jones <andrew.jones@oss.qualcomm.com> Cc: Athira Rajeev <atrajeev@linux.ibm.com> Cc: Dapeng Mi <dapeng1.mi@linux.intel.com> Cc: Dmitrii Dolgov <9erthalion6@gmail.com> Cc: Florian Fainelli <florian.fainelli@broadcom.com> Cc: Howard Chu <howardchu95@gmail.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.g.garry@oracle.com> Cc: Leo Yan <leo.yan@linux.dev> Cc: Li Guan <guanli.oerv@isrc.iscas.ac.cn> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Palmer Dabbelt <palmer@dabbelt.com> Cc: Paul Walmsley <pjw@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Shimin Guo <shimin.guo@skydio.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Tomas Glozar <tglozar@redhat.com> Cc: Will Deacon <will@kernel.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
320 lines
9.6 KiB
C
320 lines
9.6 KiB
C
// 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;
|
|
}
|
|
}
|