Commit | Line | Data |
---|---|---|
83e7a0ec SM |
1 | # Copyright 2020-2022 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 handling a vfork while another inferior is running. The bug that | |
17 | # prompted writing this test case was in the Linux native target. The target | |
18 | # assumed that the vfork-done event it received was for the current inferior | |
19 | # (an invalid assumption, the current inferior is the one randomly selected by | |
20 | # do_target_wait (at the time of writing). This caused the target to drop the | |
21 | # vfork-done event, because it was seen as unneeded and to restart the thread | |
22 | # as if nothing happened. This however resulted in the thread running with | |
23 | # breakpoints not inserted. | |
24 | # | |
25 | # To catch the bug, this test verifies that we can hit a breakpoint after a | |
26 | # vfork call, while a second inferior runs in the background. | |
27 | ||
28 | if [use_gdb_stub] { | |
29 | unsupported "test uses multiple inferiors" | |
30 | return | |
31 | } | |
32 | ||
33 | standard_testfile .c -sleep.c | |
34 | ||
35 | set srcfile_sleep $srcfile2 | |
36 | set binfile_sleep ${binfile}-sleep | |
37 | ||
38 | # The reproducibility of the bug depends on which inferior randomly selects in | |
39 | # do_target_wait when consuming the vfork-done event. Since GDB doesn't call | |
40 | # srand(), we are likely to always see the same sequence of inferior selected by | |
41 | # do_target_wait, which can hide the bug if you are not "lucky". To work | |
42 | # around that, call vfork and hit the breakpoint in a loop, it makes it | |
43 | # somewhat likely that the wrong inferior will be selected eventually. | |
44 | set nr_loops 20 | |
45 | ||
46 | # Compile the main program that calls vfork and hits a breakpoint. | |
47 | set opts [list debug additional_flags=-DNR_LOOPS=$nr_loops] | |
48 | if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ | |
49 | $opts] != "" } { | |
50 | untested "failed to compile" | |
51 | return -1 | |
52 | } | |
53 | ||
54 | # Compile the secondary program, which just sleeps. | |
55 | if { [gdb_compile "${srcdir}/${subdir}/${srcfile_sleep}" "${binfile_sleep}" executable \ | |
56 | {debug}] != "" } { | |
57 | untested "failed to compile" | |
58 | return -1 | |
59 | } | |
60 | ||
61 | # We exercise two methods of getting a second inferior to execute while the | |
62 | # first one vforks. METHOD can be: | |
63 | # | |
64 | # - non-stop: start GDB with non-stop on and run the second inferior in | |
65 | # background. | |
66 | # - schedule-multiple: set "schedule-multiple on", this will make "continue" | |
67 | # resume both inferiors. | |
68 | proc do_test {method} { | |
69 | save_vars { ::GDBFLAGS } { | |
70 | if { $method == "non-stop" } { | |
71 | append ::GDBFLAGS " -ex \"set non-stop on\"" | |
72 | } | |
73 | clean_restart | |
74 | } | |
75 | ||
76 | # Start the second inferior in background. | |
77 | gdb_test "add-inferior" "Added inferior 2.*" | |
78 | gdb_test "inferior 2" "Switching to inferior 2 .*" | |
79 | gdb_file_cmd ${::binfile_sleep} | |
80 | if { $method == "non-stop" } { | |
81 | gdb_test "run &" "Starting program: .*" "run inferior 2" | |
82 | } else { | |
83 | gdb_test "start" "Temporary breakpoint $::decimal, main .*" \ | |
84 | "start inferior 2" | |
85 | } | |
86 | ||
87 | # Start the first inferior. | |
88 | gdb_test "inferior 1" "Switching to inferior 1 .*" | |
89 | gdb_file_cmd ${::binfile} | |
90 | gdb_test "break should_break_here" "Breakpoint $::decimal at .*" | |
91 | gdb_test "start" "Thread 1.1 .* hit Temporary breakpoint.*" \ | |
92 | "start inferior 1" | |
93 | ||
94 | # Only enable schedule-multiple this late, because of: | |
95 | # https://sourceware.org/bugzilla/show_bug.cgi?id=28777 | |
96 | if { $method == "schedule-multiple" } { | |
97 | gdb_test_no_output "set schedule-multiple on" | |
98 | } | |
99 | ||
100 | ||
101 | # Continue over vfork and until the breakpoint. The number of loops here | |
102 | # matches the number of loops in the program. So if a breakpoint is missed | |
103 | # at some point, a "continue" will wrongfully continue until the end of the | |
104 | # program, which will fail the test. | |
105 | for {set i 0} {$i < $::nr_loops} {incr i} { | |
106 | with_test_prefix "i=$i" { | |
107 | gdb_test "continue" \ | |
108 | "Thread 1.1 .* hit Breakpoint $::decimal, should_break_here.*" | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | foreach_with_prefix method {schedule-multiple non-stop} { | |
114 | do_test $method | |
115 | } |