Remove path name from test case
[binutils-gdb.git] / gdb / testsuite / gdb.python / py-unwind.exp
1 # Copyright (C) 2015-2023 Free Software Foundation, Inc.
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 file is part of the GDB testsuite. It verifies that frame
17 # unwinders can be implemented in Python.
18
19 load_lib gdb-python.exp
20
21 require allow_python_tests
22
23 standard_testfile
24
25 # Stack protection can make the stack look a bit different, breaking the
26 # assumptions this test has about its layout.
27
28 set flags "additional_flags=-fno-stack-protector"
29
30 if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} "debug $flags"] } {
31 return -1
32 }
33
34 # This test runs on a specific platform.
35 require is_x86_64_m64_target
36
37 # The following tests require execution.
38
39 if {![runto_main]} {
40 return 0
41 }
42
43 # Check for the corrupt backtrace.
44 proc check_for_broken_backtrace {testname} {
45 gdb_test_sequence "where" $testname {
46 "\\r\\n#0 .* corrupt_frame_inner \\(\\) at "
47 "\\r\\n#1 .* corrupt_frame_outer \\(\\) at "
48 "Backtrace stopped: frame did not save the PC"
49 }
50 }
51
52 # Check for the correct backtrace.
53 proc check_for_fixed_backtrace {testname} {
54 gdb_test_sequence "where" $testname {
55 "\\r\\n#0 .* corrupt_frame_inner \\(\\) at "
56 "\\r\\n#1 .* corrupt_frame_outer \\(\\) at "
57 "\\r\\n#2 .* main \\(.*\\) at"
58 }
59 }
60
61 # Check the 'info unwinder' output.
62 proc check_info_unwinder {testname enabled} {
63 if {$enabled} {
64 set suffix ""
65 } else {
66 set suffix " \\\[disabled\\\]"
67 }
68
69 gdb_test_sequence "info unwinder" $testname \
70 [list \
71 "Global:" \
72 " test unwinder${suffix}"]
73 }
74
75 set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
76
77 gdb_breakpoint [gdb_get_line_number "break backtrace-broken"]
78
79 gdb_continue_to_breakpoint "break backtrace-broken"
80
81 check_for_broken_backtrace "Backtrace is initially broken"
82
83 gdb_test "source ${pyfile}" "Python script imported" \
84 "import python scripts"
85
86 check_info_unwinder "info unwinder after loading script" on
87
88 check_for_fixed_backtrace "check backtrace after loading unwinder"
89
90 # Check that the Python unwinder frames can be flushed / released.
91 gdb_test "maint flush register-cache" "Register cache flushed\\." "flush frames"
92
93 check_for_fixed_backtrace "check backtrace after flush"
94
95 # Try to disable the unwinder but instead set the enabled field to a
96 # non boolean value. This should fail. Check the 'info unwinder'
97 # output to be sure.
98 gdb_test "python global_test_unwinder.enabled = \"off\"" \
99 [multi_line \
100 "TypeError: incorrect type for enabled attribute: <class 'str'>" \
101 "Error while executing Python code\\."]
102 check_info_unwinder "info unwinder after failed disable" on
103
104 # While we're doing silly stuff, lets try to change the name of this
105 # unwider. Doing this is bad as the new name might clash with an
106 # already registered name, which violates the promises made during
107 # 'register_unwinder'.
108 set pattern_1 "can't set attribute(?: 'name')?"
109 set pattern_2 "property 'name' of 'TestUnwinder' object has no setter"
110 gdb_test "python global_test_unwinder.name = \"foo\"" \
111 [multi_line \
112 "AttributeError: (?:${pattern_1}|${pattern_2})" \
113 "Error while executing Python code\\."]
114 check_info_unwinder "info unwinder after failed name change" on
115
116 # Now actually disable the unwinder by manually adjusting the
117 # 'enabled' attribute. Check that the stack is once again broken, and
118 # that the unwinder shows as disabled in the 'info unwinder' output.
119 gdb_test_no_output "python global_test_unwinder.enabled = False"
120 check_for_broken_backtrace "stack is broken after disabling"
121 check_info_unwinder "info unwinder after manually disabling" off
122
123 # Now enable the unwinder using the 'enable unwinder' command.
124 gdb_test "enable unwinder global \"test unwinder\"" \
125 "1 unwinder enabled"
126 check_for_fixed_backtrace "check backtrace after enabling with command"
127 check_info_unwinder "info unwinder after command enabled" on
128
129 # And now disable using the command and check the stack is once again
130 # broken, and that the 'info unwinder' output updates correctly.
131 gdb_test "disable unwinder global \"test unwinder\"" \
132 "1 unwinder disabled"
133 check_for_broken_backtrace "stack is broken after command disabling"
134 check_info_unwinder "info unwinder after command disabling" off
135
136 # Check that invalid register names and values cause errors.
137 gdb_test "python print(add_saved_register_errors\[\"unknown_name\"\])" \
138 "Bad register" \
139 "add_saved_register error when an unknown register name is used"
140 gdb_test "python print(add_saved_register_errors\[\"unknown_number\"\])" \
141 "Bad register" \
142 "add_saved_register error when an unknown register number is used"
143 gdb_test "python print(add_saved_register_errors\[\"bad_value\"\])" \
144 "argument 2 must be gdb.Value, not int" \
145 "add_saved_register error when invalid register value is used"
146 gdb_test "python print(read_register_error)" "Bad register" \
147 "read_register error"
148
149 # Try to create an unwinder object with a non-string name.
150 gdb_test "python obj = simple_unwinder(True)" \
151 [multi_line \
152 "TypeError: incorrect type for name: <class 'bool'>" \
153 "Error while executing Python code\\."]
154
155 # Now register the simple_unwinder with a valid name, and use the
156 # unwinder to capture a PendingFrame object.
157 gdb_test_no_output "python obj = simple_unwinder(\"simple\")"
158 gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj)"
159 check_for_broken_backtrace "backtrace to capture a PendingFrame object"
160
161 # Check the captured PendingFrame is not valid.
162 gdb_test "python print(captured_pending_frame.is_valid())" "False"
163
164 # Check the __repr__ of an invalid PendingFrame.
165 gdb_test "python print(repr(captured_pending_frame))" \
166 "<gdb.PendingFrame \\(invalid\\)>"
167
168 # Check the __repr__ of an UnwindInfo for an invalid PendingFrame.
169 gdb_test "python print(captured_unwind_info)"
170 gdb_test "python print(repr(captured_unwind_info))" \
171 "<gdb.UnwindInfo for an invalid frame>"
172
173 # Check the repr of a PendingFrame that was copied (as a string) at a
174 # time the PendingFrame was valid.
175 gdb_test "python print(captured_pending_frame_repr)" \
176 "<gdb.PendingFrame level=0, sp=$hex, pc=$hex>"
177
178 # Check the repr of an UnwindInfo that was copied (as a string) at a
179 # time the UnwindInfo was valid.
180 gdb_test "python print(captured_unwind_info_repr)" \
181 "<gdb.UnwindInfo frame #0, saved_regs=\\(rip, rbp, rsp\\)>"
182
183 # Call methods on the captured gdb.PendingFrame and check we see the
184 # expected error.
185 gdb_test_no_output "python pf = captured_pending_frame"
186 foreach cmd {"pf.read_register(\"pc\")" \
187 "pf.create_unwind_info(None)" \
188 "pf.architecture()" \
189 "pf.level()" \
190 "pf.name()" \
191 "pf.pc()" \
192 "pf.language()" \
193 "pf.find_sal()" \
194 "pf.block()" \
195 "pf.function()" } {
196 gdb_test "python $cmd" \
197 [multi_line \
198 "ValueError: gdb\\.PendingFrame is invalid\\." \
199 "Error while executing Python code\\."]
200 }
201
202 # Turn on the useful unwinder so we have the full backtrace again, and
203 # disable the simple unwinder -- because we can!
204 gdb_test "enable unwinder global \"test unwinder\"" \
205 "1 unwinder enabled" \
206 "re-enable 'test unwinder' so we can check PendingFrame methods"
207 gdb_test "disable unwinder global \"simple\"" \
208 "1 unwinder disabled"
209 check_for_fixed_backtrace \
210 "check backtrace before testing PendingFrame methods"
211
212 # Turn the 'simple' unwinder back on.
213 gdb_test "enable unwinder global \"simple\"" \
214 "1 unwinder enabled"
215
216 # Replace the "simple" unwinder with a new version that doesn't set
217 # the 'sp' attribute. Also the 'pc' attribute is invalid, but we'll
218 # hit the missing 'sp' error first.
219 with_test_prefix "frame-id 'sp' is None" {
220 gdb_test_no_output "python obj = simple_unwinder(\"simple\", None, \"xyz\")"
221 gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
222 gdb_test_no_output "python captured_pending_frame = None"
223 gdb_test "backtrace" \
224 "Python Exception <class 'ValueError'>: frame_id should have 'sp' attribute\\.\r\n.*"
225 }
226
227 # Replace the "simple" unwinder with a new version that sets the 'sp'
228 # attribute to an invalid value. Also the 'pc' attribute is invalid, but we'll
229 # hit the invalid 'sp' error first.
230 with_test_prefix "frame-id 'sp' is invalid" {
231 gdb_test_no_output "python obj = simple_unwinder(\"simple\", \"jkl\", \"xyz\")"
232 gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
233 gdb_test_no_output "python captured_pending_frame = None"
234 gdb_test "backtrace" \
235 "Python Exception <class 'ValueError'>: invalid literal for int\\(\\) with base 10: 'jkl'\r\n.*"
236 }
237
238 # Replace the "simple" unwinder with a new version that sets the 'sp'
239 # to a valid value, but set the 'pc' attribute to an invalid value.
240 with_test_prefix "frame-id 'pc' is invalid" {
241 gdb_test_no_output "python obj = simple_unwinder(\"simple\", 0x123, \"xyz\")"
242 gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)"
243 gdb_test_no_output "python captured_pending_frame = None"
244 gdb_test "backtrace" \
245 "Python Exception <class 'ValueError'>: invalid literal for int\\(\\) with base 10: 'xyz'\r\n.*"
246 }
247
248 # Gather information about every frame.
249 gdb_test_no_output "python capture_all_frame_information()"
250 gdb_test_no_output "python gdb.newest_frame().select()"
251 gdb_test_no_output "python pspace = gdb.selected_inferior().progspace"
252 gdb_test_no_output "python obj = validating_unwinder()"
253 gdb_test_no_output "python gdb.unwinder.register_unwinder(pspace, obj)"
254
255 check_for_fixed_backtrace \
256 "check backtrace to validate all information"
257
258 gdb_test_no_output "python check_all_frame_information_matched()"
259
260 # Check we can't sub-class from gdb.UnwindInfo.
261 gdb_test_multiline "Sub-class gdb.UnwindInfo " \
262 "python" "" \
263 "class my_unwind_info(gdb.UnwindInfo):" "" \
264 " def __init__(self):" "" \
265 " pass" "" \
266 "end" \
267 [multi_line \
268 "TypeError: type 'gdb\\.UnwindInfo' is not an acceptable base type" \
269 "Error while executing Python code\\."]
270
271 # Check we can't directly instantiate a gdb.UnwindInfo.
272 gdb_test "python uw = gdb.UnwindInfo()" \
273 [multi_line \
274 "TypeError: cannot create 'gdb\\.UnwindInfo' instances" \
275 "Error while executing Python code\\."]