* [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization
@ 2026-02-03 2:43 Dapeng Mi
2026-02-03 2:43 ` [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options Dapeng Mi
` (5 more replies)
0 siblings, 6 replies; 11+ messages in thread
From: Dapeng Mi @ 2026-02-03 2:43 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
John Garry, Will Deacon, James Clark, Mike Leach, Guo Ren,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-perf-users, linux-arm-kernel, linux-csky, linux-riscv,
linux-kernel, Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao,
Dapeng Mi
Changes:
v2 -> v3:
* Fix the abort issue for "-I" or "--user-regs" options. (Patch 1/4)
* Address Ian's comments.
v1 -> v2:
* Fixing "PERF_REG_EXTENDED_MASK" redefinition building error by
changing the "asm/perf_regs.h" header path to relative UAPI path.
(Patch 1/3)
* Spliting xxx_reg_mask() and xxx_sdt_arg_parse_op() conversion into 2
patches.
This patch-set remove the below three architecture specific __weak
functions and converted them into the general architecture specific
functions which are dispatched base on "em_machine".
uint64_t arch__intr_reg_mask(void);
uint64_t arch__user_reg_mask(void);
int arch_sdt_arg_parse_op(char *old_op, char **new_op);
The advantage of this conversion is that these architectural functions
can be called even for a different architecture with host instead of
only called on the host architecture.
Although the converted functions shown below can be called on any
architecture, currently they are still only called for the host
architecture (EM_HOST).
int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op);
uint64_t perf_intr_reg_mask(uint16_t e_machine);
uint64_t perf_user_reg_mask(uint16_t e_machine);
Tests:
* This patch-set is only tested on x86 platforms. No issues are found
for both intr-regs and user-regs options.
* Tests on other architectures are welcomed and appreciated.
History:
v1: https://lore.kernel.org/all/20260123090938.2222960-1-dapeng1.mi@linux.intel.com/
v2: https://lore.kernel.org/all/20260127070259.2720468-1-dapeng1.mi@linux.intel.com/
Dapeng Mi (4):
perf regs: Fix abort for "-I" or "--user-regs" options
perf arch: Update arch headers to use relative UAPI paths
perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
tools/perf/arch/arm/include/perf_regs.h | 2 +-
tools/perf/arch/arm/util/Build | 2 -
tools/perf/arch/arm/util/perf_regs.c | 13 -
tools/perf/arch/arm64/include/perf_regs.h | 2 +-
tools/perf/arch/arm64/util/Build | 1 -
tools/perf/arch/arm64/util/perf_regs.c | 141 ---------
tools/perf/arch/csky/Build | 1 -
tools/perf/arch/csky/include/perf_regs.h | 2 +-
tools/perf/arch/csky/util/Build | 1 -
tools/perf/arch/csky/util/perf_regs.c | 13 -
tools/perf/arch/loongarch/include/perf_regs.h | 2 +-
tools/perf/arch/loongarch/util/Build | 1 -
tools/perf/arch/loongarch/util/perf_regs.c | 13 -
tools/perf/arch/mips/include/perf_regs.h | 2 +-
tools/perf/arch/mips/util/Build | 1 -
tools/perf/arch/mips/util/perf_regs.c | 13 -
tools/perf/arch/powerpc/include/perf_regs.h | 2 +-
tools/perf/arch/powerpc/util/Build | 1 -
tools/perf/arch/powerpc/util/perf_regs.c | 172 -----------
tools/perf/arch/riscv/include/perf_regs.h | 9 +-
tools/perf/arch/riscv/util/Build | 1 -
tools/perf/arch/riscv/util/perf_regs.c | 13 -
tools/perf/arch/s390/include/perf_regs.h | 2 +-
tools/perf/arch/s390/util/Build | 1 -
tools/perf/arch/s390/util/perf_regs.c | 13 -
tools/perf/arch/x86/include/perf_regs.h | 2 +-
tools/perf/arch/x86/util/Build | 1 -
tools/perf/arch/x86/util/perf_regs.c | 283 ------------------
tools/perf/util/evsel.c | 4 +-
tools/perf/util/parse-regs-options.c | 13 +-
.../util/perf-regs-arch/perf_regs_aarch64.c | 139 ++++++++-
.../perf/util/perf-regs-arch/perf_regs_arm.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_csky.c | 7 +-
.../util/perf-regs-arch/perf_regs_loongarch.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_mips.c | 7 +-
.../util/perf-regs-arch/perf_regs_powerpc.c | 183 ++++++++++-
.../util/perf-regs-arch/perf_regs_riscv.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_s390.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_x86.c | 281 ++++++++++++++++-
tools/perf/util/perf_regs.c | 109 ++++++-
tools/perf/util/perf_regs.h | 27 +-
tools/perf/util/probe-file.c | 3 +-
42 files changed, 787 insertions(+), 724 deletions(-)
delete mode 100644 tools/perf/arch/arm/util/perf_regs.c
delete mode 100644 tools/perf/arch/arm64/util/perf_regs.c
delete mode 100644 tools/perf/arch/csky/Build
delete mode 100644 tools/perf/arch/csky/util/Build
delete mode 100644 tools/perf/arch/csky/util/perf_regs.c
delete mode 100644 tools/perf/arch/loongarch/util/perf_regs.c
delete mode 100644 tools/perf/arch/mips/util/perf_regs.c
delete mode 100644 tools/perf/arch/powerpc/util/perf_regs.c
delete mode 100644 tools/perf/arch/riscv/util/perf_regs.c
delete mode 100644 tools/perf/arch/s390/util/perf_regs.c
delete mode 100644 tools/perf/arch/x86/util/perf_regs.c
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
@ 2026-02-03 2:43 ` Dapeng Mi
2026-02-03 23:06 ` Ian Rogers
2026-02-03 2:43 ` [Patch v3 2/4] perf arch: Update arch headers to use relative UAPI paths Dapeng Mi
` (4 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Dapeng Mi @ 2026-02-03 2:43 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
John Garry, Will Deacon, James Clark, Mike Leach, Guo Ren,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-perf-users, linux-arm-kernel, linux-csky, linux-riscv,
linux-kernel, Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao,
Dapeng Mi
Fix an issue where the `perf` tool aborts unexpectedly when running the
following command:
```
perf record -e cycles -I -- true
Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-I, --intr-regs[=<any register>]
sample selected machine registers on interrupt, use '-I?' to list register names
```
The usage of the `-I` or `--user-regs` options without specifying any
registers should default to sampling all general-purpose registers.
However, this currently causes an abnormal termination.
The issue was introduced by commit 3d06db9bad1a ("perf regs: Refactor
use of arch__sample_reg_masks() to perf_reg_name()"). This patch
resolves the problem, ensuring that the `-I` or `--user-regs` options
work as intended without causing an abort.
Fixes: 3d06db9bad1a ("perf regs: Refactor use of arch__sample_reg_masks() to perf_reg_name()")
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
tools/perf/util/parse-regs-options.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index 8dd35f50f644..b44b47d9059f 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -66,12 +66,14 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
if (*mode)
return -1;
- /* str may be NULL in case no arg is passed to -I */
- if (!str)
- return -1;
-
mask = intr ? arch__intr_reg_mask() : arch__user_reg_mask();
+ /* str may be NULL in case no arg is passed to -I */
+ if (!str) {
+ *mode = mask;
+ return 0;
+ }
+
/* because str is read-only */
s = os = strdup(str);
if (!s)
@@ -104,9 +106,6 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
}
ret = 0;
- /* default to all possible regs */
- if (*mode == 0)
- *mode = mask;
error:
free(os);
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Patch v3 2/4] perf arch: Update arch headers to use relative UAPI paths
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
2026-02-03 2:43 ` [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options Dapeng Mi
@ 2026-02-03 2:43 ` Dapeng Mi
2026-02-03 2:43 ` [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions Dapeng Mi
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Dapeng Mi @ 2026-02-03 2:43 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
John Garry, Will Deacon, James Clark, Mike Leach, Guo Ren,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-perf-users, linux-arm-kernel, linux-csky, linux-riscv,
linux-kernel, Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao,
Dapeng Mi
The architectural specific headers perf_regs.h currently rely on the
host architecture's 'asm/perf_regs.h'. This can lead to compilation
inconsistencies or failures when including and building perf for a
target architecture that differs from the host's architecture.
Explicitly point to the UAPI headers within the tools source tree using
relative paths. This ensures that perf is always built against the
intended architecture.
No functional changes are intended.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
tools/perf/arch/arm/include/perf_regs.h | 2 +-
tools/perf/arch/arm64/include/perf_regs.h | 2 +-
tools/perf/arch/csky/include/perf_regs.h | 2 +-
tools/perf/arch/loongarch/include/perf_regs.h | 2 +-
tools/perf/arch/mips/include/perf_regs.h | 2 +-
tools/perf/arch/powerpc/include/perf_regs.h | 2 +-
tools/perf/arch/riscv/include/perf_regs.h | 2 +-
tools/perf/arch/s390/include/perf_regs.h | 2 +-
tools/perf/arch/x86/include/perf_regs.h | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/tools/perf/arch/arm/include/perf_regs.h b/tools/perf/arch/arm/include/perf_regs.h
index 75ce1c370114..20c54766e3a0 100644
--- a/tools/perf/arch/arm/include/perf_regs.h
+++ b/tools/perf/arch/arm/include/perf_regs.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/arm/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
index 58639ee9f7ea..372f2565a9dd 100644
--- a/tools/perf/arch/arm64/include/perf_regs.h
+++ b/tools/perf/arch/arm64/include/perf_regs.h
@@ -5,7 +5,7 @@
#include <stdlib.h>
#include <linux/types.h>
#define perf_event_arm_regs perf_event_arm64_regs
-#include <asm/perf_regs.h>
+#include "../../../../arch/arm64/include/uapi/asm/perf_regs.h"
#undef perf_event_arm_regs
void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/csky/include/perf_regs.h b/tools/perf/arch/csky/include/perf_regs.h
index 076c7746c8a2..0bf7b963909c 100644
--- a/tools/perf/arch/csky/include/perf_regs.h
+++ b/tools/perf/arch/csky/include/perf_regs.h
@@ -6,7 +6,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/csky/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MASK ((1ULL << PERF_REG_CSKY_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_CSKY_MAX
diff --git a/tools/perf/arch/loongarch/include/perf_regs.h b/tools/perf/arch/loongarch/include/perf_regs.h
index 45c799fa5330..b86078a55e90 100644
--- a/tools/perf/arch/loongarch/include/perf_regs.h
+++ b/tools/perf/arch/loongarch/include/perf_regs.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/loongarch/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MAX PERF_REG_LOONGARCH_MAX
diff --git a/tools/perf/arch/mips/include/perf_regs.h b/tools/perf/arch/mips/include/perf_regs.h
index 7082e91e0ed1..66655f0c4fea 100644
--- a/tools/perf/arch/mips/include/perf_regs.h
+++ b/tools/perf/arch/mips/include/perf_regs.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/mips/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MAX PERF_REG_MIPS_MAX
diff --git a/tools/perf/arch/powerpc/include/perf_regs.h b/tools/perf/arch/powerpc/include/perf_regs.h
index 1c66f6ba6773..22b492a3dd58 100644
--- a/tools/perf/arch/powerpc/include/perf_regs.h
+++ b/tools/perf/arch/powerpc/include/perf_regs.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/powerpc/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
index d482edb413e5..89d5bbb8d2b8 100644
--- a/tools/perf/arch/riscv/include/perf_regs.h
+++ b/tools/perf/arch/riscv/include/perf_regs.h
@@ -6,7 +6,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/riscv/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_RISCV_MAX
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h
index 130dfad2b96a..9c95589965fe 100644
--- a/tools/perf/arch/s390/include/perf_regs.h
+++ b/tools/perf/arch/s390/include/perf_regs.h
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/s390/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index f209ce2c1dd9..5495e5ca7cdc 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
-#include <asm/perf_regs.h>
+#include "../../../../arch/x86/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
2026-02-03 2:43 ` [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options Dapeng Mi
2026-02-03 2:43 ` [Patch v3 2/4] perf arch: Update arch headers to use relative UAPI paths Dapeng Mi
@ 2026-02-03 2:43 ` Dapeng Mi
2026-02-03 23:08 ` Ian Rogers
2026-02-03 2:43 ` [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function Dapeng Mi
` (2 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Dapeng Mi @ 2026-02-03 2:43 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
John Garry, Will Deacon, James Clark, Mike Leach, Guo Ren,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-perf-users, linux-arm-kernel, linux-csky, linux-riscv,
linux-kernel, Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao,
Dapeng Mi
Currently, some architecture-specific perf-regs functions, such as
arch__intr_reg_mask() and arch__user_reg_mask(), are defined with the
__weak attribute. This approach ensures that only functions matching
the architecture of the build/run host are compiled and executed,
reducing build time and binary size.
However, this __weak attribute restricts these functions to be called
only on the same architecture, preventing cross-architecture
functionality. For example, a perf.data file captured on x86 cannot be
parsed on an ARM platform.
To address this limitation, this patch removes the __weak attribute from
these perf-regs functions. The architecture-specific code is moved from
the arch/ directory to the util/perf-regs-arch/ directory. The
appropriate architectural functions are then called based on the EM_HOST.
No functional changes are intended.
Suggested-by: Ian Rogers <irogers@google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
tools/perf/arch/arm/util/Build | 2 -
tools/perf/arch/arm/util/perf_regs.c | 13 ---
tools/perf/arch/arm64/util/perf_regs.c | 36 --------
tools/perf/arch/csky/Build | 1 -
tools/perf/arch/csky/util/Build | 1 -
tools/perf/arch/csky/util/perf_regs.c | 13 ---
tools/perf/arch/loongarch/util/Build | 1 -
tools/perf/arch/loongarch/util/perf_regs.c | 13 ---
tools/perf/arch/mips/util/Build | 1 -
tools/perf/arch/mips/util/perf_regs.c | 13 ---
tools/perf/arch/powerpc/util/perf_regs.c | 47 -----------
tools/perf/arch/riscv/include/perf_regs.h | 7 +-
tools/perf/arch/riscv/util/Build | 1 -
tools/perf/arch/riscv/util/perf_regs.c | 13 ---
tools/perf/arch/s390/util/Build | 1 -
tools/perf/arch/s390/util/perf_regs.c | 13 ---
tools/perf/arch/x86/util/perf_regs.c | 48 -----------
tools/perf/util/evsel.c | 4 +-
tools/perf/util/parse-regs-options.c | 2 +-
.../util/perf-regs-arch/perf_regs_aarch64.c | 53 +++++++++++-
.../perf/util/perf-regs-arch/perf_regs_arm.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_csky.c | 7 +-
.../util/perf-regs-arch/perf_regs_loongarch.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_mips.c | 7 +-
.../util/perf-regs-arch/perf_regs_powerpc.c | 77 ++++++++++++++++-
.../util/perf-regs-arch/perf_regs_riscv.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_s390.c | 7 +-
.../perf/util/perf-regs-arch/perf_regs_x86.c | 60 ++++++++++++-
tools/perf/util/perf_regs.c | 84 ++++++++++++++++++-
tools/perf/util/perf_regs.h | 22 ++++-
30 files changed, 332 insertions(+), 236 deletions(-)
delete mode 100644 tools/perf/arch/arm/util/perf_regs.c
delete mode 100644 tools/perf/arch/csky/Build
delete mode 100644 tools/perf/arch/csky/util/Build
delete mode 100644 tools/perf/arch/csky/util/perf_regs.c
delete mode 100644 tools/perf/arch/loongarch/util/perf_regs.c
delete mode 100644 tools/perf/arch/mips/util/perf_regs.c
delete mode 100644 tools/perf/arch/riscv/util/perf_regs.c
delete mode 100644 tools/perf/arch/s390/util/perf_regs.c
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index 3291f893b943..b94bf3c5279a 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -1,5 +1,3 @@
-perf-util-y += perf_regs.o
-
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-y += pmu.o auxtrace.o cs-etm.o
diff --git a/tools/perf/arch/arm/util/perf_regs.c b/tools/perf/arch/arm/util/perf_regs.c
deleted file mode 100644
index 03a5bc0cf64c..000000000000
--- a/tools/perf/arch/arm/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/arm64/util/perf_regs.c b/tools/perf/arch/arm64/util/perf_regs.c
index 9bb768e1bea1..47f58eaba032 100644
--- a/tools/perf/arch/arm64/util/perf_regs.c
+++ b/tools/perf/arch/arm64/util/perf_regs.c
@@ -103,39 +103,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
return SDT_ARG_VALID;
}
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- struct perf_event_attr attr = {
- .type = PERF_TYPE_HARDWARE,
- .config = PERF_COUNT_HW_CPU_CYCLES,
- .sample_type = PERF_SAMPLE_REGS_USER,
- .disabled = 1,
- .exclude_kernel = 1,
- .sample_period = 1,
- .sample_regs_user = PERF_REGS_MASK
- };
- int fd;
-
- if (getauxval(AT_HWCAP) & HWCAP_SVE)
- attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
-
- /*
- * Check if the pmu supports perf extended regs, before
- * returning the register mask to sample.
- */
- if (attr.sample_regs_user != PERF_REGS_MASK) {
- event_attr_init(&attr);
- fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
- if (fd != -1) {
- close(fd);
- return attr.sample_regs_user;
- }
- }
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/csky/Build b/tools/perf/arch/csky/Build
deleted file mode 100644
index e63eabc2c8f4..000000000000
--- a/tools/perf/arch/csky/Build
+++ /dev/null
@@ -1 +0,0 @@
-perf-util-y += util/
diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
deleted file mode 100644
index 6b2d0e021b11..000000000000
--- a/tools/perf/arch/csky/util/Build
+++ /dev/null
@@ -1 +0,0 @@
-perf-util-y += perf_regs.o
diff --git a/tools/perf/arch/csky/util/perf_regs.c b/tools/perf/arch/csky/util/perf_regs.c
deleted file mode 100644
index 2cf7a54106e0..000000000000
--- a/tools/perf/arch/csky/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
index 0aa31986ecb5..0c958c8e0718 100644
--- a/tools/perf/arch/loongarch/util/Build
+++ b/tools/perf/arch/loongarch/util/Build
@@ -1,5 +1,4 @@
perf-util-y += header.o
-perf-util-y += perf_regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/loongarch/util/perf_regs.c b/tools/perf/arch/loongarch/util/perf_regs.c
deleted file mode 100644
index 03a5bc0cf64c..000000000000
--- a/tools/perf/arch/loongarch/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Build
index 691fa2051958..818b808a8247 100644
--- a/tools/perf/arch/mips/util/Build
+++ b/tools/perf/arch/mips/util/Build
@@ -1,2 +1 @@
-perf-util-y += perf_regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
diff --git a/tools/perf/arch/mips/util/perf_regs.c b/tools/perf/arch/mips/util/perf_regs.c
deleted file mode 100644
index 2cf7a54106e0..000000000000
--- a/tools/perf/arch/mips/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
index 779073f7e992..93f929fc32e3 100644
--- a/tools/perf/arch/powerpc/util/perf_regs.c
+++ b/tools/perf/arch/powerpc/util/perf_regs.c
@@ -123,50 +123,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
return SDT_ARG_VALID;
}
-
-uint64_t arch__intr_reg_mask(void)
-{
- struct perf_event_attr attr = {
- .type = PERF_TYPE_HARDWARE,
- .config = PERF_COUNT_HW_CPU_CYCLES,
- .sample_type = PERF_SAMPLE_REGS_INTR,
- .precise_ip = 1,
- .disabled = 1,
- .exclude_kernel = 1,
- };
- int fd;
- u32 version;
- u64 extended_mask = 0, mask = PERF_REGS_MASK;
-
- /*
- * Get the PVR value to set the extended
- * mask specific to platform.
- */
- version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
- if (version == PVR_POWER9)
- extended_mask = PERF_REG_PMU_MASK_300;
- else if ((version == PVR_POWER10) || (version == PVR_POWER11))
- extended_mask = PERF_REG_PMU_MASK_31;
- else
- return mask;
-
- attr.sample_regs_intr = extended_mask;
- attr.sample_period = 1;
- event_attr_init(&attr);
-
- /*
- * check if the pmu supports perf extended regs, before
- * returning the register mask to sample.
- */
- fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
- if (fd != -1) {
- close(fd);
- mask |= extended_mask;
- }
- return mask;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
index 89d5bbb8d2b8..af7a1b47bf66 100644
--- a/tools/perf/arch/riscv/include/perf_regs.h
+++ b/tools/perf/arch/riscv/include/perf_regs.h
@@ -10,10 +10,15 @@
#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_RISCV_MAX
+
+#if defined(__riscv_xlen)
#if __riscv_xlen == 64
-#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#else
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
#endif
+#else
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_NONE
+#endif
#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
index 628b9ebd418b..da5b12e7f862 100644
--- a/tools/perf/arch/riscv/util/Build
+++ b/tools/perf/arch/riscv/util/Build
@@ -1,4 +1,3 @@
-perf-util-y += perf_regs.o
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
diff --git a/tools/perf/arch/riscv/util/perf_regs.c b/tools/perf/arch/riscv/util/perf_regs.c
deleted file mode 100644
index 2cf7a54106e0..000000000000
--- a/tools/perf/arch/riscv/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
index 5391d26fedd4..3b09c058e0ec 100644
--- a/tools/perf/arch/s390/util/Build
+++ b/tools/perf/arch/s390/util/Build
@@ -1,6 +1,5 @@
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
-perf-util-y += perf_regs.o
perf-util-y += machine.o
perf-util-y += pmu.o
diff --git a/tools/perf/arch/s390/util/perf_regs.c b/tools/perf/arch/s390/util/perf_regs.c
deleted file mode 100644
index 2cf7a54106e0..000000000000
--- a/tools/perf/arch/s390/util/perf_regs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "perf_regs.h"
-#include "../../util/perf_regs.h"
-
-uint64_t arch__intr_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index a7ca4154fdf9..41141cebe226 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -233,51 +233,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
return SDT_ARG_VALID;
}
-
-uint64_t arch__intr_reg_mask(void)
-{
- struct perf_event_attr attr = {
- .type = PERF_TYPE_HARDWARE,
- .config = PERF_COUNT_HW_CPU_CYCLES,
- .sample_type = PERF_SAMPLE_REGS_INTR,
- .sample_regs_intr = PERF_REG_EXTENDED_MASK,
- .precise_ip = 1,
- .disabled = 1,
- .exclude_kernel = 1,
- };
- int fd;
- /*
- * In an unnamed union, init it here to build on older gcc versions
- */
- attr.sample_period = 1;
-
- if (perf_pmus__num_core_pmus() > 1) {
- struct perf_pmu *pmu = NULL;
- __u64 type = PERF_TYPE_RAW;
-
- /*
- * The same register set is supported among different hybrid PMUs.
- * Only check the first available one.
- */
- while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
- type = pmu->type;
- break;
- }
- attr.config |= type << PERF_PMU_TYPE_SHIFT;
- }
-
- event_attr_init(&attr);
-
- fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
- if (fd != -1) {
- close(fd);
- return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
- }
-
- return PERF_REGS_MASK;
-}
-
-uint64_t arch__user_reg_mask(void)
-{
- return PERF_REGS_MASK;
-}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5ac1a05601b1..a36528fd41c6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1055,13 +1055,13 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o
evsel__set_sample_bit(evsel, REGS_USER);
evsel__set_sample_bit(evsel, STACK_USER);
if (opts->sample_user_regs &&
- DWARF_MINIMAL_REGS(e_machine) != arch__user_reg_mask()) {
+ DWARF_MINIMAL_REGS(e_machine) != perf_user_reg_mask(EM_HOST)) {
attr->sample_regs_user |= DWARF_MINIMAL_REGS(e_machine);
pr_warning("WARNING: The use of --call-graph=dwarf may require all the user registers, "
"specifying a subset with --user-regs may render DWARF unwinding unreliable, "
"so the minimal registers set (IP, SP) is explicitly forced.\n");
} else {
- attr->sample_regs_user |= arch__user_reg_mask();
+ attr->sample_regs_user |= perf_user_reg_mask(EM_HOST);
}
attr->sample_stack_user = param->dump_size;
attr->exclude_callchain_user = 1;
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index b44b47d9059f..c93c2f0c8105 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -66,7 +66,7 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
if (*mode)
return -1;
- mask = intr ? arch__intr_reg_mask() : arch__user_reg_mask();
+ mask = intr ? perf_intr_reg_mask(EM_HOST) : perf_user_reg_mask(EM_HOST);
/* str may be NULL in case no arg is passed to -I */
if (!str) {
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
index 9dcda80d310f..666874f625b6 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
@@ -1,7 +1,58 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <regex.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <linux/kernel.h>
+#include <linux/zalloc.h>
+#include "../debug.h"
+#include "../event.h"
#include "../perf_regs.h"
-#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
+#include "../../perf-sys.h"
+#include "../../arch/arm64/include/perf_regs.h"
+
+#define SMPL_REG_MASK(b) (1ULL << (b))
+
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+
+uint64_t __perf_reg_mask_arm64(bool intr)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .sample_type = PERF_SAMPLE_REGS_USER,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ .sample_period = 1,
+ .sample_regs_user = PERF_REGS_MASK
+ };
+ int fd;
+
+ if (intr)
+ return PERF_REGS_MASK;
+
+ if (getauxval(AT_HWCAP) & HWCAP_SVE)
+ attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
+
+ /*
+ * Check if the pmu supports perf extended regs, before
+ * returning the register mask to sample. Open the event
+ * on the perf process to check this.
+ */
+ if (attr.sample_regs_user != PERF_REGS_MASK) {
+ event_attr_init(&attr);
+ fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
+ /*group_fd=*/-1, /*flags=*/0);
+ if (fd != -1) {
+ close(fd);
+ return attr.sample_regs_user;
+ }
+ }
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_arm64(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_arm.c b/tools/perf/util/perf-regs-arch/perf_regs_arm.c
index e29d130a587a..184d6e248dfc 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_arm.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_arm.c
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "../perf_regs.h"
-#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
+#include "../../arch/arm/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_arm(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_arm(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_csky.c b/tools/perf/util/perf-regs-arch/perf_regs_csky.c
index 95808f93d45b..16cbd8303acf 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_csky.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_csky.c
@@ -9,7 +9,12 @@
#include "../perf_regs.h"
#undef __CSKYABIV2__
#define __CSKYABIV2__ 1 // Always want the V2 register definitions.
-#include "../../arch/csky/include/uapi/asm/perf_regs.h"
+#include "../../arch/csky/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_csky(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_csky(int id, uint32_t e_flags)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c b/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
index 043f97f4e3ac..478ee889afa1 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "../perf_regs.h"
-#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
+#include "../../arch/loongarch/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_loongarch(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_loongarch(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_mips.c b/tools/perf/util/perf-regs-arch/perf_regs_mips.c
index 793178fc3c78..c5a475f6ec64 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_mips.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_mips.c
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "../perf_regs.h"
-#include "../../../arch/mips/include/uapi/asm/perf_regs.h"
+#include "../../arch/mips/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_mips(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_mips(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
index 08636bb09a3a..f0a547ad809b 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
@@ -1,7 +1,82 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <string.h>
+#include <regex.h>
+#include <linux/zalloc.h>
+
+#include "../debug.h"
+#include "../event.h"
+#include "../header.h"
#include "../perf_regs.h"
-#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
+#include "../../perf-sys.h"
+#include "../../arch/powerpc/util/utils_header.h"
+#include "../../arch/powerpc/include/perf_regs.h"
+
+#include <linux/kernel.h>
+
+#define PVR_POWER9 0x004E
+#define PVR_POWER10 0x0080
+#define PVR_POWER11 0x0082
+
+/*
+ * mfspr is a POWERPC specific instruction, ensure it's only
+ * built and called on POWERPC by guarding with __powerpc64__
+ * or __powerpc__.
+ */
+#if defined(__powerpc64__) && defined(__powerpc__)
+uint64_t __perf_reg_mask_powerpc(bool intr)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .sample_type = PERF_SAMPLE_REGS_INTR,
+ .precise_ip = 1,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ };
+ int fd;
+ u32 version;
+ u64 extended_mask = 0, mask = PERF_REGS_MASK;
+
+ if (!intr)
+ return PERF_REGS_MASK;
+
+ /*
+ * Get the PVR value to set the extended
+ * mask specific to platform.
+ */
+ version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
+ if (version == PVR_POWER9)
+ extended_mask = PERF_REG_PMU_MASK_300;
+ else if ((version == PVR_POWER10) || (version == PVR_POWER11))
+ extended_mask = PERF_REG_PMU_MASK_31;
+ else
+ return mask;
+
+ attr.sample_regs_intr = extended_mask;
+ attr.sample_period = 1;
+ event_attr_init(&attr);
+
+ /*
+ * Check if the pmu supports perf extended regs, before
+ * returning the register mask to sample. Open the event
+ * on the perf process to check this.
+ */
+ fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
+ /*group_fd=*/-1, /*flags=*/0);
+ if (fd != -1) {
+ close(fd);
+ mask |= extended_mask;
+ }
+ return mask;
+}
+#else
+uint64_t __perf_reg_mask_powerpc(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
+#endif
const char *__perf_reg_name_powerpc(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_riscv.c b/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
index 337b687c655d..5b5f21fcba8c 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "../perf_regs.h"
-#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
+#include "../../arch/riscv/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_riscv(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_riscv(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_s390.c b/tools/perf/util/perf-regs-arch/perf_regs_s390.c
index d69bba881080..c61df24edf0f 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_s390.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_s390.c
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include "../perf_regs.h"
-#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
+#include "../../arch/s390/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_s390(bool intr __maybe_unused)
+{
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_s390(int id)
{
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_x86.c b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
index 708954a9d35d..d573f9a9ca46 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_x86.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
@@ -1,7 +1,65 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <string.h>
+#include <regex.h>
+#include <linux/kernel.h>
+#include <linux/zalloc.h>
+
+#include "../debug.h"
+#include "../event.h"
+#include "../pmu.h"
+#include "../pmus.h"
#include "../perf_regs.h"
-#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
+#include "../../perf-sys.h"
+#include "../../arch/x86/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_x86(bool intr)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .sample_type = PERF_SAMPLE_REGS_INTR,
+ .sample_regs_intr = PERF_REG_EXTENDED_MASK,
+ .precise_ip = 1,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ };
+ int fd;
+
+ if (!intr)
+ return PERF_REGS_MASK;
+
+ /*
+ * In an unnamed union, init it here to build on older gcc versions
+ */
+ attr.sample_period = 1;
+
+ if (perf_pmus__num_core_pmus() > 1) {
+ struct perf_pmu *pmu = NULL;
+ __u64 type = PERF_TYPE_RAW;
+
+ /*
+ * The same register set is supported among different hybrid PMUs.
+ * Only check the first available one.
+ */
+ while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+ type = pmu->type;
+ break;
+ }
+ attr.config |= type << PERF_PMU_TYPE_SHIFT;
+ }
+
+ event_attr_init(&attr);
+ fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
+ /*group_fd=*/-1, /*flags=*/0);
+ if (fd != -1) {
+ close(fd);
+ return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
+ }
+
+ return PERF_REGS_MASK;
+}
const char *__perf_reg_name_x86(int id)
{
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index 14b7be30ab20..4d9a286a0e56 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -13,14 +13,90 @@ int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
return SDT_ARG_SKIP;
}
-uint64_t __weak arch__intr_reg_mask(void)
+uint64_t perf_intr_reg_mask(uint16_t e_machine)
{
- return 0;
+ uint64_t mask = 0;
+
+ switch (e_machine) {
+ case EM_ARM:
+ mask = __perf_reg_mask_arm(/*intr=*/true);
+ break;
+ case EM_AARCH64:
+ mask = __perf_reg_mask_arm64(/*intr=*/true);
+ break;
+ case EM_CSKY:
+ mask = __perf_reg_mask_csky(/*intr=*/true);
+ break;
+ case EM_LOONGARCH:
+ mask = __perf_reg_mask_loongarch(/*intr=*/true);
+ break;
+ case EM_MIPS:
+ mask = __perf_reg_mask_mips(/*intr=*/true);
+ break;
+ case EM_PPC:
+ case EM_PPC64:
+ mask = __perf_reg_mask_powerpc(/*intr=*/true);
+ break;
+ case EM_RISCV:
+ mask = __perf_reg_mask_riscv(/*intr=*/true);
+ break;
+ case EM_S390:
+ mask = __perf_reg_mask_s390(/*intr=*/true);
+ break;
+ case EM_386:
+ case EM_X86_64:
+ mask = __perf_reg_mask_x86(/*intr=*/true);
+ break;
+ default:
+ pr_debug("Unknown ELF machine %d, interrupt sampling register mask will be empty.\n",
+ e_machine);
+ break;
+ }
+
+ return mask;
}
-uint64_t __weak arch__user_reg_mask(void)
+uint64_t perf_user_reg_mask(uint16_t e_machine)
{
- return 0;
+ uint64_t mask = 0;
+
+ switch (e_machine) {
+ case EM_ARM:
+ mask = __perf_reg_mask_arm(/*intr=*/false);
+ break;
+ case EM_AARCH64:
+ mask = __perf_reg_mask_arm64(/*intr=*/false);
+ break;
+ case EM_CSKY:
+ mask = __perf_reg_mask_csky(/*intr=*/false);
+ break;
+ case EM_LOONGARCH:
+ mask = __perf_reg_mask_loongarch(/*intr=*/false);
+ break;
+ case EM_MIPS:
+ mask = __perf_reg_mask_mips(/*intr=*/false);
+ break;
+ case EM_PPC:
+ case EM_PPC64:
+ mask = __perf_reg_mask_powerpc(/*intr=*/false);
+ break;
+ case EM_RISCV:
+ mask = __perf_reg_mask_riscv(/*intr=*/false);
+ break;
+ case EM_S390:
+ mask = __perf_reg_mask_s390(/*intr=*/false);
+ break;
+ case EM_386:
+ case EM_X86_64:
+ mask = __perf_reg_mask_x86(/*intr=*/false);
+ break;
+ default:
+ pr_debug("Unknown ELF machine %d, user sampling register mask will be empty.\n",
+ e_machine);
+ break;
+ }
+
+ return mask;
}
const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags)
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index ed7c1b1358fa..2b27139acadb 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -13,37 +13,55 @@ enum {
};
int arch_sdt_arg_parse_op(char *old_op, char **new_op);
-uint64_t arch__intr_reg_mask(void);
-uint64_t arch__user_reg_mask(void);
+uint64_t perf_intr_reg_mask(uint16_t e_machine);
+uint64_t perf_user_reg_mask(uint16_t e_machine);
const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags);
int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
uint64_t perf_arch_reg_ip(uint16_t e_machine);
uint64_t perf_arch_reg_sp(uint16_t e_machine);
+
+uint64_t __perf_reg_mask_arm64(bool intr);
const char *__perf_reg_name_arm64(int id);
uint64_t __perf_reg_ip_arm64(void);
uint64_t __perf_reg_sp_arm64(void);
+
+uint64_t __perf_reg_mask_arm(bool intr);
const char *__perf_reg_name_arm(int id);
uint64_t __perf_reg_ip_arm(void);
uint64_t __perf_reg_sp_arm(void);
+
+uint64_t __perf_reg_mask_csky(bool intr);
const char *__perf_reg_name_csky(int id, uint32_t e_flags);
uint64_t __perf_reg_ip_csky(void);
uint64_t __perf_reg_sp_csky(void);
+
+uint64_t __perf_reg_mask_loongarch(bool intr);
const char *__perf_reg_name_loongarch(int id);
uint64_t __perf_reg_ip_loongarch(void);
uint64_t __perf_reg_sp_loongarch(void);
+
+uint64_t __perf_reg_mask_mips(bool intr);
const char *__perf_reg_name_mips(int id);
uint64_t __perf_reg_ip_mips(void);
uint64_t __perf_reg_sp_mips(void);
+
+uint64_t __perf_reg_mask_powerpc(bool intr);
const char *__perf_reg_name_powerpc(int id);
uint64_t __perf_reg_ip_powerpc(void);
uint64_t __perf_reg_sp_powerpc(void);
+
+uint64_t __perf_reg_mask_riscv(bool intr);
const char *__perf_reg_name_riscv(int id);
uint64_t __perf_reg_ip_riscv(void);
uint64_t __perf_reg_sp_riscv(void);
+
+uint64_t __perf_reg_mask_s390(bool intr);
const char *__perf_reg_name_s390(int id);
uint64_t __perf_reg_ip_s390(void);
uint64_t __perf_reg_sp_s390(void);
+
+uint64_t __perf_reg_mask_x86(bool intr);
const char *__perf_reg_name_x86(int id);
uint64_t __perf_reg_ip_x86(void);
uint64_t __perf_reg_sp_x86(void);
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
` (2 preceding siblings ...)
2026-02-03 2:43 ` [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions Dapeng Mi
@ 2026-02-03 2:43 ` Dapeng Mi
2026-02-03 23:11 ` Ian Rogers
2026-02-06 15:17 ` [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Arnaldo Carvalho de Melo
2026-03-24 6:07 ` patchwork-bot+linux-riscv
5 siblings, 1 reply; 11+ messages in thread
From: Dapeng Mi @ 2026-02-03 2:43 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
John Garry, Will Deacon, James Clark, Mike Leach, Guo Ren,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: linux-perf-users, linux-arm-kernel, linux-csky, linux-riscv,
linux-kernel, Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao,
Dapeng Mi
In line with the previous patch, the __weak arch_sdt_arg_parse_op()
function is removed. Architectural-specific implementations in the arch/
directory are now converted into sub-functions within the
util/perf-regs-arch/ directory. The perf_sdt_arg_parse_op() function
will call these sub-functions based on the EM_HOST.
This change enables cross-architecture calls to arch_sdt_arg_parse_op().
No functional changes are intended.
Suggested-by: Ian Rogers <irogers@google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
tools/perf/arch/arm64/util/Build | 1 -
tools/perf/arch/arm64/util/perf_regs.c | 105 --------
tools/perf/arch/powerpc/util/Build | 1 -
tools/perf/arch/powerpc/util/perf_regs.c | 125 ----------
tools/perf/arch/x86/util/Build | 1 -
tools/perf/arch/x86/util/perf_regs.c | 235 ------------------
.../util/perf-regs-arch/perf_regs_aarch64.c | 86 +++++++
.../util/perf-regs-arch/perf_regs_powerpc.c | 106 ++++++++
.../perf/util/perf-regs-arch/perf_regs_x86.c | 221 ++++++++++++++++
tools/perf/util/perf_regs.c | 25 +-
tools/perf/util/perf_regs.h | 5 +-
tools/perf/util/probe-file.c | 3 +-
12 files changed, 441 insertions(+), 473 deletions(-)
delete mode 100644 tools/perf/arch/arm64/util/perf_regs.c
delete mode 100644 tools/perf/arch/powerpc/util/perf_regs.c
delete mode 100644 tools/perf/arch/x86/util/perf_regs.c
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
index 0177af19cc00..bc12c35d06c8 100644
--- a/tools/perf/arch/arm64/util/Build
+++ b/tools/perf/arch/arm64/util/Build
@@ -8,6 +8,5 @@ perf-util-y += header.o
perf-util-y += hisi-ptt.o
perf-util-y += machine.o
perf-util-y += mem-events.o
-perf-util-y += perf_regs.o
perf-util-y += pmu.o
perf-util-y += tsc.o
diff --git a/tools/perf/arch/arm64/util/perf_regs.c b/tools/perf/arch/arm64/util/perf_regs.c
deleted file mode 100644
index 47f58eaba032..000000000000
--- a/tools/perf/arch/arm64/util/perf_regs.c
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-#include <regex.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include <linux/kernel.h>
-#include <linux/zalloc.h>
-
-#include "perf_regs.h"
-#include "../../../perf-sys.h"
-#include "../../../util/debug.h"
-#include "../../../util/event.h"
-#include "../../../util/perf_regs.h"
-
-#define SMPL_REG_MASK(b) (1ULL << (b))
-
-#ifndef HWCAP_SVE
-#define HWCAP_SVE (1 << 22)
-#endif
-
-/* %xNUM */
-#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
-
-/* [sp], [sp, NUM] */
-#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
-
-static regex_t sdt_op_regex1, sdt_op_regex2;
-
-static int sdt_init_op_regex(void)
-{
- static int initialized;
- int ret = 0;
-
- if (initialized)
- return 0;
-
- ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
- if (ret)
- goto error;
-
- ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
- if (ret)
- goto free_regex1;
-
- initialized = 1;
- return 0;
-
-free_regex1:
- regfree(&sdt_op_regex1);
-error:
- pr_debug4("Regex compilation error.\n");
- return ret;
-}
-
-/*
- * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
- * support these two formats.
- */
-int arch_sdt_arg_parse_op(char *old_op, char **new_op)
-{
- int ret, new_len;
- regmatch_t rm[5];
-
- ret = sdt_init_op_regex();
- if (ret < 0)
- return ret;
-
- if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
- /* Extract xNUM */
- new_len = 2; /* % NULL */
- new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
-
- *new_op = zalloc(new_len);
- if (!*new_op)
- return -ENOMEM;
-
- scnprintf(*new_op, new_len, "%%%.*s",
- (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
- } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
- /* [sp], [sp, NUM] or [sp,NUM] */
- new_len = 7; /* + ( % s p ) NULL */
-
- /* If the argument is [sp], need to fill offset '0' */
- if (rm[2].rm_so == -1)
- new_len += 1;
- else
- new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
-
- *new_op = zalloc(new_len);
- if (!*new_op)
- return -ENOMEM;
-
- if (rm[2].rm_so == -1)
- scnprintf(*new_op, new_len, "+0(%%sp)");
- else
- scnprintf(*new_op, new_len, "+%.*s(%%sp)",
- (int)(rm[2].rm_eo - rm[2].rm_so),
- old_op + rm[2].rm_so);
- } else {
- pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
- return SDT_ARG_SKIP;
- }
-
- return SDT_ARG_VALID;
-}
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 5fd28ec713a4..43c3e7c450a3 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,6 +1,5 @@
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
-perf-util-y += perf_regs.o
perf-util-y += mem-events.o
perf-util-y += pmu.o
perf-util-y += sym-handling.o
diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
deleted file mode 100644
index 93f929fc32e3..000000000000
--- a/tools/perf/arch/powerpc/util/perf_regs.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-#include <string.h>
-#include <regex.h>
-#include <linux/zalloc.h>
-
-#include "perf_regs.h"
-#include "../../../util/perf_regs.h"
-#include "../../../util/debug.h"
-#include "../../../util/event.h"
-#include "../../../util/header.h"
-#include "../../../perf-sys.h"
-#include "utils_header.h"
-
-#include <linux/kernel.h>
-
-#define PVR_POWER9 0x004E
-#define PVR_POWER10 0x0080
-#define PVR_POWER11 0x0082
-
-/* REG or %rREG */
-#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
-
-/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
-#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
-
-static regex_t sdt_op_regex1, sdt_op_regex2;
-
-static int sdt_init_op_regex(void)
-{
- static int initialized;
- int ret = 0;
-
- if (initialized)
- return 0;
-
- ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
- if (ret)
- goto error;
-
- ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
- if (ret)
- goto free_regex1;
-
- initialized = 1;
- return 0;
-
-free_regex1:
- regfree(&sdt_op_regex1);
-error:
- pr_debug4("Regex compilation error.\n");
- return ret;
-}
-
-/*
- * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
- * Possible variants of OP are:
- * Format Example
- * -------------------------
- * NUM(REG) 48(18)
- * -NUM(REG) -48(18)
- * NUM(%rREG) 48(%r18)
- * -NUM(%rREG) -48(%r18)
- * REG 18
- * %rREG %r18
- * iNUM i0
- * i-NUM i-1
- *
- * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
- * and REG form with -mno-regnames. Here REG is general purpose register,
- * which is in 0 to 31 range.
- */
-int arch_sdt_arg_parse_op(char *old_op, char **new_op)
-{
- int ret, new_len;
- regmatch_t rm[5];
- char prefix;
-
- /* Constant argument. Uprobe does not support it */
- if (old_op[0] == 'i') {
- pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
- return SDT_ARG_SKIP;
- }
-
- ret = sdt_init_op_regex();
- if (ret < 0)
- return ret;
-
- if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
- /* REG or %rREG --> %gprREG */
-
- new_len = 5; /* % g p r NULL */
- new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
-
- *new_op = zalloc(new_len);
- if (!*new_op)
- return -ENOMEM;
-
- scnprintf(*new_op, new_len, "%%gpr%.*s",
- (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
- } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
- /*
- * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
- * +/-NUM(%gprREG)
- */
- prefix = (rm[1].rm_so == -1) ? '+' : '-';
-
- new_len = 8; /* +/- ( % g p r ) NULL */
- new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
- new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
-
- *new_op = zalloc(new_len);
- if (!*new_op)
- return -ENOMEM;
-
- scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
- (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
- (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
- } else {
- pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
- return SDT_ARG_SKIP;
- }
-
- return SDT_ARG_VALID;
-}
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index 76127eefde8b..9713fe4d8467 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -2,7 +2,6 @@ perf-util-y += header.o
perf-util-y += tsc.o
perf-util-y += pmu.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
-perf-util-y += perf_regs.o
perf-util-y += topdown.o
perf-util-y += machine.o
perf-util-y += event.o
diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
deleted file mode 100644
index 41141cebe226..000000000000
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ /dev/null
@@ -1,235 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-#include <string.h>
-#include <regex.h>
-#include <linux/kernel.h>
-#include <linux/zalloc.h>
-
-#include "perf_regs.h"
-#include "../../../perf-sys.h"
-#include "../../../util/perf_regs.h"
-#include "../../../util/debug.h"
-#include "../../../util/event.h"
-#include "../../../util/pmu.h"
-#include "../../../util/pmus.h"
-
-struct sdt_name_reg {
- const char *sdt_name;
- const char *uprobe_name;
-};
-#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
-#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
-
-static const struct sdt_name_reg sdt_reg_tbl[] = {
- SDT_NAME_REG(eax, ax),
- SDT_NAME_REG(rax, ax),
- SDT_NAME_REG(al, ax),
- SDT_NAME_REG(ah, ax),
- SDT_NAME_REG(ebx, bx),
- SDT_NAME_REG(rbx, bx),
- SDT_NAME_REG(bl, bx),
- SDT_NAME_REG(bh, bx),
- SDT_NAME_REG(ecx, cx),
- SDT_NAME_REG(rcx, cx),
- SDT_NAME_REG(cl, cx),
- SDT_NAME_REG(ch, cx),
- SDT_NAME_REG(edx, dx),
- SDT_NAME_REG(rdx, dx),
- SDT_NAME_REG(dl, dx),
- SDT_NAME_REG(dh, dx),
- SDT_NAME_REG(esi, si),
- SDT_NAME_REG(rsi, si),
- SDT_NAME_REG(sil, si),
- SDT_NAME_REG(edi, di),
- SDT_NAME_REG(rdi, di),
- SDT_NAME_REG(dil, di),
- SDT_NAME_REG(ebp, bp),
- SDT_NAME_REG(rbp, bp),
- SDT_NAME_REG(bpl, bp),
- SDT_NAME_REG(rsp, sp),
- SDT_NAME_REG(esp, sp),
- SDT_NAME_REG(spl, sp),
-
- /* rNN registers */
- SDT_NAME_REG(r8b, r8),
- SDT_NAME_REG(r8w, r8),
- SDT_NAME_REG(r8d, r8),
- SDT_NAME_REG(r9b, r9),
- SDT_NAME_REG(r9w, r9),
- SDT_NAME_REG(r9d, r9),
- SDT_NAME_REG(r10b, r10),
- SDT_NAME_REG(r10w, r10),
- SDT_NAME_REG(r10d, r10),
- SDT_NAME_REG(r11b, r11),
- SDT_NAME_REG(r11w, r11),
- SDT_NAME_REG(r11d, r11),
- SDT_NAME_REG(r12b, r12),
- SDT_NAME_REG(r12w, r12),
- SDT_NAME_REG(r12d, r12),
- SDT_NAME_REG(r13b, r13),
- SDT_NAME_REG(r13w, r13),
- SDT_NAME_REG(r13d, r13),
- SDT_NAME_REG(r14b, r14),
- SDT_NAME_REG(r14w, r14),
- SDT_NAME_REG(r14d, r14),
- SDT_NAME_REG(r15b, r15),
- SDT_NAME_REG(r15w, r15),
- SDT_NAME_REG(r15d, r15),
- SDT_NAME_REG_END,
-};
-
-/*
- * Perf only supports OP which is in +/-NUM(REG) form.
- * Here plus-minus sign, NUM and parenthesis are optional,
- * only REG is mandatory.
- *
- * SDT events also supports indirect addressing mode with a
- * symbol as offset, scaled mode and constants in OP. But
- * perf does not support them yet. Below are few examples.
- *
- * OP with scaled mode:
- * (%rax,%rsi,8)
- * 10(%ras,%rsi,8)
- *
- * OP with indirect addressing mode:
- * check_action(%rip)
- * mp_+52(%rip)
- * 44+mp_(%rip)
- *
- * OP with constant values:
- * $0
- * $123
- * $-1
- */
-#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
-
-static regex_t sdt_op_regex;
-
-static int sdt_init_op_regex(void)
-{
- static int initialized;
- int ret = 0;
-
- if (initialized)
- return 0;
-
- ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
- if (ret < 0) {
- pr_debug4("Regex compilation error.\n");
- return ret;
- }
-
- initialized = 1;
- return 0;
-}
-
-/*
- * Max x86 register name length is 5(ex: %r15d). So, 6th char
- * should always contain NULL. This helps to find register name
- * length using strlen, instead of maintaining one more variable.
- */
-#define SDT_REG_NAME_SIZE 6
-
-/*
- * The uprobe parser does not support all gas register names;
- * so, we have to replace them (ex. for x86_64: %rax -> %ax).
- * Note: If register does not require renaming, just copy
- * paste as it is, but don't leave it empty.
- */
-static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
-{
- int i = 0;
-
- for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
- if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
- strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
- return;
- }
- }
-
- strncpy(uprobe_reg, sdt_reg, sdt_len);
-}
-
-int arch_sdt_arg_parse_op(char *old_op, char **new_op)
-{
- char new_reg[SDT_REG_NAME_SIZE] = {0};
- int new_len = 0, ret;
- /*
- * rm[0]: +/-NUM(REG)
- * rm[1]: +/-
- * rm[2]: NUM
- * rm[3]: (
- * rm[4]: REG
- * rm[5]: )
- */
- regmatch_t rm[6];
- /*
- * Max prefix length is 2 as it may contains sign(+/-)
- * and displacement 0 (Both sign and displacement 0 are
- * optional so it may be empty). Use one more character
- * to hold last NULL so that strlen can be used to find
- * prefix length, instead of maintaining one more variable.
- */
- char prefix[3] = {0};
-
- ret = sdt_init_op_regex();
- if (ret < 0)
- return ret;
-
- /*
- * If unsupported OR does not match with regex OR
- * register name too long, skip it.
- */
- if (strchr(old_op, ',') || strchr(old_op, '$') ||
- regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
- rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
- pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
- return SDT_ARG_SKIP;
- }
-
- /*
- * Prepare prefix.
- * If SDT OP has parenthesis but does not provide
- * displacement, add 0 for displacement.
- * SDT Uprobe Prefix
- * -----------------------------
- * +24(%rdi) +24(%di) +
- * 24(%rdi) +24(%di) +
- * %rdi %di
- * (%rdi) +0(%di) +0
- * -80(%rbx) -80(%bx) -
- */
- if (rm[3].rm_so != rm[3].rm_eo) {
- if (rm[1].rm_so != rm[1].rm_eo)
- prefix[0] = *(old_op + rm[1].rm_so);
- else if (rm[2].rm_so != rm[2].rm_eo)
- prefix[0] = '+';
- else
- scnprintf(prefix, sizeof(prefix), "+0");
- }
-
- /* Rename register */
- sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
- new_reg);
-
- /* Prepare final OP which should be valid for uprobe_events */
- new_len = strlen(prefix) +
- (rm[2].rm_eo - rm[2].rm_so) +
- (rm[3].rm_eo - rm[3].rm_so) +
- strlen(new_reg) +
- (rm[5].rm_eo - rm[5].rm_so) +
- 1; /* NULL */
-
- *new_op = zalloc(new_len);
- if (!*new_op)
- return -ENOMEM;
-
- scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
- strlen(prefix), prefix,
- (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
- (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
- strlen(new_reg), new_reg,
- (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
-
- return SDT_ARG_VALID;
-}
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
index 666874f625b6..6833d34dcbfd 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
@@ -18,6 +18,92 @@
#define HWCAP_SVE (1 << 22)
#endif
+/* %xNUM */
+#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
+
+/* [sp], [sp, NUM] */
+#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
+
+static regex_t sdt_op_regex1, sdt_op_regex2;
+
+static int sdt_init_op_regex(void)
+{
+ static int initialized;
+ int ret = 0;
+
+ if (initialized)
+ return 0;
+
+ ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
+ if (ret)
+ goto error;
+
+ ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
+ if (ret)
+ goto free_regex1;
+
+ initialized = 1;
+ return 0;
+
+free_regex1:
+ regfree(&sdt_op_regex1);
+error:
+ pr_debug4("Regex compilation error.\n");
+ return ret;
+}
+
+/*
+ * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
+ * support these two formats.
+ */
+int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op)
+{
+ int ret, new_len;
+ regmatch_t rm[5];
+
+ ret = sdt_init_op_regex();
+ if (ret < 0)
+ return ret;
+
+ if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
+ /* Extract xNUM */
+ new_len = 2; /* % NULL */
+ new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
+
+ *new_op = zalloc(new_len);
+ if (!*new_op)
+ return -ENOMEM;
+
+ scnprintf(*new_op, new_len, "%%%.*s",
+ (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
+ } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
+ /* [sp], [sp, NUM] or [sp,NUM] */
+ new_len = 7; /* + ( % s p ) NULL */
+
+ /* If the argument is [sp], need to fill offset '0' */
+ if (rm[2].rm_so == -1)
+ new_len += 1;
+ else
+ new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+
+ *new_op = zalloc(new_len);
+ if (!*new_op)
+ return -ENOMEM;
+
+ if (rm[2].rm_so == -1)
+ scnprintf(*new_op, new_len, "+0(%%sp)");
+ else
+ scnprintf(*new_op, new_len, "+%.*s(%%sp)",
+ (int)(rm[2].rm_eo - rm[2].rm_so),
+ old_op + rm[2].rm_so);
+ } else {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+ return SDT_ARG_SKIP;
+ }
+
+ return SDT_ARG_VALID;
+}
+
uint64_t __perf_reg_mask_arm64(bool intr)
{
struct perf_event_attr attr = {
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
index f0a547ad809b..217a001ccd2e 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
@@ -19,6 +19,112 @@
#define PVR_POWER10 0x0080
#define PVR_POWER11 0x0082
+/* REG or %rREG */
+#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
+
+/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
+#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
+
+static regex_t sdt_op_regex1, sdt_op_regex2;
+
+static int sdt_init_op_regex(void)
+{
+ static int initialized;
+ int ret = 0;
+
+ if (initialized)
+ return 0;
+
+ ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
+ if (ret)
+ goto error;
+
+ ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
+ if (ret)
+ goto free_regex1;
+
+ initialized = 1;
+ return 0;
+
+free_regex1:
+ regfree(&sdt_op_regex1);
+error:
+ pr_debug4("Regex compilation error.\n");
+ return ret;
+}
+
+/*
+ * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
+ * Possible variants of OP are:
+ * Format Example
+ * -------------------------
+ * NUM(REG) 48(18)
+ * -NUM(REG) -48(18)
+ * NUM(%rREG) 48(%r18)
+ * -NUM(%rREG) -48(%r18)
+ * REG 18
+ * %rREG %r18
+ * iNUM i0
+ * i-NUM i-1
+ *
+ * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
+ * and REG form with -mno-regnames. Here REG is general purpose register,
+ * which is in 0 to 31 range.
+ */
+int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op)
+{
+ int ret, new_len;
+ regmatch_t rm[5];
+ char prefix;
+
+ /* Constant argument. Uprobe does not support it */
+ if (old_op[0] == 'i') {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+ return SDT_ARG_SKIP;
+ }
+
+ ret = sdt_init_op_regex();
+ if (ret < 0)
+ return ret;
+
+ if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
+ /* REG or %rREG --> %gprREG */
+
+ new_len = 5; /* % g p r NULL */
+ new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+
+ *new_op = zalloc(new_len);
+ if (!*new_op)
+ return -ENOMEM;
+
+ scnprintf(*new_op, new_len, "%%gpr%.*s",
+ (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
+ } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
+ /*
+ * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
+ * +/-NUM(%gprREG)
+ */
+ prefix = (rm[1].rm_so == -1) ? '+' : '-';
+
+ new_len = 8; /* +/- ( % g p r ) NULL */
+ new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
+ new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
+
+ *new_op = zalloc(new_len);
+ if (!*new_op)
+ return -ENOMEM;
+
+ scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
+ (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+ (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
+ } else {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+ return SDT_ARG_SKIP;
+ }
+
+ return SDT_ARG_VALID;
+}
+
/*
* mfspr is a POWERPC specific instruction, ensure it's only
* built and called on POWERPC by guarding with __powerpc64__
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_x86.c b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
index d573f9a9ca46..b6d20522b4e8 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_x86.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
@@ -14,6 +14,227 @@
#include "../../perf-sys.h"
#include "../../arch/x86/include/perf_regs.h"
+struct sdt_name_reg {
+ const char *sdt_name;
+ const char *uprobe_name;
+};
+#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
+#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
+
+static const struct sdt_name_reg sdt_reg_tbl[] = {
+ SDT_NAME_REG(eax, ax),
+ SDT_NAME_REG(rax, ax),
+ SDT_NAME_REG(al, ax),
+ SDT_NAME_REG(ah, ax),
+ SDT_NAME_REG(ebx, bx),
+ SDT_NAME_REG(rbx, bx),
+ SDT_NAME_REG(bl, bx),
+ SDT_NAME_REG(bh, bx),
+ SDT_NAME_REG(ecx, cx),
+ SDT_NAME_REG(rcx, cx),
+ SDT_NAME_REG(cl, cx),
+ SDT_NAME_REG(ch, cx),
+ SDT_NAME_REG(edx, dx),
+ SDT_NAME_REG(rdx, dx),
+ SDT_NAME_REG(dl, dx),
+ SDT_NAME_REG(dh, dx),
+ SDT_NAME_REG(esi, si),
+ SDT_NAME_REG(rsi, si),
+ SDT_NAME_REG(sil, si),
+ SDT_NAME_REG(edi, di),
+ SDT_NAME_REG(rdi, di),
+ SDT_NAME_REG(dil, di),
+ SDT_NAME_REG(ebp, bp),
+ SDT_NAME_REG(rbp, bp),
+ SDT_NAME_REG(bpl, bp),
+ SDT_NAME_REG(rsp, sp),
+ SDT_NAME_REG(esp, sp),
+ SDT_NAME_REG(spl, sp),
+
+ /* rNN registers */
+ SDT_NAME_REG(r8b, r8),
+ SDT_NAME_REG(r8w, r8),
+ SDT_NAME_REG(r8d, r8),
+ SDT_NAME_REG(r9b, r9),
+ SDT_NAME_REG(r9w, r9),
+ SDT_NAME_REG(r9d, r9),
+ SDT_NAME_REG(r10b, r10),
+ SDT_NAME_REG(r10w, r10),
+ SDT_NAME_REG(r10d, r10),
+ SDT_NAME_REG(r11b, r11),
+ SDT_NAME_REG(r11w, r11),
+ SDT_NAME_REG(r11d, r11),
+ SDT_NAME_REG(r12b, r12),
+ SDT_NAME_REG(r12w, r12),
+ SDT_NAME_REG(r12d, r12),
+ SDT_NAME_REG(r13b, r13),
+ SDT_NAME_REG(r13w, r13),
+ SDT_NAME_REG(r13d, r13),
+ SDT_NAME_REG(r14b, r14),
+ SDT_NAME_REG(r14w, r14),
+ SDT_NAME_REG(r14d, r14),
+ SDT_NAME_REG(r15b, r15),
+ SDT_NAME_REG(r15w, r15),
+ SDT_NAME_REG(r15d, r15),
+ SDT_NAME_REG_END,
+};
+
+/*
+ * Perf only supports OP which is in +/-NUM(REG) form.
+ * Here plus-minus sign, NUM and parenthesis are optional,
+ * only REG is mandatory.
+ *
+ * SDT events also supports indirect addressing mode with a
+ * symbol as offset, scaled mode and constants in OP. But
+ * perf does not support them yet. Below are few examples.
+ *
+ * OP with scaled mode:
+ * (%rax,%rsi,8)
+ * 10(%ras,%rsi,8)
+ *
+ * OP with indirect addressing mode:
+ * check_action(%rip)
+ * mp_+52(%rip)
+ * 44+mp_(%rip)
+ *
+ * OP with constant values:
+ * $0
+ * $123
+ * $-1
+ */
+#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
+
+static regex_t sdt_op_regex;
+
+static int sdt_init_op_regex(void)
+{
+ static int initialized;
+ int ret = 0;
+
+ if (initialized)
+ return 0;
+
+ ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
+ if (ret < 0) {
+ pr_debug4("Regex compilation error.\n");
+ return ret;
+ }
+
+ initialized = 1;
+ return 0;
+}
+
+/*
+ * Max x86 register name length is 5(ex: %r15d). So, 6th char
+ * should always contain NULL. This helps to find register name
+ * length using strlen, instead of maintaining one more variable.
+ */
+#define SDT_REG_NAME_SIZE 6
+
+/*
+ * The uprobe parser does not support all gas register names;
+ * so, we have to replace them (ex. for x86_64: %rax -> %ax).
+ * Note: If register does not require renaming, just copy
+ * paste as it is, but don't leave it empty.
+ */
+static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
+{
+ int i = 0;
+
+ for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
+ if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
+ strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
+ return;
+ }
+ }
+
+ strncpy(uprobe_reg, sdt_reg, sdt_len);
+}
+
+int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op)
+{
+ char new_reg[SDT_REG_NAME_SIZE] = {0};
+ int new_len = 0, ret;
+ /*
+ * rm[0]: +/-NUM(REG)
+ * rm[1]: +/-
+ * rm[2]: NUM
+ * rm[3]: (
+ * rm[4]: REG
+ * rm[5]: )
+ */
+ regmatch_t rm[6];
+ /*
+ * Max prefix length is 2 as it may contains sign(+/-)
+ * and displacement 0 (Both sign and displacement 0 are
+ * optional so it may be empty). Use one more character
+ * to hold last NULL so that strlen can be used to find
+ * prefix length, instead of maintaining one more variable.
+ */
+ char prefix[3] = {0};
+
+ ret = sdt_init_op_regex();
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If unsupported OR does not match with regex OR
+ * register name too long, skip it.
+ */
+ if (strchr(old_op, ',') || strchr(old_op, '$') ||
+ regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
+ rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
+ pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+ return SDT_ARG_SKIP;
+ }
+
+ /*
+ * Prepare prefix.
+ * If SDT OP has parenthesis but does not provide
+ * displacement, add 0 for displacement.
+ * SDT Uprobe Prefix
+ * -----------------------------
+ * +24(%rdi) +24(%di) +
+ * 24(%rdi) +24(%di) +
+ * %rdi %di
+ * (%rdi) +0(%di) +0
+ * -80(%rbx) -80(%bx) -
+ */
+ if (rm[3].rm_so != rm[3].rm_eo) {
+ if (rm[1].rm_so != rm[1].rm_eo)
+ prefix[0] = *(old_op + rm[1].rm_so);
+ else if (rm[2].rm_so != rm[2].rm_eo)
+ prefix[0] = '+';
+ else
+ scnprintf(prefix, sizeof(prefix), "+0");
+ }
+
+ /* Rename register */
+ sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
+ new_reg);
+
+ /* Prepare final OP which should be valid for uprobe_events */
+ new_len = strlen(prefix) +
+ (rm[2].rm_eo - rm[2].rm_so) +
+ (rm[3].rm_eo - rm[3].rm_so) +
+ strlen(new_reg) +
+ (rm[5].rm_eo - rm[5].rm_so) +
+ 1; /* NULL */
+
+ *new_op = zalloc(new_len);
+ if (!*new_op)
+ return -ENOMEM;
+
+ scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
+ strlen(prefix), prefix,
+ (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
+ (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
+ strlen(new_reg), new_reg,
+ (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
+
+ return SDT_ARG_VALID;
+}
+
uint64_t __perf_reg_mask_x86(bool intr)
{
struct perf_event_attr attr = {
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index 4d9a286a0e56..5b8f34beb24e 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -7,10 +7,29 @@
#include "util/sample.h"
#include "debug.h"
-int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
- char **new_op __maybe_unused)
+int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op)
{
- return SDT_ARG_SKIP;
+ int ret = SDT_ARG_SKIP;
+
+ switch (e_machine) {
+ case EM_AARCH64:
+ ret = __perf_sdt_arg_parse_op_arm64(old_op, new_op);
+ break;
+ case EM_PPC:
+ case EM_PPC64:
+ ret = __perf_sdt_arg_parse_op_powerpc(old_op, new_op);
+ break;
+ case EM_386:
+ case EM_X86_64:
+ ret = __perf_sdt_arg_parse_op_x86(old_op, new_op);
+ break;
+ default:
+ pr_debug("Unknown ELF machine %d, standard arguments parse will be skipped.\n",
+ e_machine);
+ break;
+ }
+
+ return ret;
}
uint64_t perf_intr_reg_mask(uint16_t e_machine)
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 2b27139acadb..7c04700bf837 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -12,7 +12,7 @@ enum {
SDT_ARG_SKIP,
};
-int arch_sdt_arg_parse_op(char *old_op, char **new_op);
+int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op);
uint64_t perf_intr_reg_mask(uint16_t e_machine);
uint64_t perf_user_reg_mask(uint16_t e_machine);
@@ -21,6 +21,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
uint64_t perf_arch_reg_ip(uint16_t e_machine);
uint64_t perf_arch_reg_sp(uint16_t e_machine);
+int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op);
uint64_t __perf_reg_mask_arm64(bool intr);
const char *__perf_reg_name_arm64(int id);
uint64_t __perf_reg_ip_arm64(void);
@@ -46,6 +47,7 @@ const char *__perf_reg_name_mips(int id);
uint64_t __perf_reg_ip_mips(void);
uint64_t __perf_reg_sp_mips(void);
+int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op);
uint64_t __perf_reg_mask_powerpc(bool intr);
const char *__perf_reg_name_powerpc(int id);
uint64_t __perf_reg_ip_powerpc(void);
@@ -61,6 +63,7 @@ const char *__perf_reg_name_s390(int id);
uint64_t __perf_reg_ip_s390(void);
uint64_t __perf_reg_sp_s390(void);
+int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op);
uint64_t __perf_reg_mask_x86(bool intr);
const char *__perf_reg_name_x86(int id);
uint64_t __perf_reg_ip_x86(void);
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 5069fb61f48c..f78c3bc3d601 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -28,6 +28,7 @@
#include "session.h"
#include "perf_regs.h"
#include "string2.h"
+#include "dwarf-regs.h"
/* 4096 - 2 ('\n' + '\0') */
#define MAX_CMDLEN 4094
@@ -784,7 +785,7 @@ static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
op = desc;
}
- ret = arch_sdt_arg_parse_op(op, &new_op);
+ ret = perf_sdt_arg_parse_op(EM_HOST, op, &new_op);
if (ret < 0)
goto error;
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options
2026-02-03 2:43 ` [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options Dapeng Mi
@ 2026-02-03 23:06 ` Ian Rogers
0 siblings, 0 replies; 11+ messages in thread
From: Ian Rogers @ 2026-02-03 23:06 UTC (permalink / raw)
To: Dapeng Mi
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Adrian Hunter, Alexander Shishkin, John Garry,
Will Deacon, James Clark, Mike Leach, Guo Ren, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-perf-users,
linux-arm-kernel, linux-csky, linux-riscv, linux-kernel,
Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao
On Mon, Feb 2, 2026 at 6:47 PM Dapeng Mi <dapeng1.mi@linux.intel.com> wrote:
>
> Fix an issue where the `perf` tool aborts unexpectedly when running the
> following command:
>
> ```
> perf record -e cycles -I -- true
>
> Usage: perf record [<options>] [<command>]
> or: perf record [<options>] -- <command> [<options>]
>
> -I, --intr-regs[=<any register>]
> sample selected machine registers on interrupt, use '-I?' to list register names
> ```
>
> The usage of the `-I` or `--user-regs` options without specifying any
> registers should default to sampling all general-purpose registers.
> However, this currently causes an abnormal termination.
>
> The issue was introduced by commit 3d06db9bad1a ("perf regs: Refactor
> use of arch__sample_reg_masks() to perf_reg_name()"). This patch
> resolves the problem, ensuring that the `-I` or `--user-regs` options
> work as intended without causing an abort.
>
> Fixes: 3d06db9bad1a ("perf regs: Refactor use of arch__sample_reg_masks() to perf_reg_name()")
> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Thanks,
Ian
> ---
> tools/perf/util/parse-regs-options.c | 13 ++++++-------
> 1 file changed, 6 insertions(+), 7 deletions(-)
>
> diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
> index 8dd35f50f644..b44b47d9059f 100644
> --- a/tools/perf/util/parse-regs-options.c
> +++ b/tools/perf/util/parse-regs-options.c
> @@ -66,12 +66,14 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
> if (*mode)
> return -1;
>
> - /* str may be NULL in case no arg is passed to -I */
> - if (!str)
> - return -1;
> -
> mask = intr ? arch__intr_reg_mask() : arch__user_reg_mask();
>
> + /* str may be NULL in case no arg is passed to -I */
> + if (!str) {
> + *mode = mask;
> + return 0;
> + }
> +
> /* because str is read-only */
> s = os = strdup(str);
> if (!s)
> @@ -104,9 +106,6 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
> }
> ret = 0;
>
> - /* default to all possible regs */
> - if (*mode == 0)
> - *mode = mask;
> error:
> free(os);
> return ret;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
2026-02-03 2:43 ` [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions Dapeng Mi
@ 2026-02-03 23:08 ` Ian Rogers
0 siblings, 0 replies; 11+ messages in thread
From: Ian Rogers @ 2026-02-03 23:08 UTC (permalink / raw)
To: Dapeng Mi
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Adrian Hunter, Alexander Shishkin, John Garry,
Will Deacon, James Clark, Mike Leach, Guo Ren, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-perf-users,
linux-arm-kernel, linux-csky, linux-riscv, linux-kernel,
Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao
On Mon, Feb 2, 2026 at 6:48 PM Dapeng Mi <dapeng1.mi@linux.intel.com> wrote:
>
> Currently, some architecture-specific perf-regs functions, such as
> arch__intr_reg_mask() and arch__user_reg_mask(), are defined with the
> __weak attribute. This approach ensures that only functions matching
> the architecture of the build/run host are compiled and executed,
> reducing build time and binary size.
>
> However, this __weak attribute restricts these functions to be called
> only on the same architecture, preventing cross-architecture
> functionality. For example, a perf.data file captured on x86 cannot be
> parsed on an ARM platform.
>
> To address this limitation, this patch removes the __weak attribute from
> these perf-regs functions. The architecture-specific code is moved from
> the arch/ directory to the util/perf-regs-arch/ directory. The
> appropriate architectural functions are then called based on the EM_HOST.
>
> No functional changes are intended.
>
> Suggested-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Thanks,
Ian
> ---
> tools/perf/arch/arm/util/Build | 2 -
> tools/perf/arch/arm/util/perf_regs.c | 13 ---
> tools/perf/arch/arm64/util/perf_regs.c | 36 --------
> tools/perf/arch/csky/Build | 1 -
> tools/perf/arch/csky/util/Build | 1 -
> tools/perf/arch/csky/util/perf_regs.c | 13 ---
> tools/perf/arch/loongarch/util/Build | 1 -
> tools/perf/arch/loongarch/util/perf_regs.c | 13 ---
> tools/perf/arch/mips/util/Build | 1 -
> tools/perf/arch/mips/util/perf_regs.c | 13 ---
> tools/perf/arch/powerpc/util/perf_regs.c | 47 -----------
> tools/perf/arch/riscv/include/perf_regs.h | 7 +-
> tools/perf/arch/riscv/util/Build | 1 -
> tools/perf/arch/riscv/util/perf_regs.c | 13 ---
> tools/perf/arch/s390/util/Build | 1 -
> tools/perf/arch/s390/util/perf_regs.c | 13 ---
> tools/perf/arch/x86/util/perf_regs.c | 48 -----------
> tools/perf/util/evsel.c | 4 +-
> tools/perf/util/parse-regs-options.c | 2 +-
> .../util/perf-regs-arch/perf_regs_aarch64.c | 53 +++++++++++-
> .../perf/util/perf-regs-arch/perf_regs_arm.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_csky.c | 7 +-
> .../util/perf-regs-arch/perf_regs_loongarch.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_mips.c | 7 +-
> .../util/perf-regs-arch/perf_regs_powerpc.c | 77 ++++++++++++++++-
> .../util/perf-regs-arch/perf_regs_riscv.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_s390.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_x86.c | 60 ++++++++++++-
> tools/perf/util/perf_regs.c | 84 ++++++++++++++++++-
> tools/perf/util/perf_regs.h | 22 ++++-
> 30 files changed, 332 insertions(+), 236 deletions(-)
> delete mode 100644 tools/perf/arch/arm/util/perf_regs.c
> delete mode 100644 tools/perf/arch/csky/Build
> delete mode 100644 tools/perf/arch/csky/util/Build
> delete mode 100644 tools/perf/arch/csky/util/perf_regs.c
> delete mode 100644 tools/perf/arch/loongarch/util/perf_regs.c
> delete mode 100644 tools/perf/arch/mips/util/perf_regs.c
> delete mode 100644 tools/perf/arch/riscv/util/perf_regs.c
> delete mode 100644 tools/perf/arch/s390/util/perf_regs.c
>
> diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
> index 3291f893b943..b94bf3c5279a 100644
> --- a/tools/perf/arch/arm/util/Build
> +++ b/tools/perf/arch/arm/util/Build
> @@ -1,5 +1,3 @@
> -perf-util-y += perf_regs.o
> -
> perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>
> perf-util-y += pmu.o auxtrace.o cs-etm.o
> diff --git a/tools/perf/arch/arm/util/perf_regs.c b/tools/perf/arch/arm/util/perf_regs.c
> deleted file mode 100644
> index 03a5bc0cf64c..000000000000
> --- a/tools/perf/arch/arm/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/arm64/util/perf_regs.c b/tools/perf/arch/arm64/util/perf_regs.c
> index 9bb768e1bea1..47f58eaba032 100644
> --- a/tools/perf/arch/arm64/util/perf_regs.c
> +++ b/tools/perf/arch/arm64/util/perf_regs.c
> @@ -103,39 +103,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
>
> return SDT_ARG_VALID;
> }
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - struct perf_event_attr attr = {
> - .type = PERF_TYPE_HARDWARE,
> - .config = PERF_COUNT_HW_CPU_CYCLES,
> - .sample_type = PERF_SAMPLE_REGS_USER,
> - .disabled = 1,
> - .exclude_kernel = 1,
> - .sample_period = 1,
> - .sample_regs_user = PERF_REGS_MASK
> - };
> - int fd;
> -
> - if (getauxval(AT_HWCAP) & HWCAP_SVE)
> - attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
> -
> - /*
> - * Check if the pmu supports perf extended regs, before
> - * returning the register mask to sample.
> - */
> - if (attr.sample_regs_user != PERF_REGS_MASK) {
> - event_attr_init(&attr);
> - fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
> - if (fd != -1) {
> - close(fd);
> - return attr.sample_regs_user;
> - }
> - }
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/csky/Build b/tools/perf/arch/csky/Build
> deleted file mode 100644
> index e63eabc2c8f4..000000000000
> --- a/tools/perf/arch/csky/Build
> +++ /dev/null
> @@ -1 +0,0 @@
> -perf-util-y += util/
> diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build
> deleted file mode 100644
> index 6b2d0e021b11..000000000000
> --- a/tools/perf/arch/csky/util/Build
> +++ /dev/null
> @@ -1 +0,0 @@
> -perf-util-y += perf_regs.o
> diff --git a/tools/perf/arch/csky/util/perf_regs.c b/tools/perf/arch/csky/util/perf_regs.c
> deleted file mode 100644
> index 2cf7a54106e0..000000000000
> --- a/tools/perf/arch/csky/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
> index 0aa31986ecb5..0c958c8e0718 100644
> --- a/tools/perf/arch/loongarch/util/Build
> +++ b/tools/perf/arch/loongarch/util/Build
> @@ -1,5 +1,4 @@
> perf-util-y += header.o
> -perf-util-y += perf_regs.o
>
> perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
> perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> diff --git a/tools/perf/arch/loongarch/util/perf_regs.c b/tools/perf/arch/loongarch/util/perf_regs.c
> deleted file mode 100644
> index 03a5bc0cf64c..000000000000
> --- a/tools/perf/arch/loongarch/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Build
> index 691fa2051958..818b808a8247 100644
> --- a/tools/perf/arch/mips/util/Build
> +++ b/tools/perf/arch/mips/util/Build
> @@ -1,2 +1 @@
> -perf-util-y += perf_regs.o
> perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
> diff --git a/tools/perf/arch/mips/util/perf_regs.c b/tools/perf/arch/mips/util/perf_regs.c
> deleted file mode 100644
> index 2cf7a54106e0..000000000000
> --- a/tools/perf/arch/mips/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
> index 779073f7e992..93f929fc32e3 100644
> --- a/tools/perf/arch/powerpc/util/perf_regs.c
> +++ b/tools/perf/arch/powerpc/util/perf_regs.c
> @@ -123,50 +123,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
>
> return SDT_ARG_VALID;
> }
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - struct perf_event_attr attr = {
> - .type = PERF_TYPE_HARDWARE,
> - .config = PERF_COUNT_HW_CPU_CYCLES,
> - .sample_type = PERF_SAMPLE_REGS_INTR,
> - .precise_ip = 1,
> - .disabled = 1,
> - .exclude_kernel = 1,
> - };
> - int fd;
> - u32 version;
> - u64 extended_mask = 0, mask = PERF_REGS_MASK;
> -
> - /*
> - * Get the PVR value to set the extended
> - * mask specific to platform.
> - */
> - version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
> - if (version == PVR_POWER9)
> - extended_mask = PERF_REG_PMU_MASK_300;
> - else if ((version == PVR_POWER10) || (version == PVR_POWER11))
> - extended_mask = PERF_REG_PMU_MASK_31;
> - else
> - return mask;
> -
> - attr.sample_regs_intr = extended_mask;
> - attr.sample_period = 1;
> - event_attr_init(&attr);
> -
> - /*
> - * check if the pmu supports perf extended regs, before
> - * returning the register mask to sample.
> - */
> - fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
> - if (fd != -1) {
> - close(fd);
> - mask |= extended_mask;
> - }
> - return mask;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
> index 89d5bbb8d2b8..af7a1b47bf66 100644
> --- a/tools/perf/arch/riscv/include/perf_regs.h
> +++ b/tools/perf/arch/riscv/include/perf_regs.h
> @@ -10,10 +10,15 @@
>
> #define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
> #define PERF_REGS_MAX PERF_REG_RISCV_MAX
> +
> +#if defined(__riscv_xlen)
> #if __riscv_xlen == 64
> -#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
> +#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
> #else
> #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
> #endif
> +#else
> +#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_NONE
> +#endif
>
> #endif /* ARCH_PERF_REGS_H */
> diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
> index 628b9ebd418b..da5b12e7f862 100644
> --- a/tools/perf/arch/riscv/util/Build
> +++ b/tools/perf/arch/riscv/util/Build
> @@ -1,4 +1,3 @@
> -perf-util-y += perf_regs.o
> perf-util-y += header.o
>
> perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> diff --git a/tools/perf/arch/riscv/util/perf_regs.c b/tools/perf/arch/riscv/util/perf_regs.c
> deleted file mode 100644
> index 2cf7a54106e0..000000000000
> --- a/tools/perf/arch/riscv/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
> index 5391d26fedd4..3b09c058e0ec 100644
> --- a/tools/perf/arch/s390/util/Build
> +++ b/tools/perf/arch/s390/util/Build
> @@ -1,6 +1,5 @@
> perf-util-y += header.o
> perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> -perf-util-y += perf_regs.o
>
> perf-util-y += machine.o
> perf-util-y += pmu.o
> diff --git a/tools/perf/arch/s390/util/perf_regs.c b/tools/perf/arch/s390/util/perf_regs.c
> deleted file mode 100644
> index 2cf7a54106e0..000000000000
> --- a/tools/perf/arch/s390/util/perf_regs.c
> +++ /dev/null
> @@ -1,13 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include "perf_regs.h"
> -#include "../../util/perf_regs.h"
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
> index a7ca4154fdf9..41141cebe226 100644
> --- a/tools/perf/arch/x86/util/perf_regs.c
> +++ b/tools/perf/arch/x86/util/perf_regs.c
> @@ -233,51 +233,3 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
>
> return SDT_ARG_VALID;
> }
> -
> -uint64_t arch__intr_reg_mask(void)
> -{
> - struct perf_event_attr attr = {
> - .type = PERF_TYPE_HARDWARE,
> - .config = PERF_COUNT_HW_CPU_CYCLES,
> - .sample_type = PERF_SAMPLE_REGS_INTR,
> - .sample_regs_intr = PERF_REG_EXTENDED_MASK,
> - .precise_ip = 1,
> - .disabled = 1,
> - .exclude_kernel = 1,
> - };
> - int fd;
> - /*
> - * In an unnamed union, init it here to build on older gcc versions
> - */
> - attr.sample_period = 1;
> -
> - if (perf_pmus__num_core_pmus() > 1) {
> - struct perf_pmu *pmu = NULL;
> - __u64 type = PERF_TYPE_RAW;
> -
> - /*
> - * The same register set is supported among different hybrid PMUs.
> - * Only check the first available one.
> - */
> - while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
> - type = pmu->type;
> - break;
> - }
> - attr.config |= type << PERF_PMU_TYPE_SHIFT;
> - }
> -
> - event_attr_init(&attr);
> -
> - fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
> - if (fd != -1) {
> - close(fd);
> - return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
> - }
> -
> - return PERF_REGS_MASK;
> -}
> -
> -uint64_t arch__user_reg_mask(void)
> -{
> - return PERF_REGS_MASK;
> -}
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 5ac1a05601b1..a36528fd41c6 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -1055,13 +1055,13 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o
> evsel__set_sample_bit(evsel, REGS_USER);
> evsel__set_sample_bit(evsel, STACK_USER);
> if (opts->sample_user_regs &&
> - DWARF_MINIMAL_REGS(e_machine) != arch__user_reg_mask()) {
> + DWARF_MINIMAL_REGS(e_machine) != perf_user_reg_mask(EM_HOST)) {
> attr->sample_regs_user |= DWARF_MINIMAL_REGS(e_machine);
> pr_warning("WARNING: The use of --call-graph=dwarf may require all the user registers, "
> "specifying a subset with --user-regs may render DWARF unwinding unreliable, "
> "so the minimal registers set (IP, SP) is explicitly forced.\n");
> } else {
> - attr->sample_regs_user |= arch__user_reg_mask();
> + attr->sample_regs_user |= perf_user_reg_mask(EM_HOST);
> }
> attr->sample_stack_user = param->dump_size;
> attr->exclude_callchain_user = 1;
> diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
> index b44b47d9059f..c93c2f0c8105 100644
> --- a/tools/perf/util/parse-regs-options.c
> +++ b/tools/perf/util/parse-regs-options.c
> @@ -66,7 +66,7 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr)
> if (*mode)
> return -1;
>
> - mask = intr ? arch__intr_reg_mask() : arch__user_reg_mask();
> + mask = intr ? perf_intr_reg_mask(EM_HOST) : perf_user_reg_mask(EM_HOST);
>
> /* str may be NULL in case no arg is passed to -I */
> if (!str) {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> index 9dcda80d310f..666874f625b6 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> @@ -1,7 +1,58 @@
> // SPDX-License-Identifier: GPL-2.0
> +#include <errno.h>
> +#include <regex.h>
> +#include <string.h>
> +#include <sys/auxv.h>
> +#include <linux/kernel.h>
> +#include <linux/zalloc.h>
>
> +#include "../debug.h"
> +#include "../event.h"
> #include "../perf_regs.h"
> -#include "../../../arch/arm64/include/uapi/asm/perf_regs.h"
> +#include "../../perf-sys.h"
> +#include "../../arch/arm64/include/perf_regs.h"
> +
> +#define SMPL_REG_MASK(b) (1ULL << (b))
> +
> +#ifndef HWCAP_SVE
> +#define HWCAP_SVE (1 << 22)
> +#endif
> +
> +uint64_t __perf_reg_mask_arm64(bool intr)
> +{
> + struct perf_event_attr attr = {
> + .type = PERF_TYPE_HARDWARE,
> + .config = PERF_COUNT_HW_CPU_CYCLES,
> + .sample_type = PERF_SAMPLE_REGS_USER,
> + .disabled = 1,
> + .exclude_kernel = 1,
> + .sample_period = 1,
> + .sample_regs_user = PERF_REGS_MASK
> + };
> + int fd;
> +
> + if (intr)
> + return PERF_REGS_MASK;
> +
> + if (getauxval(AT_HWCAP) & HWCAP_SVE)
> + attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
> +
> + /*
> + * Check if the pmu supports perf extended regs, before
> + * returning the register mask to sample. Open the event
> + * on the perf process to check this.
> + */
> + if (attr.sample_regs_user != PERF_REGS_MASK) {
> + event_attr_init(&attr);
> + fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
> + /*group_fd=*/-1, /*flags=*/0);
> + if (fd != -1) {
> + close(fd);
> + return attr.sample_regs_user;
> + }
> + }
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_arm64(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_arm.c b/tools/perf/util/perf-regs-arch/perf_regs_arm.c
> index e29d130a587a..184d6e248dfc 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_arm.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_arm.c
> @@ -1,7 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
>
> #include "../perf_regs.h"
> -#include "../../../arch/arm/include/uapi/asm/perf_regs.h"
> +#include "../../arch/arm/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_arm(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_arm(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_csky.c b/tools/perf/util/perf-regs-arch/perf_regs_csky.c
> index 95808f93d45b..16cbd8303acf 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_csky.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_csky.c
> @@ -9,7 +9,12 @@
> #include "../perf_regs.h"
> #undef __CSKYABIV2__
> #define __CSKYABIV2__ 1 // Always want the V2 register definitions.
> -#include "../../arch/csky/include/uapi/asm/perf_regs.h"
> +#include "../../arch/csky/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_csky(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_csky(int id, uint32_t e_flags)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c b/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
> index 043f97f4e3ac..478ee889afa1 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
> @@ -1,7 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
>
> #include "../perf_regs.h"
> -#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h"
> +#include "../../arch/loongarch/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_loongarch(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_loongarch(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_mips.c b/tools/perf/util/perf-regs-arch/perf_regs_mips.c
> index 793178fc3c78..c5a475f6ec64 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_mips.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_mips.c
> @@ -1,7 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
>
> #include "../perf_regs.h"
> -#include "../../../arch/mips/include/uapi/asm/perf_regs.h"
> +#include "../../arch/mips/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_mips(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_mips(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> index 08636bb09a3a..f0a547ad809b 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> @@ -1,7 +1,82 @@
> // SPDX-License-Identifier: GPL-2.0
>
> +#include <errno.h>
> +#include <string.h>
> +#include <regex.h>
> +#include <linux/zalloc.h>
> +
> +#include "../debug.h"
> +#include "../event.h"
> +#include "../header.h"
> #include "../perf_regs.h"
> -#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h"
> +#include "../../perf-sys.h"
> +#include "../../arch/powerpc/util/utils_header.h"
> +#include "../../arch/powerpc/include/perf_regs.h"
> +
> +#include <linux/kernel.h>
> +
> +#define PVR_POWER9 0x004E
> +#define PVR_POWER10 0x0080
> +#define PVR_POWER11 0x0082
> +
> +/*
> + * mfspr is a POWERPC specific instruction, ensure it's only
> + * built and called on POWERPC by guarding with __powerpc64__
> + * or __powerpc__.
> + */
> +#if defined(__powerpc64__) && defined(__powerpc__)
> +uint64_t __perf_reg_mask_powerpc(bool intr)
> +{
> + struct perf_event_attr attr = {
> + .type = PERF_TYPE_HARDWARE,
> + .config = PERF_COUNT_HW_CPU_CYCLES,
> + .sample_type = PERF_SAMPLE_REGS_INTR,
> + .precise_ip = 1,
> + .disabled = 1,
> + .exclude_kernel = 1,
> + };
> + int fd;
> + u32 version;
> + u64 extended_mask = 0, mask = PERF_REGS_MASK;
> +
> + if (!intr)
> + return PERF_REGS_MASK;
> +
> + /*
> + * Get the PVR value to set the extended
> + * mask specific to platform.
> + */
> + version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
> + if (version == PVR_POWER9)
> + extended_mask = PERF_REG_PMU_MASK_300;
> + else if ((version == PVR_POWER10) || (version == PVR_POWER11))
> + extended_mask = PERF_REG_PMU_MASK_31;
> + else
> + return mask;
> +
> + attr.sample_regs_intr = extended_mask;
> + attr.sample_period = 1;
> + event_attr_init(&attr);
> +
> + /*
> + * Check if the pmu supports perf extended regs, before
> + * returning the register mask to sample. Open the event
> + * on the perf process to check this.
> + */
> + fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
> + /*group_fd=*/-1, /*flags=*/0);
> + if (fd != -1) {
> + close(fd);
> + mask |= extended_mask;
> + }
> + return mask;
> +}
> +#else
> +uint64_t __perf_reg_mask_powerpc(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
> +#endif
>
> const char *__perf_reg_name_powerpc(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_riscv.c b/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
> index 337b687c655d..5b5f21fcba8c 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_riscv.c
> @@ -1,7 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
>
> #include "../perf_regs.h"
> -#include "../../../arch/riscv/include/uapi/asm/perf_regs.h"
> +#include "../../arch/riscv/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_riscv(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_riscv(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_s390.c b/tools/perf/util/perf-regs-arch/perf_regs_s390.c
> index d69bba881080..c61df24edf0f 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_s390.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_s390.c
> @@ -1,7 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
>
> #include "../perf_regs.h"
> -#include "../../../arch/s390/include/uapi/asm/perf_regs.h"
> +#include "../../arch/s390/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_s390(bool intr __maybe_unused)
> +{
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_s390(int id)
> {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_x86.c b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> index 708954a9d35d..d573f9a9ca46 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> @@ -1,7 +1,65 @@
> // SPDX-License-Identifier: GPL-2.0
>
> +#include <errno.h>
> +#include <string.h>
> +#include <regex.h>
> +#include <linux/kernel.h>
> +#include <linux/zalloc.h>
> +
> +#include "../debug.h"
> +#include "../event.h"
> +#include "../pmu.h"
> +#include "../pmus.h"
> #include "../perf_regs.h"
> -#include "../../../arch/x86/include/uapi/asm/perf_regs.h"
> +#include "../../perf-sys.h"
> +#include "../../arch/x86/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_x86(bool intr)
> +{
> + struct perf_event_attr attr = {
> + .type = PERF_TYPE_HARDWARE,
> + .config = PERF_COUNT_HW_CPU_CYCLES,
> + .sample_type = PERF_SAMPLE_REGS_INTR,
> + .sample_regs_intr = PERF_REG_EXTENDED_MASK,
> + .precise_ip = 1,
> + .disabled = 1,
> + .exclude_kernel = 1,
> + };
> + int fd;
> +
> + if (!intr)
> + return PERF_REGS_MASK;
> +
> + /*
> + * In an unnamed union, init it here to build on older gcc versions
> + */
> + attr.sample_period = 1;
> +
> + if (perf_pmus__num_core_pmus() > 1) {
> + struct perf_pmu *pmu = NULL;
> + __u64 type = PERF_TYPE_RAW;
> +
> + /*
> + * The same register set is supported among different hybrid PMUs.
> + * Only check the first available one.
> + */
> + while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
> + type = pmu->type;
> + break;
> + }
> + attr.config |= type << PERF_PMU_TYPE_SHIFT;
> + }
> +
> + event_attr_init(&attr);
> + fd = sys_perf_event_open(&attr, /*pid=*/0, /*cpu=*/-1,
> + /*group_fd=*/-1, /*flags=*/0);
> + if (fd != -1) {
> + close(fd);
> + return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
> + }
> +
> + return PERF_REGS_MASK;
> +}
>
> const char *__perf_reg_name_x86(int id)
> {
> diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
> index 14b7be30ab20..4d9a286a0e56 100644
> --- a/tools/perf/util/perf_regs.c
> +++ b/tools/perf/util/perf_regs.c
> @@ -13,14 +13,90 @@ int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
> return SDT_ARG_SKIP;
> }
>
> -uint64_t __weak arch__intr_reg_mask(void)
> +uint64_t perf_intr_reg_mask(uint16_t e_machine)
> {
> - return 0;
> + uint64_t mask = 0;
> +
> + switch (e_machine) {
> + case EM_ARM:
> + mask = __perf_reg_mask_arm(/*intr=*/true);
> + break;
> + case EM_AARCH64:
> + mask = __perf_reg_mask_arm64(/*intr=*/true);
> + break;
> + case EM_CSKY:
> + mask = __perf_reg_mask_csky(/*intr=*/true);
> + break;
> + case EM_LOONGARCH:
> + mask = __perf_reg_mask_loongarch(/*intr=*/true);
> + break;
> + case EM_MIPS:
> + mask = __perf_reg_mask_mips(/*intr=*/true);
> + break;
> + case EM_PPC:
> + case EM_PPC64:
> + mask = __perf_reg_mask_powerpc(/*intr=*/true);
> + break;
> + case EM_RISCV:
> + mask = __perf_reg_mask_riscv(/*intr=*/true);
> + break;
> + case EM_S390:
> + mask = __perf_reg_mask_s390(/*intr=*/true);
> + break;
> + case EM_386:
> + case EM_X86_64:
> + mask = __perf_reg_mask_x86(/*intr=*/true);
> + break;
> + default:
> + pr_debug("Unknown ELF machine %d, interrupt sampling register mask will be empty.\n",
> + e_machine);
> + break;
> + }
> +
> + return mask;
> }
>
> -uint64_t __weak arch__user_reg_mask(void)
> +uint64_t perf_user_reg_mask(uint16_t e_machine)
> {
> - return 0;
> + uint64_t mask = 0;
> +
> + switch (e_machine) {
> + case EM_ARM:
> + mask = __perf_reg_mask_arm(/*intr=*/false);
> + break;
> + case EM_AARCH64:
> + mask = __perf_reg_mask_arm64(/*intr=*/false);
> + break;
> + case EM_CSKY:
> + mask = __perf_reg_mask_csky(/*intr=*/false);
> + break;
> + case EM_LOONGARCH:
> + mask = __perf_reg_mask_loongarch(/*intr=*/false);
> + break;
> + case EM_MIPS:
> + mask = __perf_reg_mask_mips(/*intr=*/false);
> + break;
> + case EM_PPC:
> + case EM_PPC64:
> + mask = __perf_reg_mask_powerpc(/*intr=*/false);
> + break;
> + case EM_RISCV:
> + mask = __perf_reg_mask_riscv(/*intr=*/false);
> + break;
> + case EM_S390:
> + mask = __perf_reg_mask_s390(/*intr=*/false);
> + break;
> + case EM_386:
> + case EM_X86_64:
> + mask = __perf_reg_mask_x86(/*intr=*/false);
> + break;
> + default:
> + pr_debug("Unknown ELF machine %d, user sampling register mask will be empty.\n",
> + e_machine);
> + break;
> + }
> +
> + return mask;
> }
>
> const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags)
> diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
> index ed7c1b1358fa..2b27139acadb 100644
> --- a/tools/perf/util/perf_regs.h
> +++ b/tools/perf/util/perf_regs.h
> @@ -13,37 +13,55 @@ enum {
> };
>
> int arch_sdt_arg_parse_op(char *old_op, char **new_op);
> -uint64_t arch__intr_reg_mask(void);
> -uint64_t arch__user_reg_mask(void);
> +uint64_t perf_intr_reg_mask(uint16_t e_machine);
> +uint64_t perf_user_reg_mask(uint16_t e_machine);
>
> const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags);
> int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
> uint64_t perf_arch_reg_ip(uint16_t e_machine);
> uint64_t perf_arch_reg_sp(uint16_t e_machine);
> +
> +uint64_t __perf_reg_mask_arm64(bool intr);
> const char *__perf_reg_name_arm64(int id);
> uint64_t __perf_reg_ip_arm64(void);
> uint64_t __perf_reg_sp_arm64(void);
> +
> +uint64_t __perf_reg_mask_arm(bool intr);
> const char *__perf_reg_name_arm(int id);
> uint64_t __perf_reg_ip_arm(void);
> uint64_t __perf_reg_sp_arm(void);
> +
> +uint64_t __perf_reg_mask_csky(bool intr);
> const char *__perf_reg_name_csky(int id, uint32_t e_flags);
> uint64_t __perf_reg_ip_csky(void);
> uint64_t __perf_reg_sp_csky(void);
> +
> +uint64_t __perf_reg_mask_loongarch(bool intr);
> const char *__perf_reg_name_loongarch(int id);
> uint64_t __perf_reg_ip_loongarch(void);
> uint64_t __perf_reg_sp_loongarch(void);
> +
> +uint64_t __perf_reg_mask_mips(bool intr);
> const char *__perf_reg_name_mips(int id);
> uint64_t __perf_reg_ip_mips(void);
> uint64_t __perf_reg_sp_mips(void);
> +
> +uint64_t __perf_reg_mask_powerpc(bool intr);
> const char *__perf_reg_name_powerpc(int id);
> uint64_t __perf_reg_ip_powerpc(void);
> uint64_t __perf_reg_sp_powerpc(void);
> +
> +uint64_t __perf_reg_mask_riscv(bool intr);
> const char *__perf_reg_name_riscv(int id);
> uint64_t __perf_reg_ip_riscv(void);
> uint64_t __perf_reg_sp_riscv(void);
> +
> +uint64_t __perf_reg_mask_s390(bool intr);
> const char *__perf_reg_name_s390(int id);
> uint64_t __perf_reg_ip_s390(void);
> uint64_t __perf_reg_sp_s390(void);
> +
> +uint64_t __perf_reg_mask_x86(bool intr);
> const char *__perf_reg_name_x86(int id);
> uint64_t __perf_reg_ip_x86(void);
> uint64_t __perf_reg_sp_x86(void);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
2026-02-03 2:43 ` [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function Dapeng Mi
@ 2026-02-03 23:11 ` Ian Rogers
0 siblings, 0 replies; 11+ messages in thread
From: Ian Rogers @ 2026-02-03 23:11 UTC (permalink / raw)
To: Dapeng Mi
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Adrian Hunter, Alexander Shishkin, John Garry,
Will Deacon, James Clark, Mike Leach, Guo Ren, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-perf-users,
linux-arm-kernel, linux-csky, linux-riscv, linux-kernel,
Zide Chen, Falcon Thomas, Dapeng Mi, Xudong Hao
On Mon, Feb 2, 2026 at 6:48 PM Dapeng Mi <dapeng1.mi@linux.intel.com> wrote:
>
> In line with the previous patch, the __weak arch_sdt_arg_parse_op()
> function is removed. Architectural-specific implementations in the arch/
> directory are now converted into sub-functions within the
> util/perf-regs-arch/ directory. The perf_sdt_arg_parse_op() function
> will call these sub-functions based on the EM_HOST.
>
> This change enables cross-architecture calls to arch_sdt_arg_parse_op().
>
> No functional changes are intended.
>
> Suggested-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Thanks,
Ian
> ---
> tools/perf/arch/arm64/util/Build | 1 -
> tools/perf/arch/arm64/util/perf_regs.c | 105 --------
> tools/perf/arch/powerpc/util/Build | 1 -
> tools/perf/arch/powerpc/util/perf_regs.c | 125 ----------
> tools/perf/arch/x86/util/Build | 1 -
> tools/perf/arch/x86/util/perf_regs.c | 235 ------------------
> .../util/perf-regs-arch/perf_regs_aarch64.c | 86 +++++++
> .../util/perf-regs-arch/perf_regs_powerpc.c | 106 ++++++++
> .../perf/util/perf-regs-arch/perf_regs_x86.c | 221 ++++++++++++++++
> tools/perf/util/perf_regs.c | 25 +-
> tools/perf/util/perf_regs.h | 5 +-
> tools/perf/util/probe-file.c | 3 +-
> 12 files changed, 441 insertions(+), 473 deletions(-)
> delete mode 100644 tools/perf/arch/arm64/util/perf_regs.c
> delete mode 100644 tools/perf/arch/powerpc/util/perf_regs.c
> delete mode 100644 tools/perf/arch/x86/util/perf_regs.c
>
> diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
> index 0177af19cc00..bc12c35d06c8 100644
> --- a/tools/perf/arch/arm64/util/Build
> +++ b/tools/perf/arch/arm64/util/Build
> @@ -8,6 +8,5 @@ perf-util-y += header.o
> perf-util-y += hisi-ptt.o
> perf-util-y += machine.o
> perf-util-y += mem-events.o
> -perf-util-y += perf_regs.o
> perf-util-y += pmu.o
> perf-util-y += tsc.o
> diff --git a/tools/perf/arch/arm64/util/perf_regs.c b/tools/perf/arch/arm64/util/perf_regs.c
> deleted file mode 100644
> index 47f58eaba032..000000000000
> --- a/tools/perf/arch/arm64/util/perf_regs.c
> +++ /dev/null
> @@ -1,105 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include <errno.h>
> -#include <regex.h>
> -#include <string.h>
> -#include <sys/auxv.h>
> -#include <linux/kernel.h>
> -#include <linux/zalloc.h>
> -
> -#include "perf_regs.h"
> -#include "../../../perf-sys.h"
> -#include "../../../util/debug.h"
> -#include "../../../util/event.h"
> -#include "../../../util/perf_regs.h"
> -
> -#define SMPL_REG_MASK(b) (1ULL << (b))
> -
> -#ifndef HWCAP_SVE
> -#define HWCAP_SVE (1 << 22)
> -#endif
> -
> -/* %xNUM */
> -#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
> -
> -/* [sp], [sp, NUM] */
> -#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
> -
> -static regex_t sdt_op_regex1, sdt_op_regex2;
> -
> -static int sdt_init_op_regex(void)
> -{
> - static int initialized;
> - int ret = 0;
> -
> - if (initialized)
> - return 0;
> -
> - ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
> - if (ret)
> - goto error;
> -
> - ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
> - if (ret)
> - goto free_regex1;
> -
> - initialized = 1;
> - return 0;
> -
> -free_regex1:
> - regfree(&sdt_op_regex1);
> -error:
> - pr_debug4("Regex compilation error.\n");
> - return ret;
> -}
> -
> -/*
> - * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
> - * support these two formats.
> - */
> -int arch_sdt_arg_parse_op(char *old_op, char **new_op)
> -{
> - int ret, new_len;
> - regmatch_t rm[5];
> -
> - ret = sdt_init_op_regex();
> - if (ret < 0)
> - return ret;
> -
> - if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
> - /* Extract xNUM */
> - new_len = 2; /* % NULL */
> - new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
> -
> - *new_op = zalloc(new_len);
> - if (!*new_op)
> - return -ENOMEM;
> -
> - scnprintf(*new_op, new_len, "%%%.*s",
> - (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
> - } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
> - /* [sp], [sp, NUM] or [sp,NUM] */
> - new_len = 7; /* + ( % s p ) NULL */
> -
> - /* If the argument is [sp], need to fill offset '0' */
> - if (rm[2].rm_so == -1)
> - new_len += 1;
> - else
> - new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> -
> - *new_op = zalloc(new_len);
> - if (!*new_op)
> - return -ENOMEM;
> -
> - if (rm[2].rm_so == -1)
> - scnprintf(*new_op, new_len, "+0(%%sp)");
> - else
> - scnprintf(*new_op, new_len, "+%.*s(%%sp)",
> - (int)(rm[2].rm_eo - rm[2].rm_so),
> - old_op + rm[2].rm_so);
> - } else {
> - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> - return SDT_ARG_SKIP;
> - }
> -
> - return SDT_ARG_VALID;
> -}
> diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
> index 5fd28ec713a4..43c3e7c450a3 100644
> --- a/tools/perf/arch/powerpc/util/Build
> +++ b/tools/perf/arch/powerpc/util/Build
> @@ -1,6 +1,5 @@
> perf-util-y += header.o
> perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> -perf-util-y += perf_regs.o
> perf-util-y += mem-events.o
> perf-util-y += pmu.o
> perf-util-y += sym-handling.o
> diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
> deleted file mode 100644
> index 93f929fc32e3..000000000000
> --- a/tools/perf/arch/powerpc/util/perf_regs.c
> +++ /dev/null
> @@ -1,125 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include <errno.h>
> -#include <string.h>
> -#include <regex.h>
> -#include <linux/zalloc.h>
> -
> -#include "perf_regs.h"
> -#include "../../../util/perf_regs.h"
> -#include "../../../util/debug.h"
> -#include "../../../util/event.h"
> -#include "../../../util/header.h"
> -#include "../../../perf-sys.h"
> -#include "utils_header.h"
> -
> -#include <linux/kernel.h>
> -
> -#define PVR_POWER9 0x004E
> -#define PVR_POWER10 0x0080
> -#define PVR_POWER11 0x0082
> -
> -/* REG or %rREG */
> -#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
> -
> -/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
> -#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
> -
> -static regex_t sdt_op_regex1, sdt_op_regex2;
> -
> -static int sdt_init_op_regex(void)
> -{
> - static int initialized;
> - int ret = 0;
> -
> - if (initialized)
> - return 0;
> -
> - ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
> - if (ret)
> - goto error;
> -
> - ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
> - if (ret)
> - goto free_regex1;
> -
> - initialized = 1;
> - return 0;
> -
> -free_regex1:
> - regfree(&sdt_op_regex1);
> -error:
> - pr_debug4("Regex compilation error.\n");
> - return ret;
> -}
> -
> -/*
> - * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
> - * Possible variants of OP are:
> - * Format Example
> - * -------------------------
> - * NUM(REG) 48(18)
> - * -NUM(REG) -48(18)
> - * NUM(%rREG) 48(%r18)
> - * -NUM(%rREG) -48(%r18)
> - * REG 18
> - * %rREG %r18
> - * iNUM i0
> - * i-NUM i-1
> - *
> - * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
> - * and REG form with -mno-regnames. Here REG is general purpose register,
> - * which is in 0 to 31 range.
> - */
> -int arch_sdt_arg_parse_op(char *old_op, char **new_op)
> -{
> - int ret, new_len;
> - regmatch_t rm[5];
> - char prefix;
> -
> - /* Constant argument. Uprobe does not support it */
> - if (old_op[0] == 'i') {
> - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> - return SDT_ARG_SKIP;
> - }
> -
> - ret = sdt_init_op_regex();
> - if (ret < 0)
> - return ret;
> -
> - if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
> - /* REG or %rREG --> %gprREG */
> -
> - new_len = 5; /* % g p r NULL */
> - new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> -
> - *new_op = zalloc(new_len);
> - if (!*new_op)
> - return -ENOMEM;
> -
> - scnprintf(*new_op, new_len, "%%gpr%.*s",
> - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
> - } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
> - /*
> - * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
> - * +/-NUM(%gprREG)
> - */
> - prefix = (rm[1].rm_so == -1) ? '+' : '-';
> -
> - new_len = 8; /* +/- ( % g p r ) NULL */
> - new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> - new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
> -
> - *new_op = zalloc(new_len);
> - if (!*new_op)
> - return -ENOMEM;
> -
> - scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
> - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
> - (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
> - } else {
> - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> - return SDT_ARG_SKIP;
> - }
> -
> - return SDT_ARG_VALID;
> -}
> diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
> index 76127eefde8b..9713fe4d8467 100644
> --- a/tools/perf/arch/x86/util/Build
> +++ b/tools/perf/arch/x86/util/Build
> @@ -2,7 +2,6 @@ perf-util-y += header.o
> perf-util-y += tsc.o
> perf-util-y += pmu.o
> perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> -perf-util-y += perf_regs.o
> perf-util-y += topdown.o
> perf-util-y += machine.o
> perf-util-y += event.o
> diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
> deleted file mode 100644
> index 41141cebe226..000000000000
> --- a/tools/perf/arch/x86/util/perf_regs.c
> +++ /dev/null
> @@ -1,235 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include <errno.h>
> -#include <string.h>
> -#include <regex.h>
> -#include <linux/kernel.h>
> -#include <linux/zalloc.h>
> -
> -#include "perf_regs.h"
> -#include "../../../perf-sys.h"
> -#include "../../../util/perf_regs.h"
> -#include "../../../util/debug.h"
> -#include "../../../util/event.h"
> -#include "../../../util/pmu.h"
> -#include "../../../util/pmus.h"
> -
> -struct sdt_name_reg {
> - const char *sdt_name;
> - const char *uprobe_name;
> -};
> -#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
> -#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
> -
> -static const struct sdt_name_reg sdt_reg_tbl[] = {
> - SDT_NAME_REG(eax, ax),
> - SDT_NAME_REG(rax, ax),
> - SDT_NAME_REG(al, ax),
> - SDT_NAME_REG(ah, ax),
> - SDT_NAME_REG(ebx, bx),
> - SDT_NAME_REG(rbx, bx),
> - SDT_NAME_REG(bl, bx),
> - SDT_NAME_REG(bh, bx),
> - SDT_NAME_REG(ecx, cx),
> - SDT_NAME_REG(rcx, cx),
> - SDT_NAME_REG(cl, cx),
> - SDT_NAME_REG(ch, cx),
> - SDT_NAME_REG(edx, dx),
> - SDT_NAME_REG(rdx, dx),
> - SDT_NAME_REG(dl, dx),
> - SDT_NAME_REG(dh, dx),
> - SDT_NAME_REG(esi, si),
> - SDT_NAME_REG(rsi, si),
> - SDT_NAME_REG(sil, si),
> - SDT_NAME_REG(edi, di),
> - SDT_NAME_REG(rdi, di),
> - SDT_NAME_REG(dil, di),
> - SDT_NAME_REG(ebp, bp),
> - SDT_NAME_REG(rbp, bp),
> - SDT_NAME_REG(bpl, bp),
> - SDT_NAME_REG(rsp, sp),
> - SDT_NAME_REG(esp, sp),
> - SDT_NAME_REG(spl, sp),
> -
> - /* rNN registers */
> - SDT_NAME_REG(r8b, r8),
> - SDT_NAME_REG(r8w, r8),
> - SDT_NAME_REG(r8d, r8),
> - SDT_NAME_REG(r9b, r9),
> - SDT_NAME_REG(r9w, r9),
> - SDT_NAME_REG(r9d, r9),
> - SDT_NAME_REG(r10b, r10),
> - SDT_NAME_REG(r10w, r10),
> - SDT_NAME_REG(r10d, r10),
> - SDT_NAME_REG(r11b, r11),
> - SDT_NAME_REG(r11w, r11),
> - SDT_NAME_REG(r11d, r11),
> - SDT_NAME_REG(r12b, r12),
> - SDT_NAME_REG(r12w, r12),
> - SDT_NAME_REG(r12d, r12),
> - SDT_NAME_REG(r13b, r13),
> - SDT_NAME_REG(r13w, r13),
> - SDT_NAME_REG(r13d, r13),
> - SDT_NAME_REG(r14b, r14),
> - SDT_NAME_REG(r14w, r14),
> - SDT_NAME_REG(r14d, r14),
> - SDT_NAME_REG(r15b, r15),
> - SDT_NAME_REG(r15w, r15),
> - SDT_NAME_REG(r15d, r15),
> - SDT_NAME_REG_END,
> -};
> -
> -/*
> - * Perf only supports OP which is in +/-NUM(REG) form.
> - * Here plus-minus sign, NUM and parenthesis are optional,
> - * only REG is mandatory.
> - *
> - * SDT events also supports indirect addressing mode with a
> - * symbol as offset, scaled mode and constants in OP. But
> - * perf does not support them yet. Below are few examples.
> - *
> - * OP with scaled mode:
> - * (%rax,%rsi,8)
> - * 10(%ras,%rsi,8)
> - *
> - * OP with indirect addressing mode:
> - * check_action(%rip)
> - * mp_+52(%rip)
> - * 44+mp_(%rip)
> - *
> - * OP with constant values:
> - * $0
> - * $123
> - * $-1
> - */
> -#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
> -
> -static regex_t sdt_op_regex;
> -
> -static int sdt_init_op_regex(void)
> -{
> - static int initialized;
> - int ret = 0;
> -
> - if (initialized)
> - return 0;
> -
> - ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
> - if (ret < 0) {
> - pr_debug4("Regex compilation error.\n");
> - return ret;
> - }
> -
> - initialized = 1;
> - return 0;
> -}
> -
> -/*
> - * Max x86 register name length is 5(ex: %r15d). So, 6th char
> - * should always contain NULL. This helps to find register name
> - * length using strlen, instead of maintaining one more variable.
> - */
> -#define SDT_REG_NAME_SIZE 6
> -
> -/*
> - * The uprobe parser does not support all gas register names;
> - * so, we have to replace them (ex. for x86_64: %rax -> %ax).
> - * Note: If register does not require renaming, just copy
> - * paste as it is, but don't leave it empty.
> - */
> -static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
> -{
> - int i = 0;
> -
> - for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
> - if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
> - strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
> - return;
> - }
> - }
> -
> - strncpy(uprobe_reg, sdt_reg, sdt_len);
> -}
> -
> -int arch_sdt_arg_parse_op(char *old_op, char **new_op)
> -{
> - char new_reg[SDT_REG_NAME_SIZE] = {0};
> - int new_len = 0, ret;
> - /*
> - * rm[0]: +/-NUM(REG)
> - * rm[1]: +/-
> - * rm[2]: NUM
> - * rm[3]: (
> - * rm[4]: REG
> - * rm[5]: )
> - */
> - regmatch_t rm[6];
> - /*
> - * Max prefix length is 2 as it may contains sign(+/-)
> - * and displacement 0 (Both sign and displacement 0 are
> - * optional so it may be empty). Use one more character
> - * to hold last NULL so that strlen can be used to find
> - * prefix length, instead of maintaining one more variable.
> - */
> - char prefix[3] = {0};
> -
> - ret = sdt_init_op_regex();
> - if (ret < 0)
> - return ret;
> -
> - /*
> - * If unsupported OR does not match with regex OR
> - * register name too long, skip it.
> - */
> - if (strchr(old_op, ',') || strchr(old_op, '$') ||
> - regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
> - rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
> - pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> - return SDT_ARG_SKIP;
> - }
> -
> - /*
> - * Prepare prefix.
> - * If SDT OP has parenthesis but does not provide
> - * displacement, add 0 for displacement.
> - * SDT Uprobe Prefix
> - * -----------------------------
> - * +24(%rdi) +24(%di) +
> - * 24(%rdi) +24(%di) +
> - * %rdi %di
> - * (%rdi) +0(%di) +0
> - * -80(%rbx) -80(%bx) -
> - */
> - if (rm[3].rm_so != rm[3].rm_eo) {
> - if (rm[1].rm_so != rm[1].rm_eo)
> - prefix[0] = *(old_op + rm[1].rm_so);
> - else if (rm[2].rm_so != rm[2].rm_eo)
> - prefix[0] = '+';
> - else
> - scnprintf(prefix, sizeof(prefix), "+0");
> - }
> -
> - /* Rename register */
> - sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
> - new_reg);
> -
> - /* Prepare final OP which should be valid for uprobe_events */
> - new_len = strlen(prefix) +
> - (rm[2].rm_eo - rm[2].rm_so) +
> - (rm[3].rm_eo - rm[3].rm_so) +
> - strlen(new_reg) +
> - (rm[5].rm_eo - rm[5].rm_so) +
> - 1; /* NULL */
> -
> - *new_op = zalloc(new_len);
> - if (!*new_op)
> - return -ENOMEM;
> -
> - scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
> - strlen(prefix), prefix,
> - (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
> - (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
> - strlen(new_reg), new_reg,
> - (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
> -
> - return SDT_ARG_VALID;
> -}
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> index 666874f625b6..6833d34dcbfd 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
> @@ -18,6 +18,92 @@
> #define HWCAP_SVE (1 << 22)
> #endif
>
> +/* %xNUM */
> +#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
> +
> +/* [sp], [sp, NUM] */
> +#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
> +
> +static regex_t sdt_op_regex1, sdt_op_regex2;
> +
> +static int sdt_init_op_regex(void)
> +{
> + static int initialized;
> + int ret = 0;
> +
> + if (initialized)
> + return 0;
> +
> + ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
> + if (ret)
> + goto error;
> +
> + ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
> + if (ret)
> + goto free_regex1;
> +
> + initialized = 1;
> + return 0;
> +
> +free_regex1:
> + regfree(&sdt_op_regex1);
> +error:
> + pr_debug4("Regex compilation error.\n");
> + return ret;
> +}
> +
> +/*
> + * SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
> + * support these two formats.
> + */
> +int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op)
> +{
> + int ret, new_len;
> + regmatch_t rm[5];
> +
> + ret = sdt_init_op_regex();
> + if (ret < 0)
> + return ret;
> +
> + if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
> + /* Extract xNUM */
> + new_len = 2; /* % NULL */
> + new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
> +
> + *new_op = zalloc(new_len);
> + if (!*new_op)
> + return -ENOMEM;
> +
> + scnprintf(*new_op, new_len, "%%%.*s",
> + (int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
> + } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
> + /* [sp], [sp, NUM] or [sp,NUM] */
> + new_len = 7; /* + ( % s p ) NULL */
> +
> + /* If the argument is [sp], need to fill offset '0' */
> + if (rm[2].rm_so == -1)
> + new_len += 1;
> + else
> + new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> +
> + *new_op = zalloc(new_len);
> + if (!*new_op)
> + return -ENOMEM;
> +
> + if (rm[2].rm_so == -1)
> + scnprintf(*new_op, new_len, "+0(%%sp)");
> + else
> + scnprintf(*new_op, new_len, "+%.*s(%%sp)",
> + (int)(rm[2].rm_eo - rm[2].rm_so),
> + old_op + rm[2].rm_so);
> + } else {
> + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> + return SDT_ARG_SKIP;
> + }
> +
> + return SDT_ARG_VALID;
> +}
> +
> uint64_t __perf_reg_mask_arm64(bool intr)
> {
> struct perf_event_attr attr = {
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> index f0a547ad809b..217a001ccd2e 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
> @@ -19,6 +19,112 @@
> #define PVR_POWER10 0x0080
> #define PVR_POWER11 0x0082
>
> +/* REG or %rREG */
> +#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
> +
> +/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
> +#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
> +
> +static regex_t sdt_op_regex1, sdt_op_regex2;
> +
> +static int sdt_init_op_regex(void)
> +{
> + static int initialized;
> + int ret = 0;
> +
> + if (initialized)
> + return 0;
> +
> + ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
> + if (ret)
> + goto error;
> +
> + ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
> + if (ret)
> + goto free_regex1;
> +
> + initialized = 1;
> + return 0;
> +
> +free_regex1:
> + regfree(&sdt_op_regex1);
> +error:
> + pr_debug4("Regex compilation error.\n");
> + return ret;
> +}
> +
> +/*
> + * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
> + * Possible variants of OP are:
> + * Format Example
> + * -------------------------
> + * NUM(REG) 48(18)
> + * -NUM(REG) -48(18)
> + * NUM(%rREG) 48(%r18)
> + * -NUM(%rREG) -48(%r18)
> + * REG 18
> + * %rREG %r18
> + * iNUM i0
> + * i-NUM i-1
> + *
> + * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
> + * and REG form with -mno-regnames. Here REG is general purpose register,
> + * which is in 0 to 31 range.
> + */
> +int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op)
> +{
> + int ret, new_len;
> + regmatch_t rm[5];
> + char prefix;
> +
> + /* Constant argument. Uprobe does not support it */
> + if (old_op[0] == 'i') {
> + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> + return SDT_ARG_SKIP;
> + }
> +
> + ret = sdt_init_op_regex();
> + if (ret < 0)
> + return ret;
> +
> + if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
> + /* REG or %rREG --> %gprREG */
> +
> + new_len = 5; /* % g p r NULL */
> + new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> +
> + *new_op = zalloc(new_len);
> + if (!*new_op)
> + return -ENOMEM;
> +
> + scnprintf(*new_op, new_len, "%%gpr%.*s",
> + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
> + } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
> + /*
> + * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
> + * +/-NUM(%gprREG)
> + */
> + prefix = (rm[1].rm_so == -1) ? '+' : '-';
> +
> + new_len = 8; /* +/- ( % g p r ) NULL */
> + new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
> + new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
> +
> + *new_op = zalloc(new_len);
> + if (!*new_op)
> + return -ENOMEM;
> +
> + scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
> + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
> + (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
> + } else {
> + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> + return SDT_ARG_SKIP;
> + }
> +
> + return SDT_ARG_VALID;
> +}
> +
> /*
> * mfspr is a POWERPC specific instruction, ensure it's only
> * built and called on POWERPC by guarding with __powerpc64__
> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_x86.c b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> index d573f9a9ca46..b6d20522b4e8 100644
> --- a/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
> @@ -14,6 +14,227 @@
> #include "../../perf-sys.h"
> #include "../../arch/x86/include/perf_regs.h"
>
> +struct sdt_name_reg {
> + const char *sdt_name;
> + const char *uprobe_name;
> +};
> +#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
> +#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
> +
> +static const struct sdt_name_reg sdt_reg_tbl[] = {
> + SDT_NAME_REG(eax, ax),
> + SDT_NAME_REG(rax, ax),
> + SDT_NAME_REG(al, ax),
> + SDT_NAME_REG(ah, ax),
> + SDT_NAME_REG(ebx, bx),
> + SDT_NAME_REG(rbx, bx),
> + SDT_NAME_REG(bl, bx),
> + SDT_NAME_REG(bh, bx),
> + SDT_NAME_REG(ecx, cx),
> + SDT_NAME_REG(rcx, cx),
> + SDT_NAME_REG(cl, cx),
> + SDT_NAME_REG(ch, cx),
> + SDT_NAME_REG(edx, dx),
> + SDT_NAME_REG(rdx, dx),
> + SDT_NAME_REG(dl, dx),
> + SDT_NAME_REG(dh, dx),
> + SDT_NAME_REG(esi, si),
> + SDT_NAME_REG(rsi, si),
> + SDT_NAME_REG(sil, si),
> + SDT_NAME_REG(edi, di),
> + SDT_NAME_REG(rdi, di),
> + SDT_NAME_REG(dil, di),
> + SDT_NAME_REG(ebp, bp),
> + SDT_NAME_REG(rbp, bp),
> + SDT_NAME_REG(bpl, bp),
> + SDT_NAME_REG(rsp, sp),
> + SDT_NAME_REG(esp, sp),
> + SDT_NAME_REG(spl, sp),
> +
> + /* rNN registers */
> + SDT_NAME_REG(r8b, r8),
> + SDT_NAME_REG(r8w, r8),
> + SDT_NAME_REG(r8d, r8),
> + SDT_NAME_REG(r9b, r9),
> + SDT_NAME_REG(r9w, r9),
> + SDT_NAME_REG(r9d, r9),
> + SDT_NAME_REG(r10b, r10),
> + SDT_NAME_REG(r10w, r10),
> + SDT_NAME_REG(r10d, r10),
> + SDT_NAME_REG(r11b, r11),
> + SDT_NAME_REG(r11w, r11),
> + SDT_NAME_REG(r11d, r11),
> + SDT_NAME_REG(r12b, r12),
> + SDT_NAME_REG(r12w, r12),
> + SDT_NAME_REG(r12d, r12),
> + SDT_NAME_REG(r13b, r13),
> + SDT_NAME_REG(r13w, r13),
> + SDT_NAME_REG(r13d, r13),
> + SDT_NAME_REG(r14b, r14),
> + SDT_NAME_REG(r14w, r14),
> + SDT_NAME_REG(r14d, r14),
> + SDT_NAME_REG(r15b, r15),
> + SDT_NAME_REG(r15w, r15),
> + SDT_NAME_REG(r15d, r15),
> + SDT_NAME_REG_END,
> +};
> +
> +/*
> + * Perf only supports OP which is in +/-NUM(REG) form.
> + * Here plus-minus sign, NUM and parenthesis are optional,
> + * only REG is mandatory.
> + *
> + * SDT events also supports indirect addressing mode with a
> + * symbol as offset, scaled mode and constants in OP. But
> + * perf does not support them yet. Below are few examples.
> + *
> + * OP with scaled mode:
> + * (%rax,%rsi,8)
> + * 10(%ras,%rsi,8)
> + *
> + * OP with indirect addressing mode:
> + * check_action(%rip)
> + * mp_+52(%rip)
> + * 44+mp_(%rip)
> + *
> + * OP with constant values:
> + * $0
> + * $123
> + * $-1
> + */
> +#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
> +
> +static regex_t sdt_op_regex;
> +
> +static int sdt_init_op_regex(void)
> +{
> + static int initialized;
> + int ret = 0;
> +
> + if (initialized)
> + return 0;
> +
> + ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
> + if (ret < 0) {
> + pr_debug4("Regex compilation error.\n");
> + return ret;
> + }
> +
> + initialized = 1;
> + return 0;
> +}
> +
> +/*
> + * Max x86 register name length is 5(ex: %r15d). So, 6th char
> + * should always contain NULL. This helps to find register name
> + * length using strlen, instead of maintaining one more variable.
> + */
> +#define SDT_REG_NAME_SIZE 6
> +
> +/*
> + * The uprobe parser does not support all gas register names;
> + * so, we have to replace them (ex. for x86_64: %rax -> %ax).
> + * Note: If register does not require renaming, just copy
> + * paste as it is, but don't leave it empty.
> + */
> +static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
> +{
> + int i = 0;
> +
> + for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
> + if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
> + strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
> + return;
> + }
> + }
> +
> + strncpy(uprobe_reg, sdt_reg, sdt_len);
> +}
> +
> +int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op)
> +{
> + char new_reg[SDT_REG_NAME_SIZE] = {0};
> + int new_len = 0, ret;
> + /*
> + * rm[0]: +/-NUM(REG)
> + * rm[1]: +/-
> + * rm[2]: NUM
> + * rm[3]: (
> + * rm[4]: REG
> + * rm[5]: )
> + */
> + regmatch_t rm[6];
> + /*
> + * Max prefix length is 2 as it may contains sign(+/-)
> + * and displacement 0 (Both sign and displacement 0 are
> + * optional so it may be empty). Use one more character
> + * to hold last NULL so that strlen can be used to find
> + * prefix length, instead of maintaining one more variable.
> + */
> + char prefix[3] = {0};
> +
> + ret = sdt_init_op_regex();
> + if (ret < 0)
> + return ret;
> +
> + /*
> + * If unsupported OR does not match with regex OR
> + * register name too long, skip it.
> + */
> + if (strchr(old_op, ',') || strchr(old_op, '$') ||
> + regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
> + rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
> + pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
> + return SDT_ARG_SKIP;
> + }
> +
> + /*
> + * Prepare prefix.
> + * If SDT OP has parenthesis but does not provide
> + * displacement, add 0 for displacement.
> + * SDT Uprobe Prefix
> + * -----------------------------
> + * +24(%rdi) +24(%di) +
> + * 24(%rdi) +24(%di) +
> + * %rdi %di
> + * (%rdi) +0(%di) +0
> + * -80(%rbx) -80(%bx) -
> + */
> + if (rm[3].rm_so != rm[3].rm_eo) {
> + if (rm[1].rm_so != rm[1].rm_eo)
> + prefix[0] = *(old_op + rm[1].rm_so);
> + else if (rm[2].rm_so != rm[2].rm_eo)
> + prefix[0] = '+';
> + else
> + scnprintf(prefix, sizeof(prefix), "+0");
> + }
> +
> + /* Rename register */
> + sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
> + new_reg);
> +
> + /* Prepare final OP which should be valid for uprobe_events */
> + new_len = strlen(prefix) +
> + (rm[2].rm_eo - rm[2].rm_so) +
> + (rm[3].rm_eo - rm[3].rm_so) +
> + strlen(new_reg) +
> + (rm[5].rm_eo - rm[5].rm_so) +
> + 1; /* NULL */
> +
> + *new_op = zalloc(new_len);
> + if (!*new_op)
> + return -ENOMEM;
> +
> + scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
> + strlen(prefix), prefix,
> + (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
> + (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
> + strlen(new_reg), new_reg,
> + (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
> +
> + return SDT_ARG_VALID;
> +}
> +
> uint64_t __perf_reg_mask_x86(bool intr)
> {
> struct perf_event_attr attr = {
> diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
> index 4d9a286a0e56..5b8f34beb24e 100644
> --- a/tools/perf/util/perf_regs.c
> +++ b/tools/perf/util/perf_regs.c
> @@ -7,10 +7,29 @@
> #include "util/sample.h"
> #include "debug.h"
>
> -int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
> - char **new_op __maybe_unused)
> +int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op)
> {
> - return SDT_ARG_SKIP;
> + int ret = SDT_ARG_SKIP;
> +
> + switch (e_machine) {
> + case EM_AARCH64:
> + ret = __perf_sdt_arg_parse_op_arm64(old_op, new_op);
> + break;
> + case EM_PPC:
> + case EM_PPC64:
> + ret = __perf_sdt_arg_parse_op_powerpc(old_op, new_op);
> + break;
> + case EM_386:
> + case EM_X86_64:
> + ret = __perf_sdt_arg_parse_op_x86(old_op, new_op);
> + break;
> + default:
> + pr_debug("Unknown ELF machine %d, standard arguments parse will be skipped.\n",
> + e_machine);
> + break;
> + }
> +
> + return ret;
> }
>
> uint64_t perf_intr_reg_mask(uint16_t e_machine)
> diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
> index 2b27139acadb..7c04700bf837 100644
> --- a/tools/perf/util/perf_regs.h
> +++ b/tools/perf/util/perf_regs.h
> @@ -12,7 +12,7 @@ enum {
> SDT_ARG_SKIP,
> };
>
> -int arch_sdt_arg_parse_op(char *old_op, char **new_op);
> +int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op);
> uint64_t perf_intr_reg_mask(uint16_t e_machine);
> uint64_t perf_user_reg_mask(uint16_t e_machine);
>
> @@ -21,6 +21,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
> uint64_t perf_arch_reg_ip(uint16_t e_machine);
> uint64_t perf_arch_reg_sp(uint16_t e_machine);
>
> +int __perf_sdt_arg_parse_op_arm64(char *old_op, char **new_op);
> uint64_t __perf_reg_mask_arm64(bool intr);
> const char *__perf_reg_name_arm64(int id);
> uint64_t __perf_reg_ip_arm64(void);
> @@ -46,6 +47,7 @@ const char *__perf_reg_name_mips(int id);
> uint64_t __perf_reg_ip_mips(void);
> uint64_t __perf_reg_sp_mips(void);
>
> +int __perf_sdt_arg_parse_op_powerpc(char *old_op, char **new_op);
> uint64_t __perf_reg_mask_powerpc(bool intr);
> const char *__perf_reg_name_powerpc(int id);
> uint64_t __perf_reg_ip_powerpc(void);
> @@ -61,6 +63,7 @@ const char *__perf_reg_name_s390(int id);
> uint64_t __perf_reg_ip_s390(void);
> uint64_t __perf_reg_sp_s390(void);
>
> +int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op);
> uint64_t __perf_reg_mask_x86(bool intr);
> const char *__perf_reg_name_x86(int id);
> uint64_t __perf_reg_ip_x86(void);
> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
> index 5069fb61f48c..f78c3bc3d601 100644
> --- a/tools/perf/util/probe-file.c
> +++ b/tools/perf/util/probe-file.c
> @@ -28,6 +28,7 @@
> #include "session.h"
> #include "perf_regs.h"
> #include "string2.h"
> +#include "dwarf-regs.h"
>
> /* 4096 - 2 ('\n' + '\0') */
> #define MAX_CMDLEN 4094
> @@ -784,7 +785,7 @@ static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
> op = desc;
> }
>
> - ret = arch_sdt_arg_parse_op(op, &new_op);
> + ret = perf_sdt_arg_parse_op(EM_HOST, op, &new_op);
>
> if (ret < 0)
> goto error;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
` (3 preceding siblings ...)
2026-02-03 2:43 ` [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function Dapeng Mi
@ 2026-02-06 15:17 ` Arnaldo Carvalho de Melo
2026-02-09 0:46 ` Mi, Dapeng
2026-03-24 6:07 ` patchwork-bot+linux-riscv
5 siblings, 1 reply; 11+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-02-06 15:17 UTC (permalink / raw)
To: Dapeng Mi
Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Ian Rogers,
Adrian Hunter, Alexander Shishkin, John Garry, Will Deacon,
James Clark, Mike Leach, Guo Ren, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, linux-perf-users, linux-arm-kernel,
linux-csky, linux-riscv, linux-kernel, Zide Chen, Falcon Thomas,
Dapeng Mi, Xudong Hao
On Tue, Feb 03, 2026 at 10:43:52AM +0800, Dapeng Mi wrote:
> Changes:
> v2 -> v3:
> * Fix the abort issue for "-I" or "--user-regs" options. (Patch 1/4)
> * Address Ian's comments.
Fixed up somme fuzz with powerpc, x86, riscv and s390 Build files wrt
removing perf_regs.o
Thanks, applied to perf-tools-next,
- Arnaldo
> v1 -> v2:
> * Fixing "PERF_REG_EXTENDED_MASK" redefinition building error by
> changing the "asm/perf_regs.h" header path to relative UAPI path.
> (Patch 1/3)
> * Spliting xxx_reg_mask() and xxx_sdt_arg_parse_op() conversion into 2
> patches.
>
> This patch-set remove the below three architecture specific __weak
> functions and converted them into the general architecture specific
> functions which are dispatched base on "em_machine".
>
> uint64_t arch__intr_reg_mask(void);
> uint64_t arch__user_reg_mask(void);
> int arch_sdt_arg_parse_op(char *old_op, char **new_op);
>
> The advantage of this conversion is that these architectural functions
> can be called even for a different architecture with host instead of
> only called on the host architecture.
>
> Although the converted functions shown below can be called on any
> architecture, currently they are still only called for the host
> architecture (EM_HOST).
>
> int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op);
> uint64_t perf_intr_reg_mask(uint16_t e_machine);
> uint64_t perf_user_reg_mask(uint16_t e_machine);
>
> Tests:
> * This patch-set is only tested on x86 platforms. No issues are found
> for both intr-regs and user-regs options.
> * Tests on other architectures are welcomed and appreciated.
>
> History:
> v1: https://lore.kernel.org/all/20260123090938.2222960-1-dapeng1.mi@linux.intel.com/
> v2: https://lore.kernel.org/all/20260127070259.2720468-1-dapeng1.mi@linux.intel.com/
>
> Dapeng Mi (4):
> perf regs: Fix abort for "-I" or "--user-regs" options
> perf arch: Update arch headers to use relative UAPI paths
> perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
> perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
>
> tools/perf/arch/arm/include/perf_regs.h | 2 +-
> tools/perf/arch/arm/util/Build | 2 -
> tools/perf/arch/arm/util/perf_regs.c | 13 -
> tools/perf/arch/arm64/include/perf_regs.h | 2 +-
> tools/perf/arch/arm64/util/Build | 1 -
> tools/perf/arch/arm64/util/perf_regs.c | 141 ---------
> tools/perf/arch/csky/Build | 1 -
> tools/perf/arch/csky/include/perf_regs.h | 2 +-
> tools/perf/arch/csky/util/Build | 1 -
> tools/perf/arch/csky/util/perf_regs.c | 13 -
> tools/perf/arch/loongarch/include/perf_regs.h | 2 +-
> tools/perf/arch/loongarch/util/Build | 1 -
> tools/perf/arch/loongarch/util/perf_regs.c | 13 -
> tools/perf/arch/mips/include/perf_regs.h | 2 +-
> tools/perf/arch/mips/util/Build | 1 -
> tools/perf/arch/mips/util/perf_regs.c | 13 -
> tools/perf/arch/powerpc/include/perf_regs.h | 2 +-
> tools/perf/arch/powerpc/util/Build | 1 -
> tools/perf/arch/powerpc/util/perf_regs.c | 172 -----------
> tools/perf/arch/riscv/include/perf_regs.h | 9 +-
> tools/perf/arch/riscv/util/Build | 1 -
> tools/perf/arch/riscv/util/perf_regs.c | 13 -
> tools/perf/arch/s390/include/perf_regs.h | 2 +-
> tools/perf/arch/s390/util/Build | 1 -
> tools/perf/arch/s390/util/perf_regs.c | 13 -
> tools/perf/arch/x86/include/perf_regs.h | 2 +-
> tools/perf/arch/x86/util/Build | 1 -
> tools/perf/arch/x86/util/perf_regs.c | 283 ------------------
> tools/perf/util/evsel.c | 4 +-
> tools/perf/util/parse-regs-options.c | 13 +-
> .../util/perf-regs-arch/perf_regs_aarch64.c | 139 ++++++++-
> .../perf/util/perf-regs-arch/perf_regs_arm.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_csky.c | 7 +-
> .../util/perf-regs-arch/perf_regs_loongarch.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_mips.c | 7 +-
> .../util/perf-regs-arch/perf_regs_powerpc.c | 183 ++++++++++-
> .../util/perf-regs-arch/perf_regs_riscv.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_s390.c | 7 +-
> .../perf/util/perf-regs-arch/perf_regs_x86.c | 281 ++++++++++++++++-
> tools/perf/util/perf_regs.c | 109 ++++++-
> tools/perf/util/perf_regs.h | 27 +-
> tools/perf/util/probe-file.c | 3 +-
> 42 files changed, 787 insertions(+), 724 deletions(-)
> delete mode 100644 tools/perf/arch/arm/util/perf_regs.c
> delete mode 100644 tools/perf/arch/arm64/util/perf_regs.c
> delete mode 100644 tools/perf/arch/csky/Build
> delete mode 100644 tools/perf/arch/csky/util/Build
> delete mode 100644 tools/perf/arch/csky/util/perf_regs.c
> delete mode 100644 tools/perf/arch/loongarch/util/perf_regs.c
> delete mode 100644 tools/perf/arch/mips/util/perf_regs.c
> delete mode 100644 tools/perf/arch/powerpc/util/perf_regs.c
> delete mode 100644 tools/perf/arch/riscv/util/perf_regs.c
> delete mode 100644 tools/perf/arch/s390/util/perf_regs.c
> delete mode 100644 tools/perf/arch/x86/util/perf_regs.c
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization
2026-02-06 15:17 ` [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Arnaldo Carvalho de Melo
@ 2026-02-09 0:46 ` Mi, Dapeng
0 siblings, 0 replies; 11+ messages in thread
From: Mi, Dapeng @ 2026-02-09 0:46 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Ian Rogers,
Adrian Hunter, Alexander Shishkin, John Garry, Will Deacon,
James Clark, Mike Leach, Guo Ren, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, linux-perf-users, linux-arm-kernel,
linux-csky, linux-riscv, linux-kernel, Zide Chen, Falcon Thomas,
Dapeng Mi, Xudong Hao
On 2/6/2026 11:17 PM, Arnaldo Carvalho de Melo wrote:
> On Tue, Feb 03, 2026 at 10:43:52AM +0800, Dapeng Mi wrote:
>> Changes:
>> v2 -> v3:
>> * Fix the abort issue for "-I" or "--user-regs" options. (Patch 1/4)
>> * Address Ian's comments.
> Fixed up somme fuzz with powerpc, x86, riscv and s390 Build files wrt
> removing perf_regs.o
Thanks.
>
> Thanks, applied to perf-tools-next,
>
> - Arnaldo
>
>> v1 -> v2:
>> * Fixing "PERF_REG_EXTENDED_MASK" redefinition building error by
>> changing the "asm/perf_regs.h" header path to relative UAPI path.
>> (Patch 1/3)
>> * Spliting xxx_reg_mask() and xxx_sdt_arg_parse_op() conversion into 2
>> patches.
>>
>> This patch-set remove the below three architecture specific __weak
>> functions and converted them into the general architecture specific
>> functions which are dispatched base on "em_machine".
>>
>> uint64_t arch__intr_reg_mask(void);
>> uint64_t arch__user_reg_mask(void);
>> int arch_sdt_arg_parse_op(char *old_op, char **new_op);
>>
>> The advantage of this conversion is that these architectural functions
>> can be called even for a different architecture with host instead of
>> only called on the host architecture.
>>
>> Although the converted functions shown below can be called on any
>> architecture, currently they are still only called for the host
>> architecture (EM_HOST).
>>
>> int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op);
>> uint64_t perf_intr_reg_mask(uint16_t e_machine);
>> uint64_t perf_user_reg_mask(uint16_t e_machine);
>>
>> Tests:
>> * This patch-set is only tested on x86 platforms. No issues are found
>> for both intr-regs and user-regs options.
>> * Tests on other architectures are welcomed and appreciated.
>>
>> History:
>> v1: https://lore.kernel.org/all/20260123090938.2222960-1-dapeng1.mi@linux.intel.com/
>> v2: https://lore.kernel.org/all/20260127070259.2720468-1-dapeng1.mi@linux.intel.com/
>>
>> Dapeng Mi (4):
>> perf regs: Fix abort for "-I" or "--user-regs" options
>> perf arch: Update arch headers to use relative UAPI paths
>> perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
>> perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
>>
>> tools/perf/arch/arm/include/perf_regs.h | 2 +-
>> tools/perf/arch/arm/util/Build | 2 -
>> tools/perf/arch/arm/util/perf_regs.c | 13 -
>> tools/perf/arch/arm64/include/perf_regs.h | 2 +-
>> tools/perf/arch/arm64/util/Build | 1 -
>> tools/perf/arch/arm64/util/perf_regs.c | 141 ---------
>> tools/perf/arch/csky/Build | 1 -
>> tools/perf/arch/csky/include/perf_regs.h | 2 +-
>> tools/perf/arch/csky/util/Build | 1 -
>> tools/perf/arch/csky/util/perf_regs.c | 13 -
>> tools/perf/arch/loongarch/include/perf_regs.h | 2 +-
>> tools/perf/arch/loongarch/util/Build | 1 -
>> tools/perf/arch/loongarch/util/perf_regs.c | 13 -
>> tools/perf/arch/mips/include/perf_regs.h | 2 +-
>> tools/perf/arch/mips/util/Build | 1 -
>> tools/perf/arch/mips/util/perf_regs.c | 13 -
>> tools/perf/arch/powerpc/include/perf_regs.h | 2 +-
>> tools/perf/arch/powerpc/util/Build | 1 -
>> tools/perf/arch/powerpc/util/perf_regs.c | 172 -----------
>> tools/perf/arch/riscv/include/perf_regs.h | 9 +-
>> tools/perf/arch/riscv/util/Build | 1 -
>> tools/perf/arch/riscv/util/perf_regs.c | 13 -
>> tools/perf/arch/s390/include/perf_regs.h | 2 +-
>> tools/perf/arch/s390/util/Build | 1 -
>> tools/perf/arch/s390/util/perf_regs.c | 13 -
>> tools/perf/arch/x86/include/perf_regs.h | 2 +-
>> tools/perf/arch/x86/util/Build | 1 -
>> tools/perf/arch/x86/util/perf_regs.c | 283 ------------------
>> tools/perf/util/evsel.c | 4 +-
>> tools/perf/util/parse-regs-options.c | 13 +-
>> .../util/perf-regs-arch/perf_regs_aarch64.c | 139 ++++++++-
>> .../perf/util/perf-regs-arch/perf_regs_arm.c | 7 +-
>> .../perf/util/perf-regs-arch/perf_regs_csky.c | 7 +-
>> .../util/perf-regs-arch/perf_regs_loongarch.c | 7 +-
>> .../perf/util/perf-regs-arch/perf_regs_mips.c | 7 +-
>> .../util/perf-regs-arch/perf_regs_powerpc.c | 183 ++++++++++-
>> .../util/perf-regs-arch/perf_regs_riscv.c | 7 +-
>> .../perf/util/perf-regs-arch/perf_regs_s390.c | 7 +-
>> .../perf/util/perf-regs-arch/perf_regs_x86.c | 281 ++++++++++++++++-
>> tools/perf/util/perf_regs.c | 109 ++++++-
>> tools/perf/util/perf_regs.h | 27 +-
>> tools/perf/util/probe-file.c | 3 +-
>> 42 files changed, 787 insertions(+), 724 deletions(-)
>> delete mode 100644 tools/perf/arch/arm/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/arm64/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/csky/Build
>> delete mode 100644 tools/perf/arch/csky/util/Build
>> delete mode 100644 tools/perf/arch/csky/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/loongarch/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/mips/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/powerpc/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/riscv/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/s390/util/perf_regs.c
>> delete mode 100644 tools/perf/arch/x86/util/perf_regs.c
>>
>> --
>> 2.34.1
>>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
` (4 preceding siblings ...)
2026-02-06 15:17 ` [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Arnaldo Carvalho de Melo
@ 2026-03-24 6:07 ` patchwork-bot+linux-riscv
5 siblings, 0 replies; 11+ messages in thread
From: patchwork-bot+linux-riscv @ 2026-03-24 6:07 UTC (permalink / raw)
To: Mi, Dapeng
Cc: linux-riscv, peterz, mingo, acme, namhyung, irogers,
adrian.hunter, alexander.shishkin, john.g.garry, will,
james.clark, mike.leach, guoren, pjw, palmer, aou, alex,
linux-perf-users, linux-arm-kernel, linux-csky, linux-kernel,
zide.chen, thomas.falcon, dapeng1.mi, xudong.hao
Hello:
This series was applied to riscv/linux.git (for-next)
by Arnaldo Carvalho de Melo <acme@redhat.com>:
On Tue, 3 Feb 2026 10:43:52 +0800 you wrote:
> Changes:
> v2 -> v3:
> * Fix the abort issue for "-I" or "--user-regs" options. (Patch 1/4)
> * Address Ian's comments.
>
> v1 -> v2:
> * Fixing "PERF_REG_EXTENDED_MASK" redefinition building error by
> changing the "asm/perf_regs.h" header path to relative UAPI path.
> (Patch 1/3)
> * Spliting xxx_reg_mask() and xxx_sdt_arg_parse_op() conversion into 2
> patches.
>
> [...]
Here is the summary with links:
- [v3,1/4] perf regs: Fix abort for "-I" or "--user-regs" options
https://git.kernel.org/riscv/c/c2e28ae2946f
- [v3,2/4] perf arch: Update arch headers to use relative UAPI paths
https://git.kernel.org/riscv/c/e716e69cf67b
- [v3,3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
(no matching commit)
- [v3,4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function
(no matching commit)
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-03-24 6:07 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-03 2:43 [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Dapeng Mi
2026-02-03 2:43 ` [Patch v3 1/4] perf regs: Fix abort for "-I" or "--user-regs" options Dapeng Mi
2026-02-03 23:06 ` Ian Rogers
2026-02-03 2:43 ` [Patch v3 2/4] perf arch: Update arch headers to use relative UAPI paths Dapeng Mi
2026-02-03 2:43 ` [Patch v3 3/4] perf regs: Remove __weak attributive arch__xxx_reg_mask() functions Dapeng Mi
2026-02-03 23:08 ` Ian Rogers
2026-02-03 2:43 ` [Patch v3 4/4] perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function Dapeng Mi
2026-02-03 23:11 ` Ian Rogers
2026-02-06 15:17 ` [Patch v3 0/4] Perf tools: perf-regs bug fix and optimization Arnaldo Carvalho de Melo
2026-02-09 0:46 ` Mi, Dapeng
2026-03-24 6:07 ` patchwork-bot+linux-riscv
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox