X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finterps.c;h=65a01437d58020bb7ea52fd98c292316bb8581c8;hb=2f4fcf00399bc0ad5a4fed6b530128e8be4f40da;hp=f0428069d48564ea74e0561abf77d7d5def04d95;hpb=79a45e254f090b628473614054ed318d70409239;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/interps.c b/gdb/interps.c index f0428069d4..65a01437d5 100644 --- a/gdb/interps.c +++ b/gdb/interps.c @@ -1,7 +1,6 @@ /* Manages interpreters for GDB, the GNU debugger. - Copyright (C) 2000, 2002, 2003, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 2000-2020 Free Software Foundation, Inc. Written by Jim Ingham of Apple Computer, Inc. @@ -37,97 +36,110 @@ #include "event-top.h" #include "interps.h" #include "completer.h" -#include "gdb_string.h" -#include "gdb_assert.h" #include "top.h" /* For command_loop. */ -#include "exceptions.h" #include "continuations.h" +#include "main.h" -struct interp -{ - /* This is the name in "-i=" and set interpreter. */ - const char *name; +/* Each UI has its own independent set of interpreters. */ - /* Interpreters are stored in a linked list, this is the next - one... */ - struct interp *next; - - /* This is a cookie that an instance of the interpreter can use. - This is a bit confused right now as the exact initialization - sequence for it, and how it relates to the interpreter's uiout - object is a bit confused. */ - void *data; +struct ui_interp_info +{ + /* Each top level has its own independent set of interpreters. */ + struct interp *interp_list; + struct interp *current_interpreter; + struct interp *top_level_interpreter; + + /* The interpreter that is active while `interp_exec' is active, NULL + at all other times. */ + struct interp *command_interpreter; +}; - /* Has the init_proc been run? */ - int inited; +/* Get UI's ui_interp_info object. Never returns NULL. */ - /* This is the ui_out used to collect results for this interpreter. - It can be a formatter for stdout, as is the case for the console - & mi outputs, or it might be a result formatter. */ - struct ui_out *interpreter_out; +static struct ui_interp_info * +get_interp_info (struct ui *ui) +{ + if (ui->interp_info == NULL) + ui->interp_info = XCNEW (struct ui_interp_info); + return ui->interp_info; +} - const struct interp_procs *procs; - int quiet_p; -}; +/* Get the current UI's ui_interp_info object. Never returns + NULL. */ -/* Functions local to this file. */ -static void initialize_interps (void); -static char **interpreter_completer (struct cmd_list_element *cmd, - char *text, char *word); +static struct ui_interp_info * +get_current_interp_info (void) +{ + return get_interp_info (current_ui); +} /* The magic initialization routine for this module. */ -void _initialize_interpreter (void); +static struct interp *interp_lookup_existing (struct ui *ui, + const char *name); -/* Variables local to this file: */ +interp::interp (const char *name) + : m_name (xstrdup (name)) +{ + this->inited = false; +} -static struct interp *interp_list = NULL; -static struct interp *current_interpreter = NULL; -static struct interp *top_level_interpreter_ptr = NULL; +interp::~interp () +{ + xfree (m_name); +} -static int interpreter_initialized = 0; +/* An interpreter factory. Maps an interpreter name to the factory + function that instantiates an interpreter by that name. */ -/* interp_new - This allocates space for a new interpreter, - fills the fields from the inputs, and returns a pointer to the - interpreter. */ -struct interp * -interp_new (const char *name, void *data, struct ui_out *uiout, - const struct interp_procs *procs) +struct interp_factory { - struct interp *new_interp; + interp_factory (const char *name_, interp_factory_func func_) + : name (name_), func (func_) + {} + + /* This is the name in "-i=INTERP" and "interpreter-exec INTERP". */ + const char *name; + + /* The function that creates the interpreter. */ + interp_factory_func func; +}; + +/* The registered interpreter factories. */ +static std::vector interpreter_factories; - new_interp = XMALLOC (struct interp); +/* See interps.h. */ - new_interp->name = xstrdup (name); - new_interp->data = data; - new_interp->interpreter_out = uiout; - new_interp->quiet_p = 0; - new_interp->procs = procs; - new_interp->inited = 0; +void +interp_factory_register (const char *name, interp_factory_func func) +{ + /* Assert that no factory for NAME is already registered. */ + for (const interp_factory &f : interpreter_factories) + if (strcmp (f.name, name) == 0) + { + internal_error (__FILE__, __LINE__, + _("interpreter factory already registered: \"%s\"\n"), + name); + } - return new_interp; + interpreter_factories.emplace_back (name, func); } /* Add interpreter INTERP to the gdb interpreter list. The interpreter must not have previously been added. */ void -interp_add (struct interp *interp) +interp_add (struct ui *ui, struct interp *interp) { - if (!interpreter_initialized) - initialize_interps (); + struct ui_interp_info *ui_interp = get_interp_info (ui); - gdb_assert (interp_lookup (interp->name) == NULL); + gdb_assert (interp_lookup_existing (ui, interp->name ()) == NULL); - interp->next = interp_list; - interp_list = interp; + interp->next = ui_interp->interp_list; + ui_interp->interp_list = interp; } /* This sets the current interpreter to be INTERP. If INTERP has not - been initialized, then this will also run the init proc. If the - init proc is successful, return 1, if it fails, set the old - interpreter back in place and return 0. If we can't restore the - old interpreter, then raise an internal error, since we are in - pretty bad shape at this point. + been initialized, then this will also run the init method. The TOP_LEVEL parameter tells if this new interpreter is the top-level one. The top-level is what is requested @@ -136,197 +148,200 @@ interp_add (struct interp *interp) MI is the top-level interpreter, then it will always report events such as target stops and new thread creation, even if they are caused by CLI commands. */ -int -interp_set (struct interp *interp, int top_level) + +static void +interp_set (struct interp *interp, bool top_level) { - struct interp *old_interp = current_interpreter; - int first_time = 0; - char buffer[64]; + struct ui_interp_info *ui_interp = get_current_interp_info (); + struct interp *old_interp = ui_interp->current_interpreter; /* If we already have an interpreter, then trying to set top level interpreter is kinda pointless. */ - gdb_assert (!top_level || !current_interpreter); - gdb_assert (!top_level || !top_level_interpreter_ptr); + gdb_assert (!top_level || !ui_interp->current_interpreter); + gdb_assert (!top_level || !ui_interp->top_level_interpreter); - if (current_interpreter != NULL) + if (old_interp != NULL) { - ui_out_flush (current_uiout); - if (current_interpreter->procs->suspend_proc - && !current_interpreter->procs->suspend_proc (current_interpreter-> - data)) - { - error (_("Could not suspend interpreter \"%s\"."), - current_interpreter->name); - } - } - else - { - first_time = 1; + current_uiout->flush (); + old_interp->suspend (); } - current_interpreter = interp; + ui_interp->current_interpreter = interp; if (top_level) - top_level_interpreter_ptr = interp; + ui_interp->top_level_interpreter = interp; /* We use interpreter_p for the "set interpreter" variable, so we need to make sure we have a malloc'ed copy for the set command to free. */ if (interpreter_p != NULL - && strcmp (current_interpreter->name, interpreter_p) != 0) + && strcmp (interp->name (), interpreter_p) != 0) { xfree (interpreter_p); - interpreter_p = xstrdup (current_interpreter->name); + interpreter_p = xstrdup (interp->name ()); } - current_uiout = interp->interpreter_out; - - /* Run the init proc. If it fails, try to restore the old interp. */ - + /* Run the init proc. */ if (!interp->inited) { - if (interp->procs->init_proc != NULL) - { - interp->data = interp->procs->init_proc (top_level); - } - interp->inited = 1; + interp->init (top_level); + interp->inited = true; } + /* Do this only after the interpreter is initialized. */ + current_uiout = interp->interp_ui_out (); + /* Clear out any installed interpreter hooks/event handlers. */ clear_interpreter_hooks (); - if (interp->procs->resume_proc != NULL - && (!interp->procs->resume_proc (interp->data))) - { - if (old_interp == NULL || !interp_set (old_interp, 0)) - internal_error (__FILE__, __LINE__, - _("Failed to initialize new interp \"%s\" %s"), - interp->name, "and could not restore old interp!\n"); - return 0; - } + interp->resume (); +} - /* Finally, put up the new prompt to show that we are indeed here. - Also, display_gdb_prompt for the console does some readline magic - which is needed for the console interpreter, at least... */ +/* Look up the interpreter for NAME. If no such interpreter exists, + return NULL, otherwise return a pointer to the interpreter. */ - if (!first_time) +static struct interp * +interp_lookup_existing (struct ui *ui, const char *name) +{ + struct ui_interp_info *ui_interp = get_interp_info (ui); + struct interp *interp; + + for (interp = ui_interp->interp_list; + interp != NULL; + interp = interp->next) { - if (!interp_quiet_p (interp)) - { - sprintf (buffer, "Switching to interpreter \"%.24s\".\n", - interp->name); - ui_out_text (current_uiout, buffer); - } - display_gdb_prompt (NULL); + if (strcmp (interp->name (), name) == 0) + return interp; } - return 1; + return NULL; } -/* interp_lookup - Looks up the interpreter for NAME. If no such - interpreter exists, return NULL, otherwise return a pointer to the - interpreter. */ +/* See interps.h. */ + struct interp * -interp_lookup (const char *name) +interp_lookup (struct ui *ui, const char *name) { - struct interp *interp; - if (name == NULL || strlen (name) == 0) return NULL; - for (interp = interp_list; interp != NULL; interp = interp->next) - { - if (strcmp (interp->name, name) == 0) + /* Only create each interpreter once per top level. */ + struct interp *interp = interp_lookup_existing (ui, name); + if (interp != NULL) + return interp; + + for (const interp_factory &factory : interpreter_factories) + if (strcmp (factory.name, name) == 0) + { + interp = factory.func (name); + interp_add (ui, interp); return interp; - } + } return NULL; } -/* Returns the current interpreter. */ +/* See interps.h. */ -struct ui_out * -interp_ui_out (struct interp *interp) +void +set_top_level_interpreter (const char *name) { - if (interp != NULL) - return interp->interpreter_out; + /* Find it. */ + struct interp *interp = interp_lookup (current_ui, name); + + if (interp == NULL) + error (_("Interpreter `%s' unrecognized"), name); + /* Install it. */ + interp_set (interp, true); +} + +void +current_interp_set_logging (ui_file_up logfile, bool logging_redirect, + bool debug_redirect) +{ + struct ui_interp_info *ui_interp = get_current_interp_info (); + struct interp *interp = ui_interp->current_interpreter; - return current_interpreter->interpreter_out; + interp->set_logging (std::move (logfile), logging_redirect, debug_redirect); +} + +/* Temporarily overrides the current interpreter. */ +struct interp * +scoped_restore_interp::set_interp (const char *name) +{ + struct ui_interp_info *ui_interp = get_current_interp_info (); + struct interp *interp = interp_lookup (current_ui, name); + struct interp *old_interp = ui_interp->current_interpreter; + + if (interp) + ui_interp->current_interpreter = interp; + return old_interp; } /* Returns true if the current interp is the passed in name. */ int current_interp_named_p (const char *interp_name) { - if (current_interpreter) - return (strcmp (current_interpreter->name, interp_name) == 0); + struct ui_interp_info *ui_interp = get_current_interp_info (); + struct interp *interp = ui_interp->current_interpreter; + + if (interp != NULL) + return (strcmp (interp->name (), interp_name) == 0); return 0; } -/* This is called in display_gdb_prompt. If the proc returns a zero - value, display_gdb_prompt will return without displaying the - prompt. */ -int -current_interp_display_prompt_p (void) +/* The interpreter that was active when a command was executed. + Normally that'd always be CURRENT_INTERPRETER, except that MI's + -interpreter-exec command doesn't actually flip the current + interpreter when running its sub-command. The + `command_interpreter' global tracks when interp_exec is called + (IOW, when -interpreter-exec is called). If that is set, it is + INTERP in '-interpreter-exec INTERP "CMD"' or in 'interpreter-exec + INTERP "CMD". Otherwise, interp_exec isn't active, and so the + interpreter running the command is the current interpreter. */ + +struct interp * +command_interp (void) { - if (current_interpreter == NULL - || current_interpreter->procs->prompt_proc_p == NULL) - return 0; + struct ui_interp_info *ui_interp = get_current_interp_info (); + + if (ui_interp->command_interpreter != NULL) + return ui_interp->command_interpreter; else - return current_interpreter->procs->prompt_proc_p (current_interpreter-> - data); + return ui_interp->current_interpreter; } -/* Run the current command interpreter's main loop. */ +/* See interps.h. */ + void -current_interp_command_loop (void) +interp_pre_command_loop (struct interp *interp) { - /* Somewhat messy. For the moment prop up all the old ways of - selecting the command loop. `deprecated_command_loop_hook' - should be deprecated. */ - if (deprecated_command_loop_hook != NULL) - deprecated_command_loop_hook (); - else if (current_interpreter != NULL - && current_interpreter->procs->command_loop_proc != NULL) - current_interpreter->procs->command_loop_proc (current_interpreter->data); - else - cli_command_loop (); -} + gdb_assert (interp != NULL); -int -interp_quiet_p (struct interp *interp) -{ - if (interp != NULL) - return interp->quiet_p; - else - return current_interpreter->quiet_p; + interp->pre_command_loop (); } -static int -interp_set_quiet (struct interp *interp, int quiet) -{ - int old_val = interp->quiet_p; +/* See interp.h */ - interp->quiet_p = quiet; - return old_val; +int +interp_supports_command_editing (struct interp *interp) +{ + return interp->supports_command_editing (); } /* interp_exec - This executes COMMAND_STR in the current interpreter. */ -int -interp_exec_p (struct interp *interp) -{ - return interp->procs->exec_proc != NULL; -} struct gdb_exception interp_exec (struct interp *interp, const char *command_str) { - if (interp->procs->exec_proc != NULL) - { - return interp->procs->exec_proc (interp->data, command_str); - } - return exception_none; + struct ui_interp_info *ui_interp = get_current_interp_info (); + + /* See `command_interp' for why we do this. */ + scoped_restore save_command_interp + = make_scoped_restore (&ui_interp->command_interpreter, interp); + + return interp->exec (command_str); } /* A convenience routine that nulls out all the common command hooks. @@ -334,69 +349,43 @@ interp_exec (struct interp *interp, const char *command_str) void clear_interpreter_hooks (void) { - deprecated_init_ui_hook = 0; deprecated_print_frame_info_listing_hook = 0; /*print_frame_more_info_hook = 0; */ deprecated_query_hook = 0; deprecated_warning_hook = 0; - deprecated_interactive_hook = 0; deprecated_readline_begin_hook = 0; deprecated_readline_hook = 0; deprecated_readline_end_hook = 0; - deprecated_register_changed_hook = 0; deprecated_context_hook = 0; deprecated_target_wait_hook = 0; deprecated_call_command_hook = 0; deprecated_error_begin_hook = 0; - deprecated_command_loop_hook = 0; } -/* This is a lazy init routine, called the first time the interpreter - module is used. I put it here just in case, but I haven't thought - of a use for it yet. I will probably bag it soon, since I don't - think it will be necessary. */ static void -initialize_interps (void) -{ - interpreter_initialized = 1; - /* Don't know if anything needs to be done here... */ -} - -static void -interpreter_exec_cmd (char *args, int from_tty) +interpreter_exec_cmd (const char *args, int from_tty) { + struct ui_interp_info *ui_interp = get_current_interp_info (); struct interp *old_interp, *interp_to_use; - char **prules = NULL; - char **trule = NULL; unsigned int nrules; unsigned int i; - int old_quiet, use_quiet; if (args == NULL) error_no_arg (_("interpreter-exec command")); - prules = gdb_buildargv (args); - make_cleanup_freeargv (prules); - - nrules = 0; - for (trule = prules; *trule != NULL; trule++) - nrules++; + gdb_argv prules (args); + nrules = prules.count (); if (nrules < 2) - error (_("usage: interpreter-exec [ ... ]")); + error (_("Usage: interpreter-exec INTERPRETER COMMAND...")); - old_interp = current_interpreter; + old_interp = ui_interp->current_interpreter; - interp_to_use = interp_lookup (prules[0]); + interp_to_use = interp_lookup (current_ui, prules[0]); if (interp_to_use == NULL) error (_("Could not find interpreter \"%s\"."), prules[0]); - /* Temporarily set interpreters quiet. */ - old_quiet = interp_set_quiet (old_interp, 1); - use_quiet = interp_set_quiet (interp_to_use, 1); - - if (!interp_set (interp_to_use, 0)) - error (_("Could not switch to interpreter \"%s\"."), prules[0]); + interp_set (interp_to_use, false); for (i = 1; i < nrules; i++) { @@ -405,80 +394,48 @@ interpreter_exec_cmd (char *args, int from_tty) if (e.reason < 0) { interp_set (old_interp, 0); - interp_set_quiet (interp_to_use, use_quiet); - interp_set_quiet (old_interp, old_quiet); error (_("error in command: \"%s\"."), prules[i]); } } interp_set (old_interp, 0); - interp_set_quiet (interp_to_use, use_quiet); - interp_set_quiet (old_interp, old_quiet); } -/* List the possible interpreters which could complete the given text. */ -static char ** -interpreter_completer (struct cmd_list_element *ignore, char *text, char *word) -{ - int alloced = 0; - int textlen; - int num_matches; - char **matches; - struct interp *interp; +/* See interps.h. */ - /* We expect only a very limited number of interpreters, so just - allocate room for all of them plus one for the last that must be NULL - to correctly end the list. */ - for (interp = interp_list; interp != NULL; interp = interp->next) - ++alloced; - matches = (char **) xcalloc (alloced + 1, sizeof (char *)); +void +interpreter_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char *word) +{ + int textlen = strlen (text); - num_matches = 0; - textlen = strlen (text); - for (interp = interp_list; interp != NULL; interp = interp->next) + for (const interp_factory &interp : interpreter_factories) { - if (strncmp (interp->name, text, textlen) == 0) + if (strncmp (interp.name, text, textlen) == 0) { - matches[num_matches] = - (char *) xmalloc (strlen (word) + strlen (interp->name) + 1); - if (word == text) - strcpy (matches[num_matches], interp->name); - else if (word > text) - { - /* Return some portion of interp->name. */ - strcpy (matches[num_matches], interp->name + (word - text)); - } - else - { - /* Return some of text plus interp->name. */ - strncpy (matches[num_matches], word, text - word); - matches[num_matches][text - word] = '\0'; - strcat (matches[num_matches], interp->name); - } - ++num_matches; + tracker.add_completion + (make_completion_match_str (interp.name, text, word)); } } - - if (num_matches == 0) - { - xfree (matches); - matches = NULL; - } - - return matches; } struct interp * top_level_interpreter (void) { - return top_level_interpreter_ptr; + struct ui_interp_info *ui_interp = get_current_interp_info (); + + return ui_interp->top_level_interpreter; } -void * -top_level_interpreter_data (void) +/* See interps.h. */ + +struct interp * +current_interpreter (void) { - gdb_assert (top_level_interpreter_ptr); - return top_level_interpreter_ptr->data; + struct ui_interp_info *ui_interp = get_interp_info (current_ui); + + return ui_interp->current_interpreter; } /* This just adds the "interpreter-exec" command. */ @@ -489,8 +446,12 @@ _initialize_interpreter (void) c = add_cmd ("interpreter-exec", class_support, interpreter_exec_cmd, _("\ -Execute a command in an interpreter. It takes two arguments:\n\ +Execute a command in an interpreter.\n\ +Usage: interpreter-exec INTERPRETER COMMAND...\n\ The first argument is the name of the interpreter to use.\n\ -The second argument is the command to execute.\n"), &cmdlist); +The following arguments are the commands to execute.\n\ +A command can have arguments, separated by spaces.\n\ +These spaces must be escaped using \\ or the command\n\ +and its arguments must be enclosed in double quotes."), &cmdlist); set_cmd_completer (c, interpreter_completer); }