@samitouri / QOSamiQemu / commits / f83f550549

linux-user/sparc: flush register windows before core dump

Without this, only the crash frame's window is spilled to the stack; all deeper call frames remain in the register file and are absent from the core's memory segments. Stack unwinding fails past the first DWARF step because the callers' register save areas contain stale/garbage data. The real kernel calls flush_all_user_windows() at the top of do_coredump(). Mirror that via a weak target_flush_windows() hook called from dump_core_and_abort(), with the SPARC override calling the existing flush_windows() in cpu_loop.c. 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 20:30 UTC f83f5505497c2b2b08a9bc9a3bd5aee2df5fa7ca
5 files changed +64 -11
linux-user/elfload.c
+9
@@ -2445,6 +2445,9 @@ static int wmr_write_region(void *opaque, vaddr start,
2445 * handler (provided that target process haven't registered
2446 * handler for that) that does the dump when signal is received.
2447 */
2448 +#ifdef TARGET_SPARC
2449 +#include "sparc/cpu_loop.h"
2450 +#endif
2451 static int elf_core_dump(int signr, const CPUArchState *env)
2452 {
2453 const CPUState *cpu = env_cpu_const(env);
@@ -2468,6 +2471,12 @@ static int elf_core_dump(int signr, const CPUArchState *env)
2471 cpu_list_lock();
2472 mmap_lock();
2473
2474 +#ifdef TARGET_SPARC
2475 + CPU_FOREACH(cpu_iter) {
2476 + flush_windows(cpu_env(cpu_iter));
2477 + }
2478 +#endif
2479 +
2480 /* By unprotecting, we merge vmas that might be split. */
2481 walk_memory_regions(NULL, wmr_page_unprotect_regions);
2482
linux-user/sparc/cpu_loop.c
+2 -1
@@ -22,6 +22,7 @@
22 #include "user-internals.h"
23 #include "user/cpu_loop.h"
24 #include "signal-common.h"
25 +#include "sparc/cpu_loop.h"
26
27 #define SPARC64_STACK_BIAS 2047
28
@@ -119,7 +120,7 @@ static void restore_window(CPUSPARCState *env)
120 #endif
121 }
122
122 -static void flush_windows(CPUSPARCState *env)
123 +void flush_windows(CPUSPARCState *env)
124 {
125 int offset, cwp1;
126
linux-user/sparc/cpu_loop.h new
+7
@@ -0,0 +1,7 @@
1 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2 +#ifndef SPARC_CPU_LOOP_H
3 +#define SPARC_CPU_LOOP_H
4 +
5 +void flush_windows(CPUSPARCState *env);
6 +
7 +#endif
linux-user/sparc/elfload.c
+33 -6
@@ -12,16 +12,41 @@ void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
12 CPUSPARCState *e = (CPUSPARCState *)env;
13 int i;
14
15 + memset(r, 0, sizeof(*r));
16 +
17 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
18 + /* Linux kernel layout for sparc64 (arch/sparc/include/asm/elf_64.h):
19 + * [0..7] G0-G7
20 + * [8..15] O0-O7
21 + * [16..23] L0-L7
22 + * [24..31] I0-I7
23 + * [32] TSTATE
24 + * [33] TPC
25 + * [34] TNPC
26 + * [35] Y
27 + */
28 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]);
29 + r->regs[i] = tswap64(env->gregs[i]);
30 + r->regs[8 + i] = tswap64(env->regwptr[WREG_O0 + i]);
31 + r->regs[16 + i] = tswap64(env->regwptr[WREG_L0 + i]);
32 + r->regs[24 + i] = tswap64(env->regwptr[WREG_I0 + i]);
33 }
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);
34 + r->regs[32] = tswap64(sparc64_tstate(e));
35 + r->regs[33] = tswap64(env->pc);
36 + r->regs[34] = tswap64(env->npc);
37 + r->regs[35] = tswap64(env->y);
38 #else
39 + /* Linux kernel layout for sparc32 (arch/sparc/include/asm/elf_32.h):
40 + * [0] PSR
41 + * [1] PC
42 + * [2] NPC
43 + * [3] Y
44 + * [4..11] G0-G7
45 + * [12..19] O0-O7
46 + * [20..27] L0-L7
47 + * [28..35] I0-I7
48 + * [36..37] reserved (stack_check)
49 + */
50 r->regs[0] = tswap32(cpu_get_psr(e));
51 r->regs[1] = tswap32(env->pc);
52 r->regs[2] = tswap32(env->npc);
@@ -29,6 +54,8 @@ void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env)
54 for (i = 0; i < 8; i++) {
55 r->regs[4 + i] = tswap32(env->gregs[i]);
56 r->regs[12 + i] = tswap32(env->regwptr[WREG_O0 + i]);
57 + r->regs[20 + i] = tswap32(env->regwptr[WREG_L0 + i]);
58 + r->regs[28 + i] = tswap32(env->regwptr[WREG_I0 + i]);
59 }
60 #endif
61 }
linux-user/sparc/target_elf.h
+13 -4
@@ -24,12 +24,21 @@
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
27 + * Matches the kernel's elf_gregset_t.
28 + * sparc32/sparc32plus (ELF_NGREG = 38):
29 + * psr, pc, npc, y, u_regs[16] (g0-g7, o0-o7),
30 + * reg_window[16] (l0-l7, i0-i7), stack_check[2]
31 + * sparc64 (ELF_NGREG = 36):
32 + * u_regs[16] (g0-g7, o0-o7), reg_window[16] (l0-l7, i0-i7),
33 + * tstate, tpc, tnpc, y
34 */
35 +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
36 +# define TARGET_ELF_NGREG 36
37 +#else
38 +# define TARGET_ELF_NGREG 38
39 +#endif
40 typedef struct target_elf_gregset_t {
32 - abi_ulong regs[20];
41 + abi_ulong regs[TARGET_ELF_NGREG];
42 } target_elf_gregset_t;
43
44 #endif