1 # Copyright (C) 2023-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 load_lib gdb-python.exp
18 require allow_python_tests
22 if {[build_executable "failed to prepare" ${testfile} ${srcfile}]} {
26 # Remove debug information from BINFILE and place it into
28 if {[gdb_gnu_strip_debug $binfile]} {
29 unsupported "cannot produce separate debug info files"
33 set remote_python_file \
34 [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
36 set debug_filename ${binfile}.debug
37 set hidden_filename ${binfile}.hidden
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.
48 gdb_assert {$gdb_file_cmd_debug_info == "debug"} \
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"
55 gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
56 "debug info no longer found"
59 # Load the Python script into GDB.
60 gdb_test "source $remote_python_file" "^Success" \
61 "source python script"
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"
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" {
75 "python gdb.missing_debug.register_handler(None, handler_obj)" \
76 "register the initial handler"
79 gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
80 "debug info not found"
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"
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\")" \
96 gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found"
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"
103 # Setup a directory structure based on the build-id of BINFILE, but don't
104 # move the debug information into place just yet.
106 # Instead, configure the handler to move the debug info into the build-id
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"
116 # Create the build-id based directory in which the debug information
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]"
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\")" \
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"
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"
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"
143 # Configure the handler return a filename string.
144 gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \
145 \"$hidden_filename\")" \
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"
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"
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" {
162 "python gdb.missing_debug.register_handler(None, rhandler)"
164 foreach_with_prefix exception_type {gdb.GdbError TypeError} {
166 "python rhandler.exception_type = $exception_type"
168 gdb_file_cmd $binfile
169 gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \
170 "debug info not found"
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"
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"
184 gdb_test "info missing-debug-handlers" \
187 " exception_handler" \
189 "check both handlers are visible"
194 # Load the Python script into GDB.
195 gdb_test "source $remote_python_file" "^Success" \
196 "source python script for bad handler name checks"
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]
204 "ValueError: invalid character '.' in handler name: $name_re" \
205 "Error while executing Python code\\."]
207 gdb_test "python register(\"$name\")" $re \
208 "check that '$name' is not accepted"
211 # We don't attempt to be exhaustive here, just check a few random examples
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"
220 # Check that there are no handlers registered.
221 gdb_test_no_output "info missing-debug-handlers" \
222 "check no handlers are registered"
224 # Check we can use the enable/disable commands where there are no handlers
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"
231 # Grab the current program space object, used for registering handler later.
232 gdb_test_no_output "python pspace = gdb.selected_inferior().progspace"
234 # Now register some handlers.
235 foreach hspec {{\"Foo\" None}
238 {\"abc-def\" pspace}} {
239 lassign $hspec name locus
240 gdb_test "python register($name, $locus)"
243 with_test_prefix "all handlers enabled" {
244 gdb_test "info missing-debug-handlers" \
246 "Current Progspace:" \
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 = \[\]" \
260 with_test_prefix "disable 'baz-'" {
261 gdb_test "disable missing-debug-handler progspace baz-" \
262 "^1 missing debug handler disabled"
264 gdb_test "info missing-debug-handlers" \
266 "Progspace \[^\r\n\]+:" \
268 " baz- \\\[disabled\\\]" \
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 = \[\]" \
280 with_test_prefix "disable 'Foo'" {
281 gdb_test "disable missing-debug-handler .* Foo" \
282 "^1 missing debug handler disabled"
284 gdb_test "info missing-debug-handlers" \
286 "Progspace \[^\r\n\]+:" \
288 " baz- \\\[disabled\\\]" \
291 " Foo \\\[disabled\\\]"]
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 = \[\]" \
300 with_test_prefix "disable everything" {
301 gdb_test "disable missing-debug-handler .* .*" \
302 "^2 missing debug handlers disabled"
304 gdb_test "info missing-debug-handlers" \
306 "Progspace \[^\r\n\]+:" \
307 " abc-def \\\[disabled\\\]" \
308 " baz- \\\[disabled\\\]" \
310 " -bar \\\[disabled\\\]" \
311 " Foo \\\[disabled\\\]"]
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 = \[\]" \
320 with_test_prefix "enable 'abc-def'" {
321 set re [string_to_regexp $binfile]
323 gdb_test "enable missing-debug-handler \"$re\" abc-def" \
324 "^1 missing debug handler enabled" \
325 "enable missing-debug-handler"
327 gdb_test "info missing-debug-handlers" \
329 "Progspace \[^\r\n\]+:" \
331 " baz- \\\[disabled\\\]" \
333 " -bar \\\[disabled\\\]" \
334 " Foo \\\[disabled\\\]"]
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 = \[\]" \
343 with_test_prefix "enable global handlers" {
344 set re [string_to_regexp $binfile]
346 gdb_test "enable missing-debug-handler global" \
347 "^2 missing debug handlers enabled"
349 gdb_test "info missing-debug-handlers" \
351 "Progspace \[^\r\n\]+:" \
353 " baz- \\\[disabled\\\]" \
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 = \[\]" \
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
370 with_test_prefix "return False handler in progspace list" {
371 gdb_test "enable missing-debug-handler progspace" \
372 "^1 missing debug handler enabled"
375 "python gdb.missing_debug.register_handler(None, handler_obj)" \
376 "register the initial handler"
378 gdb_test "info missing-debug-handlers" \
380 "Progspace \[^\r\n\]+:" \
388 gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \
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 = \[\]" \
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" {
403 "python gdb.missing_debug.register_handler(pspace, handler_obj)" \
404 "register the initial handler"
406 gdb_test "info missing-debug-handlers" \
408 "Progspace \[^\r\n\]+:" \
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 = \[\]" \
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)"
429 gdb_test "info missing-debug-handlers" \
431 "Progspace \[^\r\n\]+:" \
441 # Now check that we get an error if we try to add a handler with
443 gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \
445 "RuntimeError: Handler Foo already exists\\." \
446 "Error while executing Python code\\."]
448 gdb_test "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \
450 "RuntimeError: Handler Foo already exists\\." \
451 "Error while executing Python code\\."]
453 # And now try again, but this time with 'replace=True', we
454 # shouldn't get an error in this case.
456 "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)"
459 "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)"
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"
465 gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \
467 "RuntimeError: Handler Foo already exists\\." \
468 "Error while executing Python code\\."] \
469 "still get an error when handler is disabled"
472 "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \
473 "can replace a disabled handler"