diff options
Diffstat (limited to 'gdb/testsuite/gdb.mi')
-rw-r--r-- | gdb/testsuite/gdb.mi/mi-multi-commands.exp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.mi/mi-multi-commands.exp b/gdb/testsuite/gdb.mi/mi-multi-commands.exp new file mode 100644 index 0000000..767d1d0 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-multi-commands.exp @@ -0,0 +1,128 @@ +# Copyright 2022 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] { + continue + } + + 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 "print \$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}\nprint \$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 "(&\"print \\\$\[ab\]\\\\n\")\r\n(~\"\\\$$decimal = \\\\\"FIRST COMMAND\\\\\"\[^\r\n\]+\r\n\\^done\r\n$mi_gdb_prompt)" { + pass $gdb_test_name + set seen_first_message true + } + } + + gdb_test_multiple "" "look for second command output, command length $i" -prompt "$mi_gdb_prompt" { + -re "(&\"print \\\$\[ab\]\\\\n\")\r\n(~\"\\\$$decimal = \\\\\"TEST COMPLETE\\\\\"\[^\r\n\]+\r\n\\^done\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 +} |