From: Vladimir Prus Date: Tue, 10 Jun 2008 09:35:09 +0000 (+0000) Subject: Use observers to report stop events in MI. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f7f9a841a31878b377a60bfc7c793e6c8400fafe;p=binutils-gdb.git Use observers to report stop events in MI. * mi/mi-interp.c (mi_on_normal_stop): New. (mi_interpreter_init): Register mi_on_normal_stop. (mi_interpreter_exec_continuation): Remove. (mi_cmd_interpreter_exec): Don't register the above. * mi/mi-main.c (captured_mi_execute_command): Don't care about sync_execution. (mi_execute_async_cli_command): Don't install continuation. Don't print *stopped. (mi_exec_async_cli_cmd_continuation): Remove. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4f4e28c2032..f18c6c98c33 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2008-06-10 Vladimir Prus + + Use observers to report stop events in MI. + * mi/mi-interp.c (mi_on_normal_stop): New. + (mi_interpreter_init): Register mi_on_normal_stop. + (mi_interpreter_exec_continuation): Remove. + (mi_cmd_interpreter_exec): Don't register the above. + * mi/mi-main.c (captured_mi_execute_command): Don't care + about sync_execution. + (mi_execute_async_cli_command): Don't install continuation. Don't + print *stopped. + (mi_exec_async_cli_cmd_continuation): Remove. + 2008-06-10 Vladimir Prus Suppress normal stop observer when it's problematic. diff --git a/gdb/infcmd.c b/gdb/infcmd.c index a844b7d4c1e..01e1ebea669 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1383,10 +1383,7 @@ finish_command (char *arg, int from_tty) arg1->data.pointer = breakpoint; arg2->data.pointer = function; add_continuation (finish_command_continuation, arg1); - - /* Do this only if not running asynchronously or if the target - cannot do async execution. Otherwise, complete this command when - the target actually stops, in fetch_inferior_event. */ + discard_cleanups (old_chain); if (!target_can_async_p ()) do_all_continuations (0); diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 8b0d9091c5b..583c288a76d 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -65,6 +65,7 @@ static void mi1_command_loop (void); static void mi_insert_notify_hooks (void); static void mi_remove_notify_hooks (void); +static void mi_on_normal_stop (struct bpstats *bs); static void mi_new_thread (struct thread_info *t); static void mi_thread_exit (struct thread_info *t); @@ -92,6 +93,7 @@ mi_interpreter_init (int top_level) { observer_attach_new_thread (mi_new_thread); observer_attach_thread_exit (mi_thread_exit); + observer_attach_normal_stop (mi_on_normal_stop); } return mi; @@ -171,26 +173,6 @@ mi_interpreter_prompt_p (void *data) return 0; } -static void -mi_interpreter_exec_continuation (struct continuation_arg *arg, int error_p) -{ - bpstat_do_actions (&stop_bpstat); - /* It's not clear what to do in the case of errror -- should we assume that - the target is stopped, or that it still runs? */ - if (!target_executing) - { - fputs_unfiltered ("*stopped", raw_stdout); - mi_out_put (uiout, raw_stdout); - fputs_unfiltered ("\n", raw_stdout); - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); - } - else if (target_can_async_p ()) - { - add_continuation (mi_interpreter_exec_continuation, NULL); - } -} - enum mi_cmd_result mi_cmd_interpreter_exec (char *command, char **argv, int argc) { @@ -241,7 +223,6 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) if (target_can_async_p () && target_executing) { fputs_unfiltered ("^running\n", raw_stdout); - add_continuation (mi_interpreter_exec_continuation, NULL); } if (mi_error_message != NULL) @@ -325,12 +306,27 @@ static void mi_thread_exit (struct thread_info *t) { struct mi_interp *mi = top_level_interpreter_data (); - target_terminal_ours (); fprintf_unfiltered (mi->event_channel, "thread-exited,id=\"%d\"", t->num); gdb_flush (mi->event_channel); } +static void +mi_on_normal_stop (struct bpstats *bs) +{ + /* Since this can be called when CLI command is executing, + using cli interpreter, be sure to use MI uiout for output, + not the current one. */ + struct ui_out *uiout = interp_ui_out (top_level_interpreter ()); + struct mi_interp *mi = top_level_interpreter_data (); + + fputs_unfiltered ("*stopped", raw_stdout); + mi_out_put (uiout, raw_stdout); + mi_out_rewind (uiout); + fputs_unfiltered ("\n", raw_stdout); + gdb_flush (raw_stdout); +} + extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ void diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 4ae509e8e7f..6dc7609ed6c 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -103,10 +103,6 @@ static void mi_execute_cli_command (const char *cmd, int args_p, const char *args); static enum mi_cmd_result mi_execute_async_cli_command (char *cli_command, char **argv, int argc); - -static void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg, - int error_p); - static int register_changed_p (int regnum, struct regcache *, struct regcache *); static void get_register (int regnum, int format); @@ -1087,15 +1083,11 @@ captured_mi_execute_command (struct ui_out *uiout, void *data) fputs_unfiltered ("\n", raw_stdout); } else + /* The command does not want anything to be printed. In that + case, the command probably should not have written anything + to uiout, but in case it has written something, discard it. */ mi_out_rewind (uiout); } - else if (sync_execution) - { - /* Don't print the prompt. We are executing the target in - synchronous mode. */ - args->action = EXECUTE_COMMAND_SUPPRESS_PROMPT; - return; - } break; case CLI_COMMAND: @@ -1311,12 +1303,6 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc) fputs_unfiltered (current_token, raw_stdout); fputs_unfiltered ("^running\n", raw_stdout); - /* Ideally, we should be intalling continuation only when - the target is already running. However, this will break right now, - because continuation installed by the 'finish' command must be after - the continuation that prints *stopped. This issue will be - fixed soon. */ - add_continuation (mi_exec_async_cli_cmd_continuation, NULL); } execute_command ( /*ui */ run, 0 /*from_tty */ ); @@ -1332,30 +1318,13 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc) /* Do this before doing any printing. It would appear that some print code leaves garbage around in the buffer. */ do_cleanups (old_cleanups); - /* If the target was doing the operation synchronously we fake - the stopped message. */ - fputs_unfiltered ("*stopped", raw_stdout); - mi_out_put (uiout, raw_stdout); - mi_out_rewind (uiout); if (do_timings) print_diff_now (current_command_ts); - fputs_unfiltered ("\n", raw_stdout); return MI_CMD_QUIET; } return MI_CMD_DONE; } -void -mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg, int error_p) -{ - /* Assume 'error' means that target is stopped, too. */ - fputs_unfiltered ("*stopped", raw_stdout); - mi_out_put (uiout, raw_stdout); - fputs_unfiltered ("\n", raw_stdout); - fputs_unfiltered ("(gdb) \n", raw_stdout); - gdb_flush (raw_stdout); -} - void mi_load_progress (const char *section_name, unsigned long sent_so_far, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d7673059e8c..d994d1fbc43 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2008-06-10 Vladimir Prus + + * gdb.mi/mi-break.exp (test_ignore_count): Adjust stopped pattern. + * gdb.mi/mi-syn-frame.exp: Use mi_expect_stop instead of direct + testing of stopped. + * gdb.mi/mi2-syn-frame.exp: Likewise. + * lib/mi-support.exp (default_mi_gdb_start): Call detect_async. + (async, detect_async): New. + (mi_expect_stop, mi_continue_to_line): Adjust expectation + depending on if we're running in sync or async mode. + 2008-06-09 Tom Tromey * gdb.base/completion.exp: New tests for field name completion diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp index f2f5b03ae0d..2798569d463 100644 --- a/gdb/testsuite/gdb.mi/mi-break.exp +++ b/gdb/testsuite/gdb.mi/mi-break.exp @@ -159,7 +159,7 @@ proc test_ignore_count {} { mi_run_cmd gdb_expect { - -re ".*func=\"callme\".*args=\\\[\{name=\"i\",value=\"2\"\}\\\].*\r\n$mi_gdb_prompt$" { + -re ".*\\*stopped.*func=\"callme\".*args=\\\[\{name=\"i\",value=\"2\"\}\\\].*\r\n($mi_gdb_prompt)?$" { pass "run to breakpoint with ignore count" } -re ".*$mi_gdb_prompt$" { diff --git a/gdb/testsuite/gdb.mi/mi-syn-frame.exp b/gdb/testsuite/gdb.mi/mi-syn-frame.exp index 2f2ca026716..208678bb83b 100644 --- a/gdb/testsuite/gdb.mi/mi-syn-frame.exp +++ b/gdb/testsuite/gdb.mi/mi-syn-frame.exp @@ -58,9 +58,7 @@ mi_gdb_test "403-exec-continue" \ "403\\^running" \ "testing exec continue" -# Presently, the *stopped notification for this case does not include -# any information. This can be considered a bug. -mi_gdb_test "" "\\*stopped" "finished exec continue" +mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue" mi_gdb_test "404-stack-list-frames 0 0" \ "404\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \ @@ -88,7 +86,7 @@ mi_gdb_test "407-stack-list-frames" \ mi_gdb_test "408-exec-continue" "408\\^running" -mi_gdb_test "" ".*\\*stopped.*" "finished exec continue" +mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue" mi_gdb_test "409-stack-list-frames 0 0" \ "409\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \ diff --git a/gdb/testsuite/gdb.mi/mi2-syn-frame.exp b/gdb/testsuite/gdb.mi/mi2-syn-frame.exp index c4474047b54..b69812fb78f 100644 --- a/gdb/testsuite/gdb.mi/mi2-syn-frame.exp +++ b/gdb/testsuite/gdb.mi/mi2-syn-frame.exp @@ -56,15 +56,11 @@ mi_gdb_test "402-stack-list-frames" "402\\^done,stack=\\\[frame=\{level=\"0\",ad # Continue back to main() # -send_gdb "403-exec-continue\n" -gdb_expect { - -re "403\\^running\[\r\n\]+${my_mi_gdb_prompt}.*\\\*stopped\[\r\n\]+${my_mi_gdb_prompt}$" { - pass "403-exec-continue" - } - timeout { - fail "403-exec-continue" - } -} +mi_gdb_test "403-exec-continue" \ + "403\\^running" \ + "testing exec continue" + +mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue" mi_gdb_test "404-stack-list-frames 0 0" \ "404\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \ @@ -89,16 +85,9 @@ mi_gdb_test "407-stack-list-frames" \ "407\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"subroutine\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"handler\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"\"\},.*frame=\{level=\"$decimal\",addr=\"$hex\",func=\"have_a_very_merry_interrupt\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"$decimal\",addr=\"$hex\",func=\"\"\},frame=\{level=\"$decimal\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\}.*\\\]" \ "list stack frames" +mi_gdb_test "408-exec-continue" "408\\^running" -send_gdb "408-exec-continue\n" -gdb_expect { - -re "408\\^running\[\r\n\]+${my_mi_gdb_prompt}.*\\\*stopped\[\r\n\]+${my_mi_gdb_prompt}$" { - pass "408-exec-continue" - } - timeout { - fail "408-exec-continue" - } -} +mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue" mi_gdb_test "409-stack-list-frames 0 0" \ "409\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \ diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp index 6a52c88ae8a..23f3f078a78 100644 --- a/gdb/testsuite/lib/mi-support.exp +++ b/gdb/testsuite/lib/mi-support.exp @@ -227,6 +227,8 @@ proc default_mi_gdb_start { args } { } } + detect_async + return 0; } @@ -911,6 +913,30 @@ proc mi_step { test } { return [mi_step_to {.*} {.*} {.*} {.*} $test] } +set async "unknown" + +proc detect_async {} { + global async + global mi_gdb_prompt + + if { $async == "unknown" } { + send_gdb "maint show linux-async\n" + + gdb_expect { + -re ".*Controlling the GNU/Linux inferior in asynchronous mode is on...*$mi_gdb_prompt$" { + set async 1 + } + -re ".*$mi_gdb_prompt$" { + set async 0 + } + timeout { + set async 0 + } + } + } + return $async +} + # Wait for MI *stopped notification to appear. # The REASON, FUNC, ARGS, FILE and LINE are regular expressions # to match against whatever is output in *stopped. ARGS should @@ -933,6 +959,7 @@ proc mi_expect_stop { reason func args file line extra test } { global hex global decimal global fullname_syntax + global async set after_stopped "" set after_reason "" @@ -944,10 +971,28 @@ proc mi_expect_stop { reason func args file line extra test } { set after_stopped [lindex $extra 0] } + if {$async} { + set prompt_re "" + } else { + set prompt_re "$mi_gdb_prompt" + } + + if { $reason == "really-no-reason" } { + gdb_expect { + -re "\\*stopped\r\n$prompt_re$" { + pass "$test" + } + timeout { + fail "$test (unknown output after running)" + } + } + return + } + if { $reason == "exited-normally" } { gdb_expect { - -re "\\*stopped,reason=\"exited-normally\"\r\n$mi_gdb_prompt$" { + -re "\\*stopped,reason=\"exited-normally\"\r\n$prompt_re$" { pass "$test" } -re ".*$mi_gdb_prompt$" {fail "continue to end (2)"} @@ -973,17 +1018,17 @@ proc mi_expect_stop { reason func args file line extra test } { set a $after_reason - verbose -log "mi_expect_stop: expecting: .*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n$mi_gdb_prompt$" + verbose -log "mi_expect_stop: expecting: .*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n$prompt_re$" gdb_expect { - -re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$mi_gdb_prompt$" { + -re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$prompt_re$" { pass "$test" return $expect_out(2,string) } - -re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$mi_gdb_prompt$" { + -re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$prompt_re$" { fail "$test (stopped at wrong place)" return -1 } - -re ".*\r\n${mi_gdb_prompt}$" { + -re ".*\r\n$mi_gdb_prompt$" { fail "$test (unknown output after running)" return -1 } @@ -1388,9 +1433,16 @@ proc mi_continue_to_line {location test} { proc mi_get_stop_line {test} { global mi_gdb_prompt + global async + + if {$async} { + set prompt_re "" + } else { + set prompt_re "$mi_gdb_prompt" + } gdb_expect { - -re ".*line=\"(.*)\".*\r\n$mi_gdb_prompt$" { + -re ".*line=\"(.*)\".*\r\n$prompt_re$" { return $expect_out(1,string) } -re ".*$mi_gdb_prompt$" {