X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fevent-top.c;h=5feb2928e22eb3e72bb8248a5abae337a28c48b0;hb=84e098cdea4eb6a5ddc525a2145ffe66475fa2af;hp=5d8d077a9a44a1209d37ed26092d8f3617857241;hpb=d7e747318f4d04af033f16325f9b6d74f67079ec;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/event-top.c b/gdb/event-top.c index 5d8d077a9a..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-2017 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,7 +49,7 @@ /* readline defines this. */ #undef savestring -static char *top_level_prompt (void); +static std::string top_level_prompt (); /* Signal handlers. */ #ifdef SIGQUIT @@ -68,8 +69,8 @@ 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); @@ -86,11 +87,11 @@ 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 set_editing_cmd_var; +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; +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 @@ -111,7 +112,7 @@ 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; @@ -164,7 +165,7 @@ void (*after_char_processing_hook) (void); static struct gdb_exception gdb_rl_callback_read_char_wrapper_noexcept () noexcept { - struct gdb_exception gdb_expt = exception_none; + 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 @@ -178,7 +179,7 @@ gdb_rl_callback_read_char_wrapper_noexcept () noexcept } CATCH_SJLJ (ex, RETURN_MASK_ALL) { - gdb_expt = ex; + gdb_expt = std::move (ex); } END_CATCH_SJLJ @@ -193,7 +194,7 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data) /* Rethrow using the normal EH mechanism. */ if (gdb_expt.reason < 0) - throw_exception (gdb_expt); + throw_exception (std::move (gdb_expt)); } /* GDB's readline callback handler. Calls the current INPUT_HANDLER, @@ -205,18 +206,21 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data) static void gdb_rl_callback_handler (char *rl) noexcept { - struct gdb_exception gdb_rl_expt = exception_none; + /* 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 + try { - ui->input_handler (rl); + /* Ensure the exception is reset on each call. */ + gdb_rl_expt = {}; + ui->input_handler (gdb::unique_xmalloc_ptr (rl)); } - CATCH (ex, RETURN_MASK_ALL) + catch (gdb_exception &ex) { - gdb_rl_expt = ex; + gdb_rl_expt = std::move (ex); } - END_CATCH /* If we caught a GDB exception, longjmp out of the readline callback. There's no other way for the callback to signal to @@ -352,16 +356,13 @@ 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. */ @@ -391,7 +392,6 @@ display_gdb_prompt (const char *new_prompt) if (current_ui->command_editing) gdb_rl_callback_handler_remove (); - do_cleanups (old_chain); return; } else if (ui->prompt_state == PROMPT_NEEDED) @@ -402,12 +402,12 @@ display_gdb_prompt (const char *new_prompt) } } else - actual_gdb_prompt = xstrdup (new_prompt); + actual_gdb_prompt = new_prompt; 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. */ @@ -416,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 (); @@ -448,10 +445,10 @@ top_level_prompt (void) beginning. */ const char suffix[] = "\n\032\032prompt\n"; - return concat (prefix, prompt, suffix, (char *) NULL); + return std::string (prefix) + prompt + suffix; } - return xstrdup (prompt); + return prompt; } /* See top.h. */ @@ -494,7 +491,7 @@ stdin_event_handler (int error, gdb_client_data client_data) else { /* Simply delete the UI. */ - delete_ui (ui); + delete ui; } } else @@ -548,7 +545,7 @@ async_enable_stdin (void) if (ui->prompt_state == PROMPT_BLOCKED) { - target_terminal_ours (); + target_terminal::ours (); ui_register_input_event_handler (ui); ui->prompt_state = PROMPT_NEEDED; } @@ -572,10 +569,10 @@ async_disable_stdin (void) a whole command. */ void -command_handler (char *command) +command_handler (const char *command) { struct ui *ui = current_ui; - char *c; + const char *c; if (ui->instream == ui->stdin_stream) reinitialize_more_filter (); @@ -598,10 +595,10 @@ command_handler (char *command) 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; @@ -622,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; } @@ -641,16 +635,16 @@ 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; @@ -676,9 +670,10 @@ 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); @@ -687,31 +682,29 @@ handle_line_of_input (struct buffer *cmd_line_buffer, /* Do history expansion if that is wished. */ 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 (); } } @@ -720,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 @@ -735,9 +728,8 @@ handle_line_of_input (struct buffer *cmd_line_buffer, /* 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; @@ -752,13 +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, 1, "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. @@ -852,8 +844,47 @@ gdb_readline_no_editing_callback (gdb_client_data client_data) buffer_grow_char (&line_buffer, '\0'); result = buffer_finish (&line_buffer); - ui->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 @@ -919,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. */ @@ -957,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 (); @@ -967,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 @@ -1137,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); @@ -1201,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. */ @@ -1212,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) {