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