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 <[email protected]> Cc: [email protected] --- linux-user/sh4/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git ./linux-user/sh4/signal.c ./linux-user/sh4/signal.c index 9ecc026fae..20d2bc8b2c 100644 --- ./linux-user/sh4/signal.c +++ ./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]); -- 2.52.0
