diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 806173c918..58c0454427 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,56 @@ +2008-04-24 Vladimir Prus + + exec_cleanup murder. + * breakpoint.c (until_break_command_continuation): Add + the 'error' parameter. Directly delete the breakoint as + opposed to running cleanups. + (until_break_command): Install continuation only + after starting the target. Don't use exec cleanups, + use ordinary cleanups. Discard cleanups is successfully + started the target in async mode. + (make_cleanup_delete_breakpoint): Remove. + * breakpoint.h (make_cleanup_delete_breakpoint): Remove + declaration. + * defs.h (do_exec_cleanups, make_exec_cleanup): Remove + declarations. + (struct continations): Add the 'error' parameter to the + continuation_hook field. + (add_continuation, do_all_continuations) + (add_intermediate_continuation) + (do_all_intermediate_continuations): Add the 'error' parameter. + * exceptions.c (throw_exception): Don't call do_exec_cleanups. + * inf-loop.c (inferior_event_handler): Instead of calling + discard_all_continuations, use do_all_continuations with 1 as + 'error' parameter. Pass 0 as 'error' parameter in existing uses + of discard_all_continuations. + * infcmd.c (step_1): Do not use exec cleanup. For async case, discard + cleanups. + (step_once): Install continuation only after resuming the target. + (step_1_continuation): Disable longjmp breakpoint on error. + (finish_command_continuation): Add the error parameter. Delete + the finish breakpoint directly, do not use cleanups. + (finish_command): Do not use exec_cleanups. Always setup + continuation. For sync case, immediately run them. + (attach_command_continuation): Add the error parameter. + * infrun.c (fetch_inferior_event): Do not use exec cleanups to + remove step_resume_breakpoint -- adjust delete it directly. + * interps.c (interp_set): Adjust call to do_all_continations. + * mi/mi-interp.c (mi_interpreter_exec_continuation): Do not + do exec cleanups. + * mi/mi-main.c (mi_cmd_target_select): Do not do exec + cleanups. + (mi_cmd_execute): Do not use exec_cleanup. + (mi_execute_async_cli_command): Simplify the string concatenation + logic. Do no use exec cleanup. + (mi_exec_async_cli_cmd_continuation): New parameter error. + Free last_async_command. + * top.c (command_line_handler_continuation): New parameter error. + * utils.c (exec_cleanup_chain, make_exec_cleanup) + (do_exec_cleanups): Remove. + (add_continuation, do_all_continations) + (add_intermediate_continuation) + (do_all_intermediate_continuations): New parameter error. + 2008-04-24 Vladimir Prus * breakpoint.h (bp_location_p): New typedef. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 84802effff..2b6e16f9d0 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -64,7 +64,8 @@ /* Prototypes for local functions. */ -static void until_break_command_continuation (struct continuation_arg *arg); +static void until_break_command_continuation (struct continuation_arg *arg, + int error); static void catch_command_1 (char *, int, int); @@ -6130,12 +6131,11 @@ awatch_command (char *arg, int from_tty) care of cleaning up the temporary breakpoints set up by the until command. */ static void -until_break_command_continuation (struct continuation_arg *arg) +until_break_command_continuation (struct continuation_arg *arg, int error) { - struct cleanup *cleanups; - - cleanups = (struct cleanup *) arg->data.pointer; - do_exec_cleanups (cleanups); + delete_breakpoint ((struct breakpoint *)(arg->data.pointer)); + if (arg->next) + delete_breakpoint ((struct breakpoint *)(arg->next->data.pointer)); } void @@ -6146,8 +6146,10 @@ until_break_command (char *arg, int from_tty, int anywhere) struct frame_info *frame = get_selected_frame (NULL); struct frame_info *prev_frame = get_prev_frame (frame); struct breakpoint *breakpoint; + struct breakpoint *breakpoint2 = NULL; struct cleanup *old_chain; struct continuation_arg *arg1; + struct continuation_arg *arg2; clear_proceed_status (); @@ -6183,31 +6185,7 @@ until_break_command (char *arg, int from_tty, int anywhere) breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_until); - if (!target_can_async_p ()) - old_chain = make_cleanup_delete_breakpoint (breakpoint); - else - old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); - - /* If we are running asynchronously, and the target supports async - execution, we are not waiting for the target to stop, in the call - tp proceed, below. This means that we cannot delete the - brekpoints until the target has actually stopped. The only place - where we get a chance to do that is in fetch_inferior_event, so - we must set things up for that. */ - - if (target_can_async_p ()) - { - /* In this case the arg for the continuation is just the point - in the exec_cleanups chain from where to start doing - cleanups, because all the continuation does is the cleanups in - the exec_cleanup_chain. */ - arg1 = - (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); - arg1->next = NULL; - arg1->data.pointer = old_chain; - - add_continuation (until_break_command_continuation, arg1); - } + old_chain = make_cleanup_delete_breakpoint (breakpoint); /* Keep within the current frame, or in frames called by the current one. */ @@ -6215,18 +6193,38 @@ until_break_command (char *arg, int from_tty, int anywhere) { sal = find_pc_line (get_frame_pc (prev_frame), 0); sal.pc = get_frame_pc (prev_frame); - breakpoint = set_momentary_breakpoint (sal, get_frame_id (prev_frame), - bp_until); - if (!target_can_async_p ()) - make_cleanup_delete_breakpoint (breakpoint); - else - make_exec_cleanup_delete_breakpoint (breakpoint); + breakpoint2 = set_momentary_breakpoint (sal, get_frame_id (prev_frame), + bp_until); + make_cleanup_delete_breakpoint (breakpoint2); } proceed (-1, TARGET_SIGNAL_DEFAULT, 0); - /* Do the cleanups now, anly if we are not running asynchronously, - of if we are, but the target is still synchronous. */ - if (!target_can_async_p ()) + + /* If we are running asynchronously, and proceed call above has actually + managed to start the target, arrange for breakpoints to be + deleted when the target stops. Otherwise, we're already stopped and + delete breakpoints via cleanup chain. */ + + if (target_can_async_p () && target_executing) + { + arg1 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg1->next = NULL; + arg1->data.pointer = breakpoint; + + if (breakpoint2) + { + arg2 = (struct continuation_arg *) + xmalloc ( sizeof (struct continuation_arg)); + arg2->next = NULL; + arg2->data.pointer = breakpoint2; + arg1->next = arg2; + } + + discard_cleanups (old_chain); + add_continuation (until_break_command_continuation, arg1); + } + else do_cleanups (old_chain); } @@ -7188,12 +7186,6 @@ make_cleanup_delete_breakpoint (struct breakpoint *b) return make_cleanup (do_delete_breakpoint_cleanup, b); } -struct cleanup * -make_exec_cleanup_delete_breakpoint (struct breakpoint *b) -{ - return make_exec_cleanup (do_delete_breakpoint_cleanup, b); -} - void delete_command (char *arg, int from_tty) { diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index ed76f30d0f..83f1cb8f19 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -700,8 +700,6 @@ extern void breakpoint_init_inferior (enum inf_context); extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *); -extern struct cleanup *make_exec_cleanup_delete_breakpoint (struct breakpoint *); - extern void delete_breakpoint (struct breakpoint *); extern void breakpoint_auto_delete (bpstat); diff --git a/gdb/defs.h b/gdb/defs.h index 2ec9199aac..2af40ab3dc 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -318,7 +318,6 @@ extern char *safe_strerror (int); extern void do_cleanups (struct cleanup *); extern void do_final_cleanups (struct cleanup *); -extern void do_exec_cleanups (struct cleanup *); extern void discard_cleanups (struct cleanup *); extern void discard_final_cleanups (struct cleanup *); @@ -351,8 +350,6 @@ extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *); extern struct cleanup *make_my_cleanup (struct cleanup **, make_cleanup_ftype *, void *); -extern struct cleanup *make_exec_cleanup (make_cleanup_ftype *, void *); - extern struct cleanup *save_cleanups (void); extern struct cleanup *save_final_cleanups (void); extern struct cleanup *save_my_cleanups (struct cleanup **); @@ -682,7 +679,7 @@ struct continuation_arg struct continuation { - void (*continuation_hook) (struct continuation_arg *); + void (*continuation_hook) (struct continuation_arg *, int); struct continuation_arg *arg_list; struct continuation *next; }; @@ -693,14 +690,14 @@ extern struct continuation *cmd_continuation; extern struct continuation *intermediate_continuation; /* From utils.c */ -extern void add_continuation (void (*)(struct continuation_arg *), +extern void add_continuation (void (*)(struct continuation_arg *, int), struct continuation_arg *); -extern void do_all_continuations (void); +extern void do_all_continuations (int error); extern void discard_all_continuations (void); -extern void add_intermediate_continuation (void (*)(struct continuation_arg *), +extern void add_intermediate_continuation (void (*)(struct continuation_arg *, int), struct continuation_arg *); -extern void do_all_intermediate_continuations (void); +extern void do_all_intermediate_continuations (int error); extern void discard_all_intermediate_continuations (void); /* String containing the current directory (what getwd would return). */ diff --git a/gdb/exceptions.c b/gdb/exceptions.c index 89d14551a5..304c8c6c27 100644 --- a/gdb/exceptions.c +++ b/gdb/exceptions.c @@ -221,12 +221,6 @@ throw_exception (struct gdb_exception exception) disable_current_display (); do_cleanups (ALL_CLEANUPS); - /* When we implement non-stop mode, this should be redone. If we get - exception in a command pertaining to one thread, or maybe even not - involving inferior at all, we should not do exec cleanups for all - threads. */ - if (target_can_async_p () && !target_executing) - do_exec_cleanups (ALL_CLEANUPS); /* Jump to the containing catch_errors() call, communicating REASON to that call via setjmp's return value. Note that REASON can't diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c index 9519c79fc6..4c61daeb00 100644 --- a/gdb/inf-loop.c +++ b/gdb/inf-loop.c @@ -50,7 +50,7 @@ inferior_event_handler (enum inferior_event_type event_type, printf_unfiltered (_("error detected from target.\n")); target_async (NULL, 0); pop_target (); - discard_all_continuations (); + do_all_continuations (1); async_enable_stdin (); break; @@ -64,7 +64,7 @@ inferior_event_handler (enum inferior_event_type event_type, { target_async (NULL, 0); pop_target (); - discard_all_continuations (); + do_all_continuations (1); async_enable_stdin (); display_gdb_prompt (0); } @@ -95,9 +95,9 @@ inferior_event_handler (enum inferior_event_type event_type, got interrupted by a breakpoint, still do the pending continuations. The continuation itself is responsible for distinguishing the cases. */ - do_all_intermediate_continuations (); + do_all_intermediate_continuations (0); - do_all_continuations (); + do_all_continuations (0); if (current_language != expected_language) { @@ -126,7 +126,7 @@ inferior_event_handler (enum inferior_event_type event_type, case INF_EXEC_CONTINUE: /* Is there anything left to do for the command issued to complete? */ - do_all_intermediate_continuations (); + do_all_intermediate_continuations (0); break; case INF_QUIT_REQ: diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 22a4abb7ec..867dadf5cc 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -72,7 +72,8 @@ static void nofp_registers_info (char *, int); static void print_return_value (struct type *func_type, struct type *value_type); -static void finish_command_continuation (struct continuation_arg *); +static void finish_command_continuation (struct continuation_arg *, + int error_p); static void until_next_command (int); @@ -106,7 +107,7 @@ static void jump_command (char *, int); static void step_1 (int, int, char *); static void step_once (int skip_subroutines, int single_inst, int count); -static void step_1_continuation (struct continuation_arg *arg); +static void step_1_continuation (struct continuation_arg *arg, int error_p); static void next_command (char *, int); @@ -701,7 +702,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string) { int count = 1; struct frame_info *frame; - struct cleanup *cleanups = 0; + struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); int async_exec = 0; ERROR_NO_INFERIOR; @@ -727,10 +728,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string) if (!single_inst || skip_subroutines) /* leave si command alone */ { enable_longjmp_breakpoint (); - if (!target_can_async_p ()) - cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); - else - make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); + make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); } /* In synchronous case, all is well, just use the regular for loop. */ @@ -782,8 +780,7 @@ which has no line number information.\n"), name); break; } - if (!single_inst || skip_subroutines) - do_cleanups (cleanups); + do_cleanups (cleanups); return; } /* In case of asynchronous target things get complicated, do only @@ -792,8 +789,10 @@ which has no line number information.\n"), name); and handle them one at the time, through step_once(). */ else { - if (target_can_async_p ()) - step_once (skip_subroutines, single_inst, count); + step_once (skip_subroutines, single_inst, count); + /* We are running, and the contination is installed. It will + disable the longjmp breakpoint as appropriate. */ + discard_cleanups (cleanups); } } @@ -803,21 +802,26 @@ which has no line number information.\n"), name); proceed(), via step_once(). Basically it is like step_once and step_1_continuation are co-recursive. */ static void -step_1_continuation (struct continuation_arg *arg) +step_1_continuation (struct continuation_arg *arg, int error_p) { - int count; - int skip_subroutines; - int single_inst; - - skip_subroutines = arg->data.integer; - single_inst = arg->next->data.integer; - count = arg->next->next->data.integer; - - if (stop_step) - step_once (skip_subroutines, single_inst, count - 1); + if (error_p) + disable_longjmp_breakpoint (); else - if (!single_inst || skip_subroutines) - do_exec_cleanups (ALL_CLEANUPS); + { + int count; + int skip_subroutines; + int single_inst; + + skip_subroutines = arg->data.integer; + single_inst = arg->next->data.integer; + count = arg->next->next->data.integer; + + if (stop_step) + step_once (skip_subroutines, single_inst, count - 1); + else + if (!single_inst || skip_subroutines) + disable_longjmp_breakpoint (); + } } /* Do just one step operation. If count >1 we will have to set up a @@ -881,6 +885,7 @@ which has no line number information.\n"), name); step_over_calls = STEP_OVER_ALL; step_multi = (count > 1); + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); arg1 = (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); arg2 = @@ -894,7 +899,6 @@ which has no line number information.\n"), name); arg3->next = NULL; arg3->data.integer = count; add_intermediate_continuation (step_1_continuation, arg1); - proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); } } @@ -1251,7 +1255,7 @@ print_return_value (struct type *func_type, struct type *value_type) called via the cmd_continuation pointer. */ static void -finish_command_continuation (struct continuation_arg *arg) +finish_command_continuation (struct continuation_arg *arg, int error_p) { struct symbol *function; struct breakpoint *breakpoint; @@ -1261,21 +1265,24 @@ finish_command_continuation (struct continuation_arg *arg) function = (struct symbol *) arg->next->data.pointer; cleanups = (struct cleanup *) arg->next->next->data.pointer; - if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL - && function != NULL) + if (!error_p) { - struct type *value_type; - - value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); - if (!value_type) - internal_error (__FILE__, __LINE__, - _("finish_command: function has no target type")); - - if (TYPE_CODE (value_type) != TYPE_CODE_VOID) - print_return_value (SYMBOL_TYPE (function), value_type); + if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL + && function != NULL) + { + struct type *value_type; + + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + internal_error (__FILE__, __LINE__, + _("finish_command: function has no target type")); + + if (TYPE_CODE (value_type) != TYPE_CODE_VOID) + print_return_value (SYMBOL_TYPE (function), value_type); + } } - do_exec_cleanups (cleanups); + delete_breakpoint (breakpoint); } /* "finish": Set a temporary breakpoint at the place the selected @@ -1326,10 +1333,7 @@ finish_command (char *arg, int from_tty) breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish); - if (!target_can_async_p ()) - old_chain = make_cleanup_delete_breakpoint (breakpoint); - else - old_chain = make_exec_cleanup_delete_breakpoint (breakpoint); + old_chain = make_cleanup_delete_breakpoint (breakpoint); /* Find the function we will return from. */ @@ -1346,51 +1350,26 @@ finish_command (char *arg, int from_tty) proceed_to_finish = 1; /* We want stop_registers, please... */ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); - /* If running asynchronously and the target support asynchronous - execution, set things up for the rest of the finish command to be - completed later on, when gdb has detected that the target has - stopped, in fetch_inferior_event. - Setup it only after proceed, so that if proceed throws, we don't - set continuation. */ - if (target_can_async_p ()) - { - arg1 = - (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); - arg2 = - (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); - arg3 = - (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); - arg1->next = arg2; - arg2->next = arg3; - arg3->next = NULL; - arg1->data.pointer = breakpoint; - arg2->data.pointer = function; - arg3->data.pointer = old_chain; - add_continuation (finish_command_continuation, arg1); - } + arg1 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg2 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg3 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg1->next = arg2; + arg2->next = arg3; + arg3->next = NULL; + arg1->data.pointer = breakpoint; + 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 ()) - { - /* Did we stop at our breakpoint? */ - if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL - && function != NULL) - { - struct type *value_type; - - value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); - if (!value_type) - internal_error (__FILE__, __LINE__, - _("finish_command: function has no target type")); - - if (TYPE_CODE (value_type) != TYPE_CODE_VOID) - print_return_value (SYMBOL_TYPE (function), value_type); - } - - do_cleanups (old_chain); - } + do_all_continuations (0); } @@ -1936,7 +1915,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec) } static void -attach_command_continuation (struct continuation_arg *arg) +attach_command_continuation (struct continuation_arg *arg, int error_p) { char *args; int from_tty; diff --git a/gdb/infrun.c b/gdb/infrun.c index da8c3e028e..e47cf1e95e 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1073,9 +1073,6 @@ fetch_inferior_event (void *client_data) if (!async_ecs->wait_some_more) { - old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint, - &step_resume_breakpoint); - /* Fill in with reasonable starting values. */ init_execution_control_state (async_ecs); @@ -1104,10 +1101,8 @@ fetch_inferior_event (void *client_data) if (!async_ecs->wait_some_more) { - /* Do only the cleanups that have been added by this - function. Let the continuations for the commands do the rest, - if there are any. */ - do_exec_cleanups (old_cleanups); + delete_step_resume_breakpoint (&step_resume_breakpoint); + normal_stop (); if (step_multi && stop_step) inferior_event_handler (INF_EXEC_CONTINUE, NULL); diff --git a/gdb/interps.c b/gdb/interps.c index b4c804afd0..0ebc3f48e2 100644 --- a/gdb/interps.c +++ b/gdb/interps.c @@ -148,7 +148,7 @@ interp_set (struct interp *interp, int top_level) if (current_interpreter != NULL) { - do_all_continuations (); + do_all_continuations (0); ui_out_flush (uiout); if (current_interpreter->procs->suspend_proc && !current_interpreter->procs->suspend_proc (current_interpreter-> diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index c968a8f9a9..8dfd3ee123 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -168,9 +168,11 @@ mi_interpreter_prompt_p (void *data) } static void -mi_interpreter_exec_continuation (struct continuation_arg *arg) +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); @@ -178,7 +180,6 @@ mi_interpreter_exec_continuation (struct continuation_arg *arg) fputs_unfiltered ("\n", raw_stdout); fputs_unfiltered ("(gdb) \n", raw_stdout); gdb_flush (raw_stdout); - do_exec_cleanups (ALL_CLEANUPS); } else if (target_can_async_p ()) { diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 153d2b5fff..76e12f30ea 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -104,7 +104,8 @@ 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); +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 *); @@ -684,7 +685,6 @@ mi_cmd_target_select (char *args, int from_tty) mi_out_put (uiout, raw_stdout); mi_out_rewind (uiout); fputs_unfiltered ("\n", raw_stdout); - do_exec_cleanups (ALL_CLEANUPS); return MI_CMD_QUIET; } @@ -1184,6 +1184,8 @@ mi_execute_command (char *cmd, int from_tty) static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse) { + struct cleanup *cleanup; + enum mi_cmd_result r; free_all_values (); if (parse->cmd->argv_func != NULL @@ -1222,11 +1224,19 @@ mi_cmd_execute (struct mi_parse *parse) } } last_async_command = xstrdup (parse->token); - make_exec_cleanup (free_current_contents, &last_async_command); + cleanup = make_cleanup (free_current_contents, &last_async_command); /* FIXME: DELETE THIS! */ if (parse->cmd->args_func != NULL) - return parse->cmd->args_func (parse->args, 0 /*from_tty */ ); - return parse->cmd->argv_func (parse->command, parse->argv, parse->argc); + r = parse->cmd->args_func (parse->args, 0 /*from_tty */ ); + else + r = parse->cmd->argv_func (parse->command, parse->argv, parse->argc); + if (target_can_async_p () && target_executing) + /* last_async_command will be freed by continuation that + all execution command set. */ + discard_cleanups (cleanup); + else + do_cleanups (cleanup); + return r; } else if (parse->cmd->cli.cmd != 0) { @@ -1287,24 +1297,12 @@ mi_execute_async_cli_command (char *mi, char *args, int from_tty) { struct cleanup *old_cleanups; char *run; - char *async_args; if (target_can_async_p ()) - { - async_args = (char *) xmalloc (strlen (args) + 2); - make_exec_cleanup (free, async_args); - strcpy (async_args, args); - strcat (async_args, "&"); - run = xstrprintf ("%s %s", mi, async_args); - make_exec_cleanup (free, run); - add_continuation (mi_exec_async_cli_cmd_continuation, NULL); - old_cleanups = NULL; - } + run = xstrprintf ("%s %s&", mi, args); else - { - run = xstrprintf ("%s %s", mi, args); - old_cleanups = make_cleanup (xfree, run); - } + run = xstrprintf ("%s %s", mi, args); + old_cleanups = make_cleanup (xfree, run); if (!target_can_async_p ()) { @@ -1326,11 +1324,24 @@ mi_execute_async_cli_command (char *mi, char *args, int from_tty) if (last_async_command) fputs_unfiltered (last_async_command, 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 */ ); - if (!target_can_async_p ()) + if (target_can_async_p ()) + { + /* If we're not executing, an exception should have been throw. */ + gdb_assert (target_executing); + do_cleanups (old_cleanups); + } + else { /* Do this before doing any printing. It would appear that some print code leaves garbage around in the buffer. */ @@ -1346,13 +1357,14 @@ mi_execute_async_cli_command (char *mi, char *args, int from_tty) 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) +mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg, int error_p) { + /* Assume 'error' means that target is stopped, too. */ if (last_async_command) fputs_unfiltered (last_async_command, raw_stdout); fputs_unfiltered ("*stopped", raw_stdout); @@ -1360,7 +1372,11 @@ mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg) fputs_unfiltered ("\n", raw_stdout); fputs_unfiltered ("(gdb) \n", raw_stdout); gdb_flush (raw_stdout); - do_exec_cleanups (ALL_CLEANUPS); + if (last_async_command) + { + free (last_async_command); + last_async_command = NULL; + } } void diff --git a/gdb/top.c b/gdb/top.c index d9b5ce403e..2454d242be 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -368,7 +368,7 @@ do_chdir_cleanup (void *old_dir) are always running synchronously. Or if we have just executed a command that doesn't start the target. */ static void -command_line_handler_continuation (struct continuation_arg *arg) +command_line_handler_continuation (struct continuation_arg *arg, int error) { extern int display_time; extern int display_space; @@ -376,6 +376,9 @@ command_line_handler_continuation (struct continuation_arg *arg) long time_at_cmd_start = arg->data.longint; long space_at_cmd_start = arg->next->data.longint; + if (error) + return; + bpstat_do_actions (&stop_bpstat); if (display_time) diff --git a/gdb/utils.c b/gdb/utils.c index 594fc733d3..d9953a07cb 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -104,7 +104,6 @@ static int debug_timestamp = 0; static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ -static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */ /* Pointer to what is left to do for an execution command after the target stops. Used only in asynchronous mode, by targets that @@ -214,12 +213,6 @@ make_final_cleanup (make_cleanup_ftype *function, void *arg) return make_my_cleanup (&final_cleanup_chain, function, arg); } -struct cleanup * -make_exec_cleanup (make_cleanup_ftype *function, void *arg) -{ - return make_my_cleanup (&exec_cleanup_chain, function, arg); -} - static void do_freeargv (void *arg) { @@ -316,12 +309,6 @@ do_final_cleanups (struct cleanup *old_chain) do_my_cleanups (&final_cleanup_chain, old_chain); } -void -do_exec_cleanups (struct cleanup *old_chain) -{ - do_my_cleanups (&exec_cleanup_chain, old_chain); -} - static void do_my_cleanups (struct cleanup **pmy_chain, struct cleanup *old_chain) @@ -440,7 +427,7 @@ null_cleanup (void *arg) /* Add a continuation to the continuation list, the global list cmd_continuation. The new continuation will be added at the front.*/ void -add_continuation (void (*continuation_hook) (struct continuation_arg *), +add_continuation (void (*continuation_hook) (struct continuation_arg *, int), struct continuation_arg *arg_list) { struct continuation *continuation_ptr; @@ -462,7 +449,7 @@ add_continuation (void (*continuation_hook) (struct continuation_arg *), and do the continuations from there on, instead of using the global beginning of list as our iteration pointer. */ void -do_all_continuations (void) +do_all_continuations (int error) { struct continuation *continuation_ptr; struct continuation *saved_continuation; @@ -477,7 +464,7 @@ do_all_continuations (void) /* Work now on the list we have set aside. */ while (continuation_ptr) { - (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); + (continuation_ptr->continuation_hook) (continuation_ptr->arg_list, error); saved_continuation = continuation_ptr; continuation_ptr = continuation_ptr->next; xfree (saved_continuation); @@ -504,7 +491,7 @@ discard_all_continuations (void) the front. */ void add_intermediate_continuation (void (*continuation_hook) - (struct continuation_arg *), + (struct continuation_arg *, int), struct continuation_arg *arg_list) { struct continuation *continuation_ptr; @@ -526,7 +513,7 @@ add_intermediate_continuation (void (*continuation_hook) and do the continuations from there on, instead of using the global beginning of list as our iteration pointer.*/ void -do_all_intermediate_continuations (void) +do_all_intermediate_continuations (int error) { struct continuation *continuation_ptr; struct continuation *saved_continuation; @@ -541,7 +528,7 @@ do_all_intermediate_continuations (void) /* Work now on the list we have set aside. */ while (continuation_ptr) { - (continuation_ptr->continuation_hook) (continuation_ptr->arg_list); + (continuation_ptr->continuation_hook) (continuation_ptr->arg_list, error); saved_continuation = continuation_ptr; continuation_ptr = continuation_ptr->next; xfree (saved_continuation);