]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf regs: Remove __weak attributive arch__xxx_reg_mask() functions
authorDapeng Mi <dapeng1.mi@linux.intel.com>
Tue, 3 Feb 2026 02:43:55 +0000 (10:43 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 6 Feb 2026 15:16:09 +0000 (12:16 -0300)
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>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Guo Ren <guoren@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: Xudong Hao <xudong.hao@intel.com>
Cc: Zide Chen <zide.chen@intel.com>
[ Fixed up somme fuzz with s390 and riscv Build files wrt removing perf_regs.o ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
30 files changed:
tools/perf/arch/arm/util/Build
tools/perf/arch/arm/util/perf_regs.c [deleted file]
tools/perf/arch/arm64/util/perf_regs.c
tools/perf/arch/csky/Build [deleted file]
tools/perf/arch/csky/util/Build [deleted file]
tools/perf/arch/csky/util/perf_regs.c [deleted file]
tools/perf/arch/loongarch/util/Build
tools/perf/arch/loongarch/util/perf_regs.c [deleted file]
tools/perf/arch/mips/util/Build
tools/perf/arch/mips/util/perf_regs.c [deleted file]
tools/perf/arch/powerpc/util/perf_regs.c
tools/perf/arch/riscv/include/perf_regs.h
tools/perf/arch/riscv/util/Build
tools/perf/arch/riscv/util/perf_regs.c [deleted file]
tools/perf/arch/s390/util/Build
tools/perf/arch/s390/util/perf_regs.c [deleted file]
tools/perf/arch/x86/util/perf_regs.c
tools/perf/util/evsel.c
tools/perf/util/parse-regs-options.c
tools/perf/util/perf-regs-arch/perf_regs_aarch64.c
tools/perf/util/perf-regs-arch/perf_regs_arm.c
tools/perf/util/perf-regs-arch/perf_regs_csky.c
tools/perf/util/perf-regs-arch/perf_regs_loongarch.c
tools/perf/util/perf-regs-arch/perf_regs_mips.c
tools/perf/util/perf-regs-arch/perf_regs_powerpc.c
tools/perf/util/perf-regs-arch/perf_regs_riscv.c
tools/perf/util/perf-regs-arch/perf_regs_s390.c
tools/perf/util/perf-regs-arch/perf_regs_x86.c
tools/perf/util/perf_regs.c
tools/perf/util/perf_regs.h

index 3291f893b943df0722dff583523fff4ae79919bc..b94bf3c5279a13d6f808cb8e75b2bf79b9802176 100644 (file)
@@ -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 (file)
index 03a5bc0..0000000
+++ /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;
-}
index 9bb768e1bea1c4e5b507e3103faf51bd1f87ee09..47f58eaba03235d95c5259b9cb95eff3d0776fe9 100644 (file)
@@ -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 (file)
index e63eabc..0000000
+++ /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 (file)
index 6b2d0e0..0000000
+++ /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 (file)
index 2cf7a54..0000000
+++ /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;
-}
index 1cb06a5f8935fd02ec8ee957873edaaba2c15e61..3ad73d0289f3ea3768a7312b4cbc1b889040cd13 100644 (file)
@@ -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 (file)
index 03a5bc0..0000000
+++ /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;
-}
index 691fa2051958a0af855c90b0e019ba7c0a56beea..818b808a824742d7fbb0d3a6fb21166e0879d7dc 100644 (file)
@@ -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 (file)
index 2cf7a54..0000000
+++ /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;
-}
index 779073f7e9929254cb0f0a347de24367a479cca5..93f929fc32e3194b7e721147473076a8563872fd 100644 (file)
@@ -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;
-}
index 89d5bbb8d2b8fa9c452355190dadd9332cea55ab..af7a1b47bf66b7fdc73238605018481a0e487319 100644 (file)
 
 #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 */
index c01231bcf9c38faf9f52b0dcdf326043a92491df..2328fb9a30a367b32d3560659b86b9bc1826ee5e 100644 (file)
@@ -1,2 +1 @@
-perf-util-y += perf_regs.o
 perf-util-y += header.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 (file)
index 2cf7a54..0000000
+++ /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;
-}
index 87229f2c4397cd46981a7e851473fa793abc1e71..65d75cd5b138f7fe7f6e2e247cc260f7db804b43 100644 (file)
@@ -1,5 +1,4 @@
 perf-util-y += header.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 (file)
index 2cf7a54..0000000
+++ /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;
-}
index a7ca4154fdf93c8407c350012f69f42283cb8f68..41141cebe2261e5d73b370d281bf3f67101c94cd 100644 (file)
@@ -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;
-}
index aff44ffd3ff12382faf48d840e8696f79cec2c13..f59228c1a39eb2bc00f816c07cb0f45dc1ca11b8 100644 (file)
@@ -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;
index b44b47d9059fd130319ae6f31274b840ac48ded2..c93c2f0c810583dc1f78dbe0bc27a24571447f15 100644 (file)
@@ -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) {
index 9dcda80d310f014b4809d3c358c333789b8ca34e..666874f625b6ca4c6bc1d4cdc6c42d6a980887b9 100644 (file)
@@ -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)
 {
index e29d130a587aa700806c5afae523c3aba5f80190..184d6e248dfcb13fb65189a72fc97860ba157bed 100644 (file)
@@ -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)
 {
index 95808f93d45bd1231e602b25418e351b30ed6447..16cbd8303acf3163b23170b401b4e1f6c2832402 100644 (file)
@@ -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)
 {
index 043f97f4e3ac4a74ca3940a849a327308375ee37..478ee889afa12319aaa9d9d04dd1c05d5364903b 100644 (file)
@@ -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)
 {
index 793178fc3c787f83bd3434857350e14846487da2..c5a475f6ec64cebbab179d052c11f45985e365ea 100644 (file)
@@ -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)
 {
index 08636bb09a3a67e46882f26c3d14a3d12b542ec1..f0a547ad809b8f7cbfb8ee4ee75b4db2cc257336 100644 (file)
@@ -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)
 {
index 337b687c655d04061758308988dd6450a78b9fe0..5b5f21fcba8c6d819754ec4d4b7beca4fe7d829e 100644 (file)
@@ -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)
 {
index d69bba88108000c28dbe97022fdc4b81784bf24b..c61df24edf0fce9f6707690c674076bf40b3cb5b 100644 (file)
@@ -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)
 {
index 708954a9d35d7bfcf842dbd169e05a075e279ebd..d573f9a9ca461f84c66fea1ad36bdbf0dcea5066 100644 (file)
@@ -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)
 {
index 14b7be30ab20348d3d715b7dc4d57351a0ccacdf..4d9a286a0e56b5e37da0d9490d7d43c366498d7a 100644 (file)
@@ -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)
index ed7c1b1358fadee2b891fbcde729288048ed23a0..2b27139acadb697aec9c1f71d65c30a19ba67423 100644 (file)
@@ -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);