]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright (C) 2023-2024 Free Software Foundation, Inc. |
8f6c452b 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 | load_lib gdb-python.exp | |
17 | ||
18 | require allow_python_tests | |
19 | ||
20 | standard_testfile | |
21 | ||
22 | if {[build_executable "failed to prepare" ${testfile} ${srcfile}]} { | |
23 | return -1 | |
24 | } | |
25 | ||
26 | # Remove debug information from BINFILE and place it into | |
27 | # BINFILE.debug. | |
28 | if {[gdb_gnu_strip_debug $binfile]} { | |
29 | unsupported "cannot produce separate debug info files" | |
30 | return -1 | |
31 | } | |
32 | ||
33 | set remote_python_file \ | |
34 | [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] | |
35 | ||
36 | set debug_filename ${binfile}.debug | |
37 | set hidden_filename ${binfile}.hidden | |
38 | ||
39 | # Start GDB. | |
40 | clean_restart | |
41 | ||
42 | # Some initial sanity checks; initially, we can find the debug information | |
43 | # (this will use the .gnu_debuglink), then after we move the debug | |
44 | # information, reload the executable, now the debug can't be found. | |
45 | with_test_prefix "initial checks" { | |
46 | # Load BINFILE, we should find the separate debug information. | |
47 | gdb_file_cmd $binfile | |
48 | gdb_assert {$gdb_file_cmd_debug_info == "debug"} \ | |
49 | "debug info is found" | |
50 | ||
51 | # Rename the debug information file, re-load BINFILE, GDB should fail | |
52 | # to find the debug information | |
53 | remote_exec build "mv $debug_filename $hidden_filename" | |
54 | gdb_file_cmd $binfile | |
55 | gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ | |
56 | "debug info no longer found" | |
57 | } | |
58 | ||
59 | # Load the Python script into GDB. | |
60 | gdb_test "source $remote_python_file" "^Success" \ | |
61 | "source python script" | |
62 | ||
63 | # Setup the separate debug info directory. This isn't actually needed until | |
64 | # some of the later tests, but might as well get this done now. | |
65 | set debug_directory [standard_output_file "debug-dir"] | |
66 | remote_exec build "mkdir -p $debug_directory" | |
67 | gdb_test_no_output "set debug-file-directory $debug_directory" \ | |
68 | "set debug-file-directory" | |
69 | ||
70 | # Initially the missing debug handler we install is in a mode where it | |
71 | # returns None, indicating that it can't help locate the debug information. | |
72 | # Check this works as expected. | |
73 | with_test_prefix "handler returning None" { | |
74 | gdb_test_no_output \ | |
75 | "python gdb.missing_debug.register_handler(None, handler_obj)" \ | |
76 | "register the initial handler" | |
77 | ||
78 | gdb_file_cmd $binfile | |
79 | gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ | |
80 | "debug info not found" | |
81 | ||
82 | # Check the handler was only called once. | |
83 | gdb_test "python print(handler_obj.call_count)" "^1" \ | |
84 | "check handler was only called once" | |
85 | } | |
86 | ||
87 | # Now configure the handler to move the debug file back to the | |
88 | # .gnu_debuglink location and then return True, this will cause GDB to | |
89 | # recheck, at which point it should find the debug info. | |
90 | with_test_prefix "handler in gnu_debuglink mode" { | |
91 | gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ | |
92 | \"$hidden_filename\", \ | |
93 | \"$debug_filename\")" \ | |
94 | "confirgure handler" | |
95 | gdb_file_cmd $binfile | |
96 | gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" | |
97 | ||
98 | # Check the handler was only called once. | |
99 | gdb_test "python print(handler_obj.call_count)" "^1" \ | |
100 | "check handler was only called once" | |
101 | } | |
102 | ||
103 | # Setup a directory structure based on the build-id of BINFILE, but don't | |
104 | # move the debug information into place just yet. | |
105 | # | |
106 | # Instead, configure the handler to move the debug info into the build-id | |
107 | # directory. | |
108 | # | |
109 | # Reload BINFILE, at which point the handler will move the debug info into | |
110 | # the build-id directory and return True, GDB will then recheck for the | |
111 | # debug information, and should find it. | |
112 | with_test_prefix "handler in build-id mode" { | |
113 | # Move the debug file out of the way once more. | |
114 | remote_exec build "mv $debug_filename $hidden_filename" | |
115 | ||
116 | # Create the build-id based directory in which the debug information | |
117 | # will be placed. | |
118 | set build_id_filename \ | |
119 | $debug_directory/[build_id_debug_filename_get $binfile] | |
120 | remote_exec build "mkdir -p [file dirname $build_id_filename]" | |
121 | ||
122 | # Configure the handler to move the debug info into the build-id dir. | |
123 | gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ | |
124 | \"$hidden_filename\", \ | |
125 | \"$build_id_filename\")" \ | |
126 | "confirgure handler" | |
127 | ||
128 | # Reload the binary and check the debug information is found. | |
129 | gdb_file_cmd $binfile | |
130 | gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" | |
131 | ||
132 | # Check the handler was only called once. | |
133 | gdb_test "python print(handler_obj.call_count)" "^1" \ | |
134 | "check handler was only called once" | |
135 | } | |
136 | ||
137 | # Move the debug information back to a hidden location and configure the | |
138 | # handler to return the filename of the hidden debug info location. GDB | |
139 | # should immediately use this file as the debug information. | |
140 | with_test_prefix "handler returning a string" { | |
141 | remote_exec build "mv $build_id_filename $hidden_filename" | |
142 | ||
143 | # Configure the handler return a filename string. | |
144 | gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \ | |
145 | \"$hidden_filename\")" \ | |
146 | "confirgure handler" | |
147 | ||
148 | # Reload the binary and check the debug information is found. | |
149 | gdb_file_cmd $binfile | |
150 | gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" | |
151 | ||
152 | # Check the handler was only called once. | |
153 | gdb_test "python print(handler_obj.call_count)" "^1" \ | |
154 | "check handler was only called once" | |
155 | } | |
156 | ||
157 | # Register another global handler, this one raises an exception. Reload the | |
158 | # debug information, the bad handler should be invoked first, which raises | |
159 | # an excetption, at which point GDB should skip further Python handlers. | |
160 | with_test_prefix "handler raises an exception" { | |
161 | gdb_test_no_output \ | |
162 | "python gdb.missing_debug.register_handler(None, rhandler)" | |
163 | ||
164 | foreach_with_prefix exception_type {gdb.GdbError TypeError} { | |
165 | gdb_test_no_output \ | |
166 | "python rhandler.exception_type = $exception_type" | |
167 | ||
168 | gdb_file_cmd $binfile | |
169 | gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ | |
170 | "debug info not found" | |
171 | ||
172 | set re [string_to_regexp \ | |
173 | "Python Exception <class '$exception_type'>: message"] | |
174 | gdb_assert {[regexp $re $gdb_file_cmd_msg]} \ | |
175 | "check for exception in file command output" | |
176 | ||
177 | # Our original handler is still registered, but should not have been | |
178 | # called again (as the exception occurs first). | |
179 | gdb_test "python print(handler_obj.call_count)" "^1" \ | |
180 | "check good handler hasn't been called again" | |
181 | } | |
182 | } | |
183 | ||
184 | gdb_test "info missing-debug-handlers" \ | |
185 | [multi_line \ | |
186 | "Global:" \ | |
187 | " exception_handler" \ | |
188 | " handler"] \ | |
189 | "check both handlers are visible" | |
190 | ||
191 | # Re-start GDB. | |
192 | clean_restart | |
193 | ||
194 | # Load the Python script into GDB. | |
195 | gdb_test "source $remote_python_file" "^Success" \ | |
196 | "source python script for bad handler name checks" | |
197 | ||
198 | # Attempt to register a missing-debug-handler with NAME. The expectation is | |
199 | # that this should fail as NAME contains some invalid characters. | |
200 | proc check_bad_name {name} { | |
201 | set name_re [string_to_regexp $name] | |
202 | set re \ | |
203 | [multi_line \ | |
204 | "ValueError: invalid character '.' in handler name: $name_re" \ | |
205 | "Error while executing Python code\\."] | |
206 | ||
207 | gdb_test "python register(\"$name\")" $re \ | |
208 | "check that '$name' is not accepted" | |
209 | } | |
210 | ||
211 | # We don't attempt to be exhaustive here, just check a few random examples | |
212 | # of invalid names. | |
213 | check_bad_name "!! Bad Name" | |
214 | check_bad_name "Bad Name" | |
215 | check_bad_name "(Bad Name)" | |
216 | check_bad_name "Bad \[Name\]" | |
217 | check_bad_name "Bad,Name" | |
218 | check_bad_name "Bad;Name" | |
219 | ||
220 | # Check that there are no handlers registered. | |
221 | gdb_test_no_output "info missing-debug-handlers" \ | |
222 | "check no handlers are registered" | |
223 | ||
224 | # Check we can use the enable/disable commands where there are no handlers | |
225 | # registered. | |
226 | gdb_test "enable missing-debug-handler foo" \ | |
227 | "^0 missing debug handlers enabled" | |
228 | gdb_test "disable missing-debug-handler foo" \ | |
229 | "^0 missing debug handlers disabled" | |
230 | ||
231 | # Grab the current program space object, used for registering handler later. | |
232 | gdb_test_no_output "python pspace = gdb.selected_inferior().progspace" | |
233 | ||
234 | # Now register some handlers. | |
235 | foreach hspec {{\"Foo\" None} | |
236 | {\"-bar\" None} | |
237 | {\"baz-\" pspace} | |
238 | {\"abc-def\" pspace}} { | |
239 | lassign $hspec name locus | |
240 | gdb_test "python register($name, $locus)" | |
241 | } | |
242 | ||
243 | with_test_prefix "all handlers enabled" { | |
244 | gdb_test "info missing-debug-handlers" \ | |
245 | [multi_line \ | |
246 | "Current Progspace:" \ | |
247 | " abc-def" \ | |
248 | " baz-" \ | |
249 | "Global:" \ | |
250 | " -bar" \ | |
251 | " Foo"] | |
252 | ||
253 | gdb_file_cmd $binfile | |
254 | gdb_test "python print(handler_call_log)" \ | |
255 | [string_to_regexp {['abc-def', 'baz-', '-bar', 'Foo']}] | |
256 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
257 | "reset call log" | |
258 | } | |
259 | ||
260 | with_test_prefix "disable 'baz-'" { | |
261 | gdb_test "disable missing-debug-handler progspace baz-" \ | |
262 | "^1 missing debug handler disabled" | |
263 | ||
264 | gdb_test "info missing-debug-handlers" \ | |
265 | [multi_line \ | |
266 | "Progspace \[^\r\n\]+:" \ | |
267 | " abc-def" \ | |
268 | " baz- \\\[disabled\\\]" \ | |
269 | "Global:" \ | |
270 | " -bar" \ | |
271 | " Foo"] | |
272 | ||
273 | gdb_file_cmd $binfile | |
274 | gdb_test "python print(handler_call_log)" \ | |
275 | [string_to_regexp {['abc-def', '-bar', 'Foo']}] | |
276 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
277 | "reset call log" | |
278 | } | |
279 | ||
280 | with_test_prefix "disable 'Foo'" { | |
281 | gdb_test "disable missing-debug-handler .* Foo" \ | |
282 | "^1 missing debug handler disabled" | |
283 | ||
284 | gdb_test "info missing-debug-handlers" \ | |
285 | [multi_line \ | |
286 | "Progspace \[^\r\n\]+:" \ | |
287 | " abc-def" \ | |
288 | " baz- \\\[disabled\\\]" \ | |
289 | "Global:" \ | |
290 | " -bar" \ | |
291 | " Foo \\\[disabled\\\]"] | |
292 | ||
293 | gdb_file_cmd $binfile | |
294 | gdb_test "python print(handler_call_log)" \ | |
295 | [string_to_regexp {['abc-def', '-bar']}] | |
296 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
297 | "reset call log" | |
298 | } | |
299 | ||
300 | with_test_prefix "disable everything" { | |
301 | gdb_test "disable missing-debug-handler .* .*" \ | |
302 | "^2 missing debug handlers disabled" | |
303 | ||
304 | gdb_test "info missing-debug-handlers" \ | |
305 | [multi_line \ | |
306 | "Progspace \[^\r\n\]+:" \ | |
307 | " abc-def \\\[disabled\\\]" \ | |
308 | " baz- \\\[disabled\\\]" \ | |
309 | "Global:" \ | |
310 | " -bar \\\[disabled\\\]" \ | |
311 | " Foo \\\[disabled\\\]"] | |
312 | ||
313 | gdb_file_cmd $binfile | |
314 | gdb_test "python print(handler_call_log)" \ | |
315 | [string_to_regexp {[]}] | |
316 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
317 | "reset call log" | |
318 | } | |
319 | ||
320 | with_test_prefix "enable 'abc-def'" { | |
321 | set re [string_to_regexp $binfile] | |
322 | ||
323 | gdb_test "enable missing-debug-handler \"$re\" abc-def" \ | |
1146d277 TT |
324 | "^1 missing debug handler enabled" \ |
325 | "enable missing-debug-handler" | |
8f6c452b AB |
326 | |
327 | gdb_test "info missing-debug-handlers" \ | |
328 | [multi_line \ | |
329 | "Progspace \[^\r\n\]+:" \ | |
330 | " abc-def" \ | |
331 | " baz- \\\[disabled\\\]" \ | |
332 | "Global:" \ | |
333 | " -bar \\\[disabled\\\]" \ | |
334 | " Foo \\\[disabled\\\]"] | |
335 | ||
336 | gdb_file_cmd $binfile | |
337 | gdb_test "python print(handler_call_log)" \ | |
338 | [string_to_regexp {['abc-def']}] | |
339 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
340 | "reset call log" | |
341 | } | |
342 | ||
343 | with_test_prefix "enable global handlers" { | |
344 | set re [string_to_regexp $binfile] | |
345 | ||
346 | gdb_test "enable missing-debug-handler global" \ | |
347 | "^2 missing debug handlers enabled" | |
348 | ||
349 | gdb_test "info missing-debug-handlers" \ | |
350 | [multi_line \ | |
351 | "Progspace \[^\r\n\]+:" \ | |
352 | " abc-def" \ | |
353 | " baz- \\\[disabled\\\]" \ | |
354 | "Global:" \ | |
355 | " -bar" \ | |
356 | " Foo"] | |
357 | ||
358 | gdb_file_cmd $binfile | |
359 | gdb_test "python print(handler_call_log)" \ | |
360 | [string_to_regexp {['abc-def', '-bar', 'Foo']}] | |
361 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
362 | "reset call log" | |
363 | } | |
364 | ||
365 | # Add handler_obj to the global handler list, and configure it to | |
366 | # return False. We should call all of the program space specific | |
367 | # handlers (which return None), and then call handler_obj from the | |
368 | # global list, which returns False, at which point we shouldn't call | |
369 | # anyone else. | |
370 | with_test_prefix "return False handler in progspace list" { | |
371 | gdb_test "enable missing-debug-handler progspace" \ | |
372 | "^1 missing debug handler enabled" | |
373 | ||
374 | gdb_test_no_output \ | |
375 | "python gdb.missing_debug.register_handler(None, handler_obj)" \ | |
376 | "register the initial handler" | |
377 | ||
378 | gdb_test "info missing-debug-handlers" \ | |
379 | [multi_line \ | |
380 | "Progspace \[^\r\n\]+:" \ | |
381 | " abc-def" \ | |
382 | " baz-" \ | |
383 | "Global:" \ | |
384 | " handler" \ | |
385 | " -bar" \ | |
386 | " Foo"] | |
387 | ||
388 | gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \ | |
389 | "confirgure handler" | |
390 | ||
391 | gdb_file_cmd $binfile | |
392 | gdb_test "python print(handler_call_log)" \ | |
393 | [string_to_regexp {['abc-def', 'baz-', 'handler']}] | |
394 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
395 | "reset call log" | |
396 | } | |
397 | ||
398 | # Now add handler_obj to the current program space's handler list. We | |
399 | # use the same handler object here, that's fine. We should only see a | |
400 | # call to the first handler object in the call log. | |
401 | with_test_prefix "return False handler in global list" { | |
402 | gdb_test_no_output \ | |
403 | "python gdb.missing_debug.register_handler(pspace, handler_obj)" \ | |
404 | "register the initial handler" | |
405 | ||
406 | gdb_test "info missing-debug-handlers" \ | |
407 | [multi_line \ | |
408 | "Progspace \[^\r\n\]+:" \ | |
409 | " handler" \ | |
410 | " abc-def" \ | |
411 | " baz-" \ | |
412 | "Global:" \ | |
413 | " handler" \ | |
414 | " -bar" \ | |
415 | " Foo"] | |
416 | ||
417 | gdb_file_cmd $binfile | |
418 | gdb_test "python print(handler_call_log)" \ | |
419 | [string_to_regexp {['handler']}] | |
420 | gdb_test_no_output "python handler_call_log = \[\]" \ | |
421 | "reset call log" | |
422 | } | |
423 | ||
424 | with_test_prefix "check handler replacement" { | |
425 | # First, check we can have the same name appear in both program | |
426 | # space and global lists without giving an error. | |
427 | gdb_test_no_output "python register(\"Foo\", pspace)" | |
428 | ||
429 | gdb_test "info missing-debug-handlers" \ | |
430 | [multi_line \ | |
431 | "Progspace \[^\r\n\]+:" \ | |
432 | " Foo" \ | |
433 | " handler" \ | |
434 | " abc-def" \ | |
435 | " baz-" \ | |
436 | "Global:" \ | |
437 | " handler" \ | |
438 | " -bar" \ | |
439 | " Foo"] | |
440 | ||
441 | # Now check that we get an error if we try to add a handler with | |
442 | # the same name. | |
443 | gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \ | |
444 | [multi_line \ | |
445 | "RuntimeError: Handler Foo already exists\\." \ | |
446 | "Error while executing Python code\\."] | |
447 | ||
448 | gdb_test "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \ | |
449 | [multi_line \ | |
450 | "RuntimeError: Handler Foo already exists\\." \ | |
451 | "Error while executing Python code\\."] | |
452 | ||
453 | # And now try again, but this time with 'replace=True', we | |
454 | # shouldn't get an error in this case. | |
455 | gdb_test_no_output \ | |
456 | "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" | |
457 | ||
458 | gdb_test_no_output \ | |
459 | "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)" | |
460 | ||
461 | # Now disable a handler and check we still need to use 'replace=True'. | |
462 | gdb_test "disable missing-debug-handler progspace Foo" \ | |
463 | "^1 missing debug handler disabled" | |
464 | ||
465 | gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \ | |
466 | [multi_line \ | |
467 | "RuntimeError: Handler Foo already exists\\." \ | |
468 | "Error while executing Python code\\."] \ | |
469 | "still get an error when handler is disabled" | |
470 | ||
471 | gdb_test_no_output \ | |
472 | "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \ | |
473 | "can replace a disabled handler" | |
474 | } |