This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC/PATCH] interpreters part 1: new files


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 &current_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");
 >     }
 > }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]