diff --git a/Misc/NEWS.d/next/Build/2026-06-26-16-30-00.gh-issue-152240.loongarch.rst b/Misc/NEWS.d/next/Build/2026-06-26-16-30-00.gh-issue-152240.loongarch.rst new file mode 100644 index 000000000000000..cf2a150b95b8ac1 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-06-26-16-30-00.gh-issue-152240.loongarch.rst @@ -0,0 +1,3 @@ +Fix C stack unwinding tests on Linux LoongArch builds. The manual frame +pointer unwinder now recognizes the LoongArch frame layout, and clang builds +now request runtime unwind tables. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index d0d1f1f1bc8e53e..8de5ee502cfb4cf 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -98,6 +98,12 @@ static const uintptr_t min_frame_pointer_addr = 0x1000; // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#STACK # define FRAME_POINTER_NEXT_OFFSET 0 # define FRAME_POINTER_RETURN_OFFSET 2 +#elif defined(__loongarch__) +// On LoongArch, the frame pointer is the caller's stack pointer. +// The saved frame pointer is stored at fp[-2], and the return +// address is stored at fp[-1]. +# define FRAME_POINTER_NEXT_OFFSET -2 +# define FRAME_POINTER_RETURN_OFFSET -1 #else # define FRAME_POINTER_NEXT_OFFSET 0 # define FRAME_POINTER_RETURN_OFFSET 1 diff --git a/configure b/configure index a978b613514f124..8416de3f1a1437a 100755 --- a/configure +++ b/configure @@ -10581,6 +10581,62 @@ printf "%s\n" "#define _Py_WITH_FRAME_POINTERS 1" >>confdefs.h CFLAGS_NODIST="$CFLAGS_NODIST -std=c11" + if test "$MACHDEP" = linux && test "$ac_cv_cc_name" = clang +then : + + case $host_cpu in #( + loongarch*) : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -funwind-tables" >&5 +printf %s "checking whether C compiler accepts -funwind-tables... " >&6; } +if test ${ax_cv_check_cflags__Werror__funwind_tables+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -Werror -funwind-tables" + 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__funwind_tables=yes +else case e in #( + e) ax_cv_check_cflags__Werror__funwind_tables=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__funwind_tables" >&5 +printf "%s\n" "$ax_cv_check_cflags__Werror__funwind_tables" >&6; } +if test "x$ax_cv_check_cflags__Werror__funwind_tables" = xyes +then : + + CFLAGS_NODIST="$CFLAGS_NODIST -funwind-tables" + +else case e in #( + e) : ;; +esac +fi + + ;; #( + *) : + ;; +esac + +fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can add -Wextra" >&5 diff --git a/configure.ac b/configure.ac index a2729c22386a951..5731e03f74d47a8 100644 --- a/configure.ac +++ b/configure.ac @@ -2631,6 +2631,16 @@ AS_VAR_IF([ac_cv_gcc_compat], [yes], [ CFLAGS_NODIST="$CFLAGS_NODIST -std=c11" + AS_IF([test "$MACHDEP" = linux && test "$ac_cv_cc_name" = clang], [ + AS_CASE([$host_cpu], [loongarch*], [ + dnl clang/LoongArch emits only .debug_frame by default, which is not + dnl available to runtime unwinders such as backtrace(). + AX_CHECK_COMPILE_FLAG([-funwind-tables], [ + CFLAGS_NODIST="$CFLAGS_NODIST -funwind-tables" + ], [], [-Werror]) + ]) + ]) + PY_CHECK_CC_WARNING([enable], [extra], [if we can add -Wextra]) AS_VAR_IF([ac_cv_enable_extra_warning], [yes], [CFLAGS_NODIST="$CFLAGS_NODIST -Wextra"])