From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11763 invoked by alias); 24 Apr 2008 12:37:56 -0000 Received: (qmail 11732 invoked by uid 22791); 24 Apr 2008 12:37:52 -0000 X-Spam-Check-By: sourceware.org Received: from zigzag.lvk.cs.msu.su (HELO zigzag.lvk.cs.msu.su) (158.250.17.23) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 24 Apr 2008 12:37:35 +0000 Received: from Debian-exim by zigzag.lvk.cs.msu.su with spam-scanned (Exim 4.63) (envelope-from ) id 1Jp0Kw-0006Nb-P9 for gdb-patches@sourceware.org; Thu, 24 Apr 2008 16:14:06 +0400 Received: from localhost ([127.0.0.1] helo=ip6-localhost) by zigzag.lvk.cs.msu.su with esmtp (Exim 4.63) (envelope-from ) id 1Jp0Kw-0006NX-Fp; Thu, 24 Apr 2008 16:14:02 +0400 From: Vladimir Prus Subject: Re: [RFA] Use observers to report stop events. To: gdb-patches@sourceware.org,Daniel Jacobowitz Date: Thu, 24 Apr 2008 13:47:00 -0000 References: <200804112145.58456.vladimir@codesourcery.com> User-Agent: KNode/0.10.5 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7Bit Message-Id: 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: 2008-04/txt/msg00554.txt.bz2 Vladimir Prus wrote: > > Presently, the *stopped async output, despite been documented as async, > is actually output during processing of MI command. Naturally, this is > not going to work in non-stop mode, since there may be more stops that > there were MI commands. This patches makes the *stopped output be printed > via observer. Presently, there's one regression in mi tests -- namely the > mi-async.exp test -- which uses hardcoded tests for *stopped and so > fails after update as predicated :-) I'll fix this up later; this is a local > change and should not affect the review of the patch itself. > > Note that there are no current uses of the normal_stop observer, so this > patch is as safe as it can get :-) Ping? > - Volodya > > * defs.h (make_cleanup_restore_integer): New declaration. > * utils.c (restore_integer_closure, restore_integer) > (make_cleanup_restore_integer): New. > * breakpoint.c (restore_always_inserted_mode): Remove. > (update_breakpoints_after_exec): Use make_cleanup_restore_integer. > > * inferior.h (suppress_normal_stop_observer): New. > * infcall.c (call_function_by_hand): Disable stop events when > doing function calls. > * infmcd.c (suppress_normal_stop_observer): New. > (finish_command_continuation): Call normal_stop observer > explicitly. > (finish_command): Disable stop events inside proceed. > * infrun.c (normal_stop): Don't call normal stop observer if > suppressed of if multi-step is in progress. > > * interps.h (top_level_interpreter): New. > * interps.c (top_level_interpreter): Rename to > top_level_interpreter_ptr. > (top_level_interpreter): New. > > * 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. > > [gdb/testsuite] > * 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. > --- > gdb/breakpoint.c | 10 +---- > gdb/defs.h | 2 + > gdb/infcall.c | 6 ++- > gdb/infcmd.c | 16 +++++-- > gdb/inferior.h | 3 + > gdb/infrun.c | 3 +- > gdb/interps.c | 17 ++++++-- > gdb/interps.h | 2 + > gdb/mi/mi-interp.c | 43 ++++++++++----------- > gdb/mi/mi-main.c | 36 +---------------- > gdb/testsuite/gdb.mi/mi-break.exp | 2 +- > gdb/testsuite/gdb.mi/mi-syn-frame.exp | 6 +-- > gdb/testsuite/gdb.mi/mi2-syn-frame.exp | 25 +++--------- > gdb/testsuite/lib/mi-support.exp | 64 +++++++++++++++++++++++++++++--- > gdb/utils.c | 27 +++++++++++++ > 15 files changed, 157 insertions(+), 105 deletions(-) > > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index d220d00..537b9bf 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -1448,12 +1448,6 @@ reattach_breakpoints (int pid) > return 0; > } > > -static void > -restore_always_inserted_mode (void *p) > -{ > - always_inserted_mode = (uintptr_t) p; > -} > - > void > update_breakpoints_after_exec (void) > { > @@ -1469,9 +1463,7 @@ update_breakpoints_after_exec (void) > /* The binary we used to debug is now gone, and we're updating > breakpoints for the new binary. Until we're done, we should not > try to insert breakpoints. */ > - cleanup = make_cleanup (restore_always_inserted_mode, > - (void *) (uintptr_t) always_inserted_mode); > - always_inserted_mode = 0; > + cleanup = make_cleanup_restore_integer (&always_inserted_mode, 0); > > ALL_BREAKPOINTS_SAFE (b, temp) > { > diff --git a/gdb/defs.h b/gdb/defs.h > index 5c35051..a632840 100644 > --- a/gdb/defs.h > +++ b/gdb/defs.h > @@ -345,6 +345,8 @@ extern struct cleanup *make_cleanup_close (int fd); > > extern struct cleanup *make_cleanup_bfd_close (bfd *abfd); > > +extern struct cleanup *make_cleanup_restore_integer (int *variable, int value); > + > extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); > > extern struct cleanup *make_my_cleanup (struct cleanup **, > diff --git a/gdb/infcall.c b/gdb/infcall.c > index 721b32d..d879b79 100644 > --- a/gdb/infcall.c > +++ b/gdb/infcall.c > @@ -706,6 +706,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) > > { > struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0); > + struct cleanup *old_cleanups2; > int saved_async = 0; > > /* If all error()s out of proceed ended up calling normal_stop > @@ -718,8 +719,11 @@ call_function_by_hand (struct value *function, int nargs, struct value > **args) > > if (target_can_async_p ()) > saved_async = target_async_mask (0); > - > + > + old_cleanups2 = make_cleanup_restore_integer > + (&suppress_normal_stop_observer, 1); > proceed (real_pc, TARGET_SIGNAL_0, 0); > + do_cleanups (old_cleanups2); > > if (saved_async) > target_async_mask (saved_async); > diff --git a/gdb/infcmd.c b/gdb/infcmd.c > index 2823259..c787f95 100644 > --- a/gdb/infcmd.c > +++ b/gdb/infcmd.c > @@ -202,6 +202,9 @@ int step_multi; > in format described in environ.h. */ > > struct gdb_environ *inferior_environ; > + > +/* When set, normal_stop will not call the normal_stop observer. */ > +int suppress_normal_stop_observer = 0; > > /* Accessor routines. */ > > @@ -1275,9 +1278,14 @@ finish_command_continuation (struct continuation_arg *arg, int error) > if (TYPE_CODE (value_type) != TYPE_CODE_VOID) > print_return_value (value_type); > } > + > + /* We suppress normal call of normal_stop observer and do it here so that > + that *stopped notification includes the return value. */ > + observer_notify_normal_stop (stop_bpstat); > } > > - delete_breakpoint (breakpoint); > + suppress_normal_stop_observer = 0; > + delete_breakpoint (breakpoint); > } > > /* "finish": Set a temporary breakpoint at the place the selected > @@ -1343,6 +1351,7 @@ finish_command (char *arg, int from_tty) > } > > proceed_to_finish = 1; /* We want stop_registers, please... */ > + make_cleanup_restore_integer (&suppress_normal_stop_observer, 1); > proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); > > arg1 = > @@ -1358,10 +1367,7 @@ finish_command (char *arg, int from_tty) > arg2->data.pointer = function; > arg3->data.pointer = old_chain; > 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/inferior.h b/gdb/inferior.h > index 3aaaa26..630cc52 100644 > --- a/gdb/inferior.h > +++ b/gdb/inferior.h > @@ -399,6 +399,9 @@ extern int debug_displaced; > void displaced_step_dump_bytes (struct ui_file *file, > const gdb_byte *buf, size_t len); > > + > +/* When set, normal_stop will not call the normal_stop observer. */ > +extern int suppress_normal_stop_observer; > > /* Possible values for gdbarch_call_dummy_location. */ > #define ON_STACK 1 > diff --git a/gdb/infrun.c b/gdb/infrun.c > index 7f151f7..d6b78ea 100644 > --- a/gdb/infrun.c > +++ b/gdb/infrun.c > @@ -3635,7 +3635,8 @@ Further execution is probably impossible.\n")); > > done: > annotate_stopped (); > - observer_notify_normal_stop (stop_bpstat); > + if (!suppress_normal_stop_observer && !step_multi) > + observer_notify_normal_stop (stop_bpstat); > } > > static int > diff --git a/gdb/interps.c b/gdb/interps.c > index 9d47843..936fe89 100644 > --- a/gdb/interps.c > +++ b/gdb/interps.c > @@ -81,7 +81,7 @@ void _initialize_interpreter (void); > > static struct interp *interp_list = NULL; > static struct interp *current_interpreter = NULL; > -static struct interp *top_level_interpreter = NULL; > +static struct interp *top_level_interpreter_ptr = NULL; > > static int interpreter_initialized = 0; > > @@ -144,7 +144,7 @@ interp_set (struct interp *interp, int top_level) > /* If we already have an interpreter, then trying to > set top level interpreter is kinda pointless. */ > gdb_assert (!top_level || !current_interpreter); > - gdb_assert (!top_level || !top_level_interpreter); > + gdb_assert (!top_level || !top_level_interpreter_ptr); > > if (current_interpreter != NULL) > { > @@ -165,7 +165,7 @@ interp_set (struct interp *interp, int top_level) > > current_interpreter = interp; > if (top_level) > - top_level_interpreter = interp; > + top_level_interpreter_ptr = interp; > > /* We use interpreter_p for the "set interpreter" variable, so we need > to make sure we have a malloc'ed copy for the set command to free. */ > @@ -476,11 +476,18 @@ interpreter_completer (char *text, char *word) > return matches; > } > > +struct interp * > +top_level_interpreter (void) > +{ > + gdb_assert (top_level_interpreter_ptr); > + return top_level_interpreter_ptr; > +} > + > extern void * > top_level_interpreter_data (void) > { > - gdb_assert (top_level_interpreter); > - return top_level_interpreter->data; > + gdb_assert (top_level_interpreter_ptr); > + return top_level_interpreter_ptr->data; > } > > /* This just adds the "interpreter-exec" command. */ > diff --git a/gdb/interps.h b/gdb/interps.h > index e1030fa..5e91080 100644 > --- a/gdb/interps.h > +++ b/gdb/interps.h > @@ -64,6 +64,8 @@ extern struct ui_out *interp_ui_out (struct interp *interp); > extern int current_interp_named_p (const char *name); > extern int current_interp_display_prompt_p (void); > extern void current_interp_command_loop (void); > +/* Returns the top-level interpreter. */ > +extern struct interp *top_level_interpreter (); > /* Returns opaque data associated with the top-level interpreter. */ > extern void *top_level_interpreter_data (void); > > diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c > index ae9e07b..e874a56 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); > > @@ -88,7 +89,10 @@ mi_interpreter_init (int top_level) > mi->event_channel = mi_console_file_new (raw_stdout, "=", 0); > > if (top_level) > - observer_attach_new_thread (mi_new_thread); > + { > + observer_attach_new_thread (mi_new_thread); > + observer_attach_normal_stop (mi_on_normal_stop); > + } > > return mi; > } > @@ -167,26 +171,6 @@ mi_interpreter_prompt_p (void *data) > return 0; > } > > -static void > -mi_interpreter_exec_continuation (struct continuation_arg *arg, int error) > -{ > - 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) > { > @@ -237,7 +221,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) > @@ -317,6 +300,22 @@ mi_new_thread (struct thread_info *t) > 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 177d0ec..deb2df9 100644 > --- a/gdb/mi/mi-main.c > +++ b/gdb/mi/mi-main.c > @@ -102,9 +102,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 *mi, char *args, int from_tty); > > -static void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg, > - int error); > - > static int register_changed_p (int regnum, struct regcache *, > struct regcache *); > static void get_register (int regnum, int format); > @@ -1067,15 +1064,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: > @@ -1296,12 +1289,6 @@ mi_execute_async_cli_command (char *mi, char *args, int from_tty) > 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 */ ); > @@ -1317,31 +1304,14 @@ mi_execute_async_cli_command (char *mi, char *args, int from_tty) > /* 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) > -{ > - /* 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, > unsigned long total_section, > diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp > index c0f5132..e4fd5c9 100644 > --- a/gdb/testsuite/gdb.mi/mi-break.exp > +++ b/gdb/testsuite/gdb.mi/mi-break.exp > @@ -163,7 +163,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 ed89965..80d36c9 100644 > --- a/gdb/testsuite/gdb.mi/mi-syn-frame.exp > +++ b/gdb/testsuite/gdb.mi/mi-syn-frame.exp > @@ -60,9 +60,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\"\}.*\\\]" > \ > @@ -91,7 +89,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 9c1daab..6e9792a 100644 > --- a/gdb/testsuite/gdb.mi/mi2-syn-frame.exp > +++ b/gdb/testsuite/gdb.mi/mi2-syn-frame.exp > @@ -58,15 +58,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\"\}.*\\\]" > \ > @@ -92,16 +88,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=\" handler > called>\"\},.*frame=\{level=\"$decimal\",addr=\"$hex\",func=\"have_a_very_merry_interrupt\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"$decimal\",addr=\"$hex\",func=\" called from > gdb>\"\},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 5926f16..0a6eb8a 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)"} > @@ -970,17 +1015,17 @@ proc mi_expect_stop { reason func args file line extra test } { > set r "reason=\"$reason\"," > } > > - verbose -log "mi_expect_stop: expecting: > .*\\*stopped ${r}${bn}${after_reason}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}${bn}${after_reason}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}${bn}${after_reason}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}${bn}${after_reason}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}${bn}${after_reason}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$mi_gdb_prompt$" > { > + -re > ".*\\*stopped ${r}${bn}${after_reason}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 > } > @@ -1337,9 +1382,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$" { > diff --git a/gdb/utils.c b/gdb/utils.c > index d9953a0..fa8e455 100644 > --- a/gdb/utils.c > +++ b/gdb/utils.c > @@ -277,6 +277,33 @@ make_cleanup_free_section_addr_info (struct section_addr_info *addrs) > return make_my_cleanup (&cleanup_chain, do_free_section_addr_info, addrs); > } > > +struct restore_integer_closure > +{ > + int *variable; > + int value; > +}; > + > +static void > +restore_integer (void *p) > +{ > + struct restore_integer_closure *closure = p; > + *(closure->variable) = closure->value; > + xfree (closure); > +} > + > +/* Assign VALUE to *VARIABLE and arranges for the old value to > + be restored via cleanup. */ > +struct cleanup * > +make_cleanup_restore_integer (int *variable, int value) > +{ > + struct restore_integer_closure *c = > + xmalloc (sizeof (struct restore_integer_closure)); > + struct cleanup *cleanup = make_cleanup (restore_integer, (void *) c); > + c->variable = variable; > + c->value = *variable; > + *variable = value; > + return cleanup; > +} > > struct cleanup * > make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,