X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fevent-top.c;h=5feb2928e22eb3e72bb8248a5abae337a28c48b0;hb=9d084466d740e40c655609f9c04b3bb2b9b9ca76;hp=fc1a6c607531b705c9750893937496e2b8f2d88f;hpb=585a46a2d01d25181926329f258f1d1374f93e99;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/event-top.c b/gdb/event-top.c index fc1a6c6075..5feb2928e2 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -1,6 +1,6 @@ /* Top level stuff for GDB, the GNU debugger. - Copyright (C) 1999-2016 Free Software Foundation, Inc. + Copyright (C) 1999-2019 Free Software Foundation, Inc. Written by Elena Zannoni of Cygnus Solutions. @@ -24,7 +24,7 @@ #include "inferior.h" #include "infrun.h" #include "target.h" -#include "terminal.h" /* for job_control */ +#include "terminal.h" #include "event-loop.h" #include "event-top.h" #include "interps.h" @@ -32,14 +32,15 @@ #include "cli/cli-script.h" /* for reset_command_nest_depth */ #include "main.h" #include "gdbthread.h" -#include "observer.h" +#include "observable.h" #include "continuations.h" #include "gdbcmd.h" /* for dont_repeat() */ #include "annotate.h" #include "maint.h" -#include "buffer.h" +#include "gdbsupport/buffer.h" #include "ser-event.h" #include "gdb_select.h" +#include "gdbsupport/gdb-sigmask.h" /* readline include files. */ #include "readline/readline.h" @@ -48,10 +49,7 @@ /* readline defines this. */ #undef savestring -static void rl_callback_read_char_wrapper (gdb_client_data client_data); -static void command_line_handler (char *rl); -static void change_line_handler (void); -static char *top_level_prompt (void); +static std::string top_level_prompt (); /* Signal handlers. */ #ifdef SIGQUIT @@ -71,33 +69,15 @@ static void async_do_nothing (gdb_client_data); static void async_disconnect (gdb_client_data); #endif static void async_float_handler (gdb_client_data); -#ifdef STOP_SIGNAL -static void async_stop_sig (gdb_client_data); +#ifdef SIGTSTP +static void async_sigtstp_handler (gdb_client_data); #endif static void async_sigterm_handler (gdb_client_data arg); -/* Readline offers an alternate interface, via callback - functions. These are all included in the file callback.c in the - readline distribution. This file provides (mainly) a function, which - the event loop uses as callback (i.e. event handler) whenever an event - is detected on the standard input file descriptor. - readline_callback_read_char is called (by the GDB event loop) whenever - there is a new character ready on the input stream. This function - incrementally builds a buffer internal to readline where it - accumulates the line read up to the point of invocation. In the - special case in which the character read is newline, the function - invokes a GDB supplied callback routine, which does the processing of - a full command line. This latter routine is the asynchronous analog - of the old command_line_input in gdb. Instead of invoking (and waiting - for) readline to read the command line and pass it back to - command_loop for processing, the new command_line_handler function has - the command line already available as its parameter. INPUT_HANDLER is - to be set to the function that readline will invoke when a complete - line of input is ready. CALL_READLINE is to be set to the function - that readline offers as callback to the event_loop. */ - -void (*input_handler) (char *); -void (*call_readline) (gdb_client_data); +/* Instead of invoking (and waiting for) readline to read the command + line and pass it back for processing, we use readline's alternate + interface, via callback functions, so that the event loop can react + to other event sources while we wait for input. */ /* Important variables for the event loop. */ @@ -107,15 +87,11 @@ void (*call_readline) (gdb_client_data); 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; +bool set_editing_cmd_var; /* This is used to display the notification of the completion of an asynchronous execution command. */ -int exec_done_display_p = 0; - -/* This is the file descriptor for the input stream that GDB uses to - read commands from. */ -int input_fd; +bool exec_done_display_p = false; /* Used by the stdin event handler to compensate for missed stdin events. Setting this to a non-zero value inside an stdin callback makes the callback @@ -136,38 +112,125 @@ static struct async_signal_handler *sighup_token; static struct async_signal_handler *sigquit_token; #endif static struct async_signal_handler *sigfpe_token; -#ifdef STOP_SIGNAL +#ifdef SIGTSTP static struct async_signal_handler *sigtstp_token; #endif static struct async_signal_handler *async_sigterm_token; -/* This hook is called by rl_callback_read_char_wrapper after each +/* This hook is called by gdb_rl_callback_read_char_wrapper after each character is processed. */ void (*after_char_processing_hook) (void); -/* Wrapper function for calling into the readline library. The event - loop expects the callback function to have a paramter, while - readline expects none. */ +/* Wrapper function for calling into the readline library. This takes + care of a couple things: + + - The event loop expects the callback function to have a parameter, + while readline expects none. + + - Propagation of GDB exceptions/errors thrown from INPUT_HANDLER + across readline requires special handling. + + On the exceptions issue: + + DWARF-based unwinding cannot cross code built without -fexceptions. + Any exception that tries to propagate through such code will fail + and the result is a call to std::terminate. While some ABIs, such + as x86-64, require all code to be built with exception tables, + others don't. + + This is a problem when GDB calls some non-EH-aware C library code, + that calls into GDB again through a callback, and that GDB callback + code throws a C++ exception. Turns out this is exactly what + happens with GDB's readline callback. + + In such cases, we must catch and save any C++ exception that might + be thrown from the GDB callback before returning to the + non-EH-aware code. When the non-EH-aware function itself returns + back to GDB, we then rethrow the original C++ exception. + + In the readline case however, the right thing to do is to longjmp + out of the callback, rather than do a normal return -- there's no + way for the callback to return to readline an indication that an + error happened, so a normal return would have rl_callback_read_char + potentially continue processing further input, redisplay the + prompt, etc. Instead of raw setjmp/longjmp however, we use our + sjlj-based TRY/CATCH mechanism, which knows to handle multiple + levels of active setjmp/longjmp frames, needed in order to handle + the readline callback recursing, as happens with e.g., secondary + prompts / queries, through gdb_readline_wrapper. This must be + noexcept in order to avoid problems with mixing sjlj and + (sjlj-based) C++ exceptions. */ + +static struct gdb_exception +gdb_rl_callback_read_char_wrapper_noexcept () noexcept +{ + struct gdb_exception gdb_expt; + + /* C++ exceptions can't normally be thrown across readline (unless + it is built with -fexceptions, but it won't by default on many + ABIs). So we instead wrap the readline call with a sjlj-based + TRY/CATCH, and rethrow the GDB exception once back in GDB. */ + TRY_SJLJ + { + rl_callback_read_char (); + if (after_char_processing_hook) + (*after_char_processing_hook) (); + } + CATCH_SJLJ (ex, RETURN_MASK_ALL) + { + gdb_expt = std::move (ex); + } + END_CATCH_SJLJ + + return gdb_expt; +} + static void -rl_callback_read_char_wrapper (gdb_client_data client_data) +gdb_rl_callback_read_char_wrapper (gdb_client_data client_data) { - rl_callback_read_char (); - if (after_char_processing_hook) - (*after_char_processing_hook) (); + struct gdb_exception gdb_expt + = gdb_rl_callback_read_char_wrapper_noexcept (); + + /* Rethrow using the normal EH mechanism. */ + if (gdb_expt.reason < 0) + throw_exception (std::move (gdb_expt)); } -/* Initialize all the necessary variables, start the event loop, - register readline, and stdin, start the loop. The DATA is the - interpreter data cookie, ignored for now. */ +/* GDB's readline callback handler. Calls the current INPUT_HANDLER, + and propagates GDB exceptions/errors thrown from INPUT_HANDLER back + across readline. See gdb_rl_callback_read_char_wrapper. This must + be noexcept in order to avoid problems with mixing sjlj and + (sjlj-based) C++ exceptions. */ -void -cli_command_loop (void *data) +static void +gdb_rl_callback_handler (char *rl) noexcept { - display_gdb_prompt (0); + /* This is static to avoid undefined behavior when calling longjmp + -- gdb_exception has a destructor with side effects. */ + static struct gdb_exception gdb_rl_expt; + struct ui *ui = current_ui; + + try + { + /* Ensure the exception is reset on each call. */ + gdb_rl_expt = {}; + ui->input_handler (gdb::unique_xmalloc_ptr (rl)); + } + catch (gdb_exception &ex) + { + gdb_rl_expt = std::move (ex); + } - /* Now it's time to start the event loop. */ - start_event_loop (); + /* If we caught a GDB exception, longjmp out of the readline + callback. There's no other way for the callback to signal to + readline that an error happened. A normal return would have + readline potentially continue processing further input, redisplay + the prompt, etc. (This is what GDB historically did when it was + a C program.) Note that since we're long jumping, local variable + dtors are NOT run automatically. */ + if (gdb_rl_expt.reason < 0) + throw_exception_sjlj (gdb_rl_expt); } /* Change the function to be invoked every time there is a character @@ -175,32 +238,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) { - /* 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. */ + struct ui *ui = current_ui; + + /* We can only have one instance of readline, so we only allow + editing on the main UI. */ + if (ui != main_ui) + return; - if (async_command_editing_p) + /* 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 (editing) { + gdb_assert (ui == main_ui); + /* Turn on editing by using readline. */ - call_readline = rl_callback_read_char_wrapper; - input_handler = command_line_handler; + ui->call_readline = gdb_rl_callback_read_char_wrapper; } else { /* Turn off editing by using gdb_readline_no_editing_callback. */ - gdb_rl_callback_handler_remove (); - call_readline = gdb_readline_no_editing_callback; - - /* Set up the command handler as well, in case we are called as - first thing from .gdbinit. */ - input_handler = command_line_handler; + if (ui->command_editing) + gdb_rl_callback_handler_remove (); + ui->call_readline = gdb_readline_no_editing_callback; } + ui->command_editing = editing; } /* The functions below are wrappers for rl_callback_handler_remove and @@ -221,6 +297,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; } @@ -232,12 +310,14 @@ 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. */ gdb_assert (!callback_handler_installed); - rl_callback_handler_install (prompt, input_handler); + rl_callback_handler_install (prompt, gdb_rl_callback_handler); callback_handler_installed = 1; } @@ -246,6 +326,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 @@ -274,22 +356,23 @@ gdb_rl_callback_handler_reinstall (void) void display_gdb_prompt (const char *new_prompt) { - char *actual_gdb_prompt = NULL; - struct cleanup *old_chain; + std::string actual_gdb_prompt; annotate_display_prompt (); /* Reset the nesting depth used when trace-commands is set. */ reset_command_nest_depth (); - old_chain = make_cleanup (free_current_contents, &actual_gdb_prompt); - /* Do not call the python hook on an explicit prompt change as passed to this function, as this forms a secondary/local prompt, IE, displayed but not set. */ if (! new_prompt) { - if (sync_execution) + struct ui *ui = current_ui; + + if (ui->prompt_state == PROMPTED) + internal_error (__FILE__, __LINE__, _("double prompt")); + else if (ui->prompt_state == PROMPT_BLOCKED) { /* This is to trick readline into not trying to display the prompt. Even though we display the prompt using this @@ -307,23 +390,24 @@ display_gdb_prompt (const char *new_prompt) the above two functions. Calling rl_callback_handler_remove(), does the job. */ - gdb_rl_callback_handler_remove (); - do_cleanups (old_chain); + if (current_ui->command_editing) + gdb_rl_callback_handler_remove (); return; } - else + else if (ui->prompt_state == PROMPT_NEEDED) { /* Display the top level prompt. */ actual_gdb_prompt = top_level_prompt (); + ui->prompt_state = PROMPTED; } } else - actual_gdb_prompt = xstrdup (new_prompt); + actual_gdb_prompt = 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); + gdb_rl_callback_handler_install (actual_gdb_prompt.c_str ()); } /* new_prompt at this point can be the top of the stack or the one passed in. It can't be NULL. */ @@ -332,26 +416,23 @@ display_gdb_prompt (const char *new_prompt) /* Don't use a _filtered function here. It causes the assumed character position to be off, since the newline we read from the user is not accounted for. */ - fputs_unfiltered (actual_gdb_prompt, gdb_stdout); + fputs_unfiltered (actual_gdb_prompt.c_str (), gdb_stdout); gdb_flush (gdb_stdout); } - - do_cleanups (old_chain); } /* Return the top level prompt, as specified by "set prompt", possibly - overriden by the python gdb.prompt_hook hook, and then composed - with the prompt prefix and suffix (annotations). The caller is - responsible for freeing the returned string. */ + overridden by the python gdb.prompt_hook hook, and then composed + with the prompt prefix and suffix (annotations). */ -static char * +static std::string top_level_prompt (void) { char *prompt; /* Give observers a chance of changing the prompt. E.g., the python `gdb.prompt_hook' is installed as an observer. */ - observer_notify_before_prompt (get_prompt ()); + gdb::observers::before_prompt.notify (get_prompt ()); prompt = get_prompt (); @@ -364,28 +445,25 @@ top_level_prompt (void) beginning. */ const char suffix[] = "\n\032\032prompt\n"; - return concat (prefix, prompt, suffix, NULL); + return std::string (prefix) + prompt + suffix; } - return xstrdup (prompt); + return prompt; } -/* Get a pointer to the command line buffer. This is used to +/* See top.h. */ + +struct ui *main_ui; +struct ui *current_ui; +struct ui *ui_list; + +/* Get a pointer to the current UI's line buffer. This is used to construct a whole line of input from partial input. */ static struct buffer * get_command_line_buffer (void) { - static struct buffer line_buffer; - static int line_buffer_initialized; - - if (!line_buffer_initialized) - { - buffer_init (&line_buffer); - line_buffer_initialized = 1; - } - - return &line_buffer; + return ¤t_ui->line_buffer; } /* When there is an event ready on the stdin file descriptor, instead @@ -396,32 +474,66 @@ get_command_line_buffer (void) void stdin_event_handler (int error, gdb_client_data client_data) { + struct ui *ui = (struct ui *) client_data; + if (error) { - printf_unfiltered (_("error detected on stdin\n")); - delete_file_handler (input_fd); - /* If stdin died, we may as well kill gdb. */ - quit_command ((char *) 0, stdin == instream); + /* Switch to the main UI, so diagnostics always go there. */ + current_ui = main_ui; + + delete_file_handler (ui->input_fd); + if (main_ui == ui) + { + /* If stdin died, we may as well kill gdb. */ + printf_unfiltered (_("error detected on stdin\n")); + quit_command ((char *) 0, 0); + } + else + { + /* Simply delete the UI. */ + delete ui; + } } else { - /* This makes sure a ^C immediately followed by further input is - always processed in that order. E.g,. with input like - "^Cprint 1\n", the SIGINT handler runs, marks the async signal - handler, and then select/poll may return with stdin ready, - instead of -1/EINTR. The - gdb.base/double-prompt-target-event-error.exp test exercises - this. */ + /* Switch to the UI whose input descriptor woke up the event + loop. */ + current_ui = ui; + + /* This makes sure a ^C immediately followed by further input is + always processed in that order. E.g,. with input like + "^Cprint 1\n", the SIGINT handler runs, marks the async + signal handler, and then select/poll may return with stdin + ready, instead of -1/EINTR. The + gdb.base/double-prompt-target-event-error.exp test exercises + this. */ QUIT; do { call_stdin_event_handler_again_p = 0; - (*call_readline) (client_data); - } while (call_stdin_event_handler_again_p != 0); + ui->call_readline (client_data); + } + while (call_stdin_event_handler_again_p != 0); } } +/* See top.h. */ + +void +ui_register_input_event_handler (struct ui *ui) +{ + add_file_handler (ui->input_fd, stdin_event_handler, ui); +} + +/* See top.h. */ + +void +ui_unregister_input_event_handler (struct ui *ui) +{ + delete_file_handler (ui->input_fd); +} + /* Re-enable stdin after the end of an execution command in synchronous mode, or after an error from the target, and we aborted the exec operation. */ @@ -429,14 +541,13 @@ stdin_event_handler (int error, gdb_client_data client_data) void async_enable_stdin (void) { - if (sync_execution) + struct ui *ui = current_ui; + + if (ui->prompt_state == PROMPT_BLOCKED) { - /* See NOTE in async_disable_stdin(). */ - /* FIXME: cagney/1999-09-27: Call this before clearing - sync_execution. Current target_terminal_ours() implementations - check for sync_execution before switching the terminal. */ - target_terminal_ours (); - sync_execution = 0; + target_terminal::ours (); + ui_register_input_event_handler (ui); + ui->prompt_state = PROMPT_NEEDED; } } @@ -446,7 +557,10 @@ async_enable_stdin (void) void async_disable_stdin (void) { - sync_execution = 1; + struct ui *ui = current_ui; + + ui->prompt_state = PROMPT_BLOCKED; + delete_file_handler (ui->input_fd); } @@ -455,38 +569,36 @@ async_disable_stdin (void) a whole command. */ void -command_handler (char *command) +command_handler (const char *command) { - struct cleanup *stat_chain; - char *c; + struct ui *ui = current_ui; + const char *c; - if (instream == stdin) + if (ui->instream == ui->stdin_stream) reinitialize_more_filter (); - stat_chain = make_command_stats_cleanup (1); + scoped_command_stats stat_reporter (true); /* Do not execute commented lines. */ for (c = command; *c == ' ' || *c == '\t'; c++) ; if (c[0] != '#') { - execute_command (command, instream == stdin); + execute_command (command, ui->instream == ui->stdin_stream); /* Do any commands attached to breakpoint we stopped at. */ bpstat_do_actions (); } - - do_cleanups (stat_chain); } /* Append RL, an input line returned by readline or one of its emulations, to CMD_LINE_BUFFER. Returns the command line if we have a whole command line ready to be processed by the command interpreter or NULL if the command line isn't complete yet (input - line ends in a backslash). Takes ownership of RL. */ + line ends in a backslash). */ static char * -command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl) +command_line_append_input_line (struct buffer *cmd_line_buffer, const char *rl) { char *cmd; size_t len; @@ -507,9 +619,6 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl) cmd = cmd_line_buffer->buffer; } - /* Allocated in readline. */ - xfree (rl); - return cmd; } @@ -526,17 +635,19 @@ command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl) If REPEAT, handle command repetitions: - If the input command line is NOT empty, the command returned is - copied into the global 'saved_command_line' var so that it can - be repeated later. + saved using save_command_line () so that it can be repeated later. - - OTOH, if the input command line IS empty, return the previously - saved command instead of the empty input line. + - OTOH, if the input command line IS empty, return the saved + command instead of the empty input line. */ char * handle_line_of_input (struct buffer *cmd_line_buffer, - char *rl, int repeat, char *annotation_suffix) + const char *rl, int repeat, + const char *annotation_suffix) { + struct ui *ui = current_ui; + int from_tty = ui->instream == ui->stdin_stream; char *p1; char *cmd; @@ -551,7 +662,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, command, but leave ownership of memory to the buffer . */ cmd_line_buffer->used_size = 0; - if (annotation_level > 1 && instream == stdin) + if (from_tty && annotation_level > 1) { printf_unfiltered (("\n\032\032post-")); puts_unfiltered (annotation_suffix); @@ -559,43 +670,41 @@ handle_line_of_input (struct buffer *cmd_line_buffer, } #define SERVER_COMMAND_PREFIX "server " - if (startswith (cmd, SERVER_COMMAND_PREFIX)) + server_command = startswith (cmd, SERVER_COMMAND_PREFIX); + if (server_command) { - /* Note that we don't set `saved_command_line'. Between this + /* Note that we don't call `save_command_line'. Between this and the check in dont_repeat, this insures that repeating will still do the right thing. */ return cmd + strlen (SERVER_COMMAND_PREFIX); } /* Do history expansion if that is wished. */ - if (history_expansion_p && instream == stdin - && ISATTY (instream)) + if (history_expansion_p && from_tty && input_interactive_p (current_ui)) { - char *history_value; + char *cmd_expansion; int expanded; - expanded = history_expand (cmd, &history_value); + expanded = history_expand (cmd, &cmd_expansion); + gdb::unique_xmalloc_ptr history_value (cmd_expansion); if (expanded) { size_t len; /* Print the changes. */ - printf_unfiltered ("%s\n", history_value); + printf_unfiltered ("%s\n", history_value.get ()); /* If there was an error, call this function again. */ if (expanded < 0) - { - xfree (history_value); - return cmd; - } + return cmd; /* history_expand returns an allocated string. Just replace our buffer with it. */ - len = strlen (history_value); + len = strlen (history_value.get ()); xfree (buffer_finish (cmd_line_buffer)); - cmd_line_buffer->buffer = history_value; + cmd_line_buffer->buffer = history_value.get (); cmd_line_buffer->buffer_size = len + 1; - cmd = history_value; + cmd = history_value.release (); } } @@ -604,7 +713,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer, for (p1 = cmd; *p1 == ' ' || *p1 == '\t'; p1++) ; if (repeat && *p1 == '\0') - return saved_command_line; + return get_saved_command_line (); /* Add command to history if appropriate. Note: lines consisting solely of comments are also added to the command history. This @@ -613,15 +722,14 @@ handle_line_of_input (struct buffer *cmd_line_buffer, and then later fetch it from the value history and remove the '#'. The kill ring is probably better, but some people are in the habit of commenting things out. */ - if (*cmd != '\0' && input_from_terminal_p ()) + if (*cmd != '\0' && from_tty && input_interactive_p (current_ui)) gdb_add_history (cmd); /* Save into global buffer if appropriate. */ if (repeat) { - xfree (saved_command_line); - saved_command_line = xstrdup (cmd); - return saved_command_line; + save_command_line (cmd); + return get_saved_command_line (); } else return cmd; @@ -636,12 +744,13 @@ handle_line_of_input (struct buffer *cmd_line_buffer, function. */ void -command_line_handler (char *rl) +command_line_handler (gdb::unique_xmalloc_ptr &&rl) { struct buffer *line_buffer = get_command_line_buffer (); + struct ui *ui = current_ui; char *cmd; - cmd = handle_line_of_input (line_buffer, rl, instream == stdin, "prompt"); + cmd = handle_line_of_input (line_buffer, rl.get (), 1, "prompt"); if (cmd == (char *) EOF) { /* stdin closed. The connection with the terminal is gone. @@ -649,7 +758,7 @@ command_line_handler (char *rl) hung up but GDB is still alive. In such a case, we just quit gdb killing the inferior program too. */ printf_unfiltered ("quit\n"); - execute_command ("quit", stdin == instream); + execute_command ("quit", 1); } else if (cmd == NULL) { @@ -658,8 +767,12 @@ command_line_handler (char *rl) } else { + ui->prompt_state = PROMPT_NEEDED; + command_handler (cmd); - display_gdb_prompt (0); + + if (ui->prompt_state != PROMPTED) + display_gdb_prompt (0); } } @@ -674,6 +787,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) char *result; struct buffer line_buffer; static int done_once = 0; + struct ui *ui = current_ui; buffer_init (&line_buffer); @@ -683,9 +797,9 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) stream after '\n'. If we buffer the input and fgetc drains the stream, getting stuff beyond the newline as well, a select, done afterwards will not trigger. */ - if (!done_once && !ISATTY (instream)) + if (!done_once && !ISATTY (ui->instream)) { - setbuf (instream, NULL); + setbuf (ui->instream, NULL); done_once = 1; } @@ -701,7 +815,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) { /* Read from stdin if we are executing a user defined command. This is the right thing for prompt_for_continue, at least. */ - c = fgetc (instream ? instream : stdin); + c = fgetc (ui->instream != NULL ? ui->instream : ui->stdin_stream); if (c == EOF) { @@ -713,7 +827,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) break; } xfree (buffer_finish (&line_buffer)); - (*input_handler) (0); + ui->input_handler (NULL); return; } @@ -730,8 +844,47 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) buffer_grow_char (&line_buffer, '\0'); result = buffer_finish (&line_buffer); - (*input_handler) (result); + ui->input_handler (gdb::unique_xmalloc_ptr (result)); +} + + +/* See event-top.h. */ + +thread_local void (*thread_local_segv_handler) (int); + +static void handle_sigsegv (int sig); + +/* Install the SIGSEGV handler. */ +static void +install_handle_sigsegv () +{ +#if defined (HAVE_SIGACTION) + struct sigaction sa; + sa.sa_handler = handle_sigsegv; + sigemptyset (&sa.sa_mask); +#ifdef HAVE_SIGALTSTACK + sa.sa_flags = SA_ONSTACK; +#else + sa.sa_flags = 0; +#endif + sigaction (SIGSEGV, &sa, nullptr); +#else + signal (SIGSEGV, handle_sigsegv); +#endif } + +/* Handler for SIGSEGV. */ + +static void +handle_sigsegv (int sig) +{ + install_handle_sigsegv (); + + if (thread_local_segv_handler == nullptr) + abort (); /* ARI: abort */ + thread_local_segv_handler (sig); +} + /* The serial event associated with the QUIT flag. set_quit_flag sets @@ -797,10 +950,12 @@ async_init_signals (void) sigfpe_token = create_async_signal_handler (async_float_handler, NULL); -#ifdef STOP_SIGNAL +#ifdef SIGTSTP sigtstp_token = - create_async_signal_handler (async_stop_sig, NULL); + create_async_signal_handler (async_sigtstp_handler, NULL); #endif + + install_handle_sigsegv (); } /* See defs.h. */ @@ -835,7 +990,7 @@ default_quit_handler (void) { if (check_quit_flag ()) { - if (target_terminal_is_ours ()) + if (target_terminal::is_ours ()) quit (); else target_pass_ctrlc (); @@ -845,51 +1000,6 @@ default_quit_handler (void) /* See defs.h. */ quit_handler_ftype *quit_handler = default_quit_handler; -/* Data for make_cleanup_override_quit_handler. Wrap the previous - handler pointer in a data struct because it's not portable to cast - a function pointer to a data pointer, which is what make_cleanup - expects. */ -struct quit_handler_cleanup_data -{ - /* The previous quit handler. */ - quit_handler_ftype *prev_handler; -}; - -/* Cleanup call that restores the previous quit handler. */ - -static void -restore_quit_handler (void *arg) -{ - struct quit_handler_cleanup_data *data - = (struct quit_handler_cleanup_data *) arg; - - quit_handler = data->prev_handler; -} - -/* Destructor for the quit handler cleanup. */ - -static void -restore_quit_handler_dtor (void *arg) -{ - xfree (arg); -} - -/* See defs.h. */ - -struct cleanup * -make_cleanup_override_quit_handler (quit_handler_ftype *new_quit_handler) -{ - struct cleanup *old_chain; - struct quit_handler_cleanup_data *data; - - data = XNEW (struct quit_handler_cleanup_data); - data->prev_handler = quit_handler; - old_chain = make_cleanup_dtor (restore_quit_handler, data, - restore_quit_handler_dtor); - quit_handler = new_quit_handler; - return old_chain; -} - /* Handle a SIGINT. */ void @@ -949,7 +1059,7 @@ interruptible_select (int n, static void async_sigterm_handler (gdb_client_data arg) { - quit_force (NULL, stdin == instream); + quit_force (NULL, 0); } /* See defs.h. */ @@ -1015,63 +1125,57 @@ static void async_disconnect (gdb_client_data arg) { - TRY + try { quit_cover (); } - CATCH (exception, RETURN_MASK_ALL) + catch (const gdb_exception &exception) { fputs_filtered ("Could not kill the program being debugged", gdb_stderr); exception_print (gdb_stderr, exception); } - END_CATCH - TRY + try { pop_all_targets (); } - CATCH (exception, RETURN_MASK_ALL) + catch (const gdb_exception &exception) { } - END_CATCH signal (SIGHUP, SIG_DFL); /*FIXME: ??????????? */ raise (SIGHUP); } #endif -#ifdef STOP_SIGNAL +#ifdef SIGTSTP void -handle_stop_sig (int sig) +handle_sigtstp (int sig) { mark_async_signal_handler (sigtstp_token); - signal (sig, handle_stop_sig); + signal (sig, handle_sigtstp); } static void -async_stop_sig (gdb_client_data arg) +async_sigtstp_handler (gdb_client_data arg) { char *prompt = get_prompt (); -#if STOP_SIGNAL == SIGTSTP signal (SIGTSTP, SIG_DFL); #if HAVE_SIGPROCMASK { sigset_t zero; sigemptyset (&zero); - sigprocmask (SIG_SETMASK, &zero, 0); + gdb_sigmask (SIG_SETMASK, &zero, 0); } #elif HAVE_SIGSETMASK sigsetmask (0); #endif raise (SIGTSTP); - signal (SIGTSTP, handle_stop_sig); -#else - signal (STOP_SIGNAL, handle_stop_sig); -#endif + signal (SIGTSTP, handle_sigtstp); printf_unfiltered ("%s", prompt); gdb_flush (gdb_stdout); @@ -1079,7 +1183,7 @@ async_stop_sig (gdb_client_data arg) nothing. */ dont_repeat (); } -#endif /* STOP_SIGNAL */ +#endif /* SIGTSTP */ /* Tell the event loop what to do if SIGFPE is received. See event-signal.c. */ @@ -1090,7 +1194,7 @@ handle_sigfpe (int sig) signal (sig, handle_sigfpe); } -/* Event loop will call this functin to process a SIGFPE. */ +/* Event loop will call this function to process a SIGFPE. */ static void async_float_handler (gdb_client_data arg) { @@ -1100,78 +1204,66 @@ 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 (rl_callback_read_char), - and hook up instream to the event loop. */ + 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; + /* This function is a noop for the sync case. The assumption is that the sync setup is ALL done in gdb_init, and we would only mess it up here. The sync stuff should really go away over time. */ if (!batch_silent) - gdb_stdout = stdio_fileopen (stdout); - gdb_stderr = stderr_fileopen (); + gdb_stdout = new stdio_file (ui->outstream); + gdb_stderr = new stderr_file (ui->errstream); gdb_stdlog = gdb_stderr; /* for moment */ 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 (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. */ - call_readline = rl_callback_read_char_wrapper; + 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; - call_readline = gdb_readline_no_editing_callback; + 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. */ - input_handler = command_line_handler; - - /* Tell readline to use the same input stream that gdb uses. */ - rl_instream = instream; - - /* Get a file descriptor for the input stream, so that we can - register it with the event loop. */ - input_fd = fileno (instream); - - /* Now we need to create the event sources for the input file - descriptor. */ - /* At this point in time, this is the only event source that we - register with the even loop. Another source is going to be the - target program (inferior), but that must be registered only when - it actually exists (I.e. after we say 'run' or after we connect - to a remote target. */ - add_file_handler (input_fd, stdin_event_handler, 0); + + /* Now create the event source for this UI's input file descriptor. + Another source is going to be the target program (inferior), but + that must be registered only when it actually exists (I.e. after + we say 'run' or after we connect to a remote target. */ + ui_register_input_event_handler (ui); } /* 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) { + struct ui *ui = current_ui; + /* FIXME - It is too heavyweight to delete and remake these every time you run an interpreter that needs readline. It is probably better to have the interpreters cache these, which in turn means @@ -1185,6 +1277,7 @@ gdb_disable_readline (void) gdb_stdtargerr = NULL; #endif - gdb_rl_callback_handler_remove (); - delete_file_handler (input_fd); + if (ui->command_editing) + gdb_rl_callback_handler_remove (); + delete_file_handler (ui->input_fd); }