]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / inline-frame-cycle-unwind.exp
CommitLineData
4a94e368 1# Copyright (C) 2021-2022 Free Software Foundation, Inc.
275ee935
AB
2
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.
7#
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.
12#
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/>.
15
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:
19#
20# main -> normal_frame -> inline_frame
21#
22# Now consider that, for whatever reason, the stack unwinding of
23# "normal_frame" becomes corrupted, such that the stack appears to be
24# this:
25#
26# .-> normal_frame -> inline_frame
27# | |
28# '------'
29#
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:
33#
34# Backtrace stopped: previous frame identical to this frame (corrupt stack?)
35#
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.
39#
40# This text 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:
43#
44# main -> normal_func -> inline_func -> normal_func -> inline_func -> normal_func -> inline_func
45#
46# Where "normal_func" is a normal frame, and "inline_func" is an inline frame.
47#
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
50# the stack.
51
52standard_testfile
53
54if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
55 return -1
56}
57
58# Skip this test if Python scripting is not enabled.
59if { [skip_python_tests] } { continue }
60
61if ![runto_main] then {
275ee935
AB
62 return 0
63}
64
65set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
66
67# Run to the breakpoint where we will carry out the test.
68gdb_breakpoint [gdb_get_line_number "Break here"]
69gdb_continue_to_breakpoint "stop at test breakpoint"
70
71# Load the script containing the unwinder, this must be done at the
72# testing point as the script will examine the stack as it is loaded.
73gdb_test_no_output "source ${pyfile}"\
74 "import python scripts"
75
76# Check the unbroken stack.
77gdb_test_sequence "bt" "backtrace when the unwind is left unbroken" {
78 "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at "
79 "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at "
80 "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at "
81 "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at "
82 "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at "
83 "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at "
84 "\\r\\n#6 \[^\r\n\]* main \\(\\) at "
85}
86
87with_test_prefix "cycle at level 5" {
88 # Arrange to introduce a stack cycle at frame 5.
89 gdb_test_no_output "python stop_at_level=5"
90 gdb_test "maint flush register-cache" \
91 "Register cache flushed\\."
92 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 5" \
93 [multi_line \
94 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
95 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
96 "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
97 "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
98 "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
99 "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
100 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
101}
102
103with_test_prefix "cycle at level 3" {
104 # Arrange to introduce a stack cycle at frame 3.
105 gdb_test_no_output "python stop_at_level=3"
106 gdb_test "maint flush register-cache" \
107 "Register cache flushed\\."
108 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 3" \
109 [multi_line \
110 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
111 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
112 "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
113 "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
114 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
115}
116
117with_test_prefix "cycle at level 1" {
118 # Arrange to introduce a stack cycle at frame 1.
119 gdb_test_no_output "python stop_at_level=1"
120 gdb_test "maint flush register-cache" \
121 "Register cache flushed\\."
122 gdb_test_lines "bt" "backtrace when the unwind is broken at frame 1" \
123 [multi_line \
124 "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
125 "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
126 "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
127}
128
129# Flush the register cache (which also flushes the frame cache) so we
130# get a full backtrace again, then switch on frame debugging and try
131# to back trace. At one point this triggered an assertion.
132gdb_test "maint flush register-cache" \
133 "Register cache flushed\\." ""
134gdb_test_no_output "set debug frame 1"
135gdb_test_multiple "bt" "backtrace with debugging on" {
136 -re "^$gdb_prompt $" {
137 pass $gdb_test_name
138 }
139 -re "\[^\r\n\]+\r\n" {
140 exp_continue
141 }
142}
143gdb_test "p 1 + 2 + 3" " = 6" \
144 "ensure GDB is still alive"