]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf record: Add support for arch_sdt_arg_parse_op() on s390
authorThomas Richter <tmricht@linux.ibm.com>
Thu, 19 Mar 2026 08:47:54 +0000 (09:47 +0100)
committerNamhyung Kim <namhyung@kernel.org>
Thu, 26 Mar 2026 21:38:54 +0000 (14:38 -0700)
commit e5e66adfe45a6 ("perf regs: Remove __weak attributive arch_sdt_arg_parse_op() function")
removes arch_sdt_arg_parse_op() functions and reveals missing s390 support.
The following warning is printed:

  Unknown ELF machine 22, standard arguments parse will be skipped.

ELF machine 22 is the EM_S390 host. This happens with command
  # ./perf record -v -- stress-ng -t 1s --matrix 0
when the event is not specified.

Add s390 specific __perf_sdt_arg_parse_op_s390() function to support
-architecture calls to arch_sdt_arg_parse_op() for s390.
The warning disappears.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Tested-by: Jan Polensky <japo@linux.ibm.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/perf-regs-arch/perf_regs_s390.c
tools/perf/util/perf_regs.c
tools/perf/util/perf_regs.h

index c61df24edf0fce9f6707690c674076bf40b3cb5b..19f2192251830047b3ebce7075ad44e3de9b1ec9 100644 (file)
@@ -1,7 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#include <errno.h>
+#include <regex.h>
 #include "../perf_regs.h"
 #include "../../arch/s390/include/perf_regs.h"
+#include "debug.h"
+
+#include <linux/zalloc.h>
+#include <linux/kernel.h>
 
 uint64_t __perf_reg_mask_s390(bool intr __maybe_unused)
 {
@@ -95,3 +101,75 @@ uint64_t __perf_reg_sp_s390(void)
 {
        return PERF_REG_S390_R15;
 }
+
+/* %rXX */
+#define SDT_OP_REGEX1  "^(%r([0-9]|1[0-5]))$"
+/* +-###(%rXX) */
+#define SDT_OP_REGEX2  "^([+-]?[0-9]+\\(%r([0-9]|1[0-5])\\))$"
+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;
+       initialized = 1;
+
+       ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
+       if (ret)
+               goto free_regex1;
+       initialized = 2;
+
+       return 0;
+
+free_regex1:
+       regfree(&sdt_op_regex1);
+error:
+       pr_debug4("Regex compilation error, initialized %d\n", initialized);
+       initialized = 0;
+       return ret;
+}
+
+/*
+ * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
+ * Possible variants of OP are:
+ *     Format          Example
+ *     -------------------------
+ *     NUM(%rREG)      48(%r1)
+ *     -NUM(%rREG)     -48(%r1)
+ *     +NUM(%rREG)     +48(%r1)
+ *     %rREG           %r1
+ */
+int __perf_sdt_arg_parse_op_s390(char *old_op, char **new_op)
+{
+       int ret, new_len;
+       regmatch_t rm[6];
+
+       *new_op = NULL;
+       ret = sdt_init_op_regex();
+       if (ret)
+               return -EINVAL;
+
+       if (!regexec(&sdt_op_regex1, old_op, ARRAY_SIZE(rm), rm, 0) ||
+           !regexec(&sdt_op_regex2, old_op, ARRAY_SIZE(rm), rm, 0)) {
+               new_len = 1;    /* NULL byte */
+               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 {
+               pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
+               return SDT_ARG_SKIP;
+       }
+
+       return SDT_ARG_VALID;
+}
index 5b8f34beb24e835b064977272d5493fb46da1e1b..f52b0e1f7fc71039500a9cf34650acfa03586bfb 100644 (file)
@@ -23,6 +23,9 @@ int perf_sdt_arg_parse_op(uint16_t e_machine, char *old_op, char **new_op)
        case EM_X86_64:
                ret = __perf_sdt_arg_parse_op_x86(old_op, new_op);
                break;
+       case EM_S390:
+               ret = __perf_sdt_arg_parse_op_s390(old_op, new_op);
+               break;
        default:
                pr_debug("Unknown ELF machine %d, standard arguments parse will be skipped.\n",
                         e_machine);
index 7c04700bf837289d9ba08820b423828fca9f63a2..573f0d1dfe049289ac8b385f4cd0ac83262b99d7 100644 (file)
@@ -62,6 +62,7 @@ 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);
+int __perf_sdt_arg_parse_op_s390(char *old_op, char **new_op);
 
 int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op);
 uint64_t __perf_reg_mask_x86(bool intr);