Read the registers of a stopped thread with PTRACE_PEEKUSER, which on
alpha takes a register number rather than a struct user offset: 0-31
for the integer registers, 32-62 for $f0-$f30, 63 for the FPCR and 64
for the pc. $31 and $f31 always read as zero, so skip them.

The peeked value is the return value, so check errno instead of
treating -1 as an error.

        * backends/alpha_initreg.c: New file.
        * backends/Makefile.am (alpha_SRCS): Add alpha_initreg.c.
        * backends/alpha_init.c (alpha_init): Hook
        set_initial_registers_tid.
        * NEWS: Add entry.
---
 NEWS                     |  4 +++
 backends/Makefile.am     |  2 +-
 backends/alpha_init.c    |  1 +
 backends/alpha_initreg.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index a66cbda7..be100686 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.197
+
+backends: Add unwinding support for alpha core files and processes.
+
 Version 0.196 "Split Personality"
 
 debuginfod: The $DEBUGINFOD_TIMEOUT environment variable is now enforced
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 604673b6..dac2c060 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -53,7 +53,7 @@ x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c 
x86_64_cfi.c \
 ia64_SRCS = ia64_init.c ia64_symbol.c ia64_regs.c ia64_retval.c
 
 alpha_SRCS = alpha_init.c alpha_symbol.c alpha_retval.c alpha_regs.c \
-            alpha_corenote.c alpha_auxv.c alpha_cfi.c
+            alpha_corenote.c alpha_auxv.c alpha_cfi.c alpha_initreg.c
 
 arm_SRCS = arm_init.c arm_symbol.c arm_regs.c arm_corenote.c \
           arm_auxv.c arm_attrs.c arm_retval.c arm_cfi.c arm_initreg.c \
diff --git a/backends/alpha_init.c b/backends/alpha_init.c
index 229c5beb..0e46e92f 100644
--- a/backends/alpha_init.c
+++ b/backends/alpha_init.c
@@ -62,6 +62,7 @@ alpha_init (Elf *elf __attribute__ ((unused)),
      DWARF_ALT_FRAME_RETURN_COLUMN and glibc's signal trampolines use
      as the return address column.  */
   eh->frame_nregs = 65;
+  HOOK (eh, set_initial_registers_tid);
   eh->sysvhash_entrysize = sizeof (Elf64_Xword);
 
   return eh;
diff --git a/backends/alpha_initreg.c b/backends/alpha_initreg.c
new file mode 100644
index 00000000..dcf81e7a
--- /dev/null
+++ b/backends/alpha_initreg.c
@@ -0,0 +1,72 @@
+/* Fetch live process registers from TID.
+   Copyright (C) 2026 Matt Turner
+   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
+
+#if defined __alpha__ && defined __linux__
+# include <errno.h>
+# include <stdint.h>
+# include <sys/ptrace.h>
+#endif
+
+#define BACKEND alpha_
+#include "libebl_CPU.h"
+
+bool
+alpha_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
+                                ebl_tid_registers_t *setfunc __attribute__ 
((unused)),
+                                void *arg __attribute__ ((unused)))
+{
+#if !defined __alpha__ || !defined __linux__
+  return false;
+#else /* __alpha__ */
+  /* PTRACE_PEEKUSER takes a register number: 0-31 for the integer
+     registers, 32-62 for $f0-$f30, 63 for the FPCR and 64 for the PC.
+     The value is the return value, so check errno rather than for -1.  */
+  Dwarf_Word regs[65];
+  for (int i = 0; i < 65; i++)
+    {
+      /* $31 and $f31 always read as zero.  */
+      if (i == 31 || i == 63)
+       {
+         regs[i] = 0;
+         continue;
+       }
+      errno = 0;
+      regs[i] = ptrace (PTRACE_PEEKUSER, tid, (void *) (uintptr_t) i, NULL);
+      if (errno != 0)
+       return false;
+    }
+
+  /* $0-$31 and $f0-$f31, then the PC.  */
+  return setfunc (0, 64, regs, arg) && setfunc (-1, 1, &regs[64], arg);
+#endif /* __alpha__ */
+}

-- 
2.55.0

Reply via email to