diff options
Diffstat (limited to 'gdb/testsuite/gdb.python')
-rw-r--r-- | gdb/testsuite/gdb.python/py-missing-objfile-lib.c | 35 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-missing-objfile.c | 49 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-missing-objfile.exp | 565 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-missing-objfile.py | 167 |
4 files changed, 816 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.python/py-missing-objfile-lib.c b/gdb/testsuite/gdb.python/py-missing-objfile-lib.c new file mode 100644 index 0000000..8d740b4 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-missing-objfile-lib.c @@ -0,0 +1,35 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2024 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +struct lib_type +{ + int a; + int b; +}; + +volatile struct lib_type global_lib_var = { 0, 0 }; + +int +foo (void) +{ + int res = 0; + + res += global_lib_var.a; + res += global_lib_var.b; + + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.c b/gdb/testsuite/gdb.python/py-missing-objfile.c new file mode 100644 index 0000000..953e1c0 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-missing-objfile.c @@ -0,0 +1,49 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2024 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +struct exec_type +{ + int a; + int b; + int c; +}; + +volatile struct exec_type global_exec_var = { 0, 0, 0 }; + +extern int foo (void); + +void +dump_core (void) +{ + abort (); +} + +int +main (void) +{ + int res = foo (); + + res += global_exec_var.a; + res += global_exec_var.b; + res += global_exec_var.c; + + dump_core (); + + return res; +} diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.exp b/gdb/testsuite/gdb.python/py-missing-objfile.exp new file mode 100644 index 0000000..15a6952 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-missing-objfile.exp @@ -0,0 +1,565 @@ +# Copyright (C) 2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +load_lib gdb-python.exp + +require allow_python_tests +require {!is_remote host} + +standard_testfile .c -lib.c + +# Build the library. +set libname ${testfile}-lib +set libfile [standard_output_file $libname] +if { [build_executable "build shlib" $libfile $srcfile2 \ + {debug shlib build-id}] == -1} { + return +} + +# Build the executable. +set opts [list debug build-id shlib=${libfile}] +if { [build_executable "build exec" $binfile $srcfile $opts] == -1} { + return +} + +# The cc-with-gnu-debuglink board will split the debug out into the +# .debug directory. This test script relies on having GDB lookup the +# objfile and debug via the build-id, which this test sets up. Trying +# to do that, while also supporting the cc-with-gnu-debuglink board is +# just too complicated. +if {[file isdirectory [standard_output_file ".debug"]]} { + unsupported "split debug testing not supported" + return +} + +set remote_python_file \ + [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +# Generate a core file. +set corefile [core_find $binfile {}] +if {$corefile == ""} { + unsupport "core file not generated" + return 0 +} + +# Create a directory named DIRNAME for use as the +# debug-file-directory. Populate the directory with links (based on +# the build-ids) to each file in the list FILES. +# +# Return the full filename of DIRNAME on the host. +proc setup_debugdir { dirname files } { + set debugdir [host_standard_output_file $dirname] + + # Create basic empty directory structure (in case FILES is empty). + remote_exec host "mkdir -p $debugdir/.build-id/" + + foreach file $files { + set build_id_filename [build_id_debug_filename_get $file ""] + + remote_exec host "mkdir -p $debugdir/[file dirname $build_id_filename]" + remote_exec host "ln -s $file $debugdir/$build_id_filename" + } + + return $debugdir +} + +# Query some symbols in the inferior to see if GDB managed to find the +# executable (when EXEC_LOADED is true) and/or the library (when LIB_LOADED +# is true). +proc check_loaded_debug { exec_loaded lib_loaded } { + if { $exec_loaded } { + gdb_test "whatis global_exec_var" "^type = volatile struct exec_type" + + if { $lib_loaded } { + gdb_test "whatis global_lib_var" "^type = volatile struct lib_type" + } else { + gdb_test "whatis global_lib_var" \ + "^No symbol \"global_lib_var\" in current context\\." + } + } else { + gdb_test "whatis global_exec_var" \ + "^No symbol table is loaded\\. Use the \"file\" command\\." + gdb_test "whatis global_lib_var" \ + "^No symbol table is loaded\\. Use the \"file\" command\\." + } +} + +# Load the global corefile. The EXTRA_RE is checked for prior to GDB +# announcing that the core-file has been loaded. +proc load_core_file { {extra_re ".*"} } { + gdb_test "core-file $::corefile" \ + [multi_line \ + "$extra_re" \ + "Core was generated by \[^\r\n\]+" \ + "Program terminated with signal SIGABRT, Aborted\\." \ + "\[^\r\n\]+(?:\r\n\[^\r\n\]+)?"] \ + "loaded the core file" +} + +# Set the debug-file-directory to DIRNAME. +proc set_debug_file_dir { dirname } { + gdb_test_no_output "set debug-file-directory $dirname" \ + "set debug-file-directory" +} + +# Restart GDB and load the support Python script. +proc clean_restart_load_python {} { + clean_restart + gdb_test "source $::remote_python_file" "^Success" \ + "load python script" +} + +# For sanity, lets check that we can load the specify the executable +# and then load the core-file the easy way. +with_test_prefix "initial sanity check" { + clean_restart $binfile + load_core_file + check_loaded_debug true true +} + +# Move the executable and library into a location that the core-file +# can't possibly know about. After this the only way GDB can track +# down these files will be by looking in the debug-file-directory. +set hidden_dir [host_standard_output_file "hidden"] +set hidden_binfile "$hidden_dir/$testfile" +set hidden_libfile "$hidden_dir/$libname" +remote_exec host "mkdir -p $hidden_dir" +remote_exec host "mv $libfile $hidden_libfile" +remote_exec host "mv $binfile $hidden_binfile" + +# If using the fission-dwp board then we'll have .dwp files that also +# need to be moved. +if {[remote_file host exists ${libfile}.dwp]} { + remote_exec host "mv ${libfile}.dwp ${hidden_libfile}.dwp" +} + +if {[remote_file host exists ${binfile}.dwp]} { + remote_exec host "mv ${binfile}.dwp ${hidden_binfile}.dwp" +} + +with_test_prefix "no objfiles, no debug-file-directory" { + clean_restart + load_core_file + check_loaded_debug false false +} + +# Setup some debug-file-directories. +set debugdir_no_lib \ + [setup_debugdir "debugdir.no-lib" [list "$hidden_binfile"]] +set debugdir_empty \ + [setup_debugdir "debugdir.empty" {}] +set debugdir_all \ + [setup_debugdir "debugdir.all" [list "$hidden_libfile" \ + "$hidden_binfile"]] + +with_test_prefix "no objfiles available" { + # Another sanity check that GDB can find the files via the + # debug-file-directory. + clean_restart + set_debug_file_dir $debugdir_empty + load_core_file + check_loaded_debug false false +} + +with_test_prefix "all objfiles available" { + # Another sanity check that GDB can find the files via the + # debug-file-directory. + set_debug_file_dir $debugdir_all + load_core_file + check_loaded_debug true true +} + +with_test_prefix "lib objfile missing" { + # Another sanity check that GDB can find the files via the + # debug-file-directory. + set_debug_file_dir $debugdir_no_lib + load_core_file + check_loaded_debug true false +} + +with_test_prefix "all objfiles missing, handler returns None" { + clean_restart_load_python + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(None, handler_obj)" \ + "register initial handler" + load_core_file + + check_loaded_debug false false + + # The handler should be called three times, once for the + # mapped-file, once for the core-file's exec, and once for the + # shared library. + gdb_test "python print(handler_obj.call_count)" "^3" \ + "check handler was called three times" +} + +with_test_prefix "lib objfile missing, handler returns None" { + # Reset handler_obj. + gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_NONE)" + + set_debug_file_dir $debugdir_no_lib + load_core_file + check_loaded_debug true false + + # The handler will be called twice, once when GDB tries to + # load the shared library during the memory-mapped file phase, + # then again for the shared library loading. + gdb_test "python print(handler_obj.call_count)" "^2" \ + "check handler was called three times" +} + +with_test_prefix "handler installs lib objfile" { + set build_id_filename [build_id_debug_filename_get \ + $hidden_libfile ""] + remote_exec host \ + "mkdir -p $debugdir_no_lib/[file dirname $build_id_filename]" + gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ + \"$hidden_libfile\", \"$debugdir_no_lib/$build_id_filename\")" \ + "configure handler" + + load_core_file + check_loaded_debug true true + + # Cleanup so the test can be reproduced again later if needed. + remote_exec host "rm $debugdir_no_lib/$build_id_filename" +} + +with_test_prefix "handler points to lib objfile" { + set build_id_filename [build_id_debug_filename_get \ + $hidden_libfile ""] + remote_exec host \ + "mkdir -p $debugdir_no_lib/[file dirname $build_id_filename]" + gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \ + \"$hidden_libfile\")" \ + "configure handler" + + load_core_file + check_loaded_debug true true + + # Cleanup so the test can be reproduced again later if needed. + remote_exec host "rm $debugdir_no_lib/$build_id_filename" + + # The handler will only have been called once when loading the + # memory-mapped file. GDB is smart enough to reuse the previously + # discovered BFD object as the shared library. + gdb_test "python print(handler_obj.call_count)" "^1" \ + "check good handler hasn't been called again" + + # Validate the filename and build-id arguments passed to the handler. + set expected_buildid [get_build_id $hidden_libfile] + gdb_test "python print(handler_last_buildid)" "^$expected_buildid" + gdb_test "python print(handler_last_filename)" \ + "^[string_to_regexp $libfile]" +} + +# Register another global handler, this one raises an exception. Reload the +# core-file, the bad handler should be invoked first, which raises an +# excetption, at which point GDB should skip further Python handlers. +with_test_prefix "handler raises an exception" { + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(None, rhandler)" + + foreach_with_prefix exception_type {gdb.GdbError TypeError} { + gdb_test_no_output \ + "python rhandler.exception_type = $exception_type" + + # Load the core file. We expect the exception message to appear at + # least once in the output. + set re [string_to_regexp \ + "Python Exception <class '$exception_type'>: message"] + load_core_file "${re}.*" + + # Our original handler is still registered, but should not have been + # called again (as the exception occurs first). + gdb_test "python print(handler_obj.call_count)" "^1" \ + "check good handler hasn't been called again" + } +} + +# Re-start GDB. +clean_restart_load_python + +# Attempt to register a missing-debug-handler with NAME. The expectation is +# that this should fail as NAME contains some invalid characters. +proc check_bad_name {name} { + set name_re [string_to_regexp $name] + set re \ + [multi_line \ + "ValueError.*: invalid character '.' in handler name: $name_re" \ + "Error occurred in Python.*"] + + gdb_test "python register(\"$name\")" $re \ + "check that '$name' is not accepted" +} + +# We don't attempt to be exhaustive here, just check a few random examples +# of invalid names. +check_bad_name "!! Bad Name" +check_bad_name "Bad Name" +check_bad_name "(Bad Name)" +check_bad_name "Bad \[Name\]" +check_bad_name "Bad,Name" +check_bad_name "Bad;Name" + +# Check that there are no handlers registered. +gdb_test_no_output "info missing-objfile-handlers" \ + "check no handlers are registered" + +# Grab the current program space object, used for registering handler later. +gdb_test_no_output "python pspace = gdb.selected_inferior().progspace" + +# Now register some handlers. +foreach hspec {{\"Foo\" None} + {\"-bar\" None} + {\"baz-\" pspace} + {\"abc-def\" pspace}} { + lassign $hspec name locus + gdb_test "python register($name, $locus)" +} + +with_test_prefix "all handlers enabled" { + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Current Progspace:" \ + " abc-def" \ + " baz-" \ + "Global:" \ + " -bar" \ + " Foo"] + + set_debug_file_dir $debugdir_no_lib + load_core_file + + # As we perform two look ups, first for the mapped-file then for the + # shared library, each handler will be called twice. + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', 'baz-', '-bar', 'Foo', 'abc-def', 'baz-', '-bar', 'Foo']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "disable 'baz-'" { + gdb_test "disable missing-objfile-handler progspace baz-" \ + "^1 missing objfile handler disabled" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def" \ + " baz- \\\[disabled\\\]" \ + "Global:" \ + " -bar" \ + " Foo"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', '-bar', 'Foo', 'abc-def', '-bar', 'Foo']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "disable 'Foo'" { + gdb_test "disable missing-objfile-handler .* Foo" \ + "^1 missing objfile handler disabled" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def" \ + " baz- \\\[disabled\\\]" \ + "Global:" \ + " -bar" \ + " Foo \\\[disabled\\\]"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', '-bar', 'abc-def', '-bar']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "disable everything" { + gdb_test "disable missing-objfile-handler .* .*" \ + "^2 missing objfile handlers disabled" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def \\\[disabled\\\]" \ + " baz- \\\[disabled\\\]" \ + "Global:" \ + " -bar \\\[disabled\\\]" \ + " Foo \\\[disabled\\\]"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {[]}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "enable 'abc-def'" { + set re [string_to_regexp $hidden_binfile] + + gdb_test "enable missing-objfile-handler \"$re\" abc-def" \ + "^1 missing objfile handler enabled" \ + "enable missing-objfile-handler" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def" \ + " baz- \\\[disabled\\\]" \ + "Global:" \ + " -bar \\\[disabled\\\]" \ + " Foo \\\[disabled\\\]"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', 'abc-def']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "enable global handlers" { + gdb_test "enable missing-objfile-handler global" \ + "^2 missing objfile handlers enabled" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def" \ + " baz- \\\[disabled\\\]" \ + "Global:" \ + " -bar" \ + " Foo"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', '-bar', 'Foo', 'abc-def', '-bar', 'Foo']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +# Add handler_obj to the global handler list, and configure it to +# return False. We should call all of the program space specific +# handlers (which return None), and then call handler_obj from the +# global list, which returns False, at which point we shouldn't call +# anyone else. +with_test_prefix "return False handler in global list" { + gdb_test "enable missing-objfile-handler progspace" \ + "^1 missing objfile handler enabled" + + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(None, handler_obj)" \ + "register handler_obj in global list" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " abc-def" \ + " baz-" \ + "Global:" \ + " handler" \ + " -bar" \ + " Foo"] + + gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \ + "confirgure handler" + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['abc-def', 'baz-', 'handler', 'abc-def', 'baz-', 'handler']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +# Now add handler_obj to the current program space's handler list. We +# use the same handler object here, that's fine. We should only see a +# call to the first handler object in the call log. +with_test_prefix "return False handler in progspace list" { + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(pspace, handler_obj)" \ + "register handler_obj in progspace list" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " handler" \ + " abc-def" \ + " baz-" \ + "Global:" \ + " handler" \ + " -bar" \ + " Foo"] + + load_core_file + gdb_test "python print(handler_call_log)" \ + [string_to_regexp {['handler', 'handler']}] + gdb_test_no_output "python handler_call_log = \[\]" \ + "reset call log" +} + +with_test_prefix "check handler replacement" { + # First, check we can have the same name appear in both program + # space and global lists without giving an error. + gdb_test_no_output "python register(\"Foo\", pspace)" + + gdb_test "info missing-objfile-handlers" \ + [multi_line \ + "Progspace \[^\r\n\]+:" \ + " Foo" \ + " handler" \ + " abc-def" \ + " baz-" \ + "Global:" \ + " handler" \ + " -bar" \ + " Foo"] + + # Now check that we get an error if we try to add a handler with + # the same name. + gdb_test "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"))" \ + [multi_line \ + "RuntimeError.*: Handler Foo already exists\\." \ + "Error occurred in Python.*"] + + gdb_test "python gdb.missing_objfile.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \ + [multi_line \ + "RuntimeError.*: Handler Foo already exists\\." \ + "Error occurred in Python.*"] + + # And now try again, but this time with 'replace=True', we + # shouldn't get an error in this case. + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"), replace=True)" + + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)" + + # Now disable a handler and check we still need to use 'replace=True'. + gdb_test "disable missing-objfile-handler progspace Foo" \ + "^1 missing objfile handler disabled" + + gdb_test "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"))" \ + [multi_line \ + "RuntimeError.*: Handler Foo already exists\\." \ + "Error occurred in Python.*"] \ + "still get an error when handler is disabled" + + gdb_test_no_output \ + "python gdb.missing_objfile.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \ + "can replace a disabled handler" +} diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.python/py-missing-objfile.py new file mode 100644 index 0000000..9b15896 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-missing-objfile.py @@ -0,0 +1,167 @@ +# Copyright (C) 2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import shutil +import os +from enum import Enum + +import gdb +from gdb.missing_objfile import MissingObjfileHandler + +# A global log that is filled in by instances of the LOG_HANDLER class +# when they are called. +handler_call_log = [] + +# A global holding a string, the build-id of the last missing objfile +# which triggered the 'handler' class below. This is set in the +# __call__ method of the 'handler' class and then checked from the +# expect script. +handler_last_buildid = None + + +# A global holding a string, the filename of the last missing objfile +# which triggered the 'handler' class below. This is set in the +# __call__ method of the 'handler' class and then checked from the +# expect script. +handler_last_filename = None + + +# A helper function that makes some assertions about the arguments +# passed to a MissingObjfileHandler.__call__() method. +def check_args(pspace, buildid, filename): + assert type(filename) == str + assert filename != "" + assert type(pspace) == gdb.Progspace + assert type(buildid) == str + assert buildid != "" + + +# Enum used to configure the 'handler' class from the test script. +class Mode(Enum): + RETURN_NONE = 0 + RETURN_TRUE = 1 + RETURN_FALSE = 2 + RETURN_STRING = 3 + + +# A missing objfile handler which can be configured to return each of +# the different possible return types. +class handler(MissingObjfileHandler): + def __init__(self): + super().__init__("handler") + self._call_count = 0 + self._mode = Mode.RETURN_NONE + + def __call__(self, pspace, buildid, filename): + global handler_call_log, handler_last_buildid, handler_last_filename + check_args(pspace, buildid, filename) + handler_call_log.append(self.name) + handler_last_buildid = buildid + handler_last_filename = filename + self._call_count += 1 + if self._mode == Mode.RETURN_NONE: + return None + + if self._mode == Mode.RETURN_TRUE: + shutil.copy(self._src, self._dest) + + # If we're using the fission-dwp board then there will + # also be a .dwp file that needs to be copied. + dwp_src = self._src + ".dwp" + if os.path.exists(dwp_src): + dwp_dest = self._dest + ".dwp" + shutil.copy(dwp_src, dwp_dest) + + return True + + if self._mode == Mode.RETURN_FALSE: + return False + + if self._mode == Mode.RETURN_STRING: + return self._dest + + assert False + + @property + def call_count(self): + """Return a count, the number of calls to __call__ since the last + call to set_mode. + """ + return self._call_count + + def set_mode(self, mode, *args): + self._call_count = 0 + self._mode = mode + + if mode == Mode.RETURN_NONE: + assert len(args) == 0 + return + + if mode == Mode.RETURN_TRUE: + assert len(args) == 2 + self._src = args[0] + self._dest = args[1] + return + + if mode == Mode.RETURN_FALSE: + assert len(args) == 0 + return + + if mode == Mode.RETURN_STRING: + assert len(args) == 1 + self._dest = args[0] + return + + assert False + + +# A missing objfile handler which raises an exception. The type of +# exception to be raised is configured from the test script. +class exception_handler(MissingObjfileHandler): + def __init__(self): + super().__init__("exception_handler") + self.exception_type = None + + def __call__(self, pspace, buildid, filename): + global handler_call_log + check_args(pspace, buildid, filename) + handler_call_log.append(self.name) + assert self.exception_type is not None + raise self.exception_type("message") + + +# A very simple logging missing objfile handler. Always returns None +# so that GDB will try any other registered handlers, but first logs +# the name of this handler into the global HANDLER_CALL_LOG, which can +# then be checked from the test script. +class log_handler(MissingObjfileHandler): + def __call__(self, pspace, buildid, filename): + global handler_call_log + check_args(pspace, buildid, filename) + handler_call_log.append(self.name) + return None + + +# A basic helper function, this keeps lines shorter in the TCL script. +def register(name, locus=None): + gdb.missing_objfile.register_handler(locus, log_handler(name)) + + +# Create instances of the handlers, but don't install any. We install +# these as needed from the TCL script. +rhandler = exception_handler() +handler_obj = handler() + +print("Success") |