Commit 68ed426cf0 for qemu.org

commit 68ed426cf0d7e7ac5549f3f2667dda9e66a501cc
Author: Matt Turner <mattst88@gmail.com>
Date:   Wed Jun 3 12:18:49 2026 -0400

    linux-user/sparc: add coredump support

    Define HAVE_ELF_CORE_DUMP and target_elf_gregset_t in target_elf.h
    sized to match the kernel's elf_gregset_t:

      sparc32/sparc32plus (ELF_NGREG = 38):
        [0]      PSR
        [1]      PC
        [2]      NPC
        [3]      Y
        [4..11]  G0-G7
        [12..19] O0-O7
        [20..27] L0-L7
        [28..35] I0-I7
        [36..37] reserved (stack_check)

      sparc64 (ELF_NGREG = 36):
        [0..7]   G0-G7
        [8..15]  O0-O7
        [16..23] L0-L7
        [24..31] I0-I7
        [32]     TSTATE
        [33]     TPC
        [34]     TNPC
        [35]     Y

    Also define ELF_MACHINE as EM_SPARC32PLUS for TARGET_ABI32 builds,
    matching the kernel and ensuring the correct machine type appears in
    the core file.

    Implement elf_core_copy_regs() in elfload.c to populate the gregset
    from CPUSPARCState, including L0-L7 and I0-I7 from env->regwptr.
    A memset() at entry zeros the trailing reserved slots.

    Without this, bprm->core_dump is NULL for SPARC targets.  When a
    guest signal goes unhandled, dump_core_and_abort() skips the core
    write and falls through to die_with_signal(), which re-raises the
    signal to the host.  The host kernel then writes an x86-64 core file
    for the qemu-sparc process instead of a SPARC guest core.

    Populating the full register layout is required for tools like
    libunwind-coredump, which reads pr_reg[33] for the trap PC and
    pr_reg[16..31] for the windowed registers.

    Signed-off-by: Matt Turner <mattst88@gmail.com>
    Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
    Signed-off-by: Helge Deller <deller@gmx.de>

diff --git a/linux-user/sparc/elfload.c b/linux-user/sparc/elfload.c
index 32ca1b05b1..e6387ec891 100644
--- a/linux-user/sparc/elfload.c
+++ b/linux-user/sparc/elfload.c
@@ -4,8 +4,35 @@
 #include "qemu.h"
 #include "loader.h"
 #include "elf.h"
+#include "target_elf.h"


+void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
+{
+    CPUSPARCState *e = (CPUSPARCState *)env;
+    int i;
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+    for (i = 0; i < 8; i++) {
+        r->regs[i]     = tswap64(env->gregs[i]);
+        r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
+    }
+    r->regs[16] = tswap64(sparc64_tstate(e));
+    r->regs[17] = tswap64(env->pc);
+    r->regs[18] = tswap64(env->npc);
+    r->regs[19] = tswap64(env->y);
+#else
+    r->regs[0] = tswap32(cpu_get_psr(e));
+    r->regs[1] = tswap32(env->pc);
+    r->regs[2] = tswap32(env->npc);
+    r->regs[3] = tswap32(env->y);
+    for (i = 0; i < 8; i++) {
+        r->regs[4 + i]  = tswap32(env->gregs[i]);
+        r->regs[12 + i] = tswap32(env->regwptr[WREG_O0 + i]);
+    }
+#endif
+}
+
 const char *get_elf_cpu_model(uint32_t eflags)
 {
 #ifdef TARGET_SPARC64
diff --git a/linux-user/sparc/target_elf.h b/linux-user/sparc/target_elf.h
index 7827767bcb..edb0b3103c 100644
--- a/linux-user/sparc/target_elf.h
+++ b/linux-user/sparc/target_elf.h
@@ -13,6 +13,7 @@
 # define ELF_MACHINE            EM_SPARC
 #elif defined(TARGET_ABI32)
 # define ELF_CLASS              ELFCLASS32
+# define ELF_MACHINE            EM_SPARC32PLUS
 # define elf_check_machine(x)   ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
 #else
 # define ELF_CLASS              ELFCLASS64
@@ -20,5 +21,15 @@
 #endif

 #define HAVE_ELF_HWCAP          1
+#define HAVE_ELF_CORE_DUMP      1
+
+/*
+ * Matches the kernel's elf_gregset_t (ELF_NGREG = 20).
+ * sparc32/sparc32plus: psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7)
+ * sparc64:             u_regs[16] (g0-g7, o0-o7), tstate, pc, npc, y
+ */
+typedef struct target_elf_gregset_t {
+    abi_ulong regs[20];
+} target_elf_gregset_t;

 #endif