Commit c3176e6457 for qemu.org

commit c3176e645774fcb795bf99c1c6c40c67432232db
Author: Matt Turner <mattst88@gmail.com>
Date:   Thu May 14 12:55:25 2026 -0400

    linux-user/sh4: Fix target_ucontext tuc_link field type

    tuc_link is declared as 'struct target_ucontext *', which is a HOST
    pointer.  On a 64-bit host running a 32-bit SH4 target, this is 8 bytes
    instead of the 4 bytes the target expects, padding pushes tuc_mcontext
    8 bytes past its correct offset.

    When a signal handler receives ucontext_t *, every field accessed through
    uc_mcontext (gregs[], pc, pr, ...) is read from the wrong address.  In
    particular the saved PC comes back as a garbage stack value, which breaks
    any code that initialises a libunwind cursor from the signal context.

    Fix it by using abi_ulong, which is always sized to the target ABI (4
    bytes for SH4), matching the layout the kernel and glibc agree on.  This
    is the same pattern used by arm/signal.c.

    Also remove the (unsigned long *) cast from the __put_user that zeros
    tuc_link.  The cast was harmless when tuc_link was pointer-sized (8
    bytes matching unsigned long on a 64-bit host), but after the type
    change __put_user's sizeof dispatch would select stq_le_p (8-byte write)
    for a now-4-byte field, silently overwriting the start of tuc_stack.

    Neither this fix nor the companion setup_sigtramp fix is independently
    sufficient: this fix corrects register values read from the signal context
    but libunwind still cannot detect the frame without the correct trampoline
    pattern; that fix makes the frame detectable but register reads remain
    garbage without the correct ucontext layout.  Together they fix the
    following libunwind tests on a 64-bit host:
      Gtest-sig-context, Gtest-trace, Ltest-init-local-signal,
      Ltest-sig-context, Ltest-trace

    Signed-off-by: Matt Turner <mattst88@gmail.com>
    Cc: qemu-stable@nongnu.org
    Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
    Signed-off-by: Helge Deller <deller@gmx.de>

diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 9ecc026fae..20d2bc8b2c 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -57,7 +57,7 @@ struct target_sigframe

 struct target_ucontext {
     target_ulong tuc_flags;
-    struct target_ucontext *tuc_link;
+    abi_ulong tuc_link;
     target_stack_t tuc_stack;
     struct target_sigcontext tuc_mcontext;
     target_sigset_t tuc_sigmask;        /* mask last for extensibility */
@@ -237,7 +237,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,

     /* Create the ucontext.  */
     __put_user(0, &frame->uc.tuc_flags);
-    __put_user(0, (unsigned long *)&frame->uc.tuc_link);
+    __put_user(0, &frame->uc.tuc_link);
     target_save_altstack(&frame->uc.tuc_stack, regs);
     setup_sigcontext(&frame->uc.tuc_mcontext,
                      regs, set->sig[0]);