Skip to content

Commit a19c781

Browse files
committed
[PATCH] Add syscall tests when following/detaching from fork
breakpoints/13457 discusses issues with syscall catchpoints when following forks, lamenting that there is no coverage for the various permutations of `follow-fork-mode' and `detach-on-fork'. This is an attempt to try and cover some of this ground. Unfortunately the state of syscall support when detaching after the fork is very, very inconsistent across various architectures. [I've tested extensively Fedora/RHEL platforms.] Right now, the only reliable platform to run tests on is x86_64/i?86 for the specific case where we do not detach from the fork. Consequently, this patch limits testing to those architectures. I have updated breakpoints/13457 with my findings on failures with the detaching case. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=13457 Approved-By: Andrew Burgess <[email protected]>
1 parent f891d8e commit a19c781

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* This testcase is part of GDB, the GNU debugger.
2+
3+
Copyright 2025 Free Software Foundation, Inc.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
17+
18+
#include <unistd.h>
19+
#include <stdio.h>
20+
21+
int
22+
main (int argc, char **argv)
23+
{
24+
int pid, x = 0;
25+
26+
pid = fork ();
27+
if (pid == 0) /* set breakpoint here */
28+
printf ("I am the child\n");
29+
else
30+
printf ("I am the parent\n");
31+
32+
chdir (".");
33+
++x; /* set exit breakpoint here */
34+
return 0;
35+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Copyright 2025 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
# Test catching syscalls with all permutations of follow-fork parent/child
17+
# and detach-on-fork on/off.
18+
19+
# Test relies on checking follow-fork output. Do not run if gdb debug is
20+
# enabled because it will be redirected to the log.
21+
require !gdb_debug_enabled
22+
require {is_any_target "i?86-*-*" "x86_64-*-*"}
23+
24+
standard_testfile
25+
26+
if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
27+
return -1
28+
}
29+
30+
proc setup_gdb {} {
31+
global testfile
32+
33+
clean_restart $testfile
34+
35+
if {![runto_main]} {
36+
return false
37+
}
38+
39+
# Set a breakpoint after the fork is "complete."
40+
if {![gdb_breakpoint [gdb_get_line_number "set breakpoint here"]]} {
41+
return false
42+
}
43+
44+
# Set exit breakpoint (to prevent inferior from exiting).
45+
if {![gdb_breakpoint [gdb_get_line_number "set exit breakpoint here"]]} {
46+
return false
47+
}
48+
return true
49+
}
50+
51+
# Check that fork catchpoints are supported, as an indicator for whether
52+
# fork-following is supported. Return 1 if they are, else 0.
53+
54+
proc_with_prefix check_fork_catchpoints {} {
55+
global gdb_prompt
56+
57+
if { ![setup_gdb] } {
58+
return false
59+
}
60+
61+
# Verify that the system supports "catch fork".
62+
gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "insert first fork catchpoint"
63+
set has_fork_catchpoints false
64+
gdb_test_multiple "continue" "continue to first fork catchpoint" {
65+
-re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" {
66+
unsupported "continue to first fork catchpoint"
67+
}
68+
-re ".*Catchpoint.*$gdb_prompt $" {
69+
set has_fork_catchpoints true
70+
pass "continue to first fork catchpoint"
71+
}
72+
}
73+
74+
return $has_fork_catchpoints
75+
}
76+
77+
proc_with_prefix test_catch_syscall {follow-fork-mode detach-on-fork} {
78+
# Start with shiny new gdb instance.
79+
if {![setup_gdb]} {
80+
return
81+
}
82+
83+
# The "Detaching..." and "Attaching..." messages may be hidden by
84+
# default.
85+
gdb_test_no_output "set verbose"
86+
87+
# Setup modes to test.
88+
gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}"
89+
gdb_test_no_output "set detach-on-fork ${detach-on-fork}"
90+
91+
gdb_test "catch fork" "Catchpoint . \\(fork\\)"
92+
gdb_test "catch syscall chdir" "Catchpoint . \\(syscall 'chdir'.*\\)"
93+
94+
# Which inferior we're expecting to follow. Assuming the parent
95+
# will be inferior #1, and the child will be inferior #2.
96+
if {${follow-fork-mode} == "parent"} {
97+
set following_inf 1
98+
} else {
99+
set followin_inf 2
100+
}
101+
# Next stop should be the fork catchpoint.
102+
set expected_re ""
103+
append expected_re "Catchpoint . \\(forked process.*"
104+
gdb_test "continue" $expected_re "continue to fork catchpoint"
105+
106+
# Next stop should be the breakpoint after the fork.
107+
set expected_re ".*"
108+
if {${follow-fork-mode} == "child" || ${detach-on-fork} == "off"} {
109+
append expected_re "\\\[New inferior.*"
110+
}
111+
if {${detach-on-fork} == "on"} {
112+
append expected_re "\\\[Detaching after fork from "
113+
if {${follow-fork-mode} == "parent"} {
114+
append expected_re "child"
115+
} else {
116+
append expected_re "parent"
117+
}
118+
append expected_re " process.*"
119+
}
120+
append expected_re "Breakpoint .*set breakpoint here.*"
121+
gdb_test "continue" $expected_re "continue to breakpoint after fork"
122+
123+
# Next stop should be the syscall catchpoint.
124+
set expected_re ".*Catchpoint . \\(call to syscall chdir\\).*"
125+
gdb_test continue $expected_re "continue to chdir syscall"
126+
}
127+
128+
# Check for follow-fork support.
129+
if {![check_fork_catchpoints]} {
130+
untested "follow-fork not supported"
131+
return
132+
}
133+
134+
# Test all permutations.
135+
foreach_with_prefix follow-fork-mode {"parent" "child"} {
136+
137+
# Do not run tests when not detaching from the parent.
138+
# See breakpoints/13457 for discussion.
139+
foreach_with_prefix detach-on-fork {"on"} {
140+
test_catch_syscall ${follow-fork-mode} ${detach-on-fork}
141+
}
142+
}

0 commit comments

Comments
 (0)