Add syscall tests when following/detaching from fork
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gdb_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gdb_check--master-arm |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 |
success
|
Test passed
|
Commit Message
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, demonstrating
the failure of gdb/gdbserver to properly handle the cases where it stays
attached to both parent and child.
According to my testing (both with this test and manually), the results
of this testing are architecture-dependent. For example, gdbserver on
s390x and ppc64le fails some tests which pass on other arches.
Given the ubiquity of x86_64, I've added KFAILs based on that architecture,
but I wonder if that's necessary (or even desired).
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=13457
---
gdb/testsuite/gdb.base/foll-fork-syscall.c | 18 +++
gdb/testsuite/gdb.base/foll-fork-syscall.exp | 150 +++++++++++++++++++
2 files changed, 168 insertions(+)
create mode 100644 gdb/testsuite/gdb.base/foll-fork-syscall.c
create mode 100644 gdb/testsuite/gdb.base/foll-fork-syscall.exp
base-commit: 753e2f771b1bba72426354aef364c8d986ed999c
new file mode 100644
@@ -0,0 +1,18 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ int pid, x = 0;
+
+ pid = fork ();
+ if (pid == 0) /* set breakpoint here */
+ printf ("I am the child\n");
+ else
+ printf ("I am the parent\n");
+
+ chdir (".");
+ ++x; /* set exit breakpoint here */
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,150 @@
+# Copyright 1997-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 catching syscalls with all permutations of follow-fork parent/child
+# and detach-on-fork on/off.
+
+# Test relies on checking follow-fork output. Do not run if gdb debug is
+# enabled because it will be redirected to the log.
+require !gdb_debug_enabled
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+ return -1
+}
+
+proc setup_gdb {} {
+ global testfile
+
+ clean_restart $testfile
+
+ if {![runto_main]} {
+ return false
+ }
+
+ # Set a breakpoint after the fork is "complete."
+ if {![gdb_breakpoint [gdb_get_line_number "set breakpoint here"]]} {
+ return false
+ }
+
+ # Set exit breakpoint (to prevent inferior from exiting).
+ if {![gdb_breakpoint [gdb_get_line_number "set exit breakpoint here"]]} {
+ return false
+ }
+ return true
+}
+
+# Check that fork catchpoints are supported, as an indicator for whether
+# fork-following is supported. Return 1 if they are, else 0.
+
+proc_with_prefix check_fork_catchpoints {} {
+ global gdb_prompt
+
+ if { ![setup_gdb] } {
+ return false
+ }
+
+ # Verify that the system supports "catch fork".
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "insert first fork catchpoint"
+ set has_fork_catchpoints false
+ gdb_test_multiple "continue" "continue to first fork catchpoint" {
+ -re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" {
+ unsupported "continue to first fork catchpoint"
+ }
+ -re ".*Catchpoint.*$gdb_prompt $" {
+ set has_fork_catchpoints true
+ pass "continue to first fork catchpoint"
+ }
+ }
+
+ return $has_fork_catchpoints
+}
+
+proc_with_prefix test_catch_syscall {follow-fork-mode detach-on-fork kfail} {
+ # Start with shiny new gdb instance.
+ if {![setup_gdb]} {
+ return
+ }
+
+ # The "Detaching..." and "Attaching..." messages may be hidden by
+ # default.
+ gdb_test_no_output "set verbose"
+
+ # Setup modes to test.
+ gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}"
+ gdb_test_no_output "set detach-on-fork ${detach-on-fork}"
+
+ gdb_test "catch fork" "Catchpoint . \\(fork\\)"
+ gdb_test "catch syscall chdir" "Catchpoint . \\(syscall 'chdir'.*\\)"
+
+ # Which inferior we're expecting to follow. Assuming the parent
+ # will be inferior #1, and the child will be inferior #2.
+ if {${follow-fork-mode} == "parent"} {
+ set following_inf 1
+ } else {
+ set followin_inf 2
+ }
+ # Next stop should be the fork catchpoint.
+ set expected_re ""
+ append expected_re "Catchpoint . \\(forked process.*"
+ gdb_test "continue" $expected_re "continue to fork catchpoint"
+
+ # Next stop should be the breakpoint after the fork.
+ set expected_re ".*"
+ if {${follow-fork-mode} == "child" || ${detach-on-fork} == "off"} {
+ append expected_re "\\\[New inferior.*"
+ }
+ if {${detach-on-fork} == "on"} {
+ append expected_re "\\\[Detaching after fork from "
+ if {${follow-fork-mode} == "parent"} {
+ append expected_re "child"
+ } else {
+ append expected_re "parent"
+ }
+ append expected_re " process.*"
+ }
+ append expected_re "Breakpoint .*set breakpoint here.*"
+ gdb_test "continue" $expected_re "continue to breakpoint after fork"
+
+ # Next stop should be the syscall catchpoint.
+ set expected_re ".*Catchpoint . \\(call to syscall chdir\\).*"
+ if {$kfail != ""} {
+ eval setup_kfail $kfail
+ }
+ gdb_test continue $expected_re "continue to chdir syscall"
+}
+
+# Array of results which expect to fail.
+array set kfail_array {
+ {parent on} ""
+ {parent off} "breakpoints/13457 *-*-*"
+ {child on} ""
+ {child off} "breakpoints/13457 *-*-*"
+}
+
+# Check for follow-fork support.
+if {![check_fork_catchpoints]} {
+ untested "follow-fork not supported"
+ return
+}
+
+# Test all permutations.
+foreach_with_prefix follow-fork-mode {"parent" "child"} {
+ foreach_with_prefix detach-on-fork {"on" "off"} {
+ test_catch_syscall ${follow-fork-mode} ${detach-on-fork} \
+ $kfail_array(${follow-fork-mode} ${detach-on-fork})
+ }
+}