# Copyright 2011-2022 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 fork handling of an inferior that has JIT-ed objfiles.
if {[skip_shlib_tests]} {
untested "skipping shared library tests"
return -1
}
if {[get_compiler_info]} {
untested "could not get compiler info"
return 1
}
load_lib jit-elf-helpers.exp
# The main code that loads and registers JIT objects.
set main_basename "jit-elf-fork-main"
set main_srcfile ${srcdir}/${subdir}/${main_basename}.c
set main_binfile [standard_output_file ${main_basename}]
# The shared library that gets loaded as JIT objects.
set jit_solib_basename jit-elf-fork-solib
set jit_solib_srcfile ${srcdir}/${subdir}/${jit_solib_basename}.c
# Compile a shared library to use as JIT objects.
set jit_solibs_target [compile_and_download_n_jit_so \
$jit_solib_basename $jit_solib_srcfile 1]
if { $jit_solibs_target == -1 } {
return
}
# Compile the main code (which loads the JIT objects).
if { [compile_jit_main ${main_srcfile} ${main_binfile} {}] != 0 } {
return
}
# Set up for the tests.
#
# detach-on-fork and follow-fork-mode are the values to use for the GDB
# parameters of the same names.
#
# Upon return, execution is stopped at the breakpoint just after fork. Which
# inferiors exist and which inferior is the current one depends on the
# parameter.
#
# The only breakpoint left is one just before the return statement in main, so
# that the callers can continue execution until there.
proc do_setup { detach-on-fork follow-fork-mode } {
clean_restart ${::main_binfile}
gdb_test_no_output "set detach-on-fork ${detach-on-fork}"
gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}"
if { ![runto_main] } {
return -1
}
# Poke desired values directly into inferior.
gdb_test_no_output "set var argc=2" "forging argc"
gdb_test_no_output "set var argv=fake_argv" "forging argv"
set jit_solib_target [lindex $::jit_solibs_target 0]
gdb_test_no_output "set var argv\[1]=\"${jit_solib_target}\"" {forging argv[1]}
# Put a breakpoint before the fork, continue there.
gdb_breakpoint [gdb_get_line_number "break before fork" $::main_srcfile]
gdb_continue_to_breakpoint "continue to before fork" ".*break before fork.*"
# We should have one JIT object loaded.
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfiles before fork"
# Put a breakpoint just after the fork, continue there.
gdb_breakpoint [gdb_get_line_number "break after fork" $::main_srcfile]
gdb_continue_to_breakpoint "continue to after fork" ".*break after fork.*"
# We should still have one JIT object loaded in whatever inferior we are
# currently stopped in, regardless of the mode.
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfiles after fork"
# Delete our breakpoints.
delete_breakpoints
# Put a breakpoint before return, for the convenience of our callers.
gdb_breakpoint [gdb_get_line_number "break before return" $::main_srcfile]
}
proc_with_prefix test_detach_on_fork_off_follow_fork_mode_parent { } {
if { [do_setup off parent] == -1 } {
return -1
}
# We are stopped in the parent.
gdb_test "inferior" "Current inferior is 1.*" "current inferior is parent"
# Switch to the child, verify there is a JIT-ed objfile.
gdb_test "inferior 2" "Switching to inferior 2.*"
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfile in child"
# Continue child past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return - child" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles in child"
# Go back to parent, the JIT-ed objfile should still be there.
gdb_test "inferior 1" "Switching to inferior 1.*"
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfile in parent"
# Continue parent past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return - parent" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles in parent"
}
proc_with_prefix test_detach_on_fork_off_follow_fork_mode_child { } {
if { [do_setup off child] == -1 } {
return -1
}
# We are stopped in the child. This is the exact same thing as
# test_detach_on_fork_off_follow_fork_mode_parent, except that we are
# stopped in the child.
gdb_test "inferior" "Current inferior is 2.*" "current inferior is child"
# Switch to the parent, verify there is a JIT-ed objfile.
gdb_test "inferior 1" "Switching to inferior 1.*"
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfile in parent"
# Continue parent past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return - parent" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles in parent"
# Go back to child, the JIT-ed objfile should still be there.
gdb_test "inferior 2" "Switching to inferior 2.*"
gdb_test "maint info jit" \
[multi_line \
"jit_code_entry address\\s+symfile address\\s+symfile size\\s*" \
"${::hex}\\s+${::hex}\\s+${::decimal}\\s*"] \
"jit-ed objfile in child"
# Continue child past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return - child" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles in child"
}
proc_with_prefix test_detach_on_fork_on_follow_fork_mode_parent { } {
if { [do_setup on parent] == -1 } {
return -1
}
# We are stopped in the parent, child is detached.
gdb_test "inferior" "Current inferior is 1.*" "current inferior is parent"
gdb_test "inferior 2" "Inferior ID 2 not known." "no inferior 2"
# Continue past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles"
}
proc_with_prefix test_detach_on_fork_on_follow_fork_mode_child { } {
if { [do_setup on child] == -1 } {
return -1
}
# We are stopped in the child, parent is detached.
gdb_test "inferior" "Current inferior is 2.*" "current inferior is child"
gdb_test "inferior 1" "Switching to inferior 1 \\\[\\\].*"
gdb_test "inferior 2" "Switching to inferior 2.*"
# Continue past JIT unload, verify there are no more JIT-ed objfiles.
gdb_continue_to_breakpoint "continue to before return" ".*break before return.*"
gdb_test_no_output "maint info jit" "no more jit-ed objfiles"
}
test_detach_on_fork_off_follow_fork_mode_parent
test_detach_on_fork_off_follow_fork_mode_child
test_detach_on_fork_on_follow_fork_mode_parent
test_detach_on_fork_on_follow_fork_mode_child