This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFC/PATCH] interpreters part 1: new files
- From: Elena Zannoni <ezannoni at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Cc:
- Date: Mon, 9 Dec 2002 10:38:25 -0500
- Subject: Re: [RFC/PATCH] interpreters part 1: new files
- References: <15816.23962.185660.557024@localhost.redhat.com>
Any comments?
I would like to start committing this stuff later today/tomorrow.
Elena
Elena Zannoni writes:
>
> Following up from the thread in:
> http://sources.redhat.com/ml/gdb-patches/2002-08/msg00308.html
>
> Here are the new files that have been added to support the
> interpreters mechanism. This is all Jim Ingham and Keith Seitz's work,
> I am just doing some cleanup and manual merging labor.
>
> How to use this feature: (lame example, yes, I know)
>
> In the console, you can use MI commands by specifying 'mi' as the interpreter:
>
> (gdb) interpreter-exec mi "-break-insert main"
> &"No symbol table is loaded. Use the \"file\" command.\n"
> ^error,msg="No symbol table is loaded. Use the \"file\" command."
>
> You can try to specify the same interpreter you are using: it will
> still do the right thing:
>
> (gdb) interpreter-exec console "-break-insert main"
> Undefined command: "-break-insert". Try "help".
>
> (gdb) interpreter-exec console "break main"
> No symbol table is loaded. Use the "file" command.
>
>
> Vice versa in the mi:
>
> (gdb)
> -interpreter-exec console "break main"
> &"No symbol table is loaded. Use the \"file\" command.\n"
> ^error,msg="No symbol table is loaded. Use the \"file\" command."
> (gdb)
> -interpreter-exec mi "break main" ******
> &"break main\n"
> &"No symbol table is loaded. Use the \"file\" command.\n"
> ^error,msg="No symbol table is loaded. Use the \"file\" command."
> (gdb)
> -interpreter-exec console "-break-insert main"
> &"Undefined command: \"-break-insert\". Try \"help\".\n"
> ^error,msg="Undefined command: \"-break-insert\". Try \"help\"."
> (gdb)
>
>
> ****** Note that the cli version of the command is OK in the MI, so it
> is processed.
>
> How this works:
>
> there is a generic structure 'interpreter' (interps.[ch]) that gets
> instantiated by the cli (cli/cli-interp.c) and by the mi
> (mi/mi-interp.c) in different ways. The interpreter "class" has its
> own methods that are instantiated by the mi and cli versions
> appropriately.
>
> The whole mechanism is started up in top.c:gdb_init() (separate
> patch). If the user starts up gdb w/o specifying -i=mi, etc, gdb will
> use the console by default, otherwise it will use the interp specified on
> the command line. There is going to always be an active
> interpreter. Gdb switches appropriately if the user specifies the
> evaluation of a command in a different one.
>
> There is some more magic that relates to starting and stopping
> readline because only the console interpreter uses it.
> But that is a separate patch.
>
> [let me know if the ChangeLog credits are not ok]
>
> Elena
>
> ChangeLog:
>
> 2002-11-05 Elena Zannoni <ezannoni@redhat.com>
>
> Written by Jim Ingham <jingham@apple.com> with changes by Keith
> Seitz <keiths@redhat.com> and Elena Zannoni <ezannoni@redhat.com>:
> * interps.c: New file.
> * interps.h: New file.
> * cli/cli-interp.c: New file.
>
>
> mi/ChangeLog:
>
> 2002-11-05 Elena Zannoni <ezannoni@redhat.com>
>
> Written by Jim Ingham <jingham@apple.com> with changes by Keith
> Seitz <keiths@redhat.com> and Elena Zannoni <ezannoni@redhat.com>:
> * mi-interp.c: New file.
>
>
> /* Manages interpreters for gdb.
> Copyright 2000,2002 Free Software Foundation, Inc.
> Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
>
> This file is part of GDB.
>
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330,
> Boston, MA 02111-1307, USA. */
>
> #ifndef GDB_INTERPRETER_H
> #define GDB_INTERPRETER_H
>
> typedef int (*interp_init_ftype) (void *data);
> typedef int (*interp_resume_ftype) (void *data);
> typedef int (*interp_suspend_ftype) (void *data);
> typedef int (*interp_prompt_ftype) (void);
> typedef int (*interp_exec_ftype) (void *data, char *command);
>
> struct ui_out;
> struct gdb_interpreter;
>
> struct gdb_interpreter_procs
> {
> interp_init_ftype init_proc;
> interp_resume_ftype resume_proc;
> interp_suspend_ftype suspend_proc;
> interp_exec_ftype exec_proc;
> interp_prompt_ftype prompt_proc_p;
> };
>
> extern struct gdb_interpreter
> *gdb_interpreter_new (char *name, void *data, struct ui_out *uiout,
> struct gdb_interpreter_procs *procs);
>
> extern int gdb_interpreter_set (struct gdb_interpreter *interp);
> extern struct gdb_interpreter *gdb_interpreter_lookup (char *name);
> extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
> extern int gdb_interpreter_current_is_named_p (char *interp_name);
> extern int gdb_interpreter_exec (char *command_str);
> extern int gdb_interpreter_display_prompt_p (void);
> extern int gdb_interpreter_is_quiet_p (struct gdb_interpreter *interp);
> extern int gdb_interpreter_add (struct gdb_interpreter *interp);
> extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
> gdb_interpreter
> *interp);
> extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
>
> extern void clear_interpreter_hooks ();
>
> /* well-known interpreters */
> #define GDB_INTERPRETER_CONSOLE "console"
> #define GDB_INTERPRETER_MI1 "mi1"
> #define GDB_INTERPRETER_MI2 "mi2"
> #define GDB_INTERPRETER_MI "mi"
> #endif /* GDB_INTERPRETER_H */
>
>
>
>
> /* Manages interpreters for gdb.
> Copyright 2000, 2002 Free Software Foundation, Inc.
> Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
>
> This file is part of GDB.
>
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330,
> Boston, MA 02111-1307, USA. */
>
> /* This is just a first cut at separating out the "interpreter" functions
> of gdb into self-contained modules. There are a couple of open areas that
> need to be sorted out:
>
> 1) The interpreter explicitly contains a UI_OUT, and can insert itself
> into the event loop, but it doesn't explicitly contain hooks for readline.
> I did this because it seems to me many interpreters won't want to use
> the readline command interface, and it is probably simpler to just let
> them take over the input in their resume proc.
> */
>
> #include "defs.h"
> #include "gdbcmd.h"
> #include "ui-out.h"
> #include "event-loop.h"
> #include "event-top.h"
> #include "interps.h"
> #include "completer.h"
> #include "gdb_string.h"
> #include "gdb-events.h"
>
> struct gdb_interpreter
> {
> /* This is the name in "-i=" and set interpreter. */
> char *name;
>
> /* Interpreters are stored in a linked list, this is the next one... */
> struct gdb_interpreter *next;
>
> /* This is a cookie that the instance of the interpreter can use, for
> instance to call itself in hook functions */
> void *data;
>
> /* Has the init_proc been run? */
> int inited;
>
> /* 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;
>
> struct gdb_interpreter_procs procs;
> int quiet_p;
> };
>
> /* Functions local to this file. */
> static void initialize_interps (void);
> static char **interpreter_completer (char *text, char *word);
>
> /* The magic initialization routine for this module. */
>
> void _initialize_interpreter (void);
>
> /* Variables local to this file: */
>
> static struct gdb_interpreter *interp_list = NULL;
> static struct gdb_interpreter *current_interpreter = NULL;
>
> static int interpreter_initialized = 0;
>
> /* gdb_interpreter_new - This allocates space for a new interpreter,
> fills the fields from the inputs, and returns a pointer to the
> interpreter. */
> struct gdb_interpreter *
> gdb_interpreter_new (char *name,
> void *data,
> struct ui_out *uiout,
> struct gdb_interpreter_procs *procs)
> {
> struct gdb_interpreter *new_interp;
>
> new_interp =
> (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));
>
> new_interp->name = xstrdup (name);
> new_interp->data = data;
> new_interp->interpreter_out = uiout;
> new_interp->quiet_p = 0;
> new_interp->procs.init_proc = procs->init_proc;
> new_interp->procs.resume_proc = procs->resume_proc;
> new_interp->procs.suspend_proc = procs->suspend_proc;
> new_interp->procs.exec_proc = procs->exec_proc;
> new_interp->procs.prompt_proc_p = procs->prompt_proc_p;
> new_interp->inited = 0;
>
> return new_interp;
> }
>
> /* Add interpreter INTERP to the gdb interpreter list. If an
> interpreter of the same name is already on the list, then
> the new one is NOT added, and the function returns 0. Otherwise
> it returns 1. */
> int
> gdb_interpreter_add (struct gdb_interpreter *interp)
> {
> if (!interpreter_initialized)
> initialize_interps ();
>
> if (gdb_interpreter_lookup (interp->name) != NULL)
> return 0;
>
> interp->next = interp_list;
> interp_list = interp;
>
> return 1;
> }
>
> /* 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. */
> int
> gdb_interpreter_set (struct gdb_interpreter *interp)
> {
> struct gdb_interpreter *old_interp = current_interpreter;
> int first_time = 0;
>
>
> char buffer[64];
>
> if (current_interpreter != NULL)
> {
> do_all_continuations ();
> ui_out_flush (uiout);
> if (current_interpreter->procs.suspend_proc
> && !current_interpreter->procs.suspend_proc (current_interpreter->
> data))
> {
> error ("Could not suspend interpreter \"%s\"\n",
> current_interpreter->name);
> }
> }
> else
> {
> first_time = 1;
> }
>
> current_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)
> {
> xfree (interpreter_p);
>
> interpreter_p = xstrdup (current_interpreter->name);
> }
>
> uiout = interp->interpreter_out;
>
> /* Run the init proc. If it fails, try to restore the old interp. */
>
> if (!interp->inited)
> {
> if (interp->procs.init_proc != NULL)
> {
> if (!interp->procs.init_proc (interp->data))
> {
> if (!gdb_interpreter_set (old_interp))
> internal_error (__FILE__, __LINE__,
> "Failed to initialize new interp \"%s\" %s",
> interp->name,
> "and could not restore old interp!\n");
> return 0;
> }
> else
> {
> interp->inited = 1;
> }
> }
> else
> {
> interp->inited = 1;
> }
> }
>
> /* Clear out any installed interpreter hooks/event handlers. */
> clear_interpreter_hooks ();
>
> if (interp->procs.resume_proc != NULL
> && (!interp->procs.resume_proc (interp->data)))
> {
> if (!gdb_interpreter_set (old_interp))
> internal_error (__FILE__, __LINE__,
> "Failed to initialize new interp \"%s\" %s",
> interp->name, "and could not restore old interp!\n");
> return 0;
> }
>
> /* 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... */
>
> if (!first_time)
> {
> if (!gdb_interpreter_is_quiet_p (interp))
> {
> sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
> interp->name);
> ui_out_text (uiout, buffer);
> }
> display_gdb_prompt (NULL);
> }
>
> return 1;
> }
>
> /* gdb_interpreter_lookup - Looks up the interpreter for NAME. If no
> such interpreter exists, return NULL, otherwise return a pointer to
> the interpreter. */
> struct gdb_interpreter *
> gdb_interpreter_lookup (char *name)
> {
> struct gdb_interpreter *interp;
>
> if (name == NULL || strlen (name) == 0)
> return NULL;
>
> for (interp = interp_list; interp != NULL; interp = interp->next)
> {
> if (strcmp (interp->name, name) == 0)
> return interp;
> }
>
> return NULL;
> }
>
> /* Returns the current interpreter. */
> static struct gdb_interpreter *
> gdb_interpreter_current (void)
> {
> return current_interpreter;
> }
>
> struct ui_out *
> gdb_interpreter_ui_out (struct gdb_interpreter *interp)
> {
> if (interp != NULL)
> return interp->interpreter_out;
>
> return current_interpreter->interpreter_out;
> }
>
> /* Returns true if the current interp is the passed in name. */
> int
> gdb_interpreter_current_is_named_p (char *interp_name)
> {
> struct gdb_interpreter *current_interp = gdb_interpreter_current ();
>
> if (current_interp)
> return (strcmp (current_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
> gdb_interpreter_display_prompt_p (void)
> {
> if (current_interpreter->procs.prompt_proc_p == NULL)
> return 0;
> else
> return current_interpreter->procs.prompt_proc_p ();
> }
>
> int
> gdb_interpreter_is_quiet_p (struct gdb_interpreter *interp)
> {
> if (interp != NULL)
> return interp->quiet_p;
> else
> return current_interpreter->quiet_p;
> }
>
> int
> gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
> {
> int old_val = interp->quiet_p;
> interp->quiet_p = quiet;
> return old_val;
> }
>
> /* gdb_interpreter_exec - This executes COMMAND_STR in the current
> interpreter. */
> int
> gdb_interpreter_exec (char *command_str)
> {
> if (current_interpreter->procs.exec_proc != NULL)
> {
> return current_interpreter->procs.exec_proc (current_interpreter->data,
> command_str);
> }
> return 0;
> }
>
> /* Accessor function. Not used at the moment. */
> struct gdb_interpreter_procs *
> gdb_interpreter_get_procs (struct gdb_interpreter *interp)
> {
> if (interp != NULL)
> return &interp->procs;
>
> return ¤t_interpreter->procs;
> }
>
> /* Accessor function. Not used at the moment. */
> void *
> gdb_interpreter_get_data (struct gdb_interpreter *interp)
> {
> if (interp != NULL)
> return interp->data;
>
> return current_interpreter->data;
> }
>
> /* A convenience routine that nulls out all the
> common command hooks. Use it when removing your interpreter in its
> suspend proc. */
> void
> clear_interpreter_hooks ()
> {
> init_ui_hook = 0;
> print_frame_info_listing_hook = 0;
> /*print_frame_more_info_hook = 0; */
> query_hook = 0;
> warning_hook = 0;
> create_breakpoint_hook = 0;
> delete_breakpoint_hook = 0;
> modify_breakpoint_hook = 0;
> interactive_hook = 0;
> registers_changed_hook = 0;
> readline_begin_hook = 0;
> readline_hook = 0;
> readline_end_hook = 0;
> register_changed_hook = 0;
> memory_changed_hook = 0;
> context_hook = 0;
> target_wait_hook = 0;
> call_command_hook = 0;
> error_hook = 0;
> error_begin_hook = 0;
> command_loop_hook = 0;
> clear_gdb_event_hooks ();
> }
>
> /* 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... */
> }
>
> void
> interpreter_exec_cmd (char *args, int from_tty)
> {
> struct gdb_interpreter *old_interp, *interp_to_use;
> char **prules = NULL;
> char **trule = NULL;
> unsigned int nrules;
> unsigned int i;
> int old_quiet, use_quiet;
>
> prules = buildargv (args);
> if (prules == NULL)
> {
> error ("unable to parse arguments");
> }
>
> nrules = 0;
> if (prules != NULL)
> {
> for (trule = prules; *trule != NULL; trule++)
> {
> nrules++;
> }
> }
>
> if (nrules < 2)
> error ("usage: interpreter-exec <interpreter> [ <command> ... ]");
>
> old_interp = gdb_interpreter_current ();
>
> interp_to_use = gdb_interpreter_lookup (prules[0]);
> if (interp_to_use == NULL)
> error ("Could not find interpreter \"%s\".", prules[0]);
>
> /* Temporarily set interpreters quiet */
> old_quiet = gdb_interpreter_set_quiet (old_interp, 1);
> use_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);
>
> if (!gdb_interpreter_set (interp_to_use))
> error ("Could not switch to interpreter \"%s\".", prules[0]);
>
> for (i = 1; i < nrules; i++)
> {
> if (!gdb_interpreter_exec (prules[i]))
> {
> gdb_interpreter_set (old_interp);
> gdb_interpreter_set_quiet (interp_to_use, old_quiet);
> error ("error in command: \"%s\".", prules[i]);
> break;
> }
> }
>
> gdb_interpreter_set (old_interp);
> gdb_interpreter_set_quiet (interp_to_use, use_quiet);
> gdb_interpreter_set_quiet (old_interp, old_quiet);
> }
>
> /* List the possible interpreters which could complete the given text. */
> static char **
> interpreter_completer (char *text, char *word)
> {
> int alloced = 0;
> int textlen;
> int num_matches;
> char **matches;
> struct gdb_interpreter *interp;
>
> /* We expect only a very limited number of interpreters, so just
> allocate room for all of them. */
> for (interp = interp_list; interp != NULL; interp = interp->next)
> ++alloced;
> matches = (char **) xmalloc (alloced * sizeof (char *));
>
> num_matches = 0;
> textlen = strlen (text);
> for (interp = interp_list; interp != NULL; interp = interp->next)
> {
> 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;
> }
> }
>
> if (num_matches == 0)
> {
> xfree (matches);
> matches = NULL;
> }
> else if (num_matches < alloced)
> {
> matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
> * sizeof (char *)));
> matches[num_matches] = NULL;
> }
>
> return matches;
> }
>
> /* This just adds the "interpreter-exec" command. */
> void
> _initialize_interpreter (void)
> {
> struct cmd_list_element *c;
>
> c = add_cmd ("interpreter-exec", class_support,
> interpreter_exec_cmd,
> "Execute a command in an interpreter. It takes two arguments:\n\
> The first argument is the name of the interpreter to use.\n\
> The second argument is the command to execute.\n", &cmdlist);
> set_cmd_completer (c, interpreter_completer);
> }
>
>
>
> /* CLI Definitions for GDB
> Copyright 2002 Free Software Foundation, Inc.
>
> This file is part of GDB.
>
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330,
> Boston, MA 02111-1307, USA. */
>
> #include "defs.h"
> #include "interps.h"
> #include "wrapper.h"
> #include "event-top.h"
> #include "ui-out.h"
> #include "cli-out.h"
> #include "top.h" /* for "execute_command" */
> /* Prototypes for the CLI Interpreter functions */
>
> static int cli_interpreter_init (void *data);
> static int cli_interpreter_resume (void *data);
> static int cli_interpreter_suspend (void *data);
> static int cli_interpreter_exec (void *data, char *command_str);
> static int cli_interpreter_display_prompt_p (void);
>
> /* These are the ui_out and the interpreter for the console interpreter. */
> static struct ui_out *cli_uiout;
> static struct gdb_interpreter *cli_interp;
>
> /* Longjmp-safe wrapper for "execute_command" */
> static int do_captured_execute_command (struct ui_out *uiout, void *data);
> static enum gdb_rc safe_execute_command (struct ui_out *uiout, char *command,
> int from_tty);
> struct captured_execute_command_args
> {
> char *command;
> int from_tty;
> };
>
> /* These implement the cli out interpreter: */
>
> static int
> cli_interpreter_init (void *data)
> {
> return 1;
> }
>
> static int
> cli_interpreter_resume (void *data)
> {
> /*sync_execution = 1;*/
> gdb_setup_readline ();
> return 1;
> }
>
> static int
> cli_interpreter_suspend (void *data)
> {
> gdb_disable_readline ();
> return 1;
> }
>
> /* Don't display the prompt if we are set quiet. */
> static int
> cli_interpreter_display_prompt_p (void)
> {
> if (gdb_interpreter_is_quiet_p (NULL))
> return 0;
> else
> return 1;
> }
>
> static int
> cli_interpreter_exec (void *data, char *command_str)
> {
> int result;
> struct ui_file *old_stream;
>
> /* gdb_stdout could change between the time cli_uiout was initialized
> and now. Since we're probably using a different interpreter which has
> a new ui_file for gdb_stdout, use that one instead of the default.
>
> 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, command_str, 1);
> cli_out_set_stream (cli_uiout, old_stream);
> return result;
> }
>
> static int
> do_captured_execute_command (struct ui_out *uiout, void *data)
> {
> struct captured_execute_command_args *args =
> (struct captured_execute_command_args *) data;
> execute_command (args->command, args->from_tty);
> return GDB_RC_OK;
> }
>
> static enum gdb_rc
> safe_execute_command (struct ui_out *uiout, char *command, int from_tty)
> {
> struct captured_execute_command_args args;
> args.command = command;
> args.from_tty = from_tty;
> return catch_exceptions (uiout, do_captured_execute_command, &args,
> NULL, RETURN_MASK_ALL);
> }
>
> /* standard gdb initialization hook */
> void
> _initialize_cli_interp (void)
> {
> struct gdb_interpreter_procs procs = {
> cli_interpreter_init, /* init_proc */
> cli_interpreter_resume, /* resume_proc */
> cli_interpreter_suspend, /* suspend_proc */
> cli_interpreter_exec, /* exec_proc */
> cli_interpreter_display_prompt_p /* prompt_proc_p */
> };
>
> /* Create a default uiout builder for the CLI. */
> cli_uiout = cli_out_new (gdb_stdout);
> cli_interp = gdb_interpreter_new (GDB_INTERPRETER_CONSOLE, NULL, cli_uiout,
> &procs);
> gdb_interpreter_add (cli_interp);
> }
>
>
>
> /* MI Interpreter Definitions and Commands
> Copyright 2002 Free Software Foundation, Inc.
>
> This file is part of GDB.
>
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
>
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> GNU General Public License for more details.
>
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330,
> Boston, MA 02111-1307, USA. */
>
> #include "defs.h"
> #include "gdb_string.h"
> #include "interps.h"
> #include "event-top.h"
> #include "event-loop.h"
> #include "inferior.h"
> #include "ui-out.h"
> #include "top.h"
>
> #include "mi.h"
> #include "mi-cmds.h"
> #include "mi-out.h"
> #include "mi-console.h"
>
> /* MI's output channels */
> struct ui_file *mi_stdout;
> struct ui_file *mi_stderr;
> struct ui_file *mi_stdlog;
> struct ui_file *mi_stdtarg;
> struct ui_file *mi_event_channel;
>
> /* This is the interpreter for the mi... */
> struct gdb_interpreter *mi2_interp;
> struct gdb_interpreter *mi1_interp;
> struct gdb_interpreter *mi_interp;
>
> /* These are the interpreter setup, etc. functions for the MI interpreter */
> static int mi_interpreter_init (void *data);
> static int mi_interpreter_resume (void *data);
> static int mi_interpreter_suspend (void *data);
> static int mi_interpreter_exec (void *data, char *command);
> static int mi_interpreter_prompt_p (void);
>
> static void mi_execute_command_wrapper (char *cmd);
> static void mi_command_loop (int mi_version);
> static char *mi_input (char *);
>
> /* These are hooks that we put in place while doing interpreter_exec
> so we can report interesting things that happened "behind the mi's
> back" in this command */
> static int mi_interp_query_hook (const char *ctlstr, va_list ap);
> static char *mi_interp_read_one_line_hook (char *prompt, int repeat,
> char *anno);
>
> static void mi2_command_loop (void);
> static void mi1_command_loop (void);
>
> static void mi_insert_notify_hooks (void);
> static void mi_remove_notify_hooks (void);
>
> static int
> mi_interpreter_init (void *data)
> {
> static struct gdb_events handlers;
>
> /* Why is this a part of the mi architecture? */
>
> mi_setup_architecture_data ();
>
> /* HACK: We need to force stdout/stderr to point at the console. This avoids
> any potential side effects caused by legacy code that is still
> using the TUI / fputs_unfiltered_hook. So we set up output channels for
> this now, and swap them in when we are run. */
>
> raw_stdout = stdio_fileopen (stdout);
>
> /* Create MI channels */
> mi_stdout = mi_console_file_new (raw_stdout, "~", '"');
> mi_stderr = mi_console_file_new (raw_stdout, "&", '"');
> mi_stdlog = mi_stderr;
> mi_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
> mi_event_channel = mi_console_file_new (raw_stdout, "=", 0);
>
> return 1;
> }
>
> static int
> mi_interpreter_resume (void *data)
> {
> /* As per hack note in mi_interpreter_init, swap in the output channels... */
>
> gdb_setup_readline ();
> mi_register_gdbarch_swap ();
>
> if (event_loop_p)
> {
> /* These overwrite some of the initialization done in
> _intialize_event_loop. */
> call_readline = gdb_readline2;
> input_handler = mi_execute_command_wrapper;
> add_file_handler (input_fd, stdin_event_handler, 0);
> async_command_editing_p = 0;
> /* FIXME: This is a total hack for now. PB's use of the MI implicitly
> relies on a bug in the async support which allows asynchronous
> commands to leak through the commmand loop. The bug involves
> (but is not limited to) the fact that sync_execution was
> erroneously initialized to 0. Duplicate by initializing it
> thus here... */
> sync_execution = 0;
> }
>
> gdb_stdout = mi_stdout;
> /* Route error and log output through the MI */
> gdb_stderr = mi_stderr;
> gdb_stdlog = mi_stdlog;
> /* Route target output through the MI. */
> gdb_stdtarg = mi_stdtarg;
>
> /* Replace all the hooks that we know about. There really needs to
> be a better way of doing this... */
> clear_interpreter_hooks ();
> set_gdb_event_hooks (&mi_event_handlers);
>
> show_load_progress = mi_load_progress;
>
> /* If we're _the_ interpreter, take control. */
> if (gdb_interpreter_current_is_named_p (GDB_INTERPRETER_MI2))
> command_loop_hook = mi2_command_loop;
> else if (gdb_interpreter_current_is_named_p (GDB_INTERPRETER_MI1))
> command_loop_hook = mi1_command_loop;
> else if (gdb_interpreter_current_is_named_p (GDB_INTERPRETER_MI))
> command_loop_hook = mi2_command_loop;
> else
> return 0;
>
> return 1;
> }
>
> static int
> mi_interpreter_suspend (void *data)
> {
> gdb_disable_readline ();
> return 1;
> }
>
> static int
> mi_interpreter_exec (void *data, char *command)
> {
> mi_execute_command_wrapper (command);
> return 1;
> }
>
> /* Never display the default gdb prompt in mi case. */
> static int
> mi_interpreter_prompt_p (void)
> {
> return 0;
> }
>
> static void
> mi_interpreter_exec_continuation (struct continuation_arg *arg)
> {
> bpstat_do_actions (&stop_bpstat);
> if (!target_executing)
> {
> fputs_unfiltered ("*stopped", raw_stdout);
> mi_out_put (uiout, raw_stdout);
> fputs_unfiltered ("\n", raw_stdout);
> fputs_unfiltered ("(gdb) \n", raw_stdout);
> gdb_flush (raw_stdout);
> do_exec_cleanups (ALL_CLEANUPS);
> }
> else if (target_can_async_p ())
> {
> add_continuation (mi_interpreter_exec_continuation, NULL);
> }
> }
>
> enum mi_cmd_result
> mi_cmd_interpreter_exec (char *command, char **argv, int argc)
> {
> struct gdb_interpreter *interp_to_use;
> enum mi_cmd_result result = MI_CMD_DONE;
> int i;
> struct gdb_interpreter_procs *procs;
>
> if (argc < 2)
> {
> xasprintf (&mi_error_message,
> "mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
> return MI_CMD_ERROR;
> }
>
> interp_to_use = gdb_interpreter_lookup (argv[0]);
> if (interp_to_use == NULL)
> {
> xasprintf (&mi_error_message,
> "mi_cmd_interpreter_exec: could not find interpreter \"%s\"",
> argv[0]);
> return MI_CMD_ERROR;
> }
>
> procs = gdb_interpreter_get_procs (interp_to_use);
> if (!procs->exec_proc)
> {
> xasprintf (&mi_error_message,
> "mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
> argv[0]);
> return MI_CMD_ERROR;
> }
>
> /* Insert the MI out hooks, making sure to also call the interpreter's hooks
> if it has any. */
> /* KRS: We shouldn't need this... Events should be installed and they should
> just ALWAYS fire something out down the MI channel... */
> mi_insert_notify_hooks ();
>
> /* Now run the code... */
>
> for (i = 1; i < argc; i++)
> {
> char *buff = NULL;
> /* Do this in a cleaner way... We want to force execution to be
> asynchronous for commands that run the target. */
> if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
> {
> int len = strlen (argv[i]);
> buff = xmalloc (len + 2);
> memcpy (buff, argv[i], len);
> buff[len] = '&';
> buff[len + 1] = '\0';
> }
>
> /* We had to set sync_execution = 0 for the mi (well really for Project
> Builder's use of the mi - particularly so interrupting would work.
> But for console commands to work, we need to initialize it to 1 -
> since that is what the cli expects - before running the command,
> and then set it back to 0 when we are done. */
> sync_execution = 1;
> if (procs->exec_proc (gdb_interpreter_get_data (interp_to_use), argv[i]) < 0)
> {
> mi_error_last_message ();
> result = MI_CMD_ERROR;
> break;
> }
> xfree (buff);
> do_exec_error_cleanups (ALL_CLEANUPS);
> sync_execution = 0;
> }
>
> mi_remove_notify_hooks ();
>
> /* Okay, now let's see if the command set the inferior going...
> Tricky point - have to do this AFTER resetting the interpreter, since
> changing the interpreter will clear out all the continuations for
> that interpreter... */
>
> if (target_can_async_p () && target_executing)
> {
> fputs_unfiltered ("^running\n", raw_stdout);
> add_continuation (mi_interpreter_exec_continuation, NULL);
> }
>
> return result;
> }
>
> /*
> * mi_insert_notify_hooks - This inserts a number of hooks that are meant to produce
> * async-notify ("=") MI messages while running commands in another interpreter
> * using mi_interpreter_exec. The canonical use for this is to allow access to
> * the gdb CLI interpreter from within the MI, while still producing MI style output
> * when actions in the CLI command change gdb's state.
> */
>
> static void
> mi_insert_notify_hooks (void)
> {
> query_hook = mi_interp_query_hook;
> }
>
> static void
> mi_remove_notify_hooks ()
> {
> query_hook = NULL;
> }
>
> static int
> mi_interp_query_hook (const char *ctlstr, va_list ap)
> {
> return 1;
> }
>
> static char *
> mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
> {
> static char buff[256];
> printf_unfiltered ("=read-one-line,prompt=\"%s\"\n", prompt);
> gdb_flush (gdb_stdout);
> (void) fgets (buff, sizeof (buff), stdin);
> buff[(strlen (buff) - 1)] = 0;
> return buff;
> }
>
> static void
> output_control_change_notification (char *notification)
> {
> printf_unfiltered ("^");
> printf_unfiltered ("%s\n", notification);
> gdb_flush (gdb_stdout);
> }
>
> static void
> mi_execute_command_wrapper (char *cmd)
> {
> mi_execute_command (cmd, stdin == instream);
> }
>
> static void
> mi1_command_loop (void)
> {
> mi_command_loop (1);
> }
>
> static void
> mi2_command_loop (void)
> {
> mi_command_loop (2);
> }
>
> static void
> mi_command_loop (int mi_version)
> {
> #if 0
> /* HACK: Force stdout/stderr to point at the console. This avoids
> any potential side effects caused by legacy code that is still
> using the TUI / fputs_unfiltered_hook */
> raw_stdout = stdio_fileopen (stdout);
> /* Route normal output through the MIx */
> gdb_stdout = mi_console_file_new (raw_stdout, "~", '"');
> /* Route error and log output through the MI */
> gdb_stderr = mi_console_file_new (raw_stdout, "&", '"');
> gdb_stdlog = gdb_stderr;
> /* Route target output through the MI. */
> gdb_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
> /* HACK: Poke the ui_out table directly. Should we be creating a
> mi_out object wired up to the above gdb_stdout / gdb_stderr? */
> uiout = mi_out_new (mi_version);
> /* HACK: Override any other interpreter hooks. We need to create a
> real event table and pass in that. */
> init_ui_hook = 0;
> /* command_loop_hook = 0; */
> print_frame_info_listing_hook = 0;
> query_hook = 0;
> warning_hook = 0;
> create_breakpoint_hook = 0;
> delete_breakpoint_hook = 0;
> modify_breakpoint_hook = 0;
> interactive_hook = 0;
> registers_changed_hook = 0;
> readline_begin_hook = 0;
> readline_hook = 0;
> readline_end_hook = 0;
> register_changed_hook = 0;
> memory_changed_hook = 0;
> context_hook = 0;
> target_wait_hook = 0;
> call_command_hook = 0;
> error_hook = 0;
> error_begin_hook = 0;
> show_load_progress = mi_load_progress;
> #endif
> /* Turn off 8 bit strings in quoted output. Any character with the
> high bit set is printed using C's octal format. */
> sevenbit_strings = 1;
> /* Tell the world that we're alive */
> fputs_unfiltered ("(gdb) \n", raw_stdout);
> gdb_flush (raw_stdout);
> if (!event_loop_p)
> simplified_command_loop (mi_input, mi_execute_command);
> else
> start_event_loop ();
> }
>
> static char *
> mi_input (char *buf)
> {
> return gdb_readline (NULL);
> }
>
> void
> _initialize_mi_interp (void)
> {
> struct gdb_interpreter_procs procs =
> {
> mi_interpreter_init, /* init_proc */
> mi_interpreter_resume, /* resume_proc */
> mi_interpreter_suspend, /* suspend_proc */
> mi_interpreter_exec, /* exec_proc */
> mi_interpreter_prompt_p /* prompt_proc_p */
> };
>
> /* Create MI1 interpreter */
> if (mi1_interp == NULL)
> {
> mi1_interp =
> gdb_interpreter_new (GDB_INTERPRETER_MI1, NULL, mi_out_new (1),
> &procs);
> if (mi1_interp == NULL)
> error
> ("Couldn't allocate a new interpreter for the mi1 interpreter\n");
> if (gdb_interpreter_add (mi1_interp) != 1)
> error ("Couldn't add the mi1 interpreter to gdb.\n");
> }
>
> /* Create MI2 interpreter */
> if (mi2_interp == NULL)
> {
> mi2_interp =
> gdb_interpreter_new (GDB_INTERPRETER_MI2, NULL, mi_out_new (2),
> &procs);
> if (mi2_interp == NULL)
> error
> ("Couldn't allocate a new interpreter for the mi2 interpreter\n");
> if (gdb_interpreter_add (mi2_interp) != 1)
> error ("Couldn't add the mi2 interpreter to gdb.\n");
> }
>
> /* Create MI3 interpreter */
> if (mi_interp == NULL)
> {
> mi_interp =
> gdb_interpreter_new (GDB_INTERPRETER_MI, NULL, mi_out_new (3),
> &procs);
> if (mi_interp == NULL)
> error
> ("Couldn't allocate a new interpreter for the mi interpreter\n");
> if (gdb_interpreter_add (mi_interp) != 1)
> error ("Couldn't add the mi interpreter to gdb.\n");
> }
> }