gh-149202: Fix frame pointer unwinding on ppc64le and armv7/clang (#149409)

- ppc64's backchain format is also different from x86
- On 32-bit ARM, clang needs `-mno-thumb`, not `-marm` like GCC
This commit is contained in:
Petr Viktorin 2026-05-07 10:37:00 +02:00 committed by GitHub
parent 5fcab14c35
commit 612140e7dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 56 additions and 4 deletions

View file

@ -789,14 +789,13 @@ also be used to improve performance.
- ``-fno-omit-frame-pointer`` and/or ``-mno-omit-leaf-frame-pointer``
are added when the compiler supports them.
- ``-marm`` is added on 32-bit ARM when supported,
- ``-marm`` and/or ``-mno-thumb`` is added on 32-bit ARM when supported,
- on s390x platforms, when supported, ``-mbackchain`` is added *instead*.
of the above frame pointer flags.
Frame pointers enable profilers, debuggers, and system tracing tools
(``perf``, ``eBPF``, ``dtrace``, ``gdb``) to walk the C call stack
without DWARF metadata.
The flags propagate to third-party C
without DWARF metadata. The flags propagate to third-party C
extensions through :mod:`sysconfig`. On compilers that do not
understand them, the build silently skips them.

View file

@ -92,6 +92,12 @@ static const uintptr_t min_frame_pointer_addr = 0x1000;
# define FRAME_POINTER_NEXT_OFFSET 0
# define FRAME_POINTER_RETURN_OFFSET \
(S390X_FRAME_RETURN_ADDRESS_OFFSET / (Py_ssize_t)sizeof(uintptr_t))
#elif defined(__powerpc64__) || defined(__ppc64__)
// ppc64le puts the return address at fp[2]; it saves the Condition Register
// in fp[1]. See:
// https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
# define FRAME_POINTER_NEXT_OFFSET 0
# define FRAME_POINTER_RETURN_OFFSET 2
#else
# define FRAME_POINTER_NEXT_OFFSET 0
# define FRAME_POINTER_RETURN_OFFSET 1

45
configure generated vendored
View file

@ -10346,7 +10346,7 @@ fi
case $host_cpu in #(
arm|armv*) :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -marm" >&5
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -marm" >&5
printf %s "checking whether C compiler accepts -marm... " >&6; }
if test ${ax_cv_check_cflags__Werror__marm+y}
then :
@ -10384,6 +10384,49 @@ then :
frame_pointer_cflags="$frame_pointer_cflags -marm"
else case e in #(
e) : ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -mno-thumb" >&5
printf %s "checking whether C compiler accepts -mno-thumb... " >&6; }
if test ${ax_cv_check_cflags__Werror__mno_thumb+y}
then :
printf %s "(cached) " >&6
else case e in #(
e)
ax_check_save_flags=$CFLAGS
CFLAGS="$CFLAGS -Werror -mno-thumb"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main (void)
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
ax_cv_check_cflags__Werror__mno_thumb=yes
else case e in #(
e) ax_cv_check_cflags__Werror__mno_thumb=no ;;
esac
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
CFLAGS=$ax_check_save_flags ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags__Werror__mno_thumb" >&5
printf "%s\n" "$ax_cv_check_cflags__Werror__mno_thumb" >&6; }
if test "x$ax_cv_check_cflags__Werror__mno_thumb" = xyes
then :
frame_pointer_cflags="$frame_pointer_cflags -mno-thumb"
else case e in #(
e) : ;;
esac

View file

@ -2549,9 +2549,13 @@ AS_VAR_IF([ac_cv_gcc_compat], [yes], [
frame_pointer_cflags="$frame_pointer_cflags -mno-omit-leaf-frame-pointer"
], [], [-Werror])
AS_CASE([$host_cpu], [arm|armv*], [
dnl GCC uses "-marm"; clang uses "-mno-thumb"
AX_CHECK_COMPILE_FLAG([-marm], [
frame_pointer_cflags="$frame_pointer_cflags -marm"
], [], [-Werror])
AX_CHECK_COMPILE_FLAG([-mno-thumb], [
frame_pointer_cflags="$frame_pointer_cflags -mno-thumb"
], [], [-Werror])
])
AS_CASE([$host_cpu], [s390*], [
AX_CHECK_COMPILE_FLAG([-mbackchain], [