For mipsn32 (TARGET_ABI32=y, TARGET_LONG_BITS=64):
  abi_ulong = uint32_t (4 bytes) — for pointers and ABI-sized fields
  target_ulong = uint64_t (8 bytes) — for general-purpose registers

linux-user/elfload.c allocates target_elf_prstatus using the
mips64/target_elf.h definition where target_elf_gregset_t has
target_ulong reserved[45] (8 bytes each, 360 bytes total).

However, in linux-user/mips64/elfload.c, #include "target_elf.h" inside
the included mips/elfload.c resolves to mips/target_elf.h (compiler
searches the file's own directory first), where the union uses abi_ulong
reserved[45].  For mipsn32 this gives 4-byte entries (180 bytes), not
the 8-byte entries (360 bytes) that elfload.c actually allocated.

Writing via r->reserved[34] therefore lands at byte offset 34*4=136
instead of the correct 34*8=272, silently zeroing the EPC in the core
file.

Fix by casting the pointer to target_ulong * so writes always use 8-byte
slots and land at the offsets matching the allocated layout.

This does not change behavior for mips64 (N64) where abi_ulong already
equals target_ulong (both 8 bytes).

Signed-off-by: Matt Turner <[email protected]>
Cc: [email protected]
---
 linux-user/mips64/elfload.c | 35 +++++++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git ./linux-user/mips64/elfload.c ./linux-user/mips64/elfload.c
index d19e5f2439..feba260462 100644
--- ./linux-user/mips64/elfload.c
+++ ./linux-user/mips64/elfload.c
@@ -15,16 +15,31 @@
  */
 void elf_core_copy_regs(target_elf_gregset_t *r, const CPUMIPSState *env)
 {
-    /* R0 is always 0; r->reserved is zero-initialised by the caller */
+    /*
+     * linux-user/elfload.c allocates target_elf_prstatus using the
+     * definition from mips64/target_elf.h, where target_elf_gregset_t
+     * has target_ulong reserved[45] (8 bytes each = 360 bytes total).
+     *
+     * But in this compilation unit, "#include target_elf.h" resolved to
+     * mips/target_elf.h (wrong directory), so our local target_elf_gregset_t
+     * has abi_ulong reserved[45] which is only 4 bytes each for mipsn32.
+     * Using r->reserved[i] would write to the wrong offsets for mipsn32.
+     *
+     * Cast to target_ulong * to always write 8-byte entries at the correct
+     * positions, matching the layout that elfload.c allocated.
+     */
+    target_ulong *regs = (target_ulong *)r;
+
+    /* R0 is always 0; buffer is zero-initialised by the caller */
     for (int i = 1; i < 32; i++) {
-        r->reserved[i] = tswapl(env->active_tc.gpr[i]);
+        regs[i] = tswapl(env->active_tc.gpr[i]);
     }
-    r->reserved[26] = 0;   /* k0 */
-    r->reserved[27] = 0;   /* k1 */
-    r->reserved[32] = tswapl(env->active_tc.LO[0]);
-    r->reserved[33] = tswapl(env->active_tc.HI[0]);
-    r->reserved[34] = tswapl(env->active_tc.PC);
-    r->reserved[35] = tswapl(env->CP0_BadVAddr);
-    r->reserved[36] = tswapl(env->CP0_Status);
-    r->reserved[37] = tswapl(env->CP0_Cause);
+    regs[26] = 0;   /* k0 */
+    regs[27] = 0;   /* k1 */
+    regs[32] = tswapl(env->active_tc.LO[0]);
+    regs[33] = tswapl(env->active_tc.HI[0]);
+    regs[34] = tswapl(env->active_tc.PC);
+    regs[35] = tswapl(env->CP0_BadVAddr);
+    regs[36] = tswapl(env->CP0_Status);
+    regs[37] = tswapl(env->CP0_Cause);
 }
-- 
2.53.0


Reply via email to