OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [mi/] [mi-main.c] - Diff between revs 107 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.