aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.mi/mi-multi-commands.exp
blob: 00ab37cb64d1cf803980475af5eae402dfe439a6 (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
# Copyright 2022-2023 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/>.

# In the past we would use glibc's buffered input for the mi tty.
# This buffering would cause problems if two commands are sent to gdb
# in a single write call, and, if the first command (excluding its
# trailing newline) exactly filled glibc's internal buffer.
#
# The solution to this problem was to stop using glibc's buffering for
# the mi tty.
#
# To test for this situation we send two command to gdb in a loop, the
# first command gets progressively bigger.  We check that gdb
# correctly sees both commands.

load_lib mi-support.exp
set MIFLAGS "-i=mi"

# Start gdb, passing ARGS to mi_gdb_start.  Then run a series of tests
# passing two commands to gdb in a single write action.  The first
# command is increasingly long, while the second command stays very
# short.
#
# Check that gdb sees, and performs, both commands.
proc run_test { args } {
    global mi_gdb_prompt
    global decimal

    gdb_exit
    if [mi_gdb_start $args] {
	return
    }

    set start 1
    set limit 2049

    mi_gdb_test "set \$a = \"FIRST COMMAND\"" ".*"
    mi_gdb_test "set \$b = \"TEST COMPLETE\"" ".*"

    for { set i $start } { $i < $limit } { incr i } {

	set cmd ""

	# Create a command that is at least `i` characters long.
	set first_cmd "-data-evaluate-expression \$a"
	while { [string length $first_cmd] < $i } {
	    set first_cmd " $first_cmd"
	}

	# We reset `i`, our loop counter, here.  When i is large this
	# should be a nop as we attempt to make the first command
	# length be i above.  However, the first time around the loop
	# we start with an i value of 1, however, we can't make a
	# command that short, so, by resetting i here we effectively
	# skip the first couple of loop iterations where i is less
	# than the minimum command length.
	set i [string length $first_cmd]
	verbose -log "length of first command is $i"

	set cmd "${first_cmd}\n-data-evaluate-expression \$b\n"

	# We need to call send_gdb ourselves here as gdb_test_multiple
	# will try to send each line of the command separately (breaking
	# the command at newline characters).  This splitting will more
	# than likely mean that gdb will see and process the first command
	# before the second command arrives, this prevents the bug from
	# triggering.
	send_gdb "$cmd"

	# Now check for output from the two commands.  We do this
	# using two calls to gdb_test_multiple, this is because the
	# echoing of the second command can sometime get mixed
	# unexpectedly with the command output, this is especially
	# likely when running using the read1 technique.
	#
	# When using a single gdb_test_multiple we need to anchor
	# patterns using a ^, however, this requires us to consume and
	# discard all lines that are not part of the output that we're
	# looking for.  However, due to the unpredictable
	# intermingling, it's much easier if we drop the ^ anchor.
	# However, with this gone dejagnu would sometimes match the
	# second comand output before the first commands output.
	#
	# This approach just looks for the first command output, then,
	# once that has been found, we start looking for the second
	# command output, this seems pretty reliable.
	set seen_first_message false
	set seen_second_message false

	gdb_test_multiple "" "look for first command output, command length $i" -prompt "$mi_gdb_prompt" {
	    -re "\\^done.*,value=\"\\\\\"FIRST COMMAND\\\\\"\"" {
		set seen_first_message true
		exp_continue
	    }
	    -re "\r\n$mi_gdb_prompt" {
		gdb_assert $seen_first_message $gdb_test_name
	    }
	}

	gdb_test_multiple "" "look for second command output, command length $i" -prompt "$mi_gdb_prompt" {
	    -re "\\^done,value=\"\\\\\"TEST COMPLETE\\\\\"\"\r\n$mi_gdb_prompt" {
		pass $gdb_test_name
		set seen_second_message true
	    }
	}

	# If one of the above tests failed then lets no waste our time
	# checking different command lengths.  The actual bug this
	# test checks for would result in a timeout, so we don't want
	# to risk lots more timeouts.
	if { ! [expr $seen_first_message && $seen_second_message ] } {
	    break
	}
    }
}

foreach_with_prefix args { "" "separate-mi-tty" } {
    run_test $args
}