diff options
-rw-r--r-- | gdb/ChangeLog | 60 | ||||
-rw-r--r-- | gdb/cli/cli-interp.c | 16 | ||||
-rw-r--r-- | gdb/cli/cli-interp.h | 25 | ||||
-rw-r--r-- | gdb/event-top.c | 94 | ||||
-rw-r--r-- | gdb/event-top.h | 10 | ||||
-rw-r--r-- | gdb/infrun.c | 2 | ||||
-rw-r--r-- | gdb/interps.c | 10 | ||||
-rw-r--r-- | gdb/interps.h | 11 | ||||
-rw-r--r-- | gdb/mi/mi-interp.c | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.mi/mi-editing.exp | 37 | ||||
-rw-r--r-- | gdb/top.c | 46 | ||||
-rw-r--r-- | gdb/top.h | 5 | ||||
-rw-r--r-- | gdb/tui/tui-interp.c | 9 | ||||
-rw-r--r-- | gdb/tui/tui-io.c | 2 |
14 files changed, 261 insertions, 71 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 58afe3b..c60ac72 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,65 @@ 2016-06-21 Pedro Alves <palves@redhat.com> + PR mi/20034 + * cli/cli-interp.c: Include cli-interp.h and event-top.h. + (cli_interpreter_resume): Pass 1 to gdb_setup_readline. Set the + UI's input_handler here. + (cli_interpreter_supports_command_editing): New function. + (cli_interp_procs): Install it. + * cli/cli-interp.h: New file. + * event-top.c (async_command_editing_p): Rename to ... + (set_editing_cmd_var): ... this. + (change_line_handler): Add parameter 'editing', and use it. Bail + early if the interpreter doesn't support editing. Don't touch + readline state if editing is off. + (gdb_rl_callback_handler_remove, gdb_rl_callback_handler_install) + (gdb_rl_callback_handler_reinstall): Assert the current UI is the + main UI. + (display_gdb_prompt): Don't call gdb_rl_callback_handler_remove if + not using readline. Check whether the current UI is using command + editing instead of checking the async_command_editing_p global. + (set_async_editing_command): Delete. + (gdb_setup_readline): Add 'editing' parameter. Only allow editing + on the main UI. Don't touch readline state if editing is off. + (gdb_disable_readline): Don't touch readline state if editing is + off. + * event-top.h (gdb_setup_readline): Add 'int' parameter. + (set_async_editing_command): Delete declaration. + (change_line_handler, command_line_handler): Declare. + (async_command_editing_p): Rename to ... + (set_editing_cmd_var): ... this. + * infrun.c (reinstall_readline_callback_handler_cleanup): Check + whether the current UI has editing enabled rather than checking + the async_command_editing_p global. + * interps.c (interp_supports_command_editing): New function. + * interps.h (interp_supports_command_editing_ftype): New typedef. + (struct interp_procs) <supports_command_editing_proc>: New field. + (interp_supports_command_editing): Declare. + * mi/mi-interp.c (mi_interpreter_resume): Pass 0 to + gdb_setup_readline. Don't clear the async_command_editing_p + global. Update comments. + * top.c (gdb_readline_wrapper_line, gdb_readline_wrapper): Check + whether the current UI has editing enabled rather than checking + the async_command_editing_p global. Don't touch readline state if + editing is off. + (undo_terminal_modifications_before_exit): Switch to the main UI. + Unconditionally call gdb_disable_readline. + (set_editing): New function. + (show_async_command_editing_p): Rename to ... + (show_editing): ... this. Show the state of the current UI. + (_initialize_top): Adjust. + * top.h (struct ui) <command_editing>: New field. + * tui/tui-interp.c: Include cli/cli-interp.h. + (tui_resume): Pass 1 to gdb_setup_readline. Set the UI's + input_handler. + (tui_interp_procs): Install + cli_interpreter_supports_command_editing. + * tui/tui-io.c (tui_getc): Check whether the current UI has + editing enabled rather than checking the async_command_editing_p + global. + +2016-06-21 Pedro Alves <palves@redhat.com> + * top.c: Call gen_ret_current_ui_field_ptr for current_uiout. * top.h (struct ui) <m_current_uiout>: New field. * ui-out.c (current_uiout): Delete. diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c index 2d20073..e5d23b5 100644 --- a/gdb/cli/cli-interp.c +++ b/gdb/cli/cli-interp.c @@ -18,11 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "cli-interp.h" #include "interps.h" #include "event-top.h" #include "ui-out.h" #include "cli-out.h" #include "top.h" /* for "execute_command" */ +#include "event-top.h" #include "infrun.h" #include "observer.h" @@ -199,6 +201,7 @@ cli_interpreter_init (struct interp *self, int top_level) static int cli_interpreter_resume (void *data) { + struct ui *ui = current_ui; struct cli_interp *cli = (struct cli_interp *) data; struct ui_file *stream; @@ -215,7 +218,9 @@ cli_interpreter_resume (void *data) stream = NULL; } - gdb_setup_readline (); + gdb_setup_readline (1); + + ui->input_handler = command_line_handler; if (stream != NULL) cli_out_set_stream (cli->cli_uiout, gdb_stdout); @@ -255,6 +260,12 @@ cli_interpreter_exec (void *data, const char *command_str) return result; } +int +cli_interpreter_supports_command_editing (struct interp *interp) +{ + return 1; +} + static struct gdb_exception safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty) { @@ -301,7 +312,8 @@ static const struct interp_procs cli_interp_procs = { cli_interpreter_exec, /* exec_proc */ cli_ui_out, /* ui_out_proc */ NULL, /* set_logging_proc */ - cli_command_loop /* command_loop_proc */ + cli_command_loop, /* command_loop_proc */ + cli_interpreter_supports_command_editing, /* supports_command_editing_proc */ }; /* Factory for CLI interpreters. */ diff --git a/gdb/cli/cli-interp.h b/gdb/cli/cli-interp.h new file mode 100644 index 0000000..07b7505 --- /dev/null +++ b/gdb/cli/cli-interp.h @@ -0,0 +1,25 @@ +/* CLI Definitions for GDB, the GNU debugger. + + Copyright (C) 2016 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/>. */ + +#ifndef CLI_INTERP_H +#define CLI_INTERP_H 1 + +struct interp; + +extern int cli_interpreter_supports_command_editing (struct interp *interp); + +#endif diff --git a/gdb/event-top.c b/gdb/event-top.c index 08eb89d..c84b3f4 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -48,8 +48,6 @@ /* readline defines this. */ #undef savestring -static void command_line_handler (char *rl); -static void change_line_handler (void); static char *top_level_prompt (void); /* Signal handlers. */ @@ -88,7 +86,7 @@ static void async_sigterm_handler (gdb_client_data arg); ezannoni: as of 1999-04-29 I expect that this variable will not be used after gdb is changed to use the event loop as default engine, and event-top.c is merged into top.c. */ -int async_command_editing_p; +int set_editing_cmd_var; /* This is used to display the notification of the completion of an asynchronous execution command. */ @@ -236,34 +234,45 @@ cli_command_loop (void *data) therefore bypassing readline, and letting gdb handle the input itself, via gdb_readline_no_editing_callback. Also it is used in the opposite case in which the user sets editing on again, by - restoring readline handling of the input. */ -static void -change_line_handler (void) + restoring readline handling of the input. + + NOTE: this operates on input_fd, not instream. If we are reading + commands from a file, instream will point to the file. However, we + always read commands from a file with editing off. This means that + the 'set editing on/off' will have effect only on the interactive + session. */ + +void +change_line_handler (int editing) { struct ui *ui = current_ui; - /* NOTE: this operates on input_fd, not instream. If we are reading - commands from a file, instream will point to the file. However in - async mode, we always read commands from a file with editing - off. This means that the 'set editing on/off' will have effect - only on the interactive session. */ + /* We can only have one instance of readline, so we only allow + editing on the main UI. */ + if (ui != main_ui) + return; + + /* Don't try enabling editing if the interpreter doesn't support it + (e.g., MI). */ + if (!interp_supports_command_editing (top_level_interpreter ()) + || !interp_supports_command_editing (command_interp ())) + return; - if (async_command_editing_p) + if (editing) { + gdb_assert (ui == main_ui); + /* Turn on editing by using readline. */ ui->call_readline = gdb_rl_callback_read_char_wrapper; - ui->input_handler = command_line_handler; } else { /* Turn off editing by using gdb_readline_no_editing_callback. */ - gdb_rl_callback_handler_remove (); + if (ui->command_editing) + gdb_rl_callback_handler_remove (); ui->call_readline = gdb_readline_no_editing_callback; - - /* Set up the command handler as well, in case we are called as - first thing from .gdbinit. */ - ui->input_handler = command_line_handler; } + ui->command_editing = editing; } /* The functions below are wrappers for rl_callback_handler_remove and @@ -284,6 +293,8 @@ static int callback_handler_installed; void gdb_rl_callback_handler_remove (void) { + gdb_assert (current_ui == main_ui); + rl_callback_handler_remove (); callback_handler_installed = 0; } @@ -295,6 +306,8 @@ gdb_rl_callback_handler_remove (void) void gdb_rl_callback_handler_install (const char *prompt) { + gdb_assert (current_ui == main_ui); + /* Calling rl_callback_handler_install resets readline's input buffer. Calling this when we were already processing input therefore loses input. */ @@ -309,6 +322,8 @@ gdb_rl_callback_handler_install (const char *prompt) void gdb_rl_callback_handler_reinstall (void) { + gdb_assert (current_ui == main_ui); + if (!callback_handler_installed) { /* Passing NULL as prompt argument tells readline to not display @@ -370,7 +385,8 @@ display_gdb_prompt (const char *new_prompt) the above two functions. Calling rl_callback_handler_remove(), does the job. */ - gdb_rl_callback_handler_remove (); + if (current_ui->command_editing) + gdb_rl_callback_handler_remove (); do_cleanups (old_chain); return; } @@ -383,7 +399,7 @@ display_gdb_prompt (const char *new_prompt) else actual_gdb_prompt = xstrdup (new_prompt); - if (async_command_editing_p) + if (current_ui->command_editing) { gdb_rl_callback_handler_remove (); gdb_rl_callback_handler_install (actual_gdb_prompt); @@ -1214,21 +1230,13 @@ async_float_handler (gdb_client_data arg) } -/* Called by do_setshow_command. */ -void -set_async_editing_command (char *args, int from_tty, - struct cmd_list_element *c) -{ - change_line_handler (); -} - /* Set things up for readline to be invoked via the alternate interface, i.e. via a callback function (gdb_rl_callback_read_char), and hook up instream to the event loop. */ void -gdb_setup_readline (void) +gdb_setup_readline (int editing) { struct ui *ui = current_ui; @@ -1243,32 +1251,28 @@ gdb_setup_readline (void) gdb_stdtarg = gdb_stderr; /* for moment */ gdb_stdtargerr = gdb_stderr; /* for moment */ - /* If the input stream is connected to a terminal, turn on - editing. */ - if (ISATTY (ui->instream)) + /* If the input stream is connected to a terminal, turn on editing. + However, that is only allowed on the main UI, as we can only have + one instance of readline. */ + if (ISATTY (ui->instream) && editing && ui == main_ui) { /* Tell gdb that we will be using the readline library. This could be overwritten by a command in .gdbinit like 'set editing on' or 'off'. */ - async_command_editing_p = 1; - + ui->command_editing = 1; + /* When a character is detected on instream by select or poll, readline will be invoked via this callback function. */ ui->call_readline = gdb_rl_callback_read_char_wrapper; + + /* Tell readline to use the same input stream that gdb uses. */ + rl_instream = ui->instream; } else { - async_command_editing_p = 0; + ui->command_editing = 0; ui->call_readline = gdb_readline_no_editing_callback; } - - /* When readline has read an end-of-line character, it passes the - complete line to gdb for processing; command_line_handler is the - function that does this. */ - ui->input_handler = command_line_handler; - - /* Tell readline to use the same input stream that gdb uses. */ - rl_instream = ui->instream; /* Now create the event source for this UI's input file descriptor. Another source is going to be the target program (inferior), but @@ -1280,6 +1284,7 @@ gdb_setup_readline (void) /* Disable command input through the standard CLI channels. Used in the suspend proc for interpreters that use the standard gdb readline interface, like the cli & the mi. */ + void gdb_disable_readline (void) { @@ -1298,6 +1303,7 @@ gdb_disable_readline (void) gdb_stdtargerr = NULL; #endif - gdb_rl_callback_handler_remove (); + if (ui->command_editing) + gdb_rl_callback_handler_remove (); delete_file_handler (ui->input_fd); } diff --git a/gdb/event-top.h b/gdb/event-top.h index 4fe7737..dd0b4bc 100644 --- a/gdb/event-top.h +++ b/gdb/event-top.h @@ -28,12 +28,12 @@ struct cmd_list_element; FIXME: these should really go into top.h. */ extern void display_gdb_prompt (const char *new_prompt); -void gdb_setup_readline (void); -void gdb_disable_readline (void); +extern void gdb_setup_readline (int); +extern void gdb_disable_readline (void); extern void async_init_signals (void); -extern void set_async_editing_command (char *args, int from_tty, - struct cmd_list_element *c); +extern void change_line_handler (int); +extern void command_line_handler (char *rl); extern void command_handler (char *command); /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */ @@ -54,7 +54,7 @@ extern void async_enable_stdin (void); /* Exported variables from event-top.c. FIXME: these should really go into top.h. */ -extern int async_command_editing_p; +extern int set_editing_cmd_var; extern int exec_done_display_p; extern struct prompts the_prompts; extern void (*after_char_processing_hook) (void); diff --git a/gdb/infrun.c b/gdb/infrun.c index f5b6ffc..0925f41 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -3812,7 +3812,7 @@ reinstall_readline_callback_handler_cleanup (void *arg) return; } - if (async_command_editing_p && !sync_execution) + if (current_ui->command_editing && !sync_execution) gdb_rl_callback_handler_reinstall (); } diff --git a/gdb/interps.c b/gdb/interps.c index fd08de5..6eed8f3 100644 --- a/gdb/interps.c +++ b/gdb/interps.c @@ -423,6 +423,16 @@ current_interp_command_loop (void) interp->procs->command_loop_proc (interp->data); } +/* See interp.h */ + +int +interp_supports_command_editing (struct interp *interp) +{ + if (interp->procs->supports_command_editing_proc != NULL) + return interp->procs->supports_command_editing_proc (interp); + return 0; +} + int interp_quiet_p (struct interp *interp) { diff --git a/gdb/interps.h b/gdb/interps.h index e5cd779..adccbb5 100644 --- a/gdb/interps.h +++ b/gdb/interps.h @@ -53,6 +53,8 @@ typedef int (interp_set_logging_ftype) (struct interp *self, int start_log, struct ui_file *out, struct ui_file *logfile); +typedef int (interp_supports_command_editing_ftype) (struct interp *self); + struct interp_procs { interp_init_ftype *init_proc; @@ -72,6 +74,11 @@ struct interp_procs interp_set_logging_ftype *set_logging_proc; interp_command_loop_ftype *command_loop_proc; + + /* Returns true if this interpreter supports using the readline + library; false if it uses GDB's own simplified readline + emulation. */ + interp_supports_command_editing_ftype *supports_command_editing_proc; }; extern struct interp *interp_new (const char *name, @@ -113,6 +120,10 @@ extern struct interp *command_interp (void); extern void clear_interpreter_hooks (void); +/* Returns true if INTERP supports using the readline library; false + if it uses GDB's own simplified form of readline. */ +extern int interp_supports_command_editing (struct interp *interp); + /* well-known interpreters */ #define INTERP_CONSOLE "console" #define INTERP_MI1 "mi1" diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index d2e5b1c..397ac1a 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -159,13 +159,10 @@ mi_interpreter_resume (void *data) /* As per hack note in mi_interpreter_init, swap in the output channels... */ - gdb_setup_readline (); + gdb_setup_readline (0); - /* These overwrite some of the initialization done in - _intialize_event_loop. */ ui->call_readline = gdb_readline_no_editing_callback; ui->input_handler = mi_execute_command_input_handler; - async_command_editing_p = 0; /* FIXME: This is a total hack for now. PB's use of the MI implicitly relies on a bug in the async support which allows asynchronous commands to leak through the commmand loop. The bug diff --git a/gdb/testsuite/gdb.mi/mi-editing.exp b/gdb/testsuite/gdb.mi/mi-editing.exp new file mode 100644 index 0000000..b7c6bd1 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-editing.exp @@ -0,0 +1,37 @@ +# Copyright 2016 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/>. + +# Regression test for PR mi/20034. Trying to turn on "set editing" +# when the top-level interpreter is MI would result in GDB/readline +# aborting with: +# +# readline: readline_callback_read_char() called with no handler! +# Aborted (core dumped) + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +gdb_exit +if {[mi_gdb_start]} { + continue +} + +mi_gdb_test "-interpreter-exec console \"set editing on\"" \ + {=cmd-param-changed,param=\"editing\",.*\^done} \ + "-interpreter-exec console \"set editing on\"" + +mi_gdb_test "-interpreter-exec console \"show editing\"" \ + ".*Editing of command lines as they are typed is off.*" \ + "-interpreter-exec console \"show editing\"" @@ -793,7 +793,7 @@ gdb_readline_wrapper_line (char *line) we're handling an asynchronous target event and running in the background, just before returning to the event loop to process further input (or more target events). */ - if (async_command_editing_p) + if (current_ui->command_editing) gdb_rl_callback_handler_remove (); } @@ -813,7 +813,8 @@ gdb_readline_wrapper_cleanup (void *arg) struct gdb_readline_wrapper_cleanup *cleanup = (struct gdb_readline_wrapper_cleanup *) arg; - rl_already_prompted = cleanup->already_prompted_orig; + if (ui->command_editing) + rl_already_prompted = cleanup->already_prompted_orig; gdb_assert (ui->input_handler == gdb_readline_wrapper_line); ui->input_handler = cleanup->handler_orig; @@ -851,7 +852,10 @@ gdb_readline_wrapper (const char *prompt) cleanup->handler_orig = ui->input_handler; ui->input_handler = gdb_readline_wrapper_line; - cleanup->already_prompted_orig = rl_already_prompted; + if (ui->command_editing) + cleanup->already_prompted_orig = rl_already_prompted; + else + cleanup->already_prompted_orig = 0; cleanup->target_is_async_orig = target_is_async_p (); @@ -863,7 +867,8 @@ gdb_readline_wrapper (const char *prompt) /* Display our prompt and prevent double prompt display. */ display_gdb_prompt (prompt); - rl_already_prompted = 1; + if (ui->command_editing) + rl_already_prompted = 1; if (after_char_processing_hook) (*after_char_processing_hook) (); @@ -1420,12 +1425,18 @@ quit_confirm (void) static void undo_terminal_modifications_before_exit (void) { + struct ui *saved_top_level = current_ui; + target_terminal_ours (); + + current_ui = main_ui; + #if defined(TUI) tui_disable (); #endif - if (async_command_editing_p) - gdb_disable_readline (); + gdb_disable_readline (); + + current_ui = saved_top_level; } @@ -1739,13 +1750,24 @@ show_prompt (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Gdb's prompt is \"%s\".\n"), value); } +/* "set editing" command. */ + +static void +set_editing (char *args, int from_tty, struct cmd_list_element *c) +{ + change_line_handler (set_editing_cmd_var); + /* Update the control variable so that MI's =cmd-param-changed event + shows the correct value. */ + set_editing_cmd_var = current_ui->command_editing; +} + static void -show_async_command_editing_p (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) +show_editing (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) { fprintf_filtered (file, _("Editing of command lines as " "they are typed is %s.\n"), - value); + current_ui->command_editing ? _("on") : _("off")); } static void @@ -1836,14 +1858,14 @@ used inside of user-defined commands that should not be repeated when\n\ hitting return.")); add_setshow_boolean_cmd ("editing", class_support, - &async_command_editing_p, _("\ + &set_editing_cmd_var, _("\ Set editing of command lines as they are typed."), _("\ Show editing of command lines as they are typed."), _("\ Use \"on\" to enable the editing, and \"off\" to disable it.\n\ Without an argument, command line editing is enabled. To edit, use\n\ EMACS-like or VI-like commands like control-P or ESC."), - set_async_editing_command, - show_async_command_editing_p, + set_editing, + show_editing, &setlist, &showlist); add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\ @@ -55,6 +55,11 @@ struct ui processing. */ void (*input_handler) (char *); + /* True if this UI is using the readline library for command + editing; false if using GDB's own simple readline emulation, with + no editing support. */ + int command_editing; + /* Each UI has its own independent set of interpreters. */ struct ui_interp_info *interp_info; diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c index 452dd20..85bb26d 100644 --- a/gdb/tui/tui-interp.c +++ b/gdb/tui/tui-interp.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "cli/cli-interp.h" #include "interps.h" #include "top.h" #include "event-top.h" @@ -219,6 +220,7 @@ tui_init (struct interp *self, int top_level) static int tui_resume (void *data) { + struct ui *ui = current_ui; struct ui_file *stream; /* gdb_setup_readline will change gdb_stdout. If the TUI was @@ -232,7 +234,9 @@ tui_resume (void *data) stream = NULL; } - gdb_setup_readline (); + gdb_setup_readline (1); + + ui->input_handler = command_line_handler; if (stream != NULL) cli_out_set_stream (tui_old_uiout, gdb_stdout); @@ -274,7 +278,8 @@ static const struct interp_procs tui_interp_procs = { tui_exec, tui_ui_out, NULL, - cli_command_loop + cli_command_loop, + cli_interpreter_supports_command_editing, }; /* Factory for TUI interpreters. */ diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c index 3fa32db..6f2d892 100644 --- a/gdb/tui/tui-io.c +++ b/gdb/tui/tui-io.c @@ -616,7 +616,7 @@ tui_getc (FILE *fp) if (ch == KEY_BACKSPACE) return '\b'; - if (async_command_editing_p && key_is_start_sequence (ch)) + if (current_ui->command_editing && key_is_start_sequence (ch)) { int ch_pending; |