]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
backends/: sketch s390 sample_regs support users/serhei/try-libdwfl-stacktrace
authorSerhei Makarov <serhei@serhei.io>
Fri, 13 Mar 2026 17:32:29 +0000 (13:32 -0400)
committerSerhei Makarov <serhei@serhei.io>
Fri, 20 Mar 2026 18:12:58 +0000 (14:12 -0400)
{speculative, but it should look roughly like this,
modulo proper PSW handling}

backends/Makefile.am
backends/libebl_PERF_FLAGS.h
backends/s390_init.c
backends/s390_initreg_sample.c [new file with mode: 0644]

index 7a8f8169e6384a8a96295eee397e139121fb6b64..7d4ad754255eaa70b21b2378dd8fe11528d2f2c2 100644 (file)
@@ -76,7 +76,7 @@ ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c ppc64_corenote.c \
 
 s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \
            s390_corenote.c s390x_corenote.c s390_cfi.c s390_initreg.c \
-           s390_unwind.c
+           s390_initreg_sample.c s390_unwind.c
 
 m68k_SRCS = m68k_init.c m68k_symbol.c m68k_regs.c \
            m68k_retval.c m68k_corenote.c m68k_cfi.c m68k_initreg.c
index 4e8b000cc28d2cc89bae1f1a4b5565bbeb45b4a7..dc1998883c4661d18c336fc9042853eab0ab0131 100644 (file)
@@ -33,7 +33,7 @@
 
 #if defined(__linux__)
 /* XXX Need to exclude __linux__ arches without perf_regs.h. */
-#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__) || defined(__powerpc__)
+#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || defined(__arm__) || defined(__powerpc__) || defined(__s390__)
 /* || defined(other_architecture)... */
 # include <asm/perf_regs.h>
 #endif
 #define PERF_FRAME_REGISTERS_POWERPC 0
 #endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */
 
+#if defined(_ASM_S390_PERF_REGS_H)
+#define REG(R) (1ULL << PERF_REG_S390_ ## R)
+/* TODO(REVIEW) Proper unwind set seems to be: callee-saved R6..R13,
+   then R14/LR, R15/SP, and PSWA/PC. Collecting all 32 regs is feasible.  */
+#define PERF_FRAME_REGISTERS_S390 (REG(R1) | REG(R2) | REG(R3) | REG(R4) \
+  | REG(R5) | REG(R6) | REG(R7) | REG(R8) | REG(R9) | REG(R10)           \
+  | REG(R11) /* FP */ | REG(R12) | REG(R13) | REG(R14) /* LR */          \
+  | REG(R15) /* SP */ | REG(PC) /* PSWA */)
+/* TODO (REVIEW): Is also including REG(MASK) at all helpful? */
+/* Register ordering defined in linux arch/s390/include/uapi/asm/perf_regs.h.  */
+#else
+/* Since asm/perf_regs.h is absent, or gives the register layout for a
+   different arch, we can't unwind s390 perf sample frames.  */
+#define PERF_FRAME_REGISTERS_S390 0
+#endif
+
 /* TODO(REVIEW) Replaces x86_sample_sp_pc -- is this header the right location for it? */
 static inline bool
 generic_sample_sp_pc (const Dwarf_Word *regs, uint32_t n_regs,
index fd79502d8bac769ddb74c1fd2477547a65add23d..4dd49c8069be2ee5552f00c942865974b480a697 100644 (file)
@@ -1,5 +1,5 @@
 /* Initialization of S/390 specific backend library.
-   Copyright (C) 2005, 2006, 2013 Red Hat, Inc.
+   Copyright (C) 2005, 2006, 2013, 2026 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@
 #define BACKEND                s390_
 #define RELOC_PREFIX   R_390_
 #include "libebl_CPU.h"
+#include "libebl_PERF_FLAGS.h"
 
 /* This defines the common reloc hooks based on arm_reloc.def.  */
 #include "common-reloc.c"
@@ -62,6 +63,10 @@ s390_init (Elf *elf __attribute__ ((unused)),
      unwinding.  */
   eh->frame_nregs = 32;
   HOOK (eh, set_initial_registers_tid);
+  HOOK (eh, set_initial_registers_sample);
+  HOOK (eh, sample_sp_pc);
+  /* TODO(REVIEW) sample_perf_regs_mapping is default ver  */
+  eh->perf_frame_regs_mask = PERF_FRAME_REGISTERS_S390;
   if (eh->class == ELFCLASS32)
     HOOK (eh, normalize_pc);
   HOOK (eh, unwind);
diff --git a/backends/s390_initreg_sample.c b/backends/s390_initreg_sample.c
new file mode 100644 (file)
index 0000000..ffca865
--- /dev/null
@@ -0,0 +1,96 @@
+/* Populate process registers from a register sample.
+   Copyright (C) 2026 Red Hat Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define BACKEND s390_
+#include "libebl_CPU.h"
+#include "libebl_PERF_FLAGS.h"
+
+bool
+s390_sample_sp_pc (const Dwarf_Word *regs, uint32_t n_regs,
+                  const int *regs_mapping, size_t n_regs_mapping,
+                  Dwarf_Word *sp, Dwarf_Word *pc)
+{
+  return generic_sample_sp_pc (regs, n_regs, regs_mapping, n_regs_mapping,
+                              sp, 31 /* index of sp in dwarf_regs */,
+                              pc, 32 /* index of pc in dwarf_regs */);
+}
+
+bool
+s390_set_initial_registers_sample (const Dwarf_Word *regs, uint32_t n_regs,
+                                  const int *regs_mapping, size_t n_regs_mapping,
+                                  ebl_tid_registers_t *setfunc,
+                                  void *arg)
+{
+/* TODO(REVIEW): The #ifdef here seems strictly optional as we don't
+   refer to perf_events or ptrace arch-specific declarations.  */
+#if !defined(__s390__)
+  (void)regs; (void)n_regs;
+  (void)regs_mapping; (void)n_regs_mapping;
+  (void)setfunc; (void)arg;
+  return false;
+#else
+#define N_GREGS 16
+  Dwarf_Word dwarf_regs[N_GREGS];
+  Dwarf_Word psw = 0x0;
+  bool scratch_present = false;
+  size_t i;
+  for (i = 0; i < N_GREGS; i++)
+    dwarf_regs[i] = 0x0;
+  for (i = 0; i < n_regs; i++)
+    {
+      if (i >= n_regs_mapping)
+       break;
+      if (regs_mapping[i] == 16)
+       psw = regs[i]; /* TODO(REVIEW): NEED to correctly extract psw.addr?  */
+      if (regs_mapping[i] < 0 || regs_mapping[i] >= N_GREGS)
+       continue;
+      if (regs_mapping[i] < 6)
+       scratch_present = true;
+      dwarf_regs[regs_mapping[i]] = regs[i];
+    }
+
+  /* R0..R5 only if present.  */
+  if (scratch_present && ! setfunc (0, 6, &dwarf_regs[0], arg))
+    return false;
+
+  /* R6..R13, R14(LR), R15(SP).  */
+  if (! setfunc (6, 15 - 5, &dwarf_regs[6], arg))
+    return false;
+
+  /* TODO(REVIEW): Do we also need the floating-point regs?  */
+
+  return setfunc (-1, 1, &psw, arg);
+#endif /* __s390__ */
+}