diff options
-rw-r--r-- | gdb/cli/cli-interp.c | 114 | ||||
-rw-r--r-- | gdb/interps.c | 659 | ||||
-rw-r--r-- | gdb/interps.h | 74 | ||||
-rw-r--r-- | gdb/mi/mi-events.c | 148 | ||||
-rw-r--r-- | gdb/mi/mi-interp.c | 500 | ||||
-rw-r--r-- | gdb/mi/mi.h | 43 |
6 files changed, 1538 insertions, 0 deletions
diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c new file mode 100644 index 0000000..db66492 --- /dev/null +++ b/gdb/cli/cli-interp.c @@ -0,0 +1,114 @@ +/* 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" + +/* Prototypes for the CLI Interpreter functions */ + +int cli_interpreter_init (void *data); +int cli_interpreter_resume (void *data); +int cli_interpreter_do_one_event (void *data); +int cli_interpreter_suspend (void *data); +int cli_interpreter_delete (void *data); +int cli_interpreter_exec (void *data, char *command_str); +int cli_interpreter_display_prompt (void *data, char *new_prompt); + +/* These are the ui_out and the interpreter for the console interpreter. */ +struct ui_out *cli_uiout; +struct gdb_interpreter *cli_interp; + +/* These implement the cli out interpreter: */ + +int +cli_interpreter_init (void *data) +{ + return 1; +} + +int +cli_interpreter_resume (void *data) +{ + /*sync_execution = 1;*/ + gdb_setup_readline (); + return 1; +} + +int +cli_interpreter_do_one_event (void *data) +{ + return 1; +} + +int +cli_interpreter_suspend (void *data) +{ + gdb_disable_readline (); + return 1; +} + +int +cli_interpreter_delete (void *data) +{ + return 1; +} + +int +cli_interpreter_display_prompt (void *data, char *new_prompt) +{ + if (gdb_interpreter_is_quiet (NULL)) + { + return 1; + } + else + { + return 0; + } +} + +int +cli_interpreter_exec (void *data, char *command_str) +{ + return gdb_execute_command (uiout, command_str, 0); +} + +/* 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_do_one_event, /* do_one_event_proc */ + cli_interpreter_suspend, /* suspend_proc */ + cli_interpreter_delete, /* delete_proc */ + cli_interpreter_exec, /* exec_proc */ + cli_interpreter_display_prompt /* prompt_proc */ + }; + + cli_uiout = cli_out_new (gdb_stdout); + cli_interp = gdb_new_interpreter (GDB_INTERPRETER_CONSOLE, NULL, cli_uiout, + &procs); + gdb_add_interpreter (cli_interp); +} diff --git a/gdb/interps.c b/gdb/interps.c new file mode 100644 index 0000000..4b9b901 --- /dev/null +++ b/gdb/interps.c @@ -0,0 +1,659 @@ +/* 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. + + 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" + +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; + } + } + + 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; +} + +/* 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 <interpreter> [ <command> ... ]"); + + 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_set_cmd ("interpreter", class_support, + var_string, + &interpreter_p, "Set the interpreter for gdb.", &setlist); + set_cmd_sfunc (c, set_interpreter_cmd); + add_show_from_set (c, &showlist); + + add_cmd ("interpreters", class_support, + list_interpreter_cmd, + "List the interpreters currently available in gdb.", &infolist); + + 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); +} diff --git a/gdb/interps.h b/gdb/interps.h new file mode 100644 index 0000000..05420b1 --- /dev/null +++ b/gdb/interps.h @@ -0,0 +1,74 @@ +/* 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_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_MI "mi" +#define GDB_INTERPRETER_MI0 "mi0" + +#endif /* GDB_INTERPRETER_H */ diff --git a/gdb/mi/mi-events.c b/gdb/mi/mi-events.c new file mode 100644 index 0000000..1d942a4 --- /dev/null +++ b/gdb/mi/mi-events.c @@ -0,0 +1,148 @@ +/* MI Event Handlers + 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 "ui-out.h" +#include "interps.h" +#include "gdb.h" +#include "breakpoint.h" + +#include "mi.h" + +void +mi_interp_stack_changed_hook (void) +{ + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "stack_changed"); + ui_out_list_end (uiout); + uiout = saved_ui_out; +} + +void +mi_interp_frame_changed_hook (int new_frame_number) +{ + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "frame_changed"); + ui_out_field_int (uiout, "frame", new_frame_number); + ui_out_list_end (uiout); + uiout = saved_ui_out; + +} + +void +mi_interp_context_hook (int thread_id) +{ + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "thread_changed"); + ui_out_field_int (uiout, "thread", thread_id); + ui_out_list_end (uiout); + uiout = saved_ui_out; +} + +void +mi_interp_create_breakpoint_hook (struct breakpoint *bpt) +{ + CORE_ADDR unusued_addr; + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + /* This is a little inefficient, but it probably isn't worth adding + a gdb_breakpoint_query that takes a bpt structure... */ + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "breakpoint_create"); + gdb_breakpoint_query (uiout, bpt->number); + ui_out_list_end (uiout); + uiout = saved_ui_out; +} + +void +mi_interp_modify_breakpoint_hook (struct breakpoint *bpt) +{ + + CORE_ADDR unusued_addr; + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + /* This is a little inefficient, but it probably isn't worth adding + a gdb_breakpoint_query that takes a bpt structure... */ + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "breakpoint_modify"); + gdb_breakpoint_query (uiout, bpt->number); + ui_out_list_end (uiout); + uiout = saved_ui_out; +} + +void +mi_interp_delete_breakpoint_hook (struct breakpoint *bpt) +{ + CORE_ADDR unusued_addr; + struct ui_out *saved_ui_out = uiout; + struct mi_out *tmp_mi_out; + + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + uiout = gdb_interpreter_ui_out (mi0_interp); + else + uiout = gdb_interpreter_ui_out (mi_interp); + + /* This is a little inefficient, but it probably isn't worth adding + a gdb_breakpoint_query that takes a bpt structure... */ + + ui_out_list_begin (uiout, "MI_HOOK_RESULT"); + ui_out_field_string (uiout, "HOOK_TYPE", "breakpoint_delete"); + ui_out_field_int (uiout, "bkptno", bpt->number); + ui_out_list_end (uiout); + uiout = saved_ui_out; +} diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c new file mode 100644 index 0000000..9a91833 --- /dev/null +++ b/gdb/mi/mi-interp.c @@ -0,0 +1,500 @@ +/* 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 "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; + +/* This is the interpreter for the mi... */ +struct gdb_interpreter *mi0_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_do_one_event (void *data); +static int mi_interpreter_suspend (void *data); +static int mi_interpreter_delete (void *data); +static int mi_interpreter_prompt (void *data, char *new_prompt); + +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 void mi_interp_stack_changed_hook (void); +static char *mi_interp_read_one_line_hook (char *prompt, int repeat, + char *anno); + +static void mi0_command_loop (void); +static void mi1_command_loop (void); + +static void mi_insert_notify_hooks (void); +static void mi_remove_notify_hooks (void); + +int +mi_interpreter_init (void *data) +{ + /* 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); + /* Route normal output through the MIx */ + mi_stdout = mi_console_file_new (raw_stdout, "~"); + /* Route error and log output through the MI */ + mi_stderr = mi_console_file_new (raw_stdout, "&"); + mi_stdlog = mi_stderr; + /* Route target output through the MI. */ + mi_stdtarg = mi_console_file_new (raw_stdout, "@"); + + return 1; +} + +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 (); + + show_load_progress = mi_load_progress; + + /* If we're _the_ interpreter, take control. */ + if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)) + command_loop_hook = mi0_command_loop; + else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI)) + command_loop_hook = mi1_command_loop; + else + return 0; + + return 1; +} + +int +mi_interpreter_suspend (void *data) +{ + gdb_disable_readline (); + return 1; +} + +int +mi_interpreter_delete (void *data) +{ + return 1; +} + +int +mi_interpreter_prompt (void *data, char *new_prompt) +{ + return 1; +} + +int +mi_do_one_event (void *data) +{ + return 1; +} + +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 *old_interp, *interp_to_use; + enum mi_cmd_result result = MI_CMD_DONE; + int i, old_quiet; + struct gdb_interpreter_procs *procs; + + if (argc < 2) + { + xasprintf (&mi_error_message, + "Wrong # or arguments, should be \"%s interp cmd <cmd ...>\".", + command); + return MI_CMD_ERROR; + } + + old_interp = gdb_current_interpreter (); + + interp_to_use = gdb_lookup_interpreter (argv[0]); + if (interp_to_use == NULL) + { + xasprintf (&mi_error_message, + "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, + "Interpreter \"%s\" does not support command execution.", + argv[0]); + return MI_CMD_ERROR; + } + old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1); + + if (!gdb_set_interpreter (interp_to_use)) + { + xasprintf (&mi_error_message, + "Could not switch to interpreter \"%s\".", argv[0]); + return MI_CMD_ERROR; + } + + /* Insert the MI out hooks, making sure to also call the interpreter's hooks + if it has any. */ + + 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])) + { + xasprintf (&mi_error_message, + "mi_interpreter_execute: error in command: \"%s\".", + argv[i]); + + result = MI_CMD_ERROR; + break; + } + xfree (buff); + do_exec_error_cleanups (ALL_CLEANUPS); + sync_execution = 0; + + } + + /* Now do the switch... */ + + gdb_set_interpreter (old_interp); + mi_remove_notify_hooks (); + gdb_interpreter_set_quiet (interp_to_use, old_quiet); + + /* 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; +} + +enum mi_cmd_result +mi_cmd_interpreter_set (char *command, char **argv, int argc) +{ + struct gdb_interpreter *interp; + int result; + + if (argc != 1) + { + xasprintf (&mi_error_message, + "mi_cmd_interpreter_set: wrong #of args, should be 1 "); + return MI_CMD_ERROR; + } + interp = gdb_lookup_interpreter (argv[0]); + if (interp == NULL) + { + xasprintf (&mi_error_message, + "mi_cmd_interpreter_set: could not find interpreter %s", + argv[0]); + return MI_CMD_ERROR; + } + + if (interp != gdb_current_interpreter ()) + { + result = gdb_set_interpreter (interp); + if (result != 1) + { + xasprintf (&mi_error_message, + "mi_cmd_interpreter_set: error setting interpreter %s", + argv[0]); + return MI_CMD_ERROR; + } + } + + /* We don't want to put up the "done" and whatnot here, since we + * are going over to another interpreter. + */ + return MI_CMD_QUIET; +} + +/* + * 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) +{ + + create_breakpoint_hook = mi_interp_create_breakpoint_hook; + delete_breakpoint_hook = mi_interp_delete_breakpoint_hook; + modify_breakpoint_hook = mi_interp_modify_breakpoint_hook; + selected_frame_level_changed_hook = mi_interp_frame_changed_hook; + context_hook = mi_interp_context_hook; + query_hook = mi_interp_query_hook; +} + +static void +mi_remove_notify_hooks () +{ + create_breakpoint_hook = NULL; + delete_breakpoint_hook = NULL; + modify_breakpoint_hook = NULL; + selected_frame_level_changed_hook = NULL; + context_hook = NULL; + query_hook = NULL; +} + +int +mi_interp_query_hook (const char *ctlstr, va_list ap) +{ + return 1; +} + +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 +mi0_command_loop (void) +{ + mi_command_loop (0); +} + +static void +mi1_command_loop (void) +{ + mi_command_loop (1); +} + +static void +mi_command_loop (int mi_version) +{ + /* 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; + /* 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 */ + NULL, /* do_one_event_proc */ + mi_interpreter_suspend, /* suspend_proc */ + mi_interpreter_delete, /* delete_proc */ + NULL, /* exec_proc */ + mi_interpreter_prompt /* prompt_proc */ + }; + + if (mi0_interp == NULL) + { + mi0_interp = + gdb_new_interpreter (GDB_INTERPRETER_MI0, NULL, mi_out_new (0), + &procs); + if (mi0_interp == NULL) + error + ("Couldn't allocate a new interpreter for the mi0 interpreter\n"); + if (gdb_add_interpreter (mi0_interp) != 1) + error ("Couldn't add the mi0 interpreter to gdb.\n"); + } + + if (mi_interp == NULL) + { + mi_interp = + gdb_new_interpreter (GDB_INTERPRETER_MI, NULL, mi_out_new (1), + &procs); + if (mi_interp == NULL) + error + ("Couldn't allocate a new interpreter for the mi interpreter\n"); + if (gdb_add_interpreter (mi_interp) != 1) + error ("Couldn't add the mi interpreter to gdb.\n"); + } +} diff --git a/gdb/mi/mi.h b/gdb/mi/mi.h new file mode 100644 index 0000000..cc921e7 --- /dev/null +++ b/gdb/mi/mi.h @@ -0,0 +1,43 @@ +/* MI Internal Functions + 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. */ + +#ifndef MI_H +#define MI_H +/* The mi interpreters. */ +struct gdb_interpreter; +extern struct gdb_interpreter *mi_interp; +extern struct gdb_interpreter *mi0_interp; + +extern void mi_setup_architecture_data (void); +extern void mi_register_gdbarch_swap (void); + +/* Events/Hooks */ +extern void mi_load_progress (const char *section_name, + unsigned long sent_so_far, + unsigned long total_section, + unsigned long total_sent, + unsigned long grand_total); +extern void mi_interp_create_breakpoint_hook (struct breakpoint *bpt); +extern void mi_interp_delete_breakpoint_hook (struct breakpoint *bpt); +extern void mi_interp_modify_breakpoint_hook (struct breakpoint *bpt); +extern void mi_interp_frame_changed_hook (int new_frame_number); +extern void mi_interp_context_hook (int thread_id); + +#endif /* MI_H */ |