From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27252 invoked by alias); 22 Sep 2002 22:40:11 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 27242 invoked from network); 22 Sep 2002 22:40:09 -0000 Received: from unknown (HELO localhost.redhat.com) (66.30.197.194) by sources.redhat.com with SMTP; 22 Sep 2002 22:40:09 -0000 Received: by localhost.redhat.com (Postfix, from userid 469) id 1D816106CC; Sun, 22 Sep 2002 18:38:11 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <15758.18002.952488.418867@localhost.redhat.com> Date: Sun, 22 Sep 2002 15:40:00 -0000 To: Keith Seitz Cc: gdb-patches@sources.redhat.com Subject: Re: [RFC] Interpreters (~final) (fwd) In-Reply-To: References: X-SW-Source: 2002-09/txt/msg00562.txt.bz2 Keith Seitz writes: > Ping. > At last.... OK, it seems innocuous enough, but I miss to see how it interacts with the event loop and the rest of gdb. I compiled it (modified the Makefile.in) and noticed a warning with alloced initialized. It should be initialized to 0. Can you just post the bare minimum that will make the MI accept interpreter-exec? Even if it won't be able to do much? We can trim the testsuite file down to what passes, if necessary. Thanks Elena > Last merge of trunk into kseitz_interps-20020528-branch was done on 29 Aug > 2002. > ---------- Forwarded message ---------- > Date: Tue, 27 Aug 2002 09:17:10 -0700 (PDT) > From: Keith Seitz > To: gdb-patches@sources.redhat.com > Subject: [RFC] Interpreters (~final) (fwd) > > Ping. > > ---------- Forwarded message ---------- > Date: Tue, 13 Aug 2002 13:22:46 -0700 (PDT) > From: Keith Seitz > To: gdb-patches@sources.redhat.com > Subject: [RFC] Interpreters (~final) > > Hi, > > Well, at long last, I think I am ready to try and get some of this work > approved. > > So, first on the chopping block: interps.c, interps.h. > > ChangeLogs (to be massaged appropriately): > 2002-08-13 Keith Seitz > > * interps.c (_initialize_interpreter): Remove ability to set > the interpreter. This could really undermine MI clients. > * top.c (catcher): Don't worry about interpreter changes. > > 2002-08-12 Keith Seitz > > * interps.c (_initialize_interpreter): Add completer function > to "set interpreter" command. > > 2002-08-12 Keith Seitz > > * interps.c: Run through gdb_indent.sh > * interps.h: Ditto. > > 2002-06-24 Keith Seitz > > * interps.c: Include gdb-events.h. > (clear_interpreter_hooks): Also clear out event handlers. > (gdb_set_interpreter): Clear out any hooks/event handlers that > may have been installed by old interpreter. > > 2002-06-18 Keith Seitz > > * interps.h: Add GDB_INTERPRETER_MI1. GDB_INTERPRETER_MI will > now be mi version 2. > > 2002-05-28 Keith Seitz > > * interps.c: New file. (Originally called interpreter.c by Apple) > * interps.h: New file. (Originally called interpreter.h by Apple) > > "Patch" > See appeneded files, interps.h and interps.c > > For the curious, you can play with the whole thing by checking out > kseitz_interps-20020528-branch, which was last merged with cvs HEAD on 9 > Aug 2002. The branch contains testcases, documentation, etc, too. > > It probably isn't perfect, but it's at least a place to start (IMO). There > are no regressions with this compared to gdb of 9 Aug 2002. > > Questions/comments welcome. > Keith > /* Manages interpreters for gdb. > Copyright 2000,2002 Free Software Foundation, Inc. > Written by Jim Ingham 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_do_one_event_ftype) (void *data); > typedef int (*interp_suspend_ftype) (void *data); > typedef int (*interp_delete_ftype) (void *data); > typedef int (*interp_prompt_ftype) (void *data, char *new_prompt); > 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_do_one_event_ftype do_one_event_proc; > interp_suspend_ftype suspend_proc; > interp_delete_ftype delete_proc; > interp_exec_ftype exec_proc; > interp_prompt_ftype prompt_proc; > }; > > extern struct gdb_interpreter > *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout, > struct gdb_interpreter_procs *procs); > > extern int gdb_add_interpreter (struct gdb_interpreter *interp); > extern int gdb_delete_interpreter (struct gdb_interpreter *interp); > extern int gdb_set_interpreter (struct gdb_interpreter *interp); > extern struct gdb_interpreter *gdb_lookup_interpreter (char *name); > extern struct gdb_interpreter *gdb_current_interpreter (); > extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp); > extern int gdb_current_interpreter_is_named (char *interp_name); > extern int gdb_interpreter_exec (char *command_str); > extern int gdb_interpreter_display_prompt (char *new_prompt); > extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp, > int quiet); > extern int gdb_interpreter_is_quiet (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 int interpreter_do_one_event (); > > void clear_interpreter_hooks (); > > /* well-known interpreters */ > #define GDB_INTERPRETER_CONSOLE "console" > #define GDB_INTERPRETER_MI0 "mi0" > #define GDB_INTERPRETER_MI1 "mi1" > #define GDB_INTERPRETER_MI "mi" > #endif /* GDB_INTERPRETER_H */ > /* Manages interpreters for gdb. > Copyright 2000, 2002 Free Software Foundation, Inc. > Written by Jim Ingham 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. > > 2) The event loop insertion is probably wrong. I just inserted a > do_one_event alongside gdb's do_one_event. This probably will lead > to one or the other event loop getting starved. It would be better > to provide conversion functions for the gdb file handlers, and when > an interpreter starts up, it grabs all the gdb created file handlers > and inserts them into its select. This is more complicated, however, > and I have run out of time for now. > */ > > #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 > { > char *name; /* This is the name in "-i=" and set interpreter. */ > struct gdb_interpreter *next; /* Interpreters are stored in a linked list, > this is the next one... */ > void *data; /* This is a cookie that the instance of the > interpreter can use, for instance to call > itself in hook functions */ > int inited; /* Has the init_proc been run? */ > struct ui_out *interpreter_out; /* 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 gdb_interpreter_procs procs; > int quiet_p; > }; > > /* Functions local to this file. */ > static void initialize_interps (void); > > static void set_interpreter_cmd (char *args, int from_tty, > struct cmd_list_element *c); > static void list_interpreter_cmd (char *args, int from_tty); > static void do_set_interpreter (int not_an_fd); > 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_new_interpreter - This allocates space for a new interpreter, > fills the fields from the inputs, and returns a pointer to the > interpreter. */ > > struct gdb_interpreter * > gdb_new_interpreter (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.do_one_event_proc = procs->do_one_event_proc; > new_interp->procs.suspend_proc = procs->suspend_proc; > new_interp->procs.delete_proc = procs->delete_proc; > new_interp->procs.exec_proc = procs->exec_proc; > new_interp->procs.prompt_proc = procs->prompt_proc; > 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_add_interpreter (struct gdb_interpreter *interp) > { > if (!interpreter_initialized) > initialize_interps (); > > if (gdb_lookup_interpreter (interp->name) != NULL) > return 0; > > interp->next = interp_list; > interp_list = interp; > > return 1; > } > > /* Looks for the interpreter INTERP in the interpreter list. If it exists, > runs the delete_proc, and if this is successful, the INTERP is deleted from > the interpreter list and the function returns 1. If the delete_proc fails, the > function returns -1 and the interpreter is NOT removed from the list. If the > interp is not found, 0 is returned. */ > > int > gdb_delete_interpreter (struct gdb_interpreter *interp) > { > struct gdb_interpreter *cur_ptr, *prev_ptr; > > if (!interpreter_initialized) > { > ui_out_message (uiout, 0, > "You can't delete an interp before you have added one!"); > return -1; > } > > if (interp_list == NULL) > { > ui_out_message (uiout, 0, "No interpreters to delete."); > return -1; > } > > if (interp_list->next == NULL) > { > ui_out_message (uiout, 0, "You can't delete gdb's only intepreter."); > return -1; > } > > for (cur_ptr = interp_list, prev_ptr = NULL; > cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next) > { > if (cur_ptr == interp) > { > /* Can't currently delete the console interpreter... */ > if (strcmp (interp->name, "console") == 0) > { > ui_out_message (uiout, 0, > "You can't delete the console interpreter."); > return -1; > } > > /* If the interpreter is the current interpreter, switch > back to the console interpreter */ > > if (interp == current_interpreter) > { > gdb_set_interpreter (gdb_lookup_interpreter ("console")); > } > > /* Don't delete the interpreter if its delete proc fails */ > > if ((interp->procs.delete_proc != NULL) > && (!interp->procs.delete_proc (interp->data))) > return -1; > > if (cur_ptr == interp_list) > interp_list = cur_ptr->next; > else > prev_ptr->next = cur_ptr->next; > > break; > } > } > > if (cur_ptr == NULL) > return 0; > else > 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_set_interpreter (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_set_interpreter (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_set_interpreter (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 (interp)) > { > sprintf (buffer, "Switching to interpreter \"%.24s\".\n", > interp->name); > ui_out_text (uiout, buffer); > } > display_gdb_prompt (NULL); > } > > return 1; > } > > /* > * gdb_lookup_interpreter - Looks up the interpreter for NAME. If > * no such interpreter exists, return NULL, otherwise return a pointer > * to the interpreter. > */ > > struct gdb_interpreter * > gdb_lookup_interpreter (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. */ > > struct gdb_interpreter * > gdb_current_interpreter () > { > 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_current_interpreter_is_named (char *interp_name) > { > struct gdb_interpreter *current_interp = gdb_current_interpreter (); > > if (current_interp) > return (strcmp (current_interp->name, interp_name) == 0); > > return 0; > } > > /* This is called in display_gdb_prompt. > If the current interpreter defines a prompt_proc, then that proc is > run. If the proc returns a non-zero value, display_gdb_prompt will > return without itself displaying the prompt. */ > > int > gdb_interpreter_display_prompt (char *new_prompt) > { > if (current_interpreter->procs.prompt_proc == NULL) > return 0; > else > return current_interpreter->procs.prompt_proc (current_interpreter->data, > new_prompt); > } > > int > gdb_interpreter_is_quiet (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; > } > > struct gdb_interpreter_procs * > gdb_interpreter_get_procs (struct gdb_interpreter *interp) > { > if (interp != NULL) > return &interp->procs; > > return ¤t_interpreter->procs; > } > > void * > gdb_interpreter_get_data (struct gdb_interpreter *interp) > { > if (interp != NULL) > return interp->data; > > return current_interpreter->data; > } > > int > interpreter_do_one_event () > { > if (current_interpreter->procs.do_one_event_proc == NULL) > return 0; > > return current_interpreter->procs.do_one_event_proc (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... */ > } > > /* set_interpreter_cmd - This implements "set interpreter foo". */ > > static void > set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c) > { > struct gdb_interpreter *interp_ptr; > > dont_repeat (); > > if (cmd_type (c) != set_cmd) > return; > > interp_ptr = gdb_lookup_interpreter (interpreter_p); > if (interp_ptr != NULL) > { > if (!gdb_set_interpreter (interp_ptr)) > error ("\nCould not switch to interpreter \"%s\", %s%s\".\n", > interp_ptr->name, "reverting to interpreter \"", > current_interpreter->name); > } > else > { > char *bad_name = interpreter_p; > interpreter_p = xstrdup (current_interpreter->name); > error ("Could not find interpreter \"%s\".", bad_name); > } > } > > /* list_interpreter_cmd - This implements "info interpreters". */ > > void > list_interpreter_cmd (char *args, int from_tty) > { > struct gdb_interpreter *interp_ptr; > > ui_out_list_begin (uiout, "interpreters"); > for (interp_ptr = interp_list; interp_ptr != NULL; > interp_ptr = interp_ptr->next) > { > ui_out_text (uiout, " * "); > ui_out_field_string (uiout, "interpreter", interp_ptr->name); > ui_out_text (uiout, "\n"); > } > ui_out_list_end (uiout); > } > > 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; > > 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 [ ... ]"); > > old_interp = gdb_current_interpreter (); > > interp_to_use = gdb_lookup_interpreter (prules[0]); > if (interp_to_use == NULL) > error ("Could not find interpreter \"%s\".", prules[0]); > > old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1); > > if (!gdb_set_interpreter (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_set_interpreter (old_interp); > gdb_interpreter_set_quiet (interp_to_use, old_quiet); > error > ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".", > prules[i]); > break; > } > } > > gdb_set_interpreter (old_interp); > gdb_interpreter_set_quiet (interp_to_use, old_quiet); > } > > /* List the possible interpreters which could complete the given text. */ > > static char ** > interpreter_completer (char *text, char *word) > { > int alloced, 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 "set interpreter" and "info interpreters" commands. */ > > 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); > }