diff options
Diffstat (limited to 'gdb/mi/mi-main.c')
-rw-r--r-- | gdb/mi/mi-main.c | 1527 |
1 files changed, 0 insertions, 1527 deletions
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c deleted file mode 100644 index 3a59fc88dec..00000000000 --- a/gdb/mi/mi-main.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* 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? */ -} |