[gdb/testsuite] Handle unrecognized escape sequences better in tuiterm

When encountering an unrecognized escape sequence in Term::accept_gdb_output,
a warning is issued:
...
WARNING: timeout in accept_gdb_output
...
and 0 is returned.

Subsequent calls run into the same problem, so matching doesn't progress.

Consequently, figuring out what the unrecognized escape sequence actually is
depends on analyzing gdb's output as echoed into gdb.log.

In the test added in this commit, gdb (well, a script gdb.tcl emulating gdb)
outputs escape sequence "ESC ( B", which doesn't show up in recognizable form
in gdb.log:
...
foo^M^M
...
and as mentioned the tuiterm screen only show:
...
foo
...
because matching doesn't progress beyond the unrecognized sequence.

Fix this by rewriting accept_gdb_output to match gdb output using a phased
approach that echoes unmatched escape sequences, giving us instead on the
tuiterm screen:
...
foo^[(B
...

[ Since "ESC ( B" is now supported, the test-case has been updated to use
"ESC ( % 5" instead. ]

Tested on x86_64-linux.

PR testsuite/33218
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33218
This commit is contained in:
Tom de Vries
2025-08-16 09:18:45 +02:00
parent 96265ee7fa
commit 06a53717f7
3 changed files with 114 additions and 17 deletions

20
gdb/testsuite/gdb.tui/gdb.tcl Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env tclsh
# 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/>.
puts "foo\033(%5"
gets stdin

View File

@@ -151,3 +151,31 @@ with_override Term::accept_gdb_output test_accept_gdb_output {
}
}
}
with_test_prefix "Unrecognized escape sequence" {
spawn $srcdir/$subdir/gdb.tcl
switch_gdb_spawn_id $spawn_id
Term::_setup 4 20
save_vars timeout {
set timeout 1
set line { 0 0 20 1 }
# Parse "foo".
gdb_assert { [Term::wait_for_region_contents \
{*}$line \
[string_to_regexp "foo"]] } \
"foo"
# Parse "\033(%5".
gdb_assert { ![Term::accept_gdb_output 0] } \
"fail to parse escape sequence"
gdb_assert { [Term::wait_for_region_contents \
{*}$line \
[string_to_regexp "^\[(%5"]] } \
"echoed escape sequence"
}
Term::dump_screen
}

View File

@@ -999,31 +999,86 @@ proc Term::_setup {rows cols} {
# Accept some output from gdb and update the screen.
# Return 1 if successful, or 0 if a timeout occurred.
proc Term::accept_gdb_output { } {
proc Term::accept_gdb_output { {warn 1} } {
global expect_out
set ctls "\x07\x08\x0a\x0d"
set esc "\x1b"
set re_ctls "\[$ctls\]"
set re_others "\[^$esc$ctls\]"
set have_esc 0
gdb_expect {
-re "^\[\x07\x08\x0a\x0d\]" {
-re ^$re_ctls {
scan $expect_out(0,string) %c val
set hexval [format "%02x" $val]
_log "wait_for: _ctl_0x${hexval}"
_ctl_0x${hexval}
}
-re "^\x1b(\[0-9a-zA-Z\])" {
-re "^$esc" {
_log "wait_for: ESC"
set have_esc 1
}
-re "^$re_others+" {
_insert $expect_out(0,string)
}
timeout {
# Assume a timeout means we somehow missed the
# expected result, and carry on.
warning "timeout in accept_gdb_output"
dump_screen
return 0
}
}
if { !$have_esc } {
return 1
}
set re_csi [string_to_regexp "\["]
set have_csi 0
gdb_expect {
-re "^(\[0-9a-zA-Z\])" {
_log "wait_for: unsupported escape"
error "unsupported escape"
}
-re "^\x1b(\[\\(\])(\[a-zA-Z\])" {
-re "^(\[\\(\])(\[a-zA-Z\])" {
scan $expect_out(1,string) %c val
set hexval [format "%02x" $val]
set cmd $expect_out(2,string)
eval _esc_0x${hexval}_$cmd
}
-re "^\x1b(\[=>\])" {
-re "^(\[=>\])" {
scan $expect_out(1,string) %c val
set hexval [format "%02x" $val]
_esc_0x$hexval
}
-re "^\x1b\\\[(\\??)(\[0-9;\]*)(\[a-zA-Z@`\])" {
-re "^$re_csi" {
_log "wait_for: CSI"
set have_csi 1
}
timeout {
# Assume a timeout means we somehow missed the
# expected result, and carry on.
if { $warn } {
warning "timeout in accept_gdb_output following ESC"
dump_screen
}
_insert "^\["
return 0
}
}
if { !$have_csi } {
return 1
}
set re_csi_prefix {[?]}
set re_csi_args {[0-9;]}
set re_csi_cmd {[a-zA-Z@`]}
gdb_expect {
-re "^($re_csi_prefix?)($re_csi_args*)($re_csi_cmd)" {
set prefix $expect_out(1,string)
set cmd $expect_out(3,string)
set params [split $expect_out(2,string) ";"]
@@ -1037,21 +1092,15 @@ proc Term::accept_gdb_output { } {
eval _csi_0x${hexval}_$cmd $params
}
}
-re "^\x1b\\\[(\[0-9;\]*)(\[a-zA-Z@`\])" {
set cmd $expect_out(2,string)
set params [split $expect_out(1,string) ";"]
_log "wait_for: _csi_$cmd <<<$expect_out(1,string)>>>"
eval _csi_$cmd $params
}
-re "^\[^\x07\x08\x0a\x0d\x1b\]+" {
_insert $expect_out(0,string)
}
timeout {
# Assume a timeout means we somehow missed the
# expected result, and carry on.
warning "timeout in accept_gdb_output"
dump_screen
if { $warn } {
warning "timeout in accept_gdb_output following CSI"
dump_screen
}
_insert "^\[\["
return 0
}
}