mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-31 14:23:49 +01:00
perf unwind-libdw: Fix a cross-arch unwinding bug
The set_initial_registers field of Dwfl_Thread_Callbacks needs to be set according to the arch of the stack samples being analyzed, not the arch that perf itself is built for. Currently perf fails to unwind stack samples collected from archs different from that of the host perf is running on. This patch moves the arch-specific implementations of set_initial_registers from tools/perf/arch to tools/perf/utli/unwind-libdw-arch, similar to the way the perf-regs-arch folder contains arch-specific functions related to registers, and chooses the implementation based on the arch of the data being processed. Reviewed-by: Ian Rogers <[email protected]> Signed-off-by: Shimin Guo <[email protected]> Acked-by: Namhyung Kim <[email protected]> Cc: Aditya Bodkhe <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Albert Ou <[email protected]> Cc: Alexandre Ghiti <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Athira Rajeev <[email protected]> Cc: Chun-Tse Shao <[email protected]> Cc: Dmitriy Vyukov <[email protected]> Cc: Dr. David Alan Gilbert <[email protected]> Cc: Guo Ren <[email protected]> Cc: Haibo Xu <[email protected]> Cc: Howard Chu <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: John Garry <[email protected]> Cc: Krzysztof Łopatowski <[email protected]> Cc: Leo Yan <[email protected]> Cc: Mark Wielaard <[email protected]> Cc: Palmer Dabbelt <[email protected]> Cc: Paul Walmsley <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Sergei Trofimovich <[email protected]> Cc: Stephen Brennan <[email protected]> Cc: Thomas Falcon <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Ian Rogers <[email protected]> Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
This commit is contained in:
1 parent
86f3801208
commit
e62fae9d9e
19 files changed
+104
-57
No files matched your search
@@ -1,6 +1,5 @@
|
||||
perf-util-y += perf_regs.o
|
||||
|
||||
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
perf-util-y += pmu.o auxtrace.o cs-etm.o
|
||||
@@ -1,4 +1,3 @@
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
|
||||
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-util-y += ../../arm/util/auxtrace.o
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
perf-util-y += perf_regs.o
|
||||
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
@@ -9,5 +9,4 @@ perf-util-y += evsel.o
|
||||
perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
|
||||
|
||||
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-util-y += auxtrace.o
|
||||
@@ -2,4 +2,3 @@ perf-util-y += perf_regs.o
|
||||
perf-util-y += header.o
|
||||
|
||||
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
@@ -2,8 +2,6 @@ perf-util-y += header.o
|
||||
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
|
||||
perf-util-y += perf_regs.o
|
||||
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
perf-util-y += machine.o
|
||||
perf-util-y += pmu.o
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ perf-util-y += evsel.o
|
||||
perf-util-y += iostat.o
|
||||
|
||||
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
|
||||
perf-util-y += auxtrace.o
|
||||
perf-util-y += archinsn.o
|
||||
|
||||
@@ -227,6 +227,7 @@ perf-util-$(CONFIG_LIBDW) += annotate-data.o
|
||||
perf-util-$(CONFIG_LIBDW) += libdw.o
|
||||
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
|
||||
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw-arch/
|
||||
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
|
||||
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
|
||||
perf-util-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
perf-util-y += unwind-libdw-x86.o
|
||||
perf-util-y += unwind-libdw-arm.o
|
||||
perf-util-y += unwind-libdw-arm64.o
|
||||
perf-util-y += unwind-libdw-csky.o
|
||||
perf-util-y += unwind-libdw-loongarch.o
|
||||
perf-util-y += unwind-libdw-powerpc.o
|
||||
perf-util-y += unwind-libdw-riscv.o
|
||||
perf-util-y += unwind-libdw-s390.o
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../../util/unwind-libdw.h"
|
||||
#include "../../../util/perf_regs.h"
|
||||
#include "../../../util/sample.h"
|
||||
#include "../arch/arm/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../../util/unwind-libdw.h"
|
||||
#include "../../../util/perf_regs.h"
|
||||
#include "../../../util/sample.h"
|
||||
#include "../arch/arm64/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+5
-5
@@ -2,12 +2,12 @@
|
||||
// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
#include "../../util/event.h"
|
||||
#include "../arch/csky/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+5
-5
@@ -2,12 +2,12 @@
|
||||
/* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
#include "../../util/sample.h"
|
||||
#include "../arch/loongarch/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../../util/unwind-libdw.h"
|
||||
#include "../../../util/perf_regs.h"
|
||||
#include "../../../util/sample.h"
|
||||
#include "../arch/powerpc/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */
|
||||
static const int special_regs[3][2] = {
|
||||
@@ -13,7 +13,7 @@ static const int special_regs[3][2] = {
|
||||
{ 109, PERF_REG_POWERPC_CTR },
|
||||
};
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+5
-5
@@ -2,12 +2,12 @@
|
||||
/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
#include "../../util/sample.h"
|
||||
#include "../arch/riscv/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+7
-7
@@ -1,14 +1,14 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
#include "../../util/event.h"
|
||||
#include "../../util/sample.h"
|
||||
#include "dwarf-regs-table.h"
|
||||
#include "perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/event.h"
|
||||
#include "util/sample.h"
|
||||
#include "../arch/s390/include/dwarf-regs-table.h"
|
||||
#include "../arch/s390/include/uapi/asm/perf_regs.h"
|
||||
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../../util/unwind-libdw.h"
|
||||
#include "../../../util/perf_regs.h"
|
||||
#include "../arch/x86/include/uapi/asm/perf_regs.h"
|
||||
#include "util/unwind-libdw.h"
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/sample.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
|
||||
@@ -225,11 +225,45 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Dwfl_Thread_Callbacks callbacks = {
|
||||
.next_thread = next_thread,
|
||||
.memory_read = memory_read,
|
||||
.set_initial_registers = libdw__arch_set_initial_registers,
|
||||
};
|
||||
#define DEFINE_DWFL_THREAD_CALLBACKS(arch) \
|
||||
static const Dwfl_Thread_Callbacks callbacks_##arch = { \
|
||||
.next_thread = next_thread, \
|
||||
.memory_read = memory_read, \
|
||||
.set_initial_registers = libdw_set_initial_registers_##arch, \
|
||||
}
|
||||
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(x86);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(arm);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(arm64);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(csky);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(loongarch);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(powerpc);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(riscv);
|
||||
DEFINE_DWFL_THREAD_CALLBACKS(s390);
|
||||
|
||||
static const Dwfl_Thread_Callbacks *get_thread_callbacks(const char *arch)
|
||||
{
|
||||
if (!strcmp(arch, "arm"))
|
||||
return &callbacks_arm;
|
||||
else if (!strcmp(arch, "arm64"))
|
||||
return &callbacks_arm64;
|
||||
else if (!strcmp(arch, "csky"))
|
||||
return &callbacks_csky;
|
||||
else if (!strcmp(arch, "loongarch"))
|
||||
return &callbacks_loongarch;
|
||||
else if (!strcmp(arch, "powerpc"))
|
||||
return &callbacks_powerpc;
|
||||
else if (!strcmp(arch, "riscv"))
|
||||
return &callbacks_riscv;
|
||||
else if (!strcmp(arch, "s390"))
|
||||
return &callbacks_s390;
|
||||
else if (!strcmp(arch, "x86"))
|
||||
return &callbacks_x86;
|
||||
|
||||
pr_err("Fail to get thread callbacks for arch %s, returns NULL\n",
|
||||
arch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
frame_callback(Dwfl_Frame *state, void *arg)
|
||||
@@ -278,6 +312,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
||||
const char *arch = perf_env__arch(ui_buf.machine->env);
|
||||
Dwarf_Word ip;
|
||||
int err = -EINVAL, i;
|
||||
const Dwfl_Thread_Callbacks *callbacks;
|
||||
|
||||
if (!data->user_regs || !data->user_regs->regs)
|
||||
return -EINVAL;
|
||||
@@ -300,7 +335,11 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
|
||||
callbacks = get_thread_callbacks(arch);
|
||||
if (!callbacks)
|
||||
goto out;
|
||||
|
||||
err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), callbacks, ui);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -9,7 +9,15 @@ struct machine;
|
||||
struct perf_sample;
|
||||
struct thread;
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_x86(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_arm(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_arm64(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_csky(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_loongarch(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_mips(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_powerpc(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_riscv(Dwfl_Thread *thread, void *arg);
|
||||
bool libdw_set_initial_registers_s390(Dwfl_Thread *thread, void *arg);
|
||||
|
||||
struct unwind_info {
|
||||
Dwfl *dwfl;
|
||||
|
||||
Reference in new issue
Block a user