aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/foll-fork-syscall.exp
blob: 21ef3347dc111d1207c123729758868d533e4bff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Copyright 2025 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
require {is_any_target "i?86-*-*" "x86_64-*-*"}
require allow_fork_tests

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} {
    # 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\\).*"
    gdb_test continue $expected_re "continue to chdir syscall"
}

# 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"} {

    # Do not run tests when not detaching from the parent.
    # See breakpoints/13457 for discussion.
    foreach_with_prefix detach-on-fork {"on"} {
	test_catch_syscall ${follow-fork-mode} ${detach-on-fork}
    }
}