[PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset

Matt Turner posted 1 patch 2 weeks, 1 day ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260414025335.2847358-1-mattst88@gmail.com
Maintainers: Laurent Vivier <laurent@vivier.eu>, Pierrick Bouvier <pierrick.bouvier@linaro.org>
There is a newer version of this series
linux-user/ppc/signal.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
[PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 2 weeks, 1 day ago
The kernel's 64-bit signal delivery (signal_64.c) uses:

    newsp = frame - __SIGNAL_FRAMESIZE

while the 32-bit path (signal_32.c) uses:

    newsp = frame - (__SIGNAL_FRAMESIZE + 16)

The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
at the same offsets as older kernels (see the comment in signal_32.c).
The 64-bit rt_sigframe starts with ucontext directly and does not need
this adjustment.

QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
on ppc64. Signal delivery and return still worked because do_rt_sigreturn
had the matching wrong offset, but the vDSO DWARF unwind info encodes
the correct kernel offset. This caused any DWARF unwinder (libunwind,
libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
register values from the signal frame.

Guard the +16 with #if !defined(TARGET_PPC64) in both setup_rt_frame
and do_rt_sigreturn to match the kernel.

This was verified by A/B testing with libunwind's test suite:

  ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
           and Ltest-sig-context all change from FAIL to PASS.
  ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
           from FAIL to PASS.

Signed-off-by: Matt Turner <mattst88@gmail.com>
---
 linux-user/ppc/signal.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git ./linux-user/ppc/signal.c ./linux-user/ppc/signal.c
index 24e5a02a78..b21aa2430e 100644
--- ./linux-user/ppc/signal.c
+++ ./linux-user/ppc/signal.c
@@ -525,7 +525,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     env->fpscr = 0;
 
     /* Create a stack frame for the caller of the handler.  */
+#if defined(TARGET_PPC64)
+    newsp = rt_sf_addr - SIGNAL_FRAMESIZE;
+#else
+    /*
+     * The +16 is to get the siginfo and ucontext in the same positions
+     * as in older kernels. See Linux's arch/powerpc/kernel/signal_32.c.
+     */
     newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+#endif
     err |= put_user(env->gpr[1], newsp, target_ulong);
 
     if (err)
@@ -641,7 +649,11 @@ long do_rt_sigreturn(CPUPPCState *env)
     struct target_rt_sigframe *rt_sf = NULL;
     target_ulong rt_sf_addr;
 
+#if defined(TARGET_PPC64)
+    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
+#else
     rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+#endif
     if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
         goto sigsegv;
 
-- 
2.52.0
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Peter Maydell 1 week, 6 days ago
On Tue, 14 Apr 2026 at 18:27, Matt Turner <mattst88@gmail.com> wrote:
>
> The kernel's 64-bit signal delivery (signal_64.c) uses:
>
>     newsp = frame - __SIGNAL_FRAMESIZE
>
> while the 32-bit path (signal_32.c) uses:
>
>     newsp = frame - (__SIGNAL_FRAMESIZE + 16)
>
> The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> at the same offsets as older kernels (see the comment in signal_32.c).
> The 64-bit rt_sigframe starts with ucontext directly and does not need
> this adjustment.
>
> QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> had the matching wrong offset, but the vDSO DWARF unwind info encodes
> the correct kernel offset. This caused any DWARF unwinder (libunwind,
> libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> register values from the signal frame.
>
> Guard the +16 with #if !defined(TARGET_PPC64) in both setup_rt_frame
> and do_rt_sigreturn to match the kernel.
>
> This was verified by A/B testing with libunwind's test suite:
>
>   ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
>            and Ltest-sig-context all change from FAIL to PASS.
>   ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
>            from FAIL to PASS.
>
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> ---
>  linux-user/ppc/signal.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git ./linux-user/ppc/signal.c ./linux-user/ppc/signal.c
> index 24e5a02a78..b21aa2430e 100644
> --- ./linux-user/ppc/signal.c
> +++ ./linux-user/ppc/signal.c
> @@ -525,7 +525,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>      env->fpscr = 0;
>
>      /* Create a stack frame for the caller of the handler.  */
> +#if defined(TARGET_PPC64)
> +    newsp = rt_sf_addr - SIGNAL_FRAMESIZE;
> +#else
> +    /*
> +     * The +16 is to get the siginfo and ucontext in the same positions
> +     * as in older kernels. See Linux's arch/powerpc/kernel/signal_32.c.
> +     */
>      newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
> +#endif
>      err |= put_user(env->gpr[1], newsp, target_ulong);
>
>      if (err)
> @@ -641,7 +649,11 @@ long do_rt_sigreturn(CPUPPCState *env)
>      struct target_rt_sigframe *rt_sf = NULL;
>      target_ulong rt_sf_addr;
>
> +#if defined(TARGET_PPC64)
> +    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
> +#else
>      rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
> +#endif
>      if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
>          goto sigsegv;

Thanks for this patch; comparing against the kernel code QEMU is
definitely wrong here.


I think I would prefer it if we avoided the in-code ifdefs
and instead had something like this defined at the top of
the file, e.g. below the target_rt_sigframe definition:

#ifdef TARGET_PPC64
#define RT_SIGFRAME_ADJUST 0
#else
/*
 * For 32-bit rt sigframes we have an extra 16 bytes of gap
 * on top of __SIGNAL_FRAMESIZE; this is to get the siginfo
 * and ucontext in the same positions as in older kernels.
 * See Linux's arch/powerpc/kernel/signal_32.c.
 */
#define RT_SIGFRAME_ADJUST 16
#endif

Then we can have the code unconditionally do
   newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST);
etc.

thanks
-- PMM
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 1 week, 6 days ago
On Thu, Apr 16, 2026 at 10:19 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 14 Apr 2026 at 18:27, Matt Turner <mattst88@gmail.com> wrote:
> >
> > The kernel's 64-bit signal delivery (signal_64.c) uses:
> >
> >     newsp = frame - __SIGNAL_FRAMESIZE
> >
> > while the 32-bit path (signal_32.c) uses:
> >
> >     newsp = frame - (__SIGNAL_FRAMESIZE + 16)
> >
> > The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> > at the same offsets as older kernels (see the comment in signal_32.c).
> > The 64-bit rt_sigframe starts with ucontext directly and does not need
> > this adjustment.
> >
> > QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> > for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> > on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> > had the matching wrong offset, but the vDSO DWARF unwind info encodes
> > the correct kernel offset. This caused any DWARF unwinder (libunwind,
> > libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> > register values from the signal frame.
> >
> > Guard the +16 with #if !defined(TARGET_PPC64) in both setup_rt_frame
> > and do_rt_sigreturn to match the kernel.
> >
> > This was verified by A/B testing with libunwind's test suite:
> >
> >   ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
> >            and Ltest-sig-context all change from FAIL to PASS.
> >   ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
> >            from FAIL to PASS.
> >
> > Signed-off-by: Matt Turner <mattst88@gmail.com>
> > ---
> >  linux-user/ppc/signal.c | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git ./linux-user/ppc/signal.c ./linux-user/ppc/signal.c
> > index 24e5a02a78..b21aa2430e 100644
> > --- ./linux-user/ppc/signal.c
> > +++ ./linux-user/ppc/signal.c
> > @@ -525,7 +525,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> >      env->fpscr = 0;
> >
> >      /* Create a stack frame for the caller of the handler.  */
> > +#if defined(TARGET_PPC64)
> > +    newsp = rt_sf_addr - SIGNAL_FRAMESIZE;
> > +#else
> > +    /*
> > +     * The +16 is to get the siginfo and ucontext in the same positions
> > +     * as in older kernels. See Linux's arch/powerpc/kernel/signal_32.c.
> > +     */
> >      newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
> > +#endif
> >      err |= put_user(env->gpr[1], newsp, target_ulong);
> >
> >      if (err)
> > @@ -641,7 +649,11 @@ long do_rt_sigreturn(CPUPPCState *env)
> >      struct target_rt_sigframe *rt_sf = NULL;
> >      target_ulong rt_sf_addr;
> >
> > +#if defined(TARGET_PPC64)
> > +    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
> > +#else
> >      rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
> > +#endif
> >      if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
> >          goto sigsegv;
>
> Thanks for this patch; comparing against the kernel code QEMU is
> definitely wrong here.
>
>
> I think I would prefer it if we avoided the in-code ifdefs
> and instead had something like this defined at the top of
> the file, e.g. below the target_rt_sigframe definition:
>
> #ifdef TARGET_PPC64
> #define RT_SIGFRAME_ADJUST 0
> #else
> /*
>  * For 32-bit rt sigframes we have an extra 16 bytes of gap
>  * on top of __SIGNAL_FRAMESIZE; this is to get the siginfo
>  * and ucontext in the same positions as in older kernels.
>  * See Linux's arch/powerpc/kernel/signal_32.c.
>  */
> #define RT_SIGFRAME_ADJUST 16
> #endif
>
> Then we can have the code unconditionally do
>    newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST);
> etc.
>
> thanks
> -- PMM

Thanks Peter! That is definitely a lot cleaner. I've sent a revised patch.
[PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 1 week, 6 days ago
The kernel's 64-bit signal delivery (signal_64.c) uses:

    newsp = frame - __SIGNAL_FRAMESIZE

while the 32-bit path (signal_32.c) uses:

    newsp = frame - (__SIGNAL_FRAMESIZE + 16)

The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
at the same offsets as older kernels (see the comment in signal_32.c).
The 64-bit rt_sigframe starts with ucontext directly and does not need
this adjustment.

QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
on ppc64. Signal delivery and return still worked because do_rt_sigreturn
had the matching wrong offset, but the vDSO DWARF unwind info encodes
the correct kernel offset. This caused any DWARF unwinder (libunwind,
libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
register values from the signal frame.

Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
setup_rt_frame and do_rt_sigreturn to match the kernel.

This was verified by A/B testing with libunwind's test suite:

  ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
           and Ltest-sig-context all change from FAIL to PASS.
  ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
           from FAIL to PASS.

Signed-off-by: Matt Turner <mattst88@gmail.com>
---
 linux-user/ppc/signal.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git ./linux-user/ppc/signal.c ./linux-user/ppc/signal.c
index 24e5a02a78..a9c10e0987 100644
--- ./linux-user/ppc/signal.c
+++ ./linux-user/ppc/signal.c
@@ -210,6 +210,18 @@ QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe, uc.tuc_mcontext)
 
 #endif
 
+#ifdef TARGET_PPC64
+#define RT_SIGFRAME_ADJUST 0
+#else
+/*
+ * For 32-bit rt sigframes we have an extra 16 bytes of gap
+ * on top of __SIGNAL_FRAMESIZE; this is to get the siginfo
+ * and ucontext in the same positions as in older kernels.
+ * See Linux's arch/powerpc/kernel/signal_32.c.
+ */
+#define RT_SIGFRAME_ADJUST 16
+#endif
+
 #if defined(TARGET_PPC64)
 
 struct target_func_ptr {
@@ -525,7 +537,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     env->fpscr = 0;
 
     /* Create a stack frame for the caller of the handler.  */
-    newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+    newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST);
     err |= put_user(env->gpr[1], newsp, target_ulong);
 
     if (err)
@@ -641,7 +653,7 @@ long do_rt_sigreturn(CPUPPCState *env)
     struct target_rt_sigframe *rt_sf = NULL;
     target_ulong rt_sf_addr;
 
-    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST;
     if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
         goto sigsegv;
 
-- 
2.52.0
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Peter Maydell 1 week, 5 days ago
On Thu, 16 Apr 2026 at 19:25, Matt Turner <mattst88@gmail.com> wrote:
>
> The kernel's 64-bit signal delivery (signal_64.c) uses:
>
>     newsp = frame - __SIGNAL_FRAMESIZE
>
> while the 32-bit path (signal_32.c) uses:
>
>     newsp = frame - (__SIGNAL_FRAMESIZE + 16)
>
> The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> at the same offsets as older kernels (see the comment in signal_32.c).
> The 64-bit rt_sigframe starts with ucontext directly and does not need
> this adjustment.
>
> QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> had the matching wrong offset, but the vDSO DWARF unwind info encodes
> the correct kernel offset. This caused any DWARF unwinder (libunwind,
> libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> register values from the signal frame.
>
> Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
> setup_rt_frame and do_rt_sigreturn to match the kernel.
>
> This was verified by A/B testing with libunwind's test suite:
>
>   ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
>            and Ltest-sig-context all change from FAIL to PASS.
>   ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
>            from FAIL to PASS.
>
> Signed-off-by: Matt Turner <mattst88@gmail.com>
> ---
>  linux-user/ppc/signal.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 1 week, 2 days ago
On Fri, Apr 17, 2026 at 4:41 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Thu, 16 Apr 2026 at 19:25, Matt Turner <mattst88@gmail.com> wrote:
> >
> > The kernel's 64-bit signal delivery (signal_64.c) uses:
> >
> >     newsp = frame - __SIGNAL_FRAMESIZE
> >
> > while the 32-bit path (signal_32.c) uses:
> >
> >     newsp = frame - (__SIGNAL_FRAMESIZE + 16)
> >
> > The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> > at the same offsets as older kernels (see the comment in signal_32.c).
> > The 64-bit rt_sigframe starts with ucontext directly and does not need
> > this adjustment.
> >
> > QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> > for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> > on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> > had the matching wrong offset, but the vDSO DWARF unwind info encodes
> > the correct kernel offset. This caused any DWARF unwinder (libunwind,
> > libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> > register values from the signal frame.
> >
> > Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
> > setup_rt_frame and do_rt_sigreturn to match the kernel.
> >
> > This was verified by A/B testing with libunwind's test suite:
> >
> >   ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
> >            and Ltest-sig-context all change from FAIL to PASS.
> >   ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
> >            from FAIL to PASS.
> >
> > Signed-off-by: Matt Turner <mattst88@gmail.com>
> > ---
> >  linux-user/ppc/signal.c | 16 ++++++++++++++--
> >  1 file changed, 14 insertions(+), 2 deletions(-)
> >
>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Thanks!

I sent this to Laurent Vivier <laurent@vivier.eu> since that's what
`get_maintainer.pl` said, but I see that he hasn't committed this
year. Should I wait on him, or can you see that this gets in?

Also, I think this is probably worth including in the stable
branch(es), so I've cc'd qemu-devel@nongnu.org.

Matt
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 6 days, 11 hours ago
On Mon, Apr 20, 2026 at 4:59 PM Matt Turner <mattst88@gmail.com> wrote:
>
> On Fri, Apr 17, 2026 at 4:41 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Thu, 16 Apr 2026 at 19:25, Matt Turner <mattst88@gmail.com> wrote:
> > >
> > > The kernel's 64-bit signal delivery (signal_64.c) uses:
> > >
> > >     newsp = frame - __SIGNAL_FRAMESIZE
> > >
> > > while the 32-bit path (signal_32.c) uses:
> > >
> > >     newsp = frame - (__SIGNAL_FRAMESIZE + 16)
> > >
> > > The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> > > at the same offsets as older kernels (see the comment in signal_32.c).
> > > The 64-bit rt_sigframe starts with ucontext directly and does not need
> > > this adjustment.
> > >
> > > QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> > > for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> > > on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> > > had the matching wrong offset, but the vDSO DWARF unwind info encodes
> > > the correct kernel offset. This caused any DWARF unwinder (libunwind,
> > > libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> > > register values from the signal frame.
> > >
> > > Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
> > > setup_rt_frame and do_rt_sigreturn to match the kernel.
> > >
> > > This was verified by A/B testing with libunwind's test suite:
> > >
> > >   ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
> > >            and Ltest-sig-context all change from FAIL to PASS.
> > >   ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
> > >            from FAIL to PASS.
> > >
> > > Signed-off-by: Matt Turner <mattst88@gmail.com>
> > > ---
> > >  linux-user/ppc/signal.c | 16 ++++++++++++++--
> > >  1 file changed, 14 insertions(+), 2 deletions(-)
> > >
> >
> > Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>
> Thanks!
>
> I sent this to Laurent Vivier <laurent@vivier.eu> since that's what
> `get_maintainer.pl` said, but I see that he hasn't committed this
> year. Should I wait on him, or can you see that this gets in?
>
> Also, I think this is probably worth including in the stable
> branch(es), so I've cc'd qemu-devel@nongnu.org.
>
> Matt

Sorry to ping. Just trying to get clarity on what I need to do.
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Helge Deller 6 days, 8 hours ago
Hi Matt,

On 4/23/26 14:02, Matt Turner wrote:
> On Mon, Apr 20, 2026 at 4:59 PM Matt Turner <mattst88@gmail.com> wrote:
>>
>> On Fri, Apr 17, 2026 at 4:41 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>>>
>>> On Thu, 16 Apr 2026 at 19:25, Matt Turner <mattst88@gmail.com> wrote:
>>>>
>>>> The kernel's 64-bit signal delivery (signal_64.c) uses:
>>>>
>>>>      newsp = frame - __SIGNAL_FRAMESIZE
>>>>
>>>> while the 32-bit path (signal_32.c) uses:
>>>>
>>>>      newsp = frame - (__SIGNAL_FRAMESIZE + 16)
>>>>
>>>> The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
>>>> at the same offsets as older kernels (see the comment in signal_32.c).
>>>> The 64-bit rt_sigframe starts with ucontext directly and does not need
>>>> this adjustment.
>>>>
>>>> QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
>>>> for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
>>>> on ppc64. Signal delivery and return still worked because do_rt_sigreturn
>>>> had the matching wrong offset, but the vDSO DWARF unwind info encodes
>>>> the correct kernel offset. This caused any DWARF unwinder (libunwind,
>>>> libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
>>>> register values from the signal frame.
>>>>
>>>> Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
>>>> setup_rt_frame and do_rt_sigreturn to match the kernel.
>>>>
>>>> This was verified by A/B testing with libunwind's test suite:
>>>>
>>>>    ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
>>>>             and Ltest-sig-context all change from FAIL to PASS.
>>>>    ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
>>>>             from FAIL to PASS.
>>>>
>>>> Signed-off-by: Matt Turner <mattst88@gmail.com>
>>>> ---
>>>>   linux-user/ppc/signal.c | 16 ++++++++++++++--
>>>>   1 file changed, 14 insertions(+), 2 deletions(-)
>>>>
>>>
>>> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
>>
>> Thanks!
>>
>> I sent this to Laurent Vivier <laurent@vivier.eu> since that's what
>> `get_maintainer.pl` said, but I see that he hasn't committed this
>> year. Should I wait on him, or can you see that this gets in?
>>
>> Also, I think this is probably worth including in the stable
>> branch(es), so I've cc'd qemu-devel@nongnu.org.
>>
>> Matt
> 
> Sorry to ping. Just trying to get clarity on what I need to do.

I've picked it up into my linux-user-next git tree and will push then
soon:

https://gitlab.com/hdeller/qemu/-/commits/linux-user-next?ref_type=heads

Helge
Re: [PATCH] linux-user/ppc: Fix ppc64 rt_sigframe stack offset
Posted by Matt Turner 6 days, 7 hours ago
On Thu, Apr 23, 2026 at 10:54 AM Helge Deller <deller@gmx.de> wrote:
>
> Hi Matt,
>
> On 4/23/26 14:02, Matt Turner wrote:
> > On Mon, Apr 20, 2026 at 4:59 PM Matt Turner <mattst88@gmail.com> wrote:
> >>
> >> On Fri, Apr 17, 2026 at 4:41 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> >>>
> >>> On Thu, 16 Apr 2026 at 19:25, Matt Turner <mattst88@gmail.com> wrote:
> >>>>
> >>>> The kernel's 64-bit signal delivery (signal_64.c) uses:
> >>>>
> >>>>      newsp = frame - __SIGNAL_FRAMESIZE
> >>>>
> >>>> while the 32-bit path (signal_32.c) uses:
> >>>>
> >>>>      newsp = frame - (__SIGNAL_FRAMESIZE + 16)
> >>>>
> >>>> The extra 16 bytes in the 32-bit case is to place siginfo and ucontext
> >>>> at the same offsets as older kernels (see the comment in signal_32.c).
> >>>> The 64-bit rt_sigframe starts with ucontext directly and does not need
> >>>> this adjustment.
> >>>>
> >>>> QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16)
> >>>> for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low
> >>>> on ppc64. Signal delivery and return still worked because do_rt_sigreturn
> >>>> had the matching wrong offset, but the vDSO DWARF unwind info encodes
> >>>> the correct kernel offset. This caused any DWARF unwinder (libunwind,
> >>>> libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage
> >>>> register values from the signal frame.
> >>>>
> >>>> Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both
> >>>> setup_rt_frame and do_rt_sigreturn to match the kernel.
> >>>>
> >>>> This was verified by A/B testing with libunwind's test suite:
> >>>>
> >>>>    ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent,
> >>>>             and Ltest-sig-context all change from FAIL to PASS.
> >>>>    ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change
> >>>>             from FAIL to PASS.
> >>>>
> >>>> Signed-off-by: Matt Turner <mattst88@gmail.com>
> >>>> ---
> >>>>   linux-user/ppc/signal.c | 16 ++++++++++++++--
> >>>>   1 file changed, 14 insertions(+), 2 deletions(-)
> >>>>
> >>>
> >>> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> >>
> >> Thanks!
> >>
> >> I sent this to Laurent Vivier <laurent@vivier.eu> since that's what
> >> `get_maintainer.pl` said, but I see that he hasn't committed this
> >> year. Should I wait on him, or can you see that this gets in?
> >>
> >> Also, I think this is probably worth including in the stable
> >> branch(es), so I've cc'd qemu-devel@nongnu.org.
> >>
> >> Matt
> >
> > Sorry to ping. Just trying to get clarity on what I need to do.
>
> I've picked it up into my linux-user-next git tree and will push then
> soon:
>
> https://gitlab.com/hdeller/qemu/-/commits/linux-user-next?ref_type=heads
>
> Helge

Awesome, thanks Helge!