From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8595 invoked by alias); 12 Jun 2009 23:00:44 -0000 Received: (qmail 8578 invoked by uid 22791); 12 Jun 2009 23:00:41 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.200.157) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 12 Jun 2009 23:00:32 +0000 Received: from baal.u-strasbg.fr (baal.u-strasbg.fr [IPv6:2001:660:2402::41]) by mailhost.u-strasbg.fr (8.14.2/jtpda-5.5pre1) with ESMTP id n5CN0SBk029589 for ; Sat, 13 Jun 2009 01:00:28 +0200 (CEST) Received: from mailserver.u-strasbg.fr (ms2.u-strasbg.fr [IPv6:2001:660:2402:d::11]) by baal.u-strasbg.fr (8.14.0/jtpda-5.5pre1) with ESMTP id n5CN0S1P051198 for ; Sat, 13 Jun 2009 01:00:28 +0200 (CEST) (envelope-from muller@ics.u-strasbg.fr) Received: from d620muller (lec67-4-82-230-53-140.fbx.proxad.net [82.230.53.140]) (user=mullerp mech=LOGIN) by mailserver.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id n5CN0QRp062317 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) for ; Sat, 13 Jun 2009 01:00:27 +0200 (CEST) (envelope-from muller@ics.u-strasbg.fr) From: "Pierre Muller" To: Subject: [RFC] Improve testsuite for poor expect behavior Date: Fri, 12 Jun 2009 23:00:00 -0000 Message-ID: <001201c9ebb1$96414b10$c2c3e130$@u-strasbg.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-06/txt/msg00346.txt.bz2 I am trying to run the testsuite in a cygwin environment, but for mingw32 or djgpp targets, using native builds of GDB. For mingw32, the main problem is that there are extra ^M generated in the output. For a while I was wondering if I could change all "\r\n" into "\r+\n" in the different test .exp files. But this would be a huge number of changes, and replacing all in wrong especially inside things like "\[^\r\n\]*" which means anything but a carriage return or line feed. Adding a "+" here would probably give lots of new errors. I finally came up with a smaller solutions, that seems to work pretty well: Simply replace all occurrences of "\r\n" by "\r+\n" in the expcode argument of gdb_expect function. This would give the same problem as above with "\r\n" inside square brackets. The solution is to first replace any "\r\n" inside square brackets by "\rzz\n" to protect them again adding the "+", and transform the "\rzz\n" inside square brackets back into "\r\n" after. As long as there are no "\r\n" inside variables to be substituted later, this works fine. The main remaining problem is gdb_expect_list, because it does use such variables with enclosed newlines. There is a second aspect, which is mainly a problem of the cygwin expect: GDB run inside expect does not believe that they are connected to a terminal, which means that queries are answered by their default values. A large part of the patch below is devoted to adding pattern that recognize correctly the cases where a query is answered automatically. I checked this patch on gcc-farm the testsuite results are totally unaffected. Is this patch something that could be acceptable, or does it go too far in trying to compensate for expect limitations? Pierre Muller Pascal language support maintainer for GDB PS: For DJGPP, I had to add some special tricks to be able to run expect on it, I will try to send this in a separate email. 2009-06-12 Pierre Muller * lib/gdb.exp (fuzzy_newline): New global. (input_not_from_terminal): New global. (gdb_input_not_from_terminal): New procedure. (gdb_proc_unload): Add pattern corresponding to automated answer if not from terminal. (delete_breakpoints): Likewise. (gdb_run_mcd): Likewise. (gdb_start_cmd): Likewise. (gdb_internal_error_resync): Likewise. (gdb_reinitialize_dir): Likewise. (default_gdb_exit): Likewise. (gdb_file_cmd): Likewise. (rerun_to_main): Likewise. (gdb_compile): Also compile set_unbuffered_output for djgpp target. (gdb_expect): If fuzzy_newline is set, replace all "\r\n" by "\r+\n" in expcode. Index: src/gdb/testsuite/lib/gdb.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/lib/gdb.exp,v retrieving revision 1.114 diff -u -p -r1.114 src/gdb/testsuite/lib/gdb.exp --- src/gdb/testsuite/lib/gdb.exp 22 Apr 2009 19:46:19 -0000 1.114 +++ src/gdb/testsuite/lib/gdb.exp 12 Jun 2009 15:14:16 -0000 @@ -93,6 +93,30 @@ if ![info exists env(EXEEXT)] { set EXEEXT $env(EXEEXT) } +global fuzzy_newline +if { [istarget "*-*-mingw*"] || [istarget "*-*-*djgpp"] } { + set fuzzy_newline 1; +} + +global input_not_from_terminal +set input_not_from_terminal 0; +#if { [istarget "*-*-mingw*"] || [istarget "*-*-*djgpp"] \ +# || [istarget "*-*-cygwin*"] } { +# set input_not_from_terminal 1; +#} + +proc gdb_input_not_from_terminal { context } { + global input_not_from_terminal + if {$input_not_from_terminal} { + verbose "Input not from terminal in $context" + } else { + fail "GDB does not seem to believe it is on a terminal\n" + verbose "Setting input_not_from_terminal to 1" + set input_not_from_terminal 1; + } +} + + set octal "\[0-7\]+" ### Only procedures should come after this point. @@ -137,11 +161,23 @@ proc gdb_unload {} { gdb_expect 60 { -re "No executable file now\[^\r\n\]*\[\r\n\]" { exp_continue } -re "No symbol file now\[^\r\n\]*\[\r\n\]" { exp_continue } + -re "A program is being debugged already..*Kill it.*y or n.*answered Y; input not from terminal."\ + { verbose "\t\tKilling previous program being debugged (not from terminal)" + gdb_input_not_from_terminal "gdb_unload" + exp_continue + } + -re "A program is being debugged already..*Kill it.*y or n. $"\ { send_gdb "y\n" verbose "\t\tKilling previous program being debugged" exp_continue } + -re "Discard symbol table from .*y or n.*answered Y; input not from terminal." { + verbose "Discard symbol table (not from terminal)" + gdb_input_not_from_terminal "gdb_unload symbols" + exp_continue + } + -re "Discard symbol table from .*y or n.*$" { send_gdb "y\n" exp_continue @@ -168,7 +204,12 @@ proc delete_breakpoints {} { # send_gdb "delete breakpoints\n" gdb_expect 100 { - -re "Delete all breakpoints.*y or n.*$" { + -re "Delete all breakpoints.*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "delete_breakpoints"; + exp_continue + } + + -re "Delete all breakpoints.*y or n. $" { send_gdb "y\n"; exp_continue } @@ -217,7 +258,7 @@ proc gdb_run_cmd {args} { } send_gdb "continue\n"; gdb_expect 60 { - -re "Continu\[^\r\n\]*\[\r\n\]" {} + -re "Continu\[^\r\n\]*\[\r\n\]+" {} default {} } return; @@ -240,7 +281,7 @@ proc gdb_run_cmd {args} { } set start_attempt [expr $start_attempt + 1]; gdb_expect 30 { - -re "Continuing at \[^\r\n\]*\[\r\n\]" { + -re "Continuing at \[^\r\n\]*\[\r\n\]+" { set start_attempt 0; } -re "No symbol \"_start\" in current.*$gdb_prompt $" { @@ -253,6 +294,10 @@ proc gdb_run_cmd {args} { -re "No symbol.*context.*$gdb_prompt $" { set start_attempt 0; } + -re "Line.* Jump anyway.*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_run_cmd jump" + } + -re "Line.* Jump anyway.*y or n. $" { send_gdb "y\n" } @@ -288,6 +333,11 @@ proc gdb_run_cmd {args} { # Use -notransfer here so that test cases (like chng-sym.exp) # may test for additional start-up messages. gdb_expect 60 { + -re "The program .* has been started already.*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_run_cmd run" + exp_continue + } + -re "The program .* has been started already.*y or n. $" { send_gdb "y\n" exp_continue @@ -319,6 +369,11 @@ proc gdb_start_cmd {args} { send_gdb "start $args\n" gdb_expect 60 { + -re "The program .* has been started already.*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_start_cmd start" + exp_continue + } + -re "The program .* has been started already.*y or n. $" { send_gdb "y\n" exp_continue @@ -506,10 +561,20 @@ proc gdb_internal_error_resync {} { set count 0 while {$count < 10} { gdb_expect { + -re "Quit this debugging session\\? \\(y or n\\).*answered N; input not from terminal." { + gdb_input_not_from_terminal "gdb_internal_error_resync Quit" + incr count + } + -re "Quit this debugging session\\? \\(y or n\\) $" { send_gdb "n\n" incr count } + -re "Create a core file of GDB\\? \\(y or n\\).*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_internal_error_resync Create core" + incr count + } + -re "Create a core file of GDB\\? \\(y or n\\) $" { send_gdb "n\n" incr count @@ -988,19 +1053,20 @@ proc gdb_reinitialize_dir { subdir } { } send_gdb "dir\n" gdb_expect 60 { + -re "Reinitialize source path to empty.*y or n. .answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_reinitialize_dir Reinitialize" + exp_continue + } + -re "Reinitialize source path to empty.*y or n. " { send_gdb "y\n" + exp_continue + } + -re "Source directories searched.*$gdb_prompt $" { + send_gdb "dir $subdir\n" gdb_expect 60 { -re "Source directories searched.*$gdb_prompt $" { - send_gdb "dir $subdir\n" - gdb_expect 60 { - -re "Source directories searched.*$gdb_prompt $" { - verbose "Dir set to $subdir" - } - -re "$gdb_prompt $" { - perror "Dir \"$subdir\" failed." - } - } + verbose "Dir set to $subdir" } -re "$gdb_prompt $" { perror "Dir \"$subdir\" failed." @@ -1033,6 +1099,10 @@ proc default_gdb_exit {} { if { [is_remote host] && [board_info host exists fileid] } { send_gdb "quit\n"; gdb_expect 10 { + -re "y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_reinitialize_dir Reinitialize" + exp_continue; + } -re "y or n" { send_gdb "y\n"; exp_continue; @@ -1090,6 +1160,11 @@ proc gdb_file_cmd { arg } { # of the testsuite, preserve this behavior. send_gdb "kill\n" gdb_expect 120 { + -re "Kill the program being debugged. .y or n.*answered Y; input not from terminal." { + verbose "\t\tKilling previous program being debugged" + gdb_input_not_from_terminal "gdb_file_cmd kill" + exp_continue + } -re "Kill the program being debugged. .y or n. $" { send_gdb "y\n" verbose "\t\tKilling previous program being debugged" @@ -1112,6 +1187,21 @@ proc gdb_file_cmd { arg } { set gdb_file_cmd_debug_info "debug" return 0 } + -re "Load new symbol table from \".*\".*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "gdb_file_cmd file" + gdb_expect 120 { + -re "Reading symbols from.*done.*$gdb_prompt $" { + verbose "\t\tLoaded $arg with new symbol table into $GDB" + set gdb_file_cmd_debug_info "debug" + return 0 + } + timeout { + perror "(timeout) Couldn't load $arg, other program already loaded." + return -1 + } + } + } + -re "Load new symbol table from \".*\".*y or n. $" { send_gdb "y\n" gdb_expect 120 { @@ -1743,6 +1833,7 @@ proc gdb_compile {source dest type optio if { $type == "executable" } { if { ([istarget "*-*-mingw*"] + || [istarget "*-*-*djgpp"] || [istarget "*-*-cygwin*"])} { # Force output to unbuffered mode, by linking in an object file # with a global contructor that calls setvbuf. @@ -1986,6 +2077,24 @@ proc gdb_expect { args } { } } + global fuzzy_newline; + + if { [info exists fuzzy_newline] && $fuzzy_newline } { + verbose "Special replacement in gdb_expect entry expcode=\"$expcode\"" + set subst1 [regsub -all {\\\[([^]]*)\\r\\n([^]]*)\\\]} "$expcode" \ + {\\[\1\\rzz\\n\2\\]} expcode1] + set subst2 [regsub -all {\\r+\\n} $expcode1 {\\r\\n} expcode2] + set subst3 [regsub -all {\\r\\n} $expcode2 {\\r+\\n} expcode3] + set subst4 [regsub -all {\\\[([^]]*)\\rzz\\n([^]]*)\\\]} $expcode3 \ + {\\[\1\\r\\n\2\\]} expcode4] + set subst [expr $subst1 + $subst2 + $subst3 + $subst4]; + verbose "Special replacement in gdb_expect returned expcode=\"$expcode4\"" + if { $subst1 != 0 || $subst2 != 0 || $subst3 != 0 } { + verbose "Special replacement gdb_expect substs=$subst" + verbose "subst1=$subst1 subst2=$subst2 subst3=$subst3 subst4=$subst4" 3 + set expcode $expcode4; + } + } global suppress_flag; global remote_suppress_flag; if [info exists remote_suppress_flag] { @@ -2573,6 +2683,10 @@ proc rerun_to_main {} { } else { send_gdb "run\n" gdb_expect { + -re "The program .* has been started already.*y or n.*answered Y; input not from terminal." { + gdb_input_not_from_terminal "rerun_to_main" + exp_continue + } -re "The program .* has been started already.*y or n. $" { send_gdb "y\n" exp_continue