From 13c14616f5ec66ca5ab262c1ee7e5b87f1171dfc Mon Sep 17 00:00:00 2001 From: Serhei Makarov Date: Fri, 13 Mar 2026 13:32:29 -0400 Subject: [PATCH] backends/: sketch s390 sample_regs support {speculative, but it should look roughly like this, modulo proper PSW handling} --- backends/Makefile.am | 2 +- backends/libebl_PERF_FLAGS.h | 18 ++++++- backends/s390_init.c | 7 ++- backends/s390_initreg_sample.c | 96 ++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 backends/s390_initreg_sample.c diff --git a/backends/Makefile.am b/backends/Makefile.am index 7a8f8169e..7d4ad7542 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -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 diff --git a/backends/libebl_PERF_FLAGS.h b/backends/libebl_PERF_FLAGS.h index 4e8b000cc..dc1998883 100644 --- a/backends/libebl_PERF_FLAGS.h +++ b/backends/libebl_PERF_FLAGS.h @@ -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 #endif @@ -118,6 +118,22 @@ #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, diff --git a/backends/s390_init.c b/backends/s390_init.c index fd79502d8..4dd49c806 100644 --- a/backends/s390_init.c +++ b/backends/s390_init.c @@ -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 index 000000000..ffca865da --- /dev/null +++ b/backends/s390_initreg_sample.c @@ -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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#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__ */ +} -- 2.47.3