1 # Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 # This test checks for an edge case when unwinding inline frames which
17 # occur towards the older end of the stack when the stack ends with a
18 # cycle. Consider this well formed stack:
20 # main -> normal_frame -> inline_frame
22 # Now consider that, for whatever reason, the stack unwinding of
23 # "normal_frame" becomes corrupted, such that the stack appears to be
26 # .-> normal_frame -> inline_frame
30 # When confronted with such a situation we would expect GDB to detect
31 # the stack frame cycle and terminate the backtrace at the first
32 # instance of "normal_frame" with a message:
34 # Backtrace stopped: previous frame identical to this frame (corrupt stack?)
36 # However, at one point there was a bug in GDB's inline frame
37 # mechanism such that the fact that "inline_frame" was inlined into
38 # "normal_frame" would cause GDB to trigger an assertion.
40 # This test makes use of a Python unwinder which can fake the cyclic
41 # stack cycle, further the test sets up multiple levels of normal and
42 # inline frames. At the point of testing the stack looks like this:
44 # main -> normal_func -> inline_func -> normal_func -> inline_func -> normal_func -> inline_func
46 # Where "normal_func" is a normal frame, and "inline_func" is an inline frame.
48 # The python unwinder is then used to force a stack cycle at each
49 # "normal_func" frame in turn, we then check that GDB can successfully unwind
54 require allow_python_tests
56 if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
64 set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
66 # Run to the breakpoint where we will carry out the test.
67 gdb_breakpoint [gdb_get_line_number "Break here"]
68 gdb_continue_to_breakpoint "stop at test breakpoint"
70 # Load the script containing the unwinder, this must be done at the
71 # testing point as the script will examine the stack as it is loaded.
72 gdb_test_no_output "source ${pyfile}"\
73 "import python scripts"
75 # Check the unbroken stack.
76 gdb_test_sequence "bt" "backtrace when the unwind is left unbroken" {
77 "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at "
78 "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at "
79 "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at "
80 "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at "
81 "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at "
82 "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at "
83 "\\r\\n#6 \[^\r\n\]* main \\(\\) at "
86 with_test_prefix "cycle at level 5" {
87 # Arrange to introduce a stack cycle at frame 5.
88 gdb_test_no_output "python stop_at_level=5"
89 gdb_test "maint flush register-cache" \
90 "Register cache flushed\\."
91 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 5" \
93 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
94 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
95 "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
96 "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
97 "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
98 "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
99 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
102 with_test_prefix "cycle at level 3" {
103 # Arrange to introduce a stack cycle at frame 3.
104 gdb_test_no_output "python stop_at_level=3"
105 gdb_test "maint flush register-cache" \
106 "Register cache flushed\\."
107 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 3" \
109 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
110 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
111 "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
112 "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
113 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
116 with_test_prefix "cycle at level 1" {
117 # Arrange to introduce a stack cycle at frame 1.
118 gdb_test_no_output "python stop_at_level=1"
119 gdb_test "maint flush register-cache" \
120 "Register cache flushed\\."
121 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 1" \
123 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
124 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
125 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
128 # Flush the register cache (which also flushes the frame cache) so we
129 # get a full backtrace again, then switch on frame debugging and try
130 # to back trace. At one point this triggered an assertion.
131 gdb_test "maint flush register-cache" \
132 "Register cache flushed\\." ""
133 gdb_test_no_output "set debug frame 1"
135 gdb_test_multiple "bt" "backtrace with debugging on" {
136 -re "^$gdb_prompt $" {
137 gdb_assert { $ok } $gdb_test_name
139 -re "Python Exception <class 'gdb.error'>: \[^\r\n\]*\r\n" {
143 -re "\[^\r\n\]+\r\n" {
147 gdb_test "p 1 + 2 + 3" " = 6" \
148 "ensure GDB is still alive"