Skip to content

gh-152240: Fix test_c_stack_unwind on Linux LoongArch builds#152241

Open
yzewei wants to merge 1 commit into
python:mainfrom
Loongson-Cloud-Community:loongarch-clang-unwind
Open

gh-152240: Fix test_c_stack_unwind on Linux LoongArch builds#152241
yzewei wants to merge 1 commit into
python:mainfrom
Loongson-Cloud-Community:loongarch-clang-unwind

Conversation

@yzewei

@yzewei yzewei commented Jun 26, 2026

Copy link
Copy Markdown

Fix test_c_stack_unwind on Linux LoongArch builds.

This change teaches _testinternalcapi's manual frame-pointer unwinder about
the LoongArch frame layout. On LoongArch, the frame pointer is the caller's
stack pointer; the previous frame pointer is at fp[-2], and the return
address is at fp[-1].

It also adds -funwind-tables for Linux LoongArch clang builds. clang/LoongArch
emits .debug_frame but not runtime .eh_frame unwind tables by default, so
glibc backtrace() cannot unwind through CPython frames unless unwind tables
are requested.

Validated on Linux LoongArch64:

GCC build:

../cpython/configure --with-pydebug CC=gcc
make -j8
PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind

clang build with clang 20.1.8:

../cpython/configure --with-pydebug CC=clang
make -j8
PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind

Also verified that -funwind-tables makes CPython C objects contain
.eh_frame, and the GNU backtrace test passes.

@python-cla-bot

python-cla-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@yzewei

yzewei commented Jun 26, 2026

Copy link
Copy Markdown
Author

Fix log:

Gcc:

PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind
== CPython 3.16.0a0 (heads/main-dirty:a00464bc33) [GCC 15.2.0 20250808]
== Linux-6.18.16-main-16k-loongarch64-with-glibc2.42 little-endian
== Python build: release
== cwd: /mnt/build-cpython-main-gcc-release/build/test_python_worker_480813æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources: all test resources are disabled, use -u option to unskip tests

Using random seed: 4035734376
0:00:00 load avg: 0.08 mem: 27.8 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 0.08 mem: 27.8 MiB [1/1] test_c_stack_unwind
test_gnu_backtrace_jit_frames_disappear_after_executor_free (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_jit_frames_disappear_after_executor_free) ... skipped 'JIT is not available'
test_gnu_backtrace_unwinds_through_jit_frames (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_unwinds_through_jit_frames) ... #00 0x7fffe3601470 -> other
#01 0x555558360384 -> python
#02 0x5555585569fc -> python
#03 0x55555855e82c -> python
#04 0x55555856d86c -> python
#05 0x555558360384 -> python
#06 0x5555585570a4 -> python
#07 0x555558563cbc -> python
#08 0x55555856d86c -> python
#09 0x555558360384 -> python
#10 0x5555585570a4 -> python
#11 0x555558563cbc -> python
#12 0x55555856d86c -> python
#13 0x555558360384 -> python
#14 0x5555585570a4 -> python
#15 0x555558563cbc -> python
#16 0x55555856d86c -> python
#17 0x555558360384 -> python
#18 0x5555585570a4 -> python
#19 0x555558563cbc -> python
#20 0x55555856d86c -> python
#21 0x555558360384 -> python
#22 0x5555585570a4 -> python
#23 0x555558563cbc -> python
#24 0x55555856d86c -> python
#25 0x555558360384 -> python
#26 0x5555585570a4 -> python
#27 0x555558563cbc -> python
#28 0x55555856d86c -> python
#29 0x555558360384 -> python
#30 0x5555585570a4 -> python
#31 0x555558563cbc -> python
#32 0x55555856d86c -> python
#33 0x555558360384 -> python
#34 0x5555585570a4 -> python
#35 0x555558563cbc -> python
#36 0x55555856d86c -> python
#37 0x555558360384 -> python
#38 0x5555585570a4 -> python
#39 0x555558563cbc -> python
#40 0x55555856d86c -> python
#41 0x555558360384 -> python
#42 0x555558360384 -> python
#43 0x5555585569fc -> python
#44 0x55555855e82c -> python
#45 0x55555856d510 -> python
#46 0x555558605d00 -> python
#47 0x55555860622c -> python
#48 0x555558608efc -> python
#49 0x555558644a6c -> python
#50 0x555558645a34 -> python
#51 0x7ffff22bd964 -> other
#52 0x7ffff22bda6c -> other
#53 0x5555582d694c -> python
{"length": 54, "python_frames": 51, "jit_frames": 0, "other_frames": 3, "jit_backend": null, "unwinder": "gnu_backtrace_unwind"}
ok
test_manual_unwind_finds_expected_frames (test.test_c_stack_unwind.ManualStackUnwindTests.test_manual_unwind_finds_expected_frames) ... #00 0x555558240384 -> python
#01 0x5555584369fc -> python
#02 0x55555843e82c -> python
#03 0x55555844d86c -> python
#04 0x555558240384 -> python
#05 0x5555584370a4 -> python
#06 0x555558443cbc -> python
#07 0x55555844d86c -> python
#08 0x555558240384 -> python
#09 0x5555584370a4 -> python
#10 0x555558443cbc -> python
#11 0x55555844d86c -> python
#12 0x555558240384 -> python
#13 0x5555584370a4 -> python
#14 0x555558443cbc -> python
#15 0x55555844d86c -> python
#16 0x555558240384 -> python
#17 0x5555584370a4 -> python
#18 0x555558443cbc -> python
#19 0x55555844d86c -> python
#20 0x555558240384 -> python
#21 0x5555584370a4 -> python
#22 0x555558443cbc -> python
#23 0x55555844d86c -> python
#24 0x555558240384 -> python
#25 0x5555584370a4 -> python
#26 0x555558443cbc -> python
#27 0x55555844d86c -> python
#28 0x555558240384 -> python
#29 0x5555584370a4 -> python
#30 0x555558443cbc -> python
#31 0x55555844d86c -> python
#32 0x555558240384 -> python
#33 0x5555584370a4 -> python
#34 0x555558443cbc -> python
#35 0x55555844d86c -> python
#36 0x555558240384 -> python
#37 0x5555584370a4 -> python
#38 0x555558443cbc -> python
#39 0x55555844d86c -> python
#40 0x555558240384 -> python
#41 0x555558240384 -> python
#42 0x5555584369fc -> python
#43 0x55555843e82c -> python
#44 0x55555844d510 -> python
#45 0x5555584e5d00 -> python
#46 0x5555584e622c -> python
#47 0x5555584e8efc -> python
#48 0x555558524a6c -> python
#49 0x555558525a34 -> python
#50 0x7ffff31dd964 -> other
#51 0x7ffff31dda6c -> other
#52 0x5555581b694c -> python
{"length": 53, "python_frames": 51, "jit_frames": 0, "other_frames": 2, "jit_backend": null, "unwinder": "manual_frame_pointer_unwind"}
ok

----------------------------------------------------------------------
Ran 3 tests in 1.347s

OK (skipped=1)
0:00:01 load avg: 0.08 mem: 28.3 MiB [1/1] test_c_stack_unwind passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 1.4 sec
Total tests: run=3 skipped=1
Total test files: run=1/1
Result: SUCCESS

Clang

PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind
== CPython 3.16.0a0 (heads/main-dirty:a00464bc33) [Clang 20.1.8 ]
== Linux-6.18.16-main-16k-loongarch64-with-glibc2.42 little-endian
== Python build: debug
== cwd: /mnt/build-cpython-main-clang-debug/build/test_python_worker_480864æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources: all test resources are disabled, use -u option to unskip tests

Using random seed: 721941152
0:00:00 load avg: 0.02 mem: 31.4 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 0.02 mem: 31.4 MiB [1/1] test_c_stack_unwind
test_gnu_backtrace_jit_frames_disappear_after_executor_free (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_jit_frames_disappear_after_executor_free) ... skipped 'JIT is not available'
test_gnu_backtrace_unwinds_through_jit_frames (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_unwinds_through_jit_frames) ... #00 0x7ffff008dea4 -> other
#01 0x555556ec1308 -> python
#02 0x555556e341e8 -> python
#03 0x555556ff546c -> python
#04 0x555556ffc0c8 -> python
#05 0x555556ff4adc -> python
#06 0x555556e341e8 -> python
#07 0x555556ff5a90 -> python
#08 0x555556ffdbd0 -> python
#09 0x555556ff4adc -> python
#10 0x555556e341e8 -> python
#11 0x555556ff5a90 -> python
#12 0x555556ffdbd0 -> python
#13 0x555556ff4adc -> python
#14 0x555556e341e8 -> python
#15 0x555556ff5a90 -> python
#16 0x555556ffdbd0 -> python
#17 0x555556ff4adc -> python
#18 0x555556e341e8 -> python
#19 0x555556ff5a90 -> python
#20 0x555556ffdbd0 -> python
#21 0x555556ff4adc -> python
#22 0x555556e341e8 -> python
#23 0x555556ff5a90 -> python
#24 0x555556ffdbd0 -> python
#25 0x555556ff4adc -> python
#26 0x555556e341e8 -> python
#27 0x555556ff5a90 -> python
#28 0x555556ffdbd0 -> python
#29 0x555556ff4adc -> python
#30 0x555556e341e8 -> python
#31 0x555556ff5a90 -> python
#32 0x555556ffdbd0 -> python
#33 0x555556ff4adc -> python
#34 0x555556e341e8 -> python
#35 0x555556ff5a90 -> python
#36 0x555556ffdbd0 -> python
#37 0x555556ff4adc -> python
#38 0x555556e341e8 -> python
#39 0x555556ff5a90 -> python
#40 0x555556ffdbd0 -> python
#41 0x555556ff4adc -> python
#42 0x555556e341e8 -> python
#43 0x555556ec1104 -> python
#44 0x555556e341e8 -> python
#45 0x555556ff546c -> python
#46 0x555556ffc0c8 -> python
#47 0x555556ff4adc -> python
#48 0x555556ff4714 -> python
#49 0x5555570e784c -> python
#50 0x5555570e4da0 -> python
#51 0x5555570e4a04 -> python
#52 0x55555711b6f8 -> python
#53 0x55555711bba8 -> python
#54 0x55555711bc0c -> python
#55 0x7ffff0f7d964 -> other
#56 0x7ffff0f7da6c -> other
#57 0x555556d8c9a4 -> python
{"length": 58, "python_frames": 55, "jit_frames": 0, "other_frames": 3, "jit_backend": null, "unwinder": "gnu_backtrace_unwind"}
ok
test_manual_unwind_finds_expected_frames (test.test_c_stack_unwind.ManualStackUnwindTests.test_manual_unwind_finds_expected_frames) ... #00 0x555556961308 -> python
#01 0x5555568d41e8 -> python
#02 0x555556a9546c -> python
#03 0x555556a9c0c8 -> python
#04 0x555556a94adc -> python
#05 0x5555568d41e8 -> python
#06 0x555556a95a90 -> python
#07 0x555556a9dbd0 -> python
#08 0x555556a94adc -> python
#09 0x5555568d41e8 -> python
#10 0x555556a95a90 -> python
#11 0x555556a9dbd0 -> python
#12 0x555556a94adc -> python
#13 0x5555568d41e8 -> python
#14 0x555556a95a90 -> python
#15 0x555556a9dbd0 -> python
#16 0x555556a94adc -> python
#17 0x5555568d41e8 -> python
#18 0x555556a95a90 -> python
#19 0x555556a9dbd0 -> python
#20 0x555556a94adc -> python
#21 0x5555568d41e8 -> python
#22 0x555556a95a90 -> python
#23 0x555556a9dbd0 -> python
#24 0x555556a94adc -> python
#25 0x5555568d41e8 -> python
#26 0x555556a95a90 -> python
#27 0x555556a9dbd0 -> python
#28 0x555556a94adc -> python
#29 0x5555568d41e8 -> python
#30 0x555556a95a90 -> python
#31 0x555556a9dbd0 -> python
#32 0x555556a94adc -> python
#33 0x5555568d41e8 -> python
#34 0x555556a95a90 -> python
#35 0x555556a9dbd0 -> python
#36 0x555556a94adc -> python
#37 0x5555568d41e8 -> python
#38 0x555556a95a90 -> python
#39 0x555556a9dbd0 -> python
#40 0x555556a94adc -> python
#41 0x5555568d41e8 -> python
#42 0x555556961104 -> python
#43 0x5555568d41e8 -> python
#44 0x555556a9546c -> python
#45 0x555556a9c0c8 -> python
#46 0x555556a94adc -> python
#47 0x555556a94714 -> python
#48 0x555556b8784c -> python
#49 0x555556b84da0 -> python
#50 0x555556b84a04 -> python
#51 0x555556bbb6f8 -> python
#52 0x555556bbbba8 -> python
#53 0x555556bbbc0c -> python
#54 0x7ffff028d964 -> other
#55 0x7ffff028da6c -> other
#56 0x55555682c9a4 -> python
{"length": 57, "python_frames": 55, "jit_frames": 0, "other_frames": 2, "jit_backend": null, "unwinder": "manual_frame_pointer_unwind"}
ok

----------------------------------------------------------------------
Ran 3 tests in 2.709s

OK (skipped=1)
0:00:02 load avg: 0.10 mem: 31.9 MiB [1/1] test_c_stack_unwind passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 2.8 sec
Total tests: run=3 skipped=1
Total test files: run=1/1
Result: SUCCESS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant