@samitouri / QOSamiQemu / commits / 68ed426cf0

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>

Matt Turner committed Jun 3, 2026 at 12:18 UTC 68ed426cf0d7e7ac5549f3f2667dda9e66a501cc
2 files changed +38
linux-user/sparc/elfload.c
+27
@@ -4,8 +4,35 @@
4 #include "qemu.h"
5 #include "loader.h"
6 #include "elf.h"
7 +#include "target_elf.h"
8
9
10 +void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
11 +{
12 + CPUSPARCState *e = (CPUSPARCState *)env;
13 + int i;
14 +
15 +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
16 + for (i = 0; i < 8; i++) {
17 + r->regs[i] = tswap64(env->gregs[i]);
18 + r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
19 + }
20 + r->regs[16] = tswap64(sparc64_tstate(e));
21 + r->regs[17] = tswap64(env->pc);
22 + r->regs[18] = tswap64(env->npc);
23 + r->regs[19] = tswap64(env->y);
24 +#else
25 + r->regs[0] = tswap32(cpu_get_psr(e));
26 + r->regs[1] = tswap32(env->pc);
27 + r->regs[2] = tswap32(env->npc);
28 + r->regs[3] = tswap32(env->y);
29 + for (i = 0; i < 8; i++) {
30 + r->regs[4 + i] = tswap32(env->gregs[i]);
31 + r->regs[12 + i] = tswap32(env->regwptr[WREG_O0 + i]);
32 + }
33 +#endif
34 +}
35 +
36 const char *get_elf_cpu_model(uint32_t eflags)
37 {
38 #ifdef TARGET_SPARC64
linux-user/sparc/target_elf.h
+11
@@ -13,6 +13,7 @@
13 # define ELF_MACHINE EM_SPARC
14 #elif defined(TARGET_ABI32)
15 # define ELF_CLASS ELFCLASS32
16 +# define ELF_MACHINE EM_SPARC32PLUS
17 # define elf_check_machine(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
18 #else
19 # define ELF_CLASS ELFCLASS64
@@ -20,5 +21,15 @@
21 #endif
22
23 #define HAVE_ELF_HWCAP 1
24 +#define HAVE_ELF_CORE_DUMP 1
25 +
26 +/*
27 + * Matches the kernel's elf_gregset_t (ELF_NGREG = 20).
28 + * sparc32/sparc32plus: psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7)
29 + * sparc64: u_regs[16] (g0-g7, o0-o7), tstate, pc, npc, y
30 + */
31 +typedef struct target_elf_gregset_t {
32 + abi_ulong regs[20];
33 +} target_elf_gregset_t;
34
35 #endif