summaryrefslogtreecommitdiffstats
path: root/contrib/gdb/gdb/mi/mi-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gdb/gdb/mi/mi-main.c')
-rw-r--r--contrib/gdb/gdb/mi/mi-main.c1527
1 files changed, 1527 insertions, 0 deletions
diff --git a/contrib/gdb/gdb/mi/mi-main.c b/contrib/gdb/gdb/mi/mi-main.c
new file mode 100644
index 0000000..3a59fc8
--- /dev/null
+++ b/contrib/gdb/gdb/mi/mi-main.c
@@ -0,0 +1,1527 @@
+/* MI Command Set.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions (a Red Hat company).
+
+ 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. */
+
+/* Work in progress */
+
+#include "defs.h"
+#include "target.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "top.h"
+#include "gdbthread.h"
+#include "mi-cmds.h"
+#include "mi-parse.h"
+#include "mi-getopt.h"
+#include "mi-console.h"
+#include "ui-out.h"
+#include "mi-out.h"
+#include "event-loop.h"
+#include "event-top.h"
+#include "gdbcore.h" /* for write_memory() */
+#include "value.h" /* for write_register_bytes() */
+#include "regcache.h"
+#include "gdb.h"
+#include <ctype.h>
+#include <sys/time.h>
+
+/* Convenience macro for allocting typesafe memory. */
+
+#undef XMALLOC
+#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE))
+
+enum
+ {
+ FROM_TTY = 0
+ };
+
+
+int mi_debug_p;
+struct ui_file *raw_stdout;
+
+/* The token of the last asynchronous command */
+static char *last_async_command;
+static char *previous_async_command;
+static char *mi_error_message;
+static char *old_regs;
+
+extern void _initialize_mi_main (void);
+static char *mi_input (char *);
+static void mi_execute_command (char *cmd, int from_tty);
+static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
+
+static void mi_execute_cli_command (const char *cli, char *args);
+static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
+static void mi_execute_command_wrapper (char *cmd);
+
+void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
+
+static int register_changed_p (int regnum);
+static int get_register (int regnum, int format);
+static 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);
+
+/* FIXME: these should go in some .h file, but infcmd.c doesn't have a
+ corresponding .h file. These wrappers will be obsolete anyway, once
+ we pull the plug on the sanitization. */
+extern void interrupt_target_command_wrapper (char *, int);
+extern void return_command_wrapper (char *, int);
+
+/* Command implementations. FIXME: Is this libgdb? No. This is the MI
+ layer that calls libgdb. Any operation used in the below should be
+ formalized. */
+
+enum mi_cmd_result
+mi_cmd_gdb_exit (char *command, char **argv, int argc)
+{
+ /* We have to print everything right here because we never return */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^exit\n", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ /* FIXME: The function called is not yet a formal libgdb function */
+ quit_force (NULL, FROM_TTY);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_exec_run (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("run", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_next (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("next", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_next_instruction (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("nexti", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_step (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("step", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_step_instruction (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("stepi", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_finish (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("finish", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_until (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("until", args, from_tty);
+}
+
+enum mi_cmd_result
+mi_cmd_exec_return (char *args, int from_tty)
+{
+ /* This command doesn't really execute the target, it just pops the
+ specified number of frames. */
+ if (*args)
+ /* Call return_command with from_tty argument equal to 0 so as to
+ avoid being queried. */
+ return_command_wrapper (args, 0);
+ else
+ /* Call return_command with from_tty argument equal to 0 so as to
+ avoid being queried. */
+ return_command_wrapper (NULL, 0);
+
+ /* Because we have called return_command with from_tty = 0, we need
+ to print the frame here. */
+ show_and_print_stack_frame (selected_frame,
+ selected_frame_level,
+ LOC_AND_ADDRESS);
+
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_exec_continue (char *args, int from_tty)
+{
+ /* FIXME: Should call a libgdb function, not a cli wrapper */
+ return mi_execute_async_cli_command ("continue", args, from_tty);
+}
+
+/* Interrupt the execution of the target. Note how we must play around
+ with the token varialbes, in order to display the current token in
+ the result of the interrupt command, and the previous execution
+ token when the target finally stops. See comments in
+ mi_cmd_execute. */
+enum mi_cmd_result
+mi_cmd_exec_interrupt (char *args, int from_tty)
+{
+ if (!target_executing)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_exec_interrupt: Inferior not executing.");
+ return MI_CMD_ERROR;
+ }
+ interrupt_target_command_wrapper (args, from_tty);
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ xfree (last_async_command);
+ if (previous_async_command)
+ last_async_command = xstrdup (previous_async_command);
+ xfree (previous_async_command);
+ previous_async_command = NULL;
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ return MI_CMD_QUIET;
+}
+
+enum mi_cmd_result
+mi_cmd_thread_select (char *command, char **argv, int argc)
+{
+ enum gdb_rc rc;
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_thread_select: USAGE: threadnum.");
+ return MI_CMD_ERROR;
+ }
+ else
+ rc = gdb_thread_select (uiout, argv[0]);
+
+ if (rc == GDB_RC_FAIL)
+ return MI_CMD_CAUGHT_ERROR;
+ else
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_thread_list_ids (char *command, char **argv, int argc)
+{
+ enum gdb_rc rc = MI_CMD_DONE;
+
+ if (argc != 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_thread_list_ids: No arguments required.");
+ return MI_CMD_ERROR;
+ }
+ else
+ rc = gdb_list_thread_ids (uiout);
+
+ if (rc == GDB_RC_FAIL)
+ return MI_CMD_CAUGHT_ERROR;
+ else
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_data_list_register_names (char *command, char **argv, int argc)
+{
+ int regnum, numregs;
+ int i;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS + NUM_PSEUDO_REGS;
+
+ ui_out_list_begin (uiout, "register-names");
+
+ if (argc == 0) /* No args, just do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ ui_out_field_string (uiout, NULL, "");
+ else
+ ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 0; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+ if (regnum < 0 || regnum >= numregs)
+ {
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ ui_out_field_string (uiout, NULL, "");
+ else
+ ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+ }
+ ui_out_list_end (uiout);
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
+{
+ int regnum, numregs, changed;
+ int i;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ ui_out_list_begin (uiout, "changed-registers");
+
+ if (argc == 0) /* No args, just do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ continue;
+ changed = register_changed_p (regnum);
+ if (changed < 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_changed_registers: Unable to read register contents.");
+ return MI_CMD_ERROR;
+ }
+ else if (changed)
+ ui_out_field_int (uiout, NULL, regnum);
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 0; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ changed = register_changed_p (regnum);
+ if (changed < 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_change: Unable to read register contents.");
+ return MI_CMD_ERROR;
+ }
+ else if (changed)
+ ui_out_field_int (uiout, NULL, regnum);
+ }
+ else
+ {
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ ui_out_list_end (uiout);
+ return MI_CMD_DONE;
+}
+
+static int
+register_changed_p (int regnum)
+{
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+
+ if (read_relative_register_raw_bytes (regnum, raw_buffer))
+ return -1;
+
+ if (memcmp (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
+ REGISTER_RAW_SIZE (regnum)) == 0)
+ return 0;
+
+ /* Found a changed register. Return 1. */
+
+ memcpy (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
+ REGISTER_RAW_SIZE (regnum));
+
+ return 1;
+}
+
+/* Return a list of register number and value pairs. The valid
+ arguments expected are: a letter indicating the format in which to
+ display the registers contents. This can be one of: x (hexadecimal), d
+ (decimal), N (natural), t (binary), o (octal), r (raw). After the
+ format argumetn there can be a sequence of numbers, indicating which
+ registers to fetch the content of. If the format is the only argument,
+ a list of all the registers with their values is returned. */
+enum mi_cmd_result
+mi_cmd_data_list_register_values (char *command, char **argv, int argc)
+{
+ int regnum, numregs, format, result;
+ int i;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ if (argc == 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
+ return MI_CMD_ERROR;
+ }
+
+ format = (int) argv[0][0];
+
+ if (!target_has_registers)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_list_register_values: No registers.");
+ return MI_CMD_ERROR;
+ }
+
+ ui_out_list_begin (uiout, "register-values");
+
+ if (argc == 1) /* No args, beside the format: do all the regs */
+ {
+ for (regnum = 0;
+ regnum < numregs;
+ regnum++)
+ {
+ if (REGISTER_NAME (regnum) == NULL
+ || *(REGISTER_NAME (regnum)) == '\0')
+ continue;
+ ui_out_tuple_begin (uiout, NULL);
+ ui_out_field_int (uiout, "number", regnum);
+ result = get_register (regnum, format);
+ if (result == -1)
+ return MI_CMD_ERROR;
+ ui_out_tuple_end (uiout);
+ }
+ }
+
+ /* Else, list of register #s, just do listed regs */
+ for (i = 1; i < argc; i++)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ ui_out_tuple_begin (uiout, NULL);
+ ui_out_field_int (uiout, "number", regnum);
+ result = get_register (regnum, format);
+ if (result == -1)
+ return MI_CMD_ERROR;
+ ui_out_tuple_end (uiout);
+ }
+ else
+ {
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ ui_out_list_end (uiout);
+ return MI_CMD_DONE;
+}
+
+/* Output one register's contents in the desired format. */
+static int
+get_register (int regnum, int format)
+{
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+ char *virtual_buffer = alloca (MAX_REGISTER_VIRTUAL_SIZE);
+ int optim;
+ static struct ui_stream *stb = NULL;
+
+ stb = ui_out_stream_new (uiout);
+
+ if (format == 'N')
+ format = 0;
+
+ /* read_relative_register_raw_bytes returns a virtual frame pointer
+ (FRAME_FP (selected_frame)) if regnum == FP_REGNUM instead
+ of the real contents of the register. To get around this,
+ use get_saved_register instead. */
+ get_saved_register (raw_buffer, &optim, (CORE_ADDR *) NULL, selected_frame,
+ regnum, (enum lval_type *) NULL);
+ if (optim)
+ {
+ xasprintf (&mi_error_message, "Optimized out");
+ return -1;
+ }
+
+ /* Convert raw data to virtual format if necessary. */
+
+ if (REGISTER_CONVERTIBLE (regnum))
+ {
+ REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum),
+ raw_buffer, virtual_buffer);
+ }
+ else
+ memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
+
+ if (format == 'r')
+ {
+ int j;
+ char *ptr, buf[1024];
+
+ strcpy (buf, "0x");
+ ptr = buf + 2;
+ for (j = 0; j < REGISTER_RAW_SIZE (regnum); j++)
+ {
+ register int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
+ : REGISTER_RAW_SIZE (regnum) - 1 - j;
+ sprintf (ptr, "%02x", (unsigned char) raw_buffer[idx]);
+ ptr += 2;
+ }
+ ui_out_field_string (uiout, "value", buf);
+ /*fputs_filtered (buf, gdb_stdout); */
+ }
+ else
+ {
+ val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0, 0,
+ stb->stream, format, 1, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "value", stb);
+ ui_out_stream_delete (stb);
+ }
+ return 1;
+}
+
+/* Write given values into registers. The registers and values are
+ given as pairs. The corresponding MI command is
+ -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]*/
+enum mi_cmd_result
+mi_cmd_data_write_register_values (char *command, char **argv, int argc)
+{
+ int regnum;
+ int i;
+ int numregs;
+ LONGEST value;
+ char format;
+
+ /* Note that the test for a valid register must include checking the
+ REGISTER_NAME because NUM_REGS may be allocated for the union of
+ the register sets within a family of related processors. In this
+ case, some entries of REGISTER_NAME will change depending upon
+ the particular processor being debugged. */
+
+ numregs = NUM_REGS;
+
+ if (argc == 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
+ return MI_CMD_ERROR;
+ }
+
+ format = (int) argv[0][0];
+
+ if (!target_has_registers)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: No registers.");
+ return MI_CMD_ERROR;
+ }
+
+ if (!(argc - 1))
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: No regs and values specified.");
+ return MI_CMD_ERROR;
+ }
+
+ if ((argc - 1) % 2)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
+ return MI_CMD_ERROR;
+ }
+
+ for (i = 1; i < argc; i = i + 2)
+ {
+ regnum = atoi (argv[i]);
+
+ if (regnum >= 0
+ && regnum < numregs
+ && REGISTER_NAME (regnum) != NULL
+ && *REGISTER_NAME (regnum) != '\000')
+ {
+ void *buffer;
+ struct cleanup *old_chain;
+
+ /* Get the value as a number */
+ value = parse_and_eval_address (argv[i + 1]);
+ /* Get the value into an array */
+ buffer = xmalloc (REGISTER_SIZE);
+ old_chain = make_cleanup (xfree, buffer);
+ store_signed_integer (buffer, REGISTER_SIZE, value);
+ /* Write it down */
+ write_register_bytes (REGISTER_BYTE (regnum), buffer, REGISTER_RAW_SIZE (regnum));
+ /* Free the buffer. */
+ do_cleanups (old_chain);
+ }
+ else
+ {
+ xasprintf (&mi_error_message, "bad register number");
+ return MI_CMD_ERROR;
+ }
+ }
+ return MI_CMD_DONE;
+}
+
+#if 0
+/*This is commented out because we decided it was not useful. I leave
+ it, just in case. ezannoni:1999-12-08 */
+
+/* Assign a value to a variable. The expression argument must be in
+ the form A=2 or "A = 2" (I.e. if there are spaces it needs to be
+ quoted. */
+enum mi_cmd_result
+mi_cmd_data_assign (char *command, char **argv, int argc)
+{
+ struct expression *expr;
+ struct cleanup *old_chain;
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_assign: Usage: -data-assign expression");
+ return MI_CMD_ERROR;
+ }
+
+ /* NOTE what follows is a clone of set_command(). FIXME: ezannoni
+ 01-12-1999: Need to decide what to do with this for libgdb purposes. */
+
+ expr = parse_expression (argv[0]);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+ return MI_CMD_DONE;
+}
+#endif
+
+/* Evaluate the value of the argument. The argument is an
+ expression. If the expression contains spaces it needs to be
+ included in double quotes. */
+enum mi_cmd_result
+mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
+{
+ struct expression *expr;
+ struct cleanup *old_chain = NULL;
+ struct value *val;
+ struct ui_stream *stb = NULL;
+
+ stb = ui_out_stream_new (uiout);
+
+ if (argc != 1)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression expression");
+ return MI_CMD_ERROR;
+ }
+
+ expr = parse_expression (argv[0]);
+
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ /* Print the result of the expression evaluation. */
+ val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+ VALUE_EMBEDDED_OFFSET (val), VALUE_ADDRESS (val),
+ stb->stream, 0, 0, 0, 0);
+
+ ui_out_field_stream (uiout, "value", stb);
+ ui_out_stream_delete (stb);
+
+ do_cleanups (old_chain);
+
+ return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_target_download (char *args, int from_tty)
+{
+ char *run;
+ struct cleanup *old_cleanups = NULL;
+
+ xasprintf (&run, "load %s", args);
+ old_cleanups = make_cleanup (xfree, run);
+ execute_command (run, from_tty);
+
+ do_cleanups (old_cleanups);
+ return MI_CMD_DONE;
+}
+
+/* Connect to the remote target. */
+enum mi_cmd_result
+mi_cmd_target_select (char *args, int from_tty)
+{
+ char *run;
+ struct cleanup *old_cleanups = NULL;
+
+ xasprintf (&run, "target %s", args);
+ old_cleanups = make_cleanup (xfree, run);
+
+ /* target-select is always synchronous. once the call has returned
+ we know that we are connected. */
+ /* NOTE: At present all targets that are connected are also
+ (implicitly) talking to a halted target. In the future this may
+ change. */
+ execute_command (run, from_tty);
+
+ do_cleanups (old_cleanups);
+
+ /* Issue the completion message here. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^connected", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ do_exec_cleanups (ALL_CLEANUPS);
+ return MI_CMD_QUIET;
+}
+
+/* DATA-MEMORY-READ:
+
+ ADDR: start address of data to be dumped.
+ WORD-FORMAT: a char indicating format for the ``word''. See
+ the ``x'' command.
+ WORD-SIZE: size of each ``word''; 1,2,4, or 8 bytes
+ NR_ROW: Number of rows.
+ NR_COL: The number of colums (words per row).
+ ASCHAR: (OPTIONAL) Append an ascii character dump to each row. Use
+ ASCHAR for unprintable characters.
+
+ Reads SIZE*NR_ROW*NR_COL bytes starting at ADDR from memory and
+ displayes them. Returns:
+
+ {addr="...",rowN={wordN="..." ,... [,ascii="..."]}, ...}
+
+ Returns:
+ The number of bytes read is SIZE*ROW*COL. */
+
+enum mi_cmd_result
+mi_cmd_data_read_memory (char *command, char **argv, int argc)
+{
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ CORE_ADDR addr;
+ long total_bytes;
+ long nr_cols;
+ long nr_rows;
+ char word_format;
+ struct type *word_type;
+ long word_size;
+ char word_asize;
+ char aschar;
+ char *mbuf;
+ int nr_bytes;
+ long offset = 0;
+ int optind = 0;
+ char *optarg;
+ enum opt
+ {
+ OFFSET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"o", OFFSET_OPT, 1},
+ 0
+ };
+
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case OFFSET_OPT:
+ offset = atol (optarg);
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 5 || argc > 6)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR].");
+ return MI_CMD_ERROR;
+ }
+
+ /* Extract all the arguments. */
+
+ /* Start address of the memory dump. */
+ addr = parse_and_eval_address (argv[0]) + offset;
+ /* The format character to use when displaying a memory word. See
+ the ``x'' command. */
+ word_format = argv[1][0];
+ /* The size of the memory word. */
+ word_size = atol (argv[2]);
+ switch (word_size)
+ {
+ case 1:
+ word_type = builtin_type_int8;
+ word_asize = 'b';
+ break;
+ case 2:
+ word_type = builtin_type_int16;
+ word_asize = 'h';
+ break;
+ case 4:
+ word_type = builtin_type_int32;
+ word_asize = 'w';
+ break;
+ case 8:
+ word_type = builtin_type_int64;
+ word_asize = 'g';
+ break;
+ default:
+ word_type = builtin_type_int8;
+ word_asize = 'b';
+ }
+ /* The number of rows */
+ nr_rows = atol (argv[3]);
+ if (nr_rows <= 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: invalid number of rows.");
+ return MI_CMD_ERROR;
+ }
+ /* number of bytes per row. */
+ nr_cols = atol (argv[4]);
+ if (nr_cols <= 0)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: invalid number of columns.");
+ }
+ /* The un-printable character when printing ascii. */
+ if (argc == 6)
+ aschar = *argv[5];
+ else
+ aschar = 0;
+
+ /* create a buffer and read it in. */
+ total_bytes = word_size * nr_rows * nr_cols;
+ mbuf = xcalloc (total_bytes, 1);
+ make_cleanup (xfree, mbuf);
+ if (mbuf == NULL)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_read_memory: out of memory.");
+ return MI_CMD_ERROR;
+ }
+ nr_bytes = 0;
+ while (nr_bytes < total_bytes)
+ {
+ int error;
+ long num = target_read_memory_partial (addr + nr_bytes, mbuf + nr_bytes,
+ total_bytes - nr_bytes,
+ &error);
+ if (num <= 0)
+ break;
+ nr_bytes += num;
+ }
+
+ /* output the header information. */
+ ui_out_field_core_addr (uiout, "addr", addr);
+ ui_out_field_int (uiout, "nr-bytes", nr_bytes);
+ ui_out_field_int (uiout, "total-bytes", total_bytes);
+ ui_out_field_core_addr (uiout, "next-row", addr + word_size * nr_cols);
+ ui_out_field_core_addr (uiout, "prev-row", addr - word_size * nr_cols);
+ ui_out_field_core_addr (uiout, "next-page", addr + total_bytes);
+ ui_out_field_core_addr (uiout, "prev-page", addr - total_bytes);
+
+ /* Build the result as a two dimentional table. */
+ {
+ struct ui_stream *stream = ui_out_stream_new (uiout);
+ int row;
+ int row_byte;
+ ui_out_list_begin (uiout, "memory");
+ for (row = 0, row_byte = 0;
+ row < nr_rows;
+ row++, row_byte += nr_cols * word_size)
+ {
+ int col;
+ int col_byte;
+ ui_out_tuple_begin (uiout, NULL);
+ ui_out_field_core_addr (uiout, "addr", addr + row_byte);
+ /* ui_out_field_core_addr_symbolic (uiout, "saddr", addr + row_byte); */
+ ui_out_list_begin (uiout, "data");
+ for (col = 0, col_byte = row_byte;
+ col < nr_cols;
+ col++, col_byte += word_size)
+ {
+ if (col_byte + word_size > nr_bytes)
+ {
+ ui_out_field_string (uiout, NULL, "N/A");
+ }
+ else
+ {
+ ui_file_rewind (stream->stream);
+ print_scalar_formatted (mbuf + col_byte, word_type, word_format,
+ word_asize, stream->stream);
+ ui_out_field_stream (uiout, NULL, stream);
+ }
+ }
+ ui_out_list_end (uiout);
+ if (aschar)
+ {
+ int byte;
+ ui_file_rewind (stream->stream);
+ for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++)
+ {
+ if (byte >= nr_bytes)
+ {
+ fputc_unfiltered ('X', stream->stream);
+ }
+ else if (mbuf[byte] < 32 || mbuf[byte] > 126)
+ {
+ fputc_unfiltered (aschar, stream->stream);
+ }
+ else
+ fputc_unfiltered (mbuf[byte], stream->stream);
+ }
+ ui_out_field_stream (uiout, "ascii", stream);
+ }
+ ui_out_tuple_end (uiout);
+ }
+ ui_out_stream_delete (stream);
+ ui_out_list_end (uiout);
+ }
+ do_cleanups (cleanups);
+ return MI_CMD_DONE;
+}
+
+/* DATA-MEMORY-WRITE:
+
+ COLUMN_OFFSET: optional argument. Must be preceeded by '-o'. The
+ offset from the beginning of the memory grid row where the cell to
+ be written is.
+ ADDR: start address of the row in the memory grid where the memory
+ cell is, if OFFSET_COLUMN is specified. Otherwise, the address of
+ the location to write to.
+ FORMAT: a char indicating format for the ``word''. See
+ the ``x'' command.
+ WORD_SIZE: size of each ``word''; 1,2,4, or 8 bytes
+ VALUE: value to be written into the memory address.
+
+ Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE).
+
+ Prints nothing. */
+enum mi_cmd_result
+mi_cmd_data_write_memory (char *command, char **argv, int argc)
+{
+ CORE_ADDR addr;
+ char word_format;
+ long word_size;
+ /* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big
+ enough when using a compiler other than GCC. */
+ LONGEST value;
+ void *buffer;
+ struct cleanup *old_chain;
+ long offset = 0;
+ int optind = 0;
+ char *optarg;
+ enum opt
+ {
+ OFFSET_OPT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"o", OFFSET_OPT, 1},
+ 0
+ };
+
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
+ &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case OFFSET_OPT:
+ offset = atol (optarg);
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 4)
+ {
+ xasprintf (&mi_error_message,
+ "mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
+ return MI_CMD_ERROR;
+ }
+
+ /* Extract all the arguments. */
+ /* Start address of the memory dump. */
+ addr = parse_and_eval_address (argv[0]);
+ /* The format character to use when displaying a memory word. See
+ the ``x'' command. */
+ word_format = argv[1][0];
+ /* The size of the memory word. */
+ word_size = atol (argv[2]);
+
+ /* Calculate the real address of the write destination. */
+ addr += (offset * word_size);
+
+ /* Get the value as a number */
+ value = parse_and_eval_address (argv[3]);
+ /* Get the value into an array */
+ buffer = xmalloc (word_size);
+ old_chain = make_cleanup (xfree, buffer);
+ store_signed_integer (buffer, word_size, value);
+ /* Write it down to memory */
+ write_memory (addr, buffer, word_size);
+ /* Free the buffer. */
+ do_cleanups (old_chain);
+
+ return MI_CMD_DONE;
+}
+
+/* Execute a command within a safe environment. Return >0 for
+ ok. Return <0 for supress prompt. Return 0 to have the error
+ extracted from error_last_message(). */
+
+static int
+captured_mi_execute_command (void *data)
+{
+ struct mi_parse *context = data;
+ enum mi_cmd_result rc;
+
+ switch (context->op)
+ {
+
+ case MI_COMMAND:
+ /* A MI command was read from the input stream */
+ if (mi_debug_p)
+ /* FIXME: gdb_???? */
+ fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n",
+ context->token, context->command, context->args);
+ /* FIXME: cagney/1999-09-25: Rather than this convoluted
+ condition expression, each function should return an
+ indication of what action is required and then switch on
+ that. */
+ rc = mi_cmd_execute (context);
+ if (!target_can_async_p () || !target_executing)
+ {
+ /* print the result if there were no errors */
+ if (rc == MI_CMD_DONE)
+ {
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ }
+ else if (rc == MI_CMD_ERROR)
+ {
+ if (mi_error_message)
+ {
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputstr_unfiltered (mi_error_message, '"', raw_stdout);
+ xfree (mi_error_message);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ }
+ mi_out_rewind (uiout);
+ }
+ else if (rc == MI_CMD_CAUGHT_ERROR)
+ {
+ mi_out_rewind (uiout);
+ return 0;
+ }
+ else
+ mi_out_rewind (uiout);
+ }
+ else if (sync_execution)
+ /* Don't print the prompt. We are executing the target in
+ synchronous mode. */
+ return -1;
+ break;
+
+ case CLI_COMMAND:
+ /* A CLI command was read from the input stream */
+ /* This will be removed as soon as we have a complete set of
+ mi commands */
+ /* echo the command on the console. */
+ fprintf_unfiltered (gdb_stdlog, "%s\n", context->command);
+ /* FIXME: If the command string has something that looks like
+ a format spec (e.g. %s) we will get a core dump */
+ mi_execute_cli_command ("%s", context->command);
+ /* print the result */
+ /* FIXME: Check for errors here. */
+ fputs_unfiltered (context->token, raw_stdout);
+ fputs_unfiltered ("^done", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ break;
+
+ }
+ return 1;
+}
+
+
+void
+mi_execute_command (char *cmd, int from_tty)
+{
+ struct mi_parse *command;
+
+ /* This is to handle EOF (^D). We just quit gdb. */
+ /* FIXME: we should call some API function here. */
+ if (cmd == 0)
+ quit_force (NULL, from_tty);
+
+ command = mi_parse (cmd);
+
+ if (command != NULL)
+ {
+ /* FIXME: cagney/1999-11-04: Can this use of catch_errors either
+ be pushed even further down or even eliminated? */
+ int rc = catch_errors (captured_mi_execute_command, command, "",
+ RETURN_MASK_ALL);
+ if (rc < 0)
+ {
+ /* The command is executing synchronously. Bail out early
+ suppressing the finished prompt. */
+ mi_parse_free (command);
+ return;
+ }
+ if (rc == 0)
+ {
+ char *msg = error_last_message ();
+ struct cleanup *cleanup = make_cleanup (xfree, msg);
+ /* The command execution failed and error() was called
+ somewhere */
+ fputs_unfiltered (command->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputstr_unfiltered (msg, '"', raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ }
+ mi_parse_free (command);
+ }
+
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ /* print any buffered hook code */
+ /* ..... */
+}
+
+static enum mi_cmd_result
+mi_cmd_execute (struct mi_parse *parse)
+{
+ if (parse->cmd->argv_func != NULL
+ || parse->cmd->args_func != NULL)
+ {
+ /* FIXME: We need to save the token because the command executed
+ may be asynchronous and need to print the token again.
+ In the future we can pass the token down to the func
+ and get rid of the last_async_command */
+ /* The problem here is to keep the token around when we launch
+ the target, and we want to interrupt it later on. The
+ interrupt command will have its own token, but when the
+ target stops, we must display the token corresponding to the
+ last execution command given. So we have another string where
+ we copy the token (previous_async_command), if this was
+ indeed the token of an execution command, and when we stop we
+ print that one. This is possible because the interrupt
+ command, when over, will copy that token back into the
+ default token string (last_async_command). */
+
+ if (target_executing)
+ {
+ if (!previous_async_command)
+ previous_async_command = xstrdup (last_async_command);
+ if (strcmp (parse->command, "exec-interrupt"))
+ {
+ fputs_unfiltered (parse->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputs_unfiltered ("Cannot execute command ", raw_stdout);
+ fputstr_unfiltered (parse->command, '"', raw_stdout);
+ fputs_unfiltered (" while target running", raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ return MI_CMD_ERROR;
+ }
+ }
+ last_async_command = xstrdup (parse->token);
+ make_exec_cleanup (free_current_contents, &last_async_command);
+ /* FIXME: DELETE THIS! */
+ if (parse->cmd->args_func != NULL)
+ return parse->cmd->args_func (parse->args, 0 /*from_tty */ );
+ return parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
+ }
+ else if (parse->cmd->cli != 0)
+ {
+ /* FIXME: DELETE THIS. */
+ /* The operation is still implemented by a cli command */
+ /* Must be a synchronous one */
+ mi_execute_cli_command (parse->cmd->cli, parse->args);
+ return MI_CMD_DONE;
+ }
+ else
+ {
+ /* FIXME: DELETE THIS. */
+ fputs_unfiltered (parse->token, raw_stdout);
+ fputs_unfiltered ("^error,msg=\"", raw_stdout);
+ fputs_unfiltered ("Undefined mi command: ", raw_stdout);
+ fputstr_unfiltered (parse->command, '"', raw_stdout);
+ fputs_unfiltered (" (missing implementation)", raw_stdout);
+ fputs_unfiltered ("\"\n", raw_stdout);
+ return MI_CMD_ERROR;
+ }
+}
+
+static void
+mi_execute_command_wrapper (char *cmd)
+{
+ mi_execute_command (cmd, stdin == instream);
+}
+
+/* FIXME: This is just a hack so we can get some extra commands going.
+ We don't want to channel things through the CLI, but call libgdb directly */
+/* Use only for synchronous commands */
+
+void
+mi_execute_cli_command (const char *cli, char *args)
+{
+ if (cli != 0)
+ {
+ struct cleanup *old_cleanups;
+ char *run;
+ xasprintf (&run, cli, args);
+ if (mi_debug_p)
+ /* FIXME: gdb_???? */
+ fprintf_unfiltered (gdb_stdout, "cli=%s run=%s\n",
+ cli, run);
+ old_cleanups = make_cleanup (xfree, run);
+ execute_command ( /*ui */ run, 0 /*from_tty */ );
+ do_cleanups (old_cleanups);
+ return;
+ }
+}
+
+enum mi_cmd_result
+mi_execute_async_cli_command (char *mi, char *args, int from_tty)
+{
+ struct cleanup *old_cleanups;
+ char *run;
+ char *async_args;
+
+ if (target_can_async_p ())
+ {
+ async_args = (char *) xmalloc (strlen (args) + 2);
+ make_exec_cleanup (free, async_args);
+ strcpy (async_args, args);
+ strcat (async_args, "&");
+ xasprintf (&run, "%s %s", mi, async_args);
+ make_exec_cleanup (free, run);
+ add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
+ old_cleanups = NULL;
+ }
+ else
+ {
+ xasprintf (&run, "%s %s", mi, args);
+ old_cleanups = make_cleanup (xfree, run);
+ }
+
+ if (!target_can_async_p ())
+ {
+ /* NOTE: For synchronous targets asynchronous behavour is faked by
+ printing out the GDB prompt before we even try to execute the
+ command. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^running\n", raw_stdout);
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+ else
+ {
+ /* FIXME: cagney/1999-11-29: Printing this message before
+ calling execute_command is wrong. It should only be printed
+ once gdb has confirmed that it really has managed to send a
+ run command to the target. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("^running\n", raw_stdout);
+ }
+
+ execute_command ( /*ui */ run, 0 /*from_tty */ );
+
+ if (!target_can_async_p ())
+ {
+ /* Do this before doing any printing. It would appear that some
+ print code leaves garbage around in the buffer. */
+ do_cleanups (old_cleanups);
+ /* If the target was doing the operation synchronously we fake
+ the stopped message. */
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("*stopped", raw_stdout);
+ mi_out_put (uiout, raw_stdout);
+ mi_out_rewind (uiout);
+ fputs_unfiltered ("\n", raw_stdout);
+ return MI_CMD_QUIET;
+ }
+ return MI_CMD_DONE;
+}
+
+void
+mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg)
+{
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ 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);
+}
+
+static char *
+mi_input (char *buf)
+{
+ return gdb_readline (NULL);
+}
+
+static 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)
+{
+ struct timeval time_now, delta, update_threshold;
+ static struct timeval last_update;
+ static char *previous_sect_name = NULL;
+ int new_section;
+
+ if (!interpreter_p || strncmp (interpreter_p, "mi", 2) != 0)
+ return;
+
+ update_threshold.tv_sec = 0;
+ update_threshold.tv_usec = 500000;
+ gettimeofday (&time_now, NULL);
+
+ delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
+ delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
+
+ if (delta.tv_usec < 0)
+ {
+ delta.tv_sec -= 1;
+ delta.tv_usec += 1000000;
+ }
+
+ new_section = (previous_sect_name ?
+ strcmp (previous_sect_name, section_name) : 1);
+ if (new_section)
+ {
+ xfree (previous_sect_name);
+ previous_sect_name = xstrdup (section_name);
+
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("+download", raw_stdout);
+ ui_out_tuple_begin (uiout, NULL);
+ ui_out_field_string (uiout, "section", section_name);
+ ui_out_field_int (uiout, "section-size", total_section);
+ ui_out_field_int (uiout, "total-size", grand_total);
+ ui_out_tuple_end (uiout);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+
+ if (delta.tv_sec >= update_threshold.tv_sec &&
+ delta.tv_usec >= update_threshold.tv_usec)
+ {
+ last_update.tv_sec = time_now.tv_sec;
+ last_update.tv_usec = time_now.tv_usec;
+ if (last_async_command)
+ fputs_unfiltered (last_async_command, raw_stdout);
+ fputs_unfiltered ("+download", raw_stdout);
+ ui_out_tuple_begin (uiout, NULL);
+ ui_out_field_string (uiout, "section", section_name);
+ ui_out_field_int (uiout, "section-sent", sent_so_far);
+ ui_out_field_int (uiout, "section-size", total_section);
+ ui_out_field_int (uiout, "total-sent", total_sent);
+ ui_out_field_int (uiout, "total-size", grand_total);
+ ui_out_tuple_end (uiout);
+ mi_out_put (uiout, raw_stdout);
+ fputs_unfiltered ("\n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+}
+
+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 void
+mi0_command_loop (void)
+{
+ mi_command_loop (0);
+}
+
+static void
+mi1_command_loop (void)
+{
+ mi_command_loop (1);
+}
+
+static void
+setup_architecture_data (void)
+{
+ /* don't trust REGISTER_BYTES to be zero. */
+ old_regs = xmalloc (REGISTER_BYTES + 1);
+ memset (old_regs, 0, REGISTER_BYTES + 1);
+}
+
+static void
+mi_init_ui (char *arg0)
+{
+ /* Eventually this will contain code that takes control of the
+ console. */
+}
+
+void
+_initialize_mi_main (void)
+{
+ if (interpreter_p == NULL)
+ return;
+
+ /* If we're _the_ interpreter, take control. */
+ if (strcmp (interpreter_p, "mi0") == 0)
+ command_loop_hook = mi0_command_loop;
+ else if (strcmp (interpreter_p, "mi") == 0
+ || strcmp (interpreter_p, "mi1") == 0)
+ command_loop_hook = mi1_command_loop;
+ else
+ return;
+
+ init_ui_hook = mi_init_ui;
+ setup_architecture_data ();
+ register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
+ register_gdbarch_swap (NULL, 0, setup_architecture_data);
+ 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: Should we notify main that we are here as a possible
+ interpreter? */
+}
OpenPOWER on IntegriCloud