diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a6b34edcd26..599f43af55c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,49 @@ +2016-06-21 Pedro Alves + + * cli/cli-interp.c (cli_uiout): Delete, moved into ... + (struct cli_interp): ... this new structure. + (cli_on_normal_stop, cli_on_signal_received) + (cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited) + (cli_on_no_history): Use interp_ui_out. + (cli_interpreter_init): If top level, set the cli_interp global. + (cli_interpreter_init): Return the interp's data instead of NULL. + (cli_interpreter_resume, cli_interpreter_exec, cli_ui_out): Adjust + to cli_uiout being in the interpreter's data. + (cli_interp_procs): New, factored out from _initialize_cli_interp. + (cli_interp_factory): New function. + (_initialize_cli_interp): Call interp_factory_register. + * interps.c (get_interp_info): New, factored out from ... + (get_current_interp_info): ... this. + (interp_new): Add parameter 'data'. Store it. + (struct interp_factory): New function. + (interp_factory_p): New typedef. Define a VEC_P. + (interpreter_factories): New global. + (interp_factory_register): New function. + (interp_add): Add 'ui' parameter. Use get_interp_info and + interp_lookup_existing. + (interp_lookup): Rename to ... + (interp_lookup_existing): ... this. Add 'ui' parameter. Don't + check for NULL or empty name here. + (interp_lookup): Add 'ui' parameter and reimplement. + (interp_set_temp, interpreter_exec_cmd): Adjust. + (interpreter_completer): Complete on registered interpreter + factories instead of interpreters. + * interps.h (interp_factory_func): New typedef. + (interp_factory_register): Declare. + (interp_new, interp_add): Adjust. + (interp_lookup): Declare. + * main.c (captured_main): Adjust. + * mi/mi-interp.c (mi_cmd_interpreter_exec): Adjust. + (mi_interp_procs): New, factored out from + _initialize_mi_interp. + (mi_interp_factory): New function. + * python/python.c (execute_gdb_command): Adjust. + * tui/tui-interp.c (tui_init): If top level, set the tui_interp + global. + (tui_interp_procs): New. + (tui_interp_factory): New function. + (_initialize_tui_interp): Call interp_factory_register. + 2016-06-21 Pedro Alves * breakpoint.c (bpstat_do_actions_1): Access the current UI's diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c index dfbd808cb08..8eae0acc3b1 100644 --- a/gdb/cli/cli-interp.c +++ b/gdb/cli/cli-interp.c @@ -26,9 +26,14 @@ #include "infrun.h" #include "observer.h" -/* These are the ui_out and the interpreter for the console - interpreter. */ -struct ui_out *cli_uiout; +/* The console interpreter. */ +struct cli_interp +{ + /* The ui_out for the console interpreter. */ + struct ui_out *cli_uiout; +}; + +/* The interpreter for the console interpreter. */ static struct interp *cli_interp; /* Longjmp-safe wrapper for "execute_command". */ @@ -48,7 +53,7 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame) if (!interp_quiet_p (cli_interp)) { if (print_frame) - print_stop_event (cli_uiout); + print_stop_event (interp_ui_out (cli_interp)); } } @@ -58,7 +63,7 @@ static void cli_on_signal_received (enum gdb_signal siggnal) { if (!interp_quiet_p (cli_interp)) - print_signal_received_reason (cli_uiout, siggnal); + print_signal_received_reason (interp_ui_out (cli_interp), siggnal); } /* Observer for the end_stepping_range notification. */ @@ -67,7 +72,7 @@ static void cli_on_end_stepping_range (void) { if (!interp_quiet_p (cli_interp)) - print_end_stepping_range_reason (cli_uiout); + print_end_stepping_range_reason (interp_ui_out (cli_interp)); } /* Observer for the signalled notification. */ @@ -76,7 +81,7 @@ static void cli_on_signal_exited (enum gdb_signal siggnal) { if (!interp_quiet_p (cli_interp)) - print_signal_exited_reason (cli_uiout, siggnal); + print_signal_exited_reason (interp_ui_out (cli_interp), siggnal); } /* Observer for the exited notification. */ @@ -85,7 +90,7 @@ static void cli_on_exited (int exitstatus) { if (!interp_quiet_p (cli_interp)) - print_exited_reason (cli_uiout, exitstatus); + print_exited_reason (interp_ui_out (cli_interp), exitstatus); } /* Observer for the no_history notification. */ @@ -94,7 +99,7 @@ static void cli_on_no_history (void) { if (!interp_quiet_p (cli_interp)) - print_no_history_reason (cli_uiout); + print_no_history_reason (interp_ui_out (cli_interp)); } /* Observer for the sync_execution_done notification. */ @@ -120,6 +125,9 @@ cli_on_command_error (void) static void * cli_interpreter_init (struct interp *self, int top_level) { + if (top_level) + cli_interp = self; + /* If changing this, remember to update tui-interp.c as well. */ observer_attach_normal_stop (cli_on_normal_stop); observer_attach_end_stepping_range (cli_on_end_stepping_range); @@ -130,12 +138,13 @@ cli_interpreter_init (struct interp *self, int top_level) observer_attach_sync_execution_done (cli_on_sync_execution_done); observer_attach_command_error (cli_on_command_error); - return NULL; + return interp_data (self); } static int cli_interpreter_resume (void *data) { + struct cli_interp *cli = (struct cli_interp *) data; struct ui_file *stream; /*sync_execution = 1; */ @@ -144,17 +153,17 @@ cli_interpreter_resume (void *data) previously writing to gdb_stdout, then set it to the new gdb_stdout afterwards. */ - stream = cli_out_set_stream (cli_uiout, gdb_stdout); + stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout); if (stream != gdb_stdout) { - cli_out_set_stream (cli_uiout, stream); + cli_out_set_stream (cli->cli_uiout, stream); stream = NULL; } gdb_setup_readline (); if (stream != NULL) - cli_out_set_stream (cli_uiout, gdb_stdout); + cli_out_set_stream (cli->cli_uiout, gdb_stdout); return 1; } @@ -169,6 +178,7 @@ cli_interpreter_suspend (void *data) static struct gdb_exception cli_interpreter_exec (void *data, const char *command_str) { + struct cli_interp *cli = (struct cli_interp *) data; struct ui_file *old_stream; struct gdb_exception result; @@ -184,9 +194,9 @@ cli_interpreter_exec (void *data, const char *command_str) It is important that it gets reset everytime, since the user could set gdb to use a different interpreter. */ - old_stream = cli_out_set_stream (cli_uiout, gdb_stdout); - result = safe_execute_command (cli_uiout, str, 1); - cli_out_set_stream (cli_uiout, old_stream); + old_stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout); + result = safe_execute_command (cli->cli_uiout, str, 1); + cli_out_set_stream (cli->cli_uiout, old_stream); return result; } @@ -222,7 +232,34 @@ safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty) static struct ui_out * cli_ui_out (struct interp *self) { - return cli_uiout; + struct cli_interp *cli = (struct cli_interp *) interp_data (self); + + return cli->cli_uiout; +} + +/* The CLI interpreter's vtable. */ + +static const struct interp_procs cli_interp_procs = { + cli_interpreter_init, /* init_proc */ + cli_interpreter_resume, /* resume_proc */ + cli_interpreter_suspend, /* suspend_proc */ + cli_interpreter_exec, /* exec_proc */ + cli_ui_out, /* ui_out_proc */ + NULL, /* set_logging_proc */ + cli_command_loop /* command_loop_proc */ +}; + +/* Factory for CLI interpreters. */ + +static struct interp * +cli_interp_factory (const char *name) +{ + struct cli_interp *cli = XNEW (struct cli_interp); + + /* Create a default uiout builder for the CLI. */ + cli->cli_uiout = cli_out_new (gdb_stdout); + + return interp_new (name, &cli_interp_procs, cli); } /* Standard gdb initialization hook. */ @@ -231,19 +268,5 @@ extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */ void _initialize_cli_interp (void) { - static const struct interp_procs procs = { - cli_interpreter_init, /* init_proc */ - cli_interpreter_resume, /* resume_proc */ - cli_interpreter_suspend, /* suspend_proc */ - cli_interpreter_exec, /* exec_proc */ - cli_ui_out, /* ui_out_proc */ - NULL, /* set_logging_proc */ - cli_command_loop /* command_loop_proc */ - }; - - /* Create a default uiout builder for the CLI. */ - cli_uiout = cli_out_new (gdb_stdout); - cli_interp = interp_new (INTERP_CONSOLE, &procs); - - interp_add (cli_interp); + interp_factory_register (INTERP_CONSOLE, cli_interp_factory); } diff --git a/gdb/interps.c b/gdb/interps.c index f19db544278..fd08de55fc5 100644 --- a/gdb/interps.c +++ b/gdb/interps.c @@ -53,16 +53,23 @@ struct ui_interp_info struct interp *command_interpreter; }; -/* Get the current UI's ui_interp_info object. Never returns NULL. */ +/* Get UI's ui_interp_info object. Never returns NULL. */ + +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; +} + +/* Get the current UI's ui_interp_info object. Never returns + NULL. */ static struct ui_interp_info * get_current_interp_info (void) { - struct ui *ui = current_ui; - - if (ui->interp_info == NULL) - ui->interp_info = XCNEW (struct ui_interp_info); - return ui->interp_info; + return get_interp_info (current_ui); } struct interp @@ -91,18 +98,21 @@ struct interp void _initialize_interpreter (void); +static struct interp *interp_lookup_existing (struct ui *ui, + const char *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, const struct interp_procs *procs) +interp_new (const char *name, const struct interp_procs *procs, void *data) { struct interp *new_interp; new_interp = XNEW (struct interp); new_interp->name = xstrdup (name); - new_interp->data = NULL; + new_interp->data = data; new_interp->quiet_p = 0; new_interp->procs = procs; new_interp->inited = 0; @@ -113,14 +123,57 @@ interp_new (const char *name, const struct interp_procs *procs) return new_interp; } +/* An interpreter factory. Maps an interpreter name to the factory + function that instantiates an interpreter by that name. */ + +struct interp_factory +{ + /* This is the name in "-i=INTERP" and "interpreter-exec INTERP". */ + const char *name; + + /* The function that creates the interpreter. */ + interp_factory_func func; +}; + +typedef struct interp_factory *interp_factory_p; +DEF_VEC_P(interp_factory_p); + +/* The registered interpreter factories. */ +static VEC(interp_factory_p) *interpreter_factories = NULL; + +/* See interps.h. */ + +void +interp_factory_register (const char *name, interp_factory_func func) +{ + struct interp_factory *f; + int ix; + + /* Assert that no factory for NAME is already registered. */ + for (ix = 0; + VEC_iterate (interp_factory_p, interpreter_factories, ix, f); + ++ix) + if (strcmp (f->name, name) == 0) + { + internal_error (__FILE__, __LINE__, + _("interpreter factory already registered: \"%s\"\n"), + name); + } + + f = XNEW (struct interp_factory); + f->name = name; + f->func = func; + VEC_safe_push (interp_factory_p, interpreter_factories, f); +} + /* 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) { - struct ui_interp_info *ui_interp = get_current_interp_info (); + 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 = ui_interp->interp_list; ui_interp->interp_list = interp; @@ -219,17 +272,14 @@ interp_set (struct interp *interp, int top_level) return 1; } -/* interp_lookup - Looks up the interpreter for NAME. If no such - interpreter exists, return NULL, otherwise return a pointer to the - interpreter. */ -struct interp * -interp_lookup (const char *name) -{ - struct ui_interp_info *ui_interp = get_current_interp_info (); - struct interp *interp; +/* Look up the interpreter for NAME. If no such interpreter exists, + return NULL, otherwise return a pointer to the interpreter. */ - if (name == NULL || strlen (name) == 0) - return NULL; +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; @@ -242,6 +292,36 @@ interp_lookup (const char *name) return NULL; } +/* See interps.h. */ + +struct interp * +interp_lookup (struct ui *ui, const char *name) +{ + struct interp_factory *factory; + struct interp *interp; + int ix; + + if (name == NULL || strlen (name) == 0) + return NULL; + + /* Only create each interpreter once per top level. */ + interp = interp_lookup_existing (ui, name); + if (interp != NULL) + return interp; + + for (ix = 0; + VEC_iterate (interp_factory_p, interpreter_factories, ix, factory); + ++ix) + if (strcmp (factory->name, name) == 0) + { + interp = factory->func (name); + interp_add (ui, interp); + return interp; + } + + return NULL; +} + /* Returns the current interpreter. */ struct ui_out * @@ -273,7 +353,7 @@ struct interp * interp_set_temp (const char *name) { struct ui_interp_info *ui_interp = get_current_interp_info (); - struct interp *interp = interp_lookup (name); + struct interp *interp = interp_lookup (current_ui, name); struct interp *old_interp = ui_interp->current_interpreter; if (interp) @@ -433,7 +513,7 @@ interpreter_exec_cmd (char *args, int from_tty) 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]); @@ -469,15 +549,15 @@ static VEC (char_ptr) * interpreter_completer (struct cmd_list_element *ignore, const char *text, const char *word) { - struct ui_interp_info *ui_interp = get_current_interp_info (); + struct interp_factory *interp; int textlen; VEC (char_ptr) *matches = NULL; - struct interp *interp; + int ix; textlen = strlen (text); - for (interp = ui_interp->interp_list; - interp != NULL; - interp = interp->next) + for (ix = 0; + VEC_iterate (interp_factory_p, interpreter_factories, ix, interp); + ++ix) { if (strncmp (interp->name, text, textlen) == 0) { diff --git a/gdb/interps.h b/gdb/interps.h index f0badc5e6c7..e5cd779f264 100644 --- a/gdb/interps.h +++ b/gdb/interps.h @@ -24,6 +24,16 @@ struct ui_out; struct interp; +struct ui; + +typedef struct interp *(*interp_factory_func) (const char *name); + +/* Each interpreter kind (CLI, MI, etc.) registers itself with a call + to this function, passing along its name, and a pointer to a + function that creates a new instance of an interpreter with that + name. */ +extern void interp_factory_register (const char *name, + interp_factory_func func); extern int interp_resume (struct interp *interp); extern int interp_suspend (struct interp *interp); @@ -64,10 +74,18 @@ struct interp_procs interp_command_loop_ftype *command_loop_proc; }; -extern struct interp *interp_new (const char *name, const struct interp_procs *procs); -extern void interp_add (struct interp *interp); +extern struct interp *interp_new (const char *name, + const struct interp_procs *procs, + void *data); +extern void interp_add (struct ui *ui, struct interp *interp); extern int interp_set (struct interp *interp, int top_level); -extern struct interp *interp_lookup (const char *name); + +/* Look up the interpreter for NAME, creating one if none exists yet. + If NAME is not a interpreter type previously registered with + interp_factory_register, return NULL; otherwise return a pointer to + the interpreter. */ +extern struct interp *interp_lookup (struct ui *ui, const char *name); + extern struct ui_out *interp_ui_out (struct interp *interp); extern void *interp_data (struct interp *interp); extern const char *interp_name (struct interp *interp); diff --git a/gdb/main.c b/gdb/main.c index d84340e8222..221888d39f4 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -962,7 +962,7 @@ captured_main (void *data) { /* Find it. */ - struct interp *interp = interp_lookup (interpreter_p); + struct interp *interp = interp_lookup (current_ui, interpreter_p); if (interp == NULL) error (_("Interpreter `%s' unrecognized"), interpreter_p); diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 4656e892b47..f8c007cf578 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -238,7 +238,7 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) error (_("-interpreter-exec: " "Usage: -interpreter-exec interp command")); - interp_to_use = interp_lookup (argv[0]); + interp_to_use = interp_lookup (current_ui, argv[0]); if (interp_to_use == NULL) error (_("-interpreter-exec: could not find interpreter \"%s\""), argv[0]); @@ -1242,25 +1242,35 @@ mi_set_logging (struct interp *interp, int start_log, return 1; } +/* The MI interpreter's vtable. */ + +static const struct interp_procs mi_interp_procs = +{ + mi_interpreter_init, /* init_proc */ + mi_interpreter_resume, /* resume_proc */ + mi_interpreter_suspend, /* suspend_proc */ + mi_interpreter_exec, /* exec_proc */ + mi_ui_out, /* ui_out_proc */ + mi_set_logging, /* set_logging_proc */ + mi_command_loop /* command_loop_proc */ +}; + +/* Factory for MI interpreters. */ + +static struct interp * +mi_interp_factory (const char *name) +{ + return interp_new (name, &mi_interp_procs, NULL); +} + extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ void _initialize_mi_interp (void) { - static const struct interp_procs procs = - { - mi_interpreter_init, /* init_proc */ - mi_interpreter_resume, /* resume_proc */ - mi_interpreter_suspend, /* suspend_proc */ - mi_interpreter_exec, /* exec_proc */ - mi_ui_out, /* ui_out_proc */ - mi_set_logging, /* set_logging_proc */ - mi_command_loop /* command_loop_proc */ - }; - /* The various interpreter levels. */ - interp_add (interp_new (INTERP_MI1, &procs)); - interp_add (interp_new (INTERP_MI2, &procs)); - interp_add (interp_new (INTERP_MI3, &procs)); - interp_add (interp_new (INTERP_MI, &procs)); + interp_factory_register (INTERP_MI1, mi_interp_factory); + interp_factory_register (INTERP_MI2, mi_interp_factory); + interp_factory_register (INTERP_MI3, mi_interp_factory); + interp_factory_register (INTERP_MI, mi_interp_factory); } diff --git a/gdb/python/python.c b/gdb/python/python.c index 19590f49a78..8a968281b3b 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -656,7 +656,7 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) make_cleanup_restore_ui_out (¤t_uiout); /* Use the console interpreter uiout to have the same print format for console or MI. */ - interp = interp_lookup ("console"); + interp = interp_lookup (current_ui, "console"); current_uiout = interp_ui_out (interp); prevent_dont_repeat (); diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c index 7a0da482e3c..75445001233 100644 --- a/gdb/tui/tui-interp.c +++ b/gdb/tui/tui-interp.c @@ -138,6 +138,9 @@ tui_init (struct interp *self, int top_level) /* Install exit handler to leave the screen in a good shape. */ atexit (tui_exit); + if (top_level) + tui_interp = self; + tui_initialize_static_data (); tui_initialize_io (); @@ -207,25 +210,34 @@ tui_exec (void *data, const char *command_str) internal_error (__FILE__, __LINE__, _("tui_exec called")); } +/* The TUI interpreter's vtable. */ + +static const struct interp_procs tui_interp_procs = { + tui_init, + tui_resume, + tui_suspend, + tui_exec, + tui_ui_out, + NULL, + cli_command_loop +}; + +/* Factory for TUI interpreters. */ + +static struct interp * +tui_interp_factory (const char *name) +{ + return interp_new (name, &tui_interp_procs, NULL); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_tui_interp; void _initialize_tui_interp (void) { - static const struct interp_procs procs = { - tui_init, - tui_resume, - tui_suspend, - tui_exec, - tui_ui_out, - NULL, - cli_command_loop - }; + interp_factory_register (INTERP_TUI, tui_interp_factory); - /* Create a default uiout builder for the TUI. */ - tui_interp = interp_new (INTERP_TUI, &procs); - interp_add (tui_interp); if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0) tui_start_enabled = 1;