blob: dabacd474671bb4b6bcb5d37ab7c4f8fe6452b4d [file] [log] [blame] [edit]
# 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/>.
# 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
}