reinit_frame_cache ();
}
+ /* Immediately detach breakpoints from the child before there's
+ any chance of letting the user delete breakpoints from the
+ breakpoint lists. If we don't do this early, it's easy to
+ leave left over traps in the child, vis: "break foo; catch
+ fork; c; <fork>; del; c; <child calls foo>". We only follow
+ the fork on the last `continue', and by that time the
+ breakpoint at "foo" is long gone from the breakpoint table.
+ If we vforked, then we don't need to unpatch here, since both
+ parent and child are sharing the same memory pages; we'll
+ need to unpatch at follow/detach time instead to be certain
+ that new breakpoints added between catchpoint hit time and
+ vfork follow are detached. */
+ if (ecs->ws.kind != TARGET_WAITKIND_VFORKED)
+ {
+ int child_pid = ptid_get_pid (ecs->ws.value.related_pid);
+
+ /* This won't actually modify the breakpoint list, but will
+ physically remove the breakpoints from the child. */
+ detach_breakpoints (child_pid);
+ }
+
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
/* We're already attached to the parent, by default. */
/* Before detaching from the child, remove all breakpoints from
- it. (This won't actually modify the breakpoint list, but will
- physically remove the breakpoints from the child.) */
- /* If we vforked this will remove the breakpoints from the parent
- also, but they'll be reinserted below. */
- detach_breakpoints (child_pid);
+ it. If we forked, then this has already been taken care of
+ by infrun.c. If we vforked however, any breakpoint inserted
+ in the parent is visible in the child, even those added while
+ stopped in a vfork catchpoint. This won't actually modify
+ the breakpoint list, but will physically remove the
+ breakpoints from the child. This will remove the breakpoints
+ from the parent also, but they'll be reinserted below. */
+ if (has_vforked)
+ detach_breakpoints (child_pid);
/* Detach new forked process? */
if (detach_fork)
breakpoint. */
last_tp->step_resume_breakpoint = NULL;
- /* Needed to keep the breakpoint lists in sync. */
- if (! has_vforked)
- detach_breakpoints (child_pid);
-
/* Before detaching from the parent, remove all breakpoints from it. */
remove_breakpoints ();
global gdb_prompt
global srcfile
+ set bp_after_fork [gdb_get_line_number "set breakpoint here"]
+
send_gdb "catch fork\n"
gdb_expect {
-re "Catchpoint .*(fork).*$gdb_prompt $"\
-re "$gdb_prompt $" {pass "set follow child"}
timeout {fail "(timeout) set follow child"}
}
- send_gdb "tbreak ${srcfile}:24\n"
+ send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
- -re "Temporary breakpoint.*, line 24.*$gdb_prompt $"\
+ -re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
{pass "set follow child, tbreak"}
-re "$gdb_prompt $" {fail "set follow child, tbreak"}
timeout {fail "(timeout) set follow child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
- -re "Attaching after fork to.* at .*24.*$gdb_prompt $"\
+ -re "Attaching after fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
{pass "set follow child, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
timeout {fail "(timeout) set follow child, hit tbreak"}
}
- # The child has been detached; allow time for any output it might
+ # The parent has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
# any expected debugger output from a subsequent testpoint.
#
}
}
+proc catch_fork_unpatch_child {} {
+ global gdb_prompt
+ global srcfile
+
+ set bp_exit [gdb_get_line_number "at exit"]
+
+ gdb_test "break callee" "file .*$srcfile, line .*" "unpatch child, break at callee"
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "unpatch child, set catch fork"
+
+ gdb_test "continue" \
+ "Catchpoint.*\\(forked process.*\\).*,.*in .*(fork|__kernel_v?syscall).*" \
+ "unpatch child, catch fork"
+
+ # Delete all breakpoints and catchpoints.
+ delete_breakpoints
+
+ gdb_test "break $bp_exit" \
+ "Breakpoint .*file .*$srcfile, line .*" \
+ "unpatch child, breakpoint at exit call"
+
+ gdb_test "set follow child" "" "unpatch child, set follow child"
+
+ set test "unpatch child, unpatched parent breakpoints from child"
+ gdb_test_multiple "continue" $test {
+ -re "at exit.*$gdb_prompt $" {
+ pass "$test"
+ }
+ -re "SIGTRAP.*$gdb_prompt $" {
+ fail "$test"
+
+ # Explicitly kill this child, so we can continue gracefully
+ # with further testing...
+ send_gdb "kill\n"
+ gdb_expect {
+ -re ".*Kill the program being debugged.*y or n. $" {
+ send_gdb "y\n"
+ gdb_expect -re "$gdb_prompt $" {}
+ }
+ }
+ }
+ -re ".*$gdb_prompt $" {
+ fail "$test (unknown output)"
+ }
+ timeout {
+ fail "$test (timeout)"
+ }
+ }
+}
+
proc tcatch_fork_parent_follow {} {
global gdb_prompt
global srcfile
+ set bp_after_fork [gdb_get_line_number "set breakpoint here"]
+
send_gdb "catch fork\n"
gdb_expect {
-re "Catchpoint .*(fork).*$gdb_prompt $"\
-re "$gdb_prompt $" {pass "set follow parent"}
timeout {fail "(timeout) set follow parent"}
}
- send_gdb "tbreak ${srcfile}:24\n"
+ send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
- -re "Temporary breakpoint.*, line 24.*$gdb_prompt $"\
+ -re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
{pass "set follow parent, tbreak"}
-re "$gdb_prompt $" {fail "set follow parent, tbreak"}
timeout {fail "(timeout) set follow child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
- -re ".*Detaching after fork from.* at .*24.*$gdb_prompt $"\
+ -re ".*Detaching after fork from.* at .*$bp_after_fork.*$gdb_prompt $"\
{pass "set follow parent, hit tbreak"}
-re "$gdb_prompt $" {fail "set follow parent, hit tbreak"}
timeout {fail "(timeout) set follow parent, hit tbreak"}
#
if [runto_main] then { catch_fork_child_follow }
+ # Test that parent breakpoints are successfully detached from the
+ # child at fork time, even if the user removes them from the
+ # breakpoints list after stopping at a fork catchpoint.
+ if [runto_main] then { catch_fork_unpatch_child }
+
# Test the ability to catch a fork, specify via a -do clause that
# the parent be followed, and continue. Make the catchpoint temporary.
#