# 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 . # Test that the condition for a catchpoint is correctly reset after # shared libraries are unloaded, as happens when an inferior is # restarted. # # If this is not done then, when the catchpoint is hit on the second # run, we'll evaluate the parsed expression from the first run, which # might include references to types owned by the now deleted objfile # (for the shared library loaded in the first run). # # This scripts tests a number of different catchpoint types. Inside # GDB these are all sub-classes of the 'catchpoint' type, which is # where the fix for the above issue resides, so all catchpoint types # should work correctly. standard_testfile .c -lib.c set libfile $binfile-lib.so set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] if {[build_executable "build shared library" $libfile $srcfile2 \ {debug shlib}] == -1} { return } # Depending on whether or not libc debug info is installed, when we # hit a syscall catchpoint inside libc there might be a source line # included in the output. # # This regexp will match an optional line and can be added to the # expected catchpoint output to ignore the (possibly missing) source # line. set libc_src_line_re "(?:\r\n\[^\r\n\]+)?" # Check the Python bp_modified_list and then reset the list back to # empty. TESTNAME is just a string. BP_NUM is a list of breakpoint # numbers that are expected to appear (in the given order) in the # bp_modified_list. proc check_modified_bp_list { testname bp_num } { if { [allow_python_tests] } { set expected [join $bp_num ", "] gdb_test "python print(bp_modified_list)" "\\\[$expected\\\]" \ $testname gdb_test_no_output -nopass "python bp_modified_list=\[\]" \ "reset bp_modified_list after $testname" } } # Build an executable and run tests on 'catch MODE'. proc run_test { mode } { set exec_name ${::binfile}-${mode} set macro TEST_[string toupper $mode] if {[build_executable "build test executable" $exec_name $::srcfile \ [list debug shlib=$::libfile additional_flags=-D${macro}]] == -1} { return } clean_restart $exec_name gdb_load_shlib $::libfile if {![runto_main]} { return } if { $mode eq "syscall" } { gdb_test "catch syscall write" \ "Catchpoint $::decimal \\(syscall 'write' \[^)\]+\\)" set catch_re "call to syscall write" } elseif { $mode eq "signal" } { gdb_test "catch signal SIGUSR1" \ "Catchpoint $::decimal \\(signal SIGUSR1\\)" set catch_re "signal SIGUSR1" } elseif { $mode eq "fork" } { gdb_test "catch fork" \ "Catchpoint $::decimal \\(fork\\)" set catch_re "forked process $::decimal" } else { error "unknown mode $mode" } set cp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*"] gdb_breakpoint "breakpt_before_exit" gdb_test "continue" \ "Catchpoint ${cp_num} \[^\r\n\]+$::libc_src_line_re" if { [allow_python_tests] } { gdb_test_no_output "source $::pyfile" "import python scripts" check_modified_bp_list \ "check b/p modified observer has not yet triggered" {} } with_test_prefix "with false condition" { gdb_test_no_output "condition $cp_num ((struct lib_type *) opaque_ptr) != 0" \ "set catchpoint condition" check_modified_bp_list \ "catchpoint modified once by setting condition" \ [list $cp_num] gdb_run_cmd gdb_test "" [multi_line \ "Breakpoint $::decimal, main \\(\\) \[^\r\n\]+" \ "$::decimal\\s+\[^\r\n\]+"] check_modified_bp_list "catchpoint modified twice at startup" \ [list $cp_num $cp_num "$::decimal"] gdb_test "continue" \ [multi_line \ "Breakpoint $::decimal, breakpt_before_exit \\(\\) at \[^\r\n\]+" \ "$::decimal\\s+\[^\r\n\]+"] \ "continue to breakpt_before_exit" } # Check the bp_modified_list against '.*'. We don't care at this # point what's in the list (nothing relevant has happened since we # last checked), but this has the side effect of clearing the list. check_modified_bp_list "clear bp modified list" { .* } with_test_prefix "with true condition" { gdb_test_no_output "condition $cp_num ((struct lib_type *) opaque_ptr) == 0" \ "set catchpoint condition" check_modified_bp_list \ "catchpoint modified once by setting condition" \ [list $cp_num] gdb_run_cmd gdb_test "" [multi_line \ "Breakpoint $::decimal, main \\(\\) \[^\r\n\]+" \ "$::decimal\\s+\[^\r\n\]+"] check_modified_bp_list "catchpoint modified twice at startup" \ [list $cp_num $cp_num "$::decimal"] gdb_test "continue" \ "Catchpoint $cp_num \\($catch_re\\), \[^\r\n\]+$::libc_src_line_re" \ "continue until catchpoint hit" check_modified_bp_list "catchpoint modified again when hit" \ [list $cp_num] } } # Run the tests. foreach_with_prefix mode { syscall signal fork } { if { $mode == "syscall" && ![allow_xml_test] } { continue } run_test $mode }