]>
Commit | Line | Data |
---|---|---|
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 | ||
52 | standard_testfile | |
53 | ||
54 | if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} { | |
55 | return -1 | |
56 | } | |
57 | ||
58 | # Skip this test if Python scripting is not enabled. | |
59 | if { [skip_python_tests] } { continue } | |
60 | ||
61 | if ![runto_main] then { | |
275ee935 AB |
62 | return 0 |
63 | } | |
64 | ||
65 | set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] | |
66 | ||
67 | # Run to the breakpoint where we will carry out the test. | |
68 | gdb_breakpoint [gdb_get_line_number "Break here"] | |
69 | gdb_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. | |
73 | gdb_test_no_output "source ${pyfile}"\ | |
74 | "import python scripts" | |
75 | ||
76 | # Check the unbroken stack. | |
77 | gdb_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 | ||
87 | with_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 | ||
103 | with_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 | ||
117 | with_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. | |
132 | gdb_test "maint flush register-cache" \ | |
133 | "Register cache flushed\\." "" | |
134 | gdb_test_no_output "set debug frame 1" | |
135 | gdb_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 | } | |
143 | gdb_test "p 1 + 2 + 3" " = 6" \ | |
144 | "ensure GDB is still alive" |