linux-user/ppc/signal.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
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
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
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.
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
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
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
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.
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
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!
© 2016 - 2026 Red Hat, Inc.