2010-05-17 Michael Snyder <msnyder@vmware.com>
[deliverable/binutils-gdb.git] / gdb / mi / mi-main.c
index 213f97af72062d1e759e3b85ca9a4a15301d0790..c9472ed240afeaecec6d906bb15ba5d1ff37e6c9 100644 (file)
@@ -1,7 +1,7 @@
 /* MI Command Set.
 
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software
-   Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    Contributed by Cygnus Solutions (a Red Hat company).
 
@@ -9,7 +9,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* Work in progress */
+/* Work in progress */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "target.h"
 #include "inferior.h"
 #include "gdb_string.h"
 #include "interps.h"
 #include "event-loop.h"
 #include "event-top.h"
-#include "gdbcore.h"           /* for write_memory() */
-#include "value.h"             /* for deprecated_write_register_bytes() */
+#include "gdbcore.h"           /* For write_memory().  */
+#include "value.h"
 #include "regcache.h"
 #include "gdb.h"
 #include "frame.h"
 #include "mi-main.h"
+#include "mi-common.h"
+#include "language.h"
+#include "valprint.h"
+#include "inferior.h"
+#include "osdata.h"
+#include "splay-tree.h"
+#include "tracepoint.h"
 
 #include <ctype.h>
 #include <sys/time.h>
 
+#if defined HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifdef HAVE_GETRUSAGE
+struct rusage rusage;
+#endif
+
 enum
   {
     FROM_TTY = 0
   };
 
-/* Enumerations of the actions that may result from calling
-   captured_mi_execute_command */
+int mi_debug_p;
+struct ui_file *raw_stdout;
 
-enum captured_mi_execute_command_actions
-  {
-    EXECUTE_COMMAND_DISPLAY_PROMPT,
-    EXECUTE_COMMAND_SUPRESS_PROMPT
-  };
+/* This is used to pass the current command timestamp
+   down to continuation routines.  */
+static struct mi_timestamp *current_command_ts;
 
-/* This structure is used to pass information from captured_mi_execute_command
-   to mi_execute_command. */
-struct captured_mi_execute_command_args
-{
-  /* This return result of the MI command (output) */
-  enum mi_cmd_result rc;
+static int do_timings = 0;
 
-  /* What action to perform when the call is finished (output) */
-  enum captured_mi_execute_command_actions action;
+char *current_token;
+/* Few commands would like to know if options like --thread-group
+   were explicitly specified.  This variable keeps the current
+   parsed command including all option, and make it possible.  */
+static struct mi_parse *current_context;
 
-  /* The command context to be executed (input) */
-  struct mi_parse *command;
-};
+int running_result_record_printed = 1;
 
-int mi_debug_p;
-struct ui_file *raw_stdout;
-
-/* The token of the last asynchronous command */
-static char *last_async_command;
-static char *previous_async_command;
-char *mi_error_message;
-static char *old_regs;
+/* Flag indicating that the target has proceeded since the last
+   command was issued.  */
+int mi_proceeded;
 
 extern void _initialize_mi_main (void);
-static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
+static void mi_cmd_execute (struct mi_parse *parse);
 
 static void mi_execute_cli_command (const char *cmd, int args_p,
                                    const char *args);
-static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
+static void mi_execute_async_cli_command (char *cli_command, 
+                                                       char **argv, int argc);
+static int register_changed_p (int regnum, struct regcache *,
+                              struct regcache *);
+static void get_register (struct frame_info *, int regnum, int format);
 
-static void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
+/* Command implementations.  FIXME: Is this libgdb?  No.  This is the MI
+   layer that calls libgdb.  Any operation used in the below should be
+   formalized.  */
 
-static int register_changed_p (int regnum);
-static int get_register (int regnum, int format);
+static void timestamp (struct mi_timestamp *tv);
 
-/* Command implementations. FIXME: Is this libgdb? No.  This is the MI
-   layer that calls libgdb.  Any operation used in the below should be
-   formalized. */
+static void print_diff_now (struct mi_timestamp *start);
+static void print_diff (struct mi_timestamp *start, struct mi_timestamp *end);
 
-enum mi_cmd_result
+void
 mi_cmd_gdb_exit (char *command, char **argv, int argc)
 {
-  /* We have to print everything right here because we never return */
-  if (last_async_command)
-    fputs_unfiltered (last_async_command, raw_stdout);
+  /* We have to print everything right here because we never return */
+  if (current_token)
+    fputs_unfiltered (current_token, raw_stdout);
   fputs_unfiltered ("^exit\n", raw_stdout);
   mi_out_put (uiout, raw_stdout);
-  /* FIXME: The function called is not yet a formal libgdb function */
+  gdb_flush (raw_stdout);
+  /* FIXME: The function called is not yet a formal libgdb function.  */
   quit_force (NULL, FROM_TTY);
-  return MI_CMD_DONE;
 }
 
-enum mi_cmd_result
-mi_cmd_exec_run (char *args, int from_tty)
-{
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("run", args, from_tty);
-}
-
-enum mi_cmd_result
-mi_cmd_exec_next (char *args, int from_tty)
-{
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("next", args, from_tty);
-}
-
-enum mi_cmd_result
-mi_cmd_exec_next_instruction (char *args, int from_tty)
+void
+mi_cmd_exec_next (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("nexti", args, from_tty);
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+    mi_execute_async_cli_command ("reverse-next", argv + 1, argc - 1);
+  else
+    mi_execute_async_cli_command ("next", argv, argc);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_step (char *args, int from_tty)
+void
+mi_cmd_exec_next_instruction (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("step", args, from_tty);
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+    mi_execute_async_cli_command ("reverse-nexti", argv + 1, argc - 1);
+  else
+    mi_execute_async_cli_command ("nexti", argv, argc);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_step_instruction (char *args, int from_tty)
+void
+mi_cmd_exec_step (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("stepi", args, from_tty);
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+    mi_execute_async_cli_command ("reverse-step", argv + 1, argc - 1);
+  else
+    mi_execute_async_cli_command ("step", argv, argc);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_finish (char *args, int from_tty)
+void
+mi_cmd_exec_step_instruction (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("finish", args, from_tty);
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+    mi_execute_async_cli_command ("reverse-stepi", argv + 1, argc - 1);
+  else
+    mi_execute_async_cli_command ("stepi", argv, argc);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_until (char *args, int from_tty)
+void
+mi_cmd_exec_finish (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("until", args, from_tty);
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+    mi_execute_async_cli_command ("reverse-finish", argv + 1, argc - 1);
+  else
+    mi_execute_async_cli_command ("finish", argv, argc);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_return (char *args, int from_tty)
+void
+mi_cmd_exec_return (char *command, char **argv, int argc)
 {
   /* This command doesn't really execute the target, it just pops the
      specified number of frames. */
-  if (*args)
+  if (argc)
     /* Call return_command with from_tty argument equal to 0 so as to
-       avoid being queried. */
-    return_command (args, 0);
+       avoid being queried.  */
+    return_command (*argv, 0);
   else
     /* Call return_command with from_tty argument equal to 0 so as to
-       avoid being queried. */
+       avoid being queried.  */
     return_command (NULL, 0);
 
   /* Because we have called return_command with from_tty = 0, we need
-     to print the frame here. */
+     to print the frame here.  */
   print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS);
+}
+
+void
+mi_cmd_exec_jump (char *args, char **argv, int argc)
+{
+  /* FIXME: Should call a libgdb function, not a cli wrapper.  */
+  mi_execute_async_cli_command ("jump", argv, argc);
+}
+static void
+proceed_thread (struct thread_info *thread, int pid)
+{
+  if (!is_stopped (thread->ptid))
+    return;
+
+  if (pid != 0 && PIDGET (thread->ptid) != pid)
+    return;
+
+  switch_to_thread (thread->ptid);
+  clear_proceed_status ();
+  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+
+static int
+proceed_thread_callback (struct thread_info *thread, void *arg)
+{
+  int pid = *(int *)arg;
+
+  proceed_thread (thread, pid);
+  return 0;
+}
 
-  return MI_CMD_DONE;
+static void
+exec_continue (char **argv, int argc)
+{
+  if (non_stop)
+    {
+      /* In non-stop mode, 'resume' always resumes a single thread.  Therefore,
+        to resume all threads of the current inferior, or all threads in all
+        inferiors, we need to iterate over threads.
+
+        See comment on infcmd.c:proceed_thread_callback for rationale.  */
+      if (current_context->all || current_context->thread_group != -1)
+       {
+         int pid = 0;
+         struct cleanup *back_to = make_cleanup_restore_current_thread ();
+
+         if (!current_context->all)
+           {
+             struct inferior *inf = find_inferior_id (current_context->thread_group);
+             pid = inf->pid;
+           }
+         iterate_over_threads (proceed_thread_callback, &pid);
+         do_cleanups (back_to);
+       }
+      else
+       {
+         continue_1 (0);
+       }
+    }
+  else
+    {
+      struct cleanup *back_to = make_cleanup_restore_integer (&sched_multi);
+
+      if (current_context->all)
+       {
+         sched_multi = 1;
+         continue_1 (0);
+       }
+      else
+       {
+         /* In all-stop mode, -exec-continue traditionally resumed either
+            all threads, or one thread, depending on the 'scheduler-locking'
+            variable.  Let's continue to do the same.  */
+         continue_1 (1);
+       }
+      do_cleanups (back_to);
+    }
+}
+
+static void
+exec_direction_forward (void *notused)
+{
+  execution_direction = EXEC_FORWARD;
+}
+
+static void
+exec_reverse_continue (char **argv, int argc)
+{
+  enum exec_direction_kind dir = execution_direction;
+  struct cleanup *old_chain;
+
+  if (dir == EXEC_ERROR)
+    error (_("Target %s does not support this command."), target_shortname);
+
+  if (dir == EXEC_REVERSE)
+    error (_("Already in reverse mode."));
+
+  if (!target_can_execute_reverse)
+    error (_("Target %s does not support this command."), target_shortname);
+
+  old_chain = make_cleanup (exec_direction_forward, NULL);
+  execution_direction = EXEC_REVERSE;
+  exec_continue (argv, argc);
+  do_cleanups (old_chain);
 }
 
-enum mi_cmd_result
-mi_cmd_exec_continue (char *args, int from_tty)
+void
+mi_cmd_exec_continue (char *command, char **argv, int argc)
 {
-  /* FIXME: Should call a libgdb function, not a cli wrapper */
-  return mi_execute_async_cli_command ("continue", args, from_tty);
+  if (argc > 0 && strcmp (argv[0], "--reverse") == 0)
+    exec_reverse_continue (argv + 1, argc - 1);
+  else
+    exec_continue (argv, argc);
 }
 
-/* Interrupt the execution of the target. Note how we must play around
-   with the token varialbes, in order to display the current token in
+static int
+interrupt_thread_callback (struct thread_info *thread, void *arg)
+{
+  int pid = *(int *)arg;
+
+  if (!is_running (thread->ptid))
+    return 0;
+
+  if (PIDGET (thread->ptid) != pid)
+    return 0;
+
+  target_stop (thread->ptid);
+  return 0;
+}
+
+/* Interrupt the execution of the target.  Note how we must play around
+   with the token variables, in order to display the current token in
    the result of the interrupt command, and the previous execution
-   token when the target finally stops. See comments in
-   mi_cmd_execute. */
-enum mi_cmd_result
-mi_cmd_exec_interrupt (char *args, int from_tty)
+   token when the target finally stops.  See comments in
+   mi_cmd_execute.  */
+void
+mi_cmd_exec_interrupt (char *command, char **argv, int argc)
 {
-  if (!target_executing)
+  /* In all-stop mode, everything stops, so we don't need to try
+     anything specific.  */
+  if (!non_stop)
     {
-      mi_error_message = xstrprintf ("mi_cmd_exec_interrupt: Inferior not executing.");
-      return MI_CMD_ERROR;
+      interrupt_target_1 (0);
+      return;
     }
-  interrupt_target_command (args, from_tty);
-  if (last_async_command)
-    fputs_unfiltered (last_async_command, raw_stdout);
-  fputs_unfiltered ("^done", raw_stdout);
-  xfree (last_async_command);
-  if (previous_async_command)
-    last_async_command = xstrdup (previous_async_command);
-  xfree (previous_async_command);
-  previous_async_command = NULL;
-  mi_out_put (uiout, raw_stdout);
-  mi_out_rewind (uiout);
-  fputs_unfiltered ("\n", raw_stdout);
-  return MI_CMD_QUIET;
+
+  if (current_context->all)
+    {
+      /* This will interrupt all threads in all inferiors.  */
+      interrupt_target_1 (1);
+    }
+  else if (current_context->thread_group != -1)
+    {
+      struct inferior *inf = find_inferior_id (current_context->thread_group);
+
+      iterate_over_threads (interrupt_thread_callback, &inf->pid);
+    }
+  else
+    {
+      /* Interrupt just the current thread -- either explicitly
+        specified via --thread or whatever was current before
+        MI command was sent.  */
+      interrupt_target_1 (0);
+    }
+}
+
+static int
+run_one_inferior (struct inferior *inf, void *arg)
+{
+  if (inf->pid != 0)
+    {
+      if (inf->pid != ptid_get_pid (inferior_ptid))
+       {
+         struct thread_info *tp;
+
+         tp = any_thread_of_process (inf->pid);
+         if (!tp)
+           error (_("Inferior has no threads."));
+
+         switch_to_thread (tp->ptid);
+       }
+    }
+  else
+    {
+      set_current_inferior (inf);
+      switch_to_thread (null_ptid);
+      set_current_program_space (inf->pspace);
+    }
+  mi_execute_cli_command ("run", target_can_async_p (),
+                         target_can_async_p () ? "&" : NULL);
+  return 0;
+}
+
+void
+mi_cmd_exec_run (char *command, char **argv, int argc)
+{
+  if (current_context->all)
+    {
+      struct cleanup *back_to = save_current_space_and_thread ();
+
+      iterate_over_inferiors (run_one_inferior, NULL);
+      do_cleanups (back_to);
+    }
+  else
+    {
+      mi_execute_cli_command ("run", target_can_async_p (),
+                             target_can_async_p () ? "&" : NULL);
+    }
+}
+
+
+static int
+find_thread_of_process (struct thread_info *ti, void *p)
+{
+  int pid = *(int *)p;
+
+  if (PIDGET (ti->ptid) == pid && !is_exited (ti->ptid))
+    return 1;
+
+  return 0;
 }
 
-enum mi_cmd_result
+void
+mi_cmd_target_detach (char *command, char **argv, int argc)
+{
+  if (argc != 0 && argc != 1)
+    error ("Usage: -target-detach [thread-group]");
+
+  if (argc == 1)
+    {
+      struct thread_info *tp;
+      char *end = argv[0];
+      int pid = strtol (argv[0], &end, 10);
+
+      if (*end != '\0')
+       error (_("Cannot parse thread group id '%s'"), argv[0]);
+
+      /* Pick any thread in the desired process.  Current
+        target_detach deteches from the parent of inferior_ptid.  */
+      tp = iterate_over_threads (find_thread_of_process, &pid);
+      if (!tp)
+       error (_("Thread group is empty"));
+
+      switch_to_thread (tp->ptid);
+    }
+
+  detach_command (NULL, 0);
+}
+
+void
 mi_cmd_thread_select (char *command, char **argv, int argc)
 {
   enum gdb_rc rc;
+  char *mi_error_message;
 
   if (argc != 1)
+    error ("mi_cmd_thread_select: USAGE: threadnum.");
+
+  rc = gdb_thread_select (uiout, argv[0], &mi_error_message);
+
+  if (rc == GDB_RC_FAIL)
     {
-      mi_error_message = xstrprintf ("mi_cmd_thread_select: USAGE: threadnum.");
-      return MI_CMD_ERROR;
+      make_cleanup (xfree, mi_error_message);
+      error ("%s", mi_error_message);
     }
-  else
-    rc = gdb_thread_select (uiout, argv[0], &mi_error_message);
-
-  /* RC is enum gdb_rc if it is successful (>=0)
-     enum return_reason if not (<0). */
-  if ((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR)
-    return MI_CMD_ERROR;
-  else if ((int) rc >= 0 && rc == GDB_RC_FAIL)
-    return MI_CMD_ERROR;
-  else
-    return MI_CMD_DONE;
 }
 
-enum mi_cmd_result
+void
 mi_cmd_thread_list_ids (char *command, char **argv, int argc)
 {
-  enum gdb_rc rc = MI_CMD_DONE;
+  enum gdb_rc rc;
+  char *mi_error_message;
 
   if (argc != 0)
+    error ("mi_cmd_thread_list_ids: No arguments required.");
+
+  rc = gdb_list_thread_ids (uiout, &mi_error_message);
+
+  if (rc == GDB_RC_FAIL)
     {
-      mi_error_message = xstrprintf ("mi_cmd_thread_list_ids: No arguments required.");
-      return MI_CMD_ERROR;
+      make_cleanup (xfree, mi_error_message);
+      error ("%s", mi_error_message);
     }
-  else
-    rc = gdb_list_thread_ids (uiout, &mi_error_message);
+}
 
-  if (rc == GDB_RC_FAIL)
-    return MI_CMD_ERROR;
+void
+mi_cmd_thread_info (char *command, char **argv, int argc)
+{
+  int thread = -1;
+  
+  if (argc != 0 && argc != 1)
+    error ("Invalid MI command");
+
+  if (argc == 1)
+    thread = atoi (argv[0]);
+
+  print_thread_info (uiout, thread, -1);
+}
+
+struct collect_cores_data
+{
+  int pid;
+
+  VEC (int) *cores;
+};
+
+static int
+collect_cores (struct thread_info *ti, void *xdata)
+{
+  struct collect_cores_data *data = xdata;
+
+  if (ptid_get_pid (ti->ptid) == data->pid)
+    {
+      int core = target_core_of_thread (ti->ptid);
+
+      if (core != -1)
+       VEC_safe_push (int, data->cores, core);
+    }
+
+  return 0;
+}
+
+static int *
+unique (int *b, int *e)
+{
+  int *d = b;
+
+  while (++b != e)
+    if (*d != *b)
+      *++d = *b;
+  return ++d;
+}
+
+struct print_one_inferior_data
+{
+  int recurse;
+  VEC (int) *inferiors;
+};
+
+static int
+print_one_inferior (struct inferior *inferior, void *xdata)
+{
+  struct print_one_inferior_data *top_data = xdata;
+
+  if (VEC_empty (int, top_data->inferiors)
+      || bsearch (&(inferior->pid), VEC_address (int, top_data->inferiors),
+                 VEC_length (int, top_data->inferiors), sizeof (int),
+                 compare_positive_ints))
+    {
+      struct collect_cores_data data;
+      struct cleanup *back_to
+       = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+      ui_out_field_fmt (uiout, "id", "i%d", inferior->num);
+      ui_out_field_string (uiout, "type", "process");
+      if (inferior->pid != 0)
+       ui_out_field_int (uiout, "pid", inferior->pid);
+
+      if (inferior->pspace->ebfd)
+       {
+         ui_out_field_string (uiout, "executable",
+                              bfd_get_filename (inferior->pspace->ebfd));
+       }
+
+      data.cores = 0;
+      if (inferior->pid != 0)
+       {
+         data.pid = inferior->pid;
+         iterate_over_threads (collect_cores, &data);
+       }
+
+      if (!VEC_empty (int, data.cores))
+       {
+         int *b, *e;
+         struct cleanup *back_to_2 =
+           make_cleanup_ui_out_list_begin_end (uiout, "cores");
+
+         qsort (VEC_address (int, data.cores),
+                VEC_length (int, data.cores), sizeof (int),
+                compare_positive_ints);
+
+         b = VEC_address (int, data.cores);
+         e = b + VEC_length (int, data.cores);
+         e = unique (b, e);
+
+         for (; b != e; ++b)
+           ui_out_field_int (uiout, NULL, *b);
+
+         do_cleanups (back_to_2);
+       }
+
+      if (top_data->recurse)
+       print_thread_info (uiout, -1, inferior->pid);
+
+      do_cleanups (back_to);
+    }
+
+  return 0;
+}
+
+/* Output a field named 'cores' with a list as the value.  The elements of
+   the list are obtained by splitting 'cores' on comma.  */
+
+static void
+output_cores (struct ui_out *uiout, const char *field_name, const char *xcores)
+{
+  struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout,
+                                                               field_name);
+  char *cores = xstrdup (xcores);
+  char *p = cores;
+
+  make_cleanup (xfree, cores);
+
+  for (p = strtok (p, ","); p;  p = strtok (NULL, ","))
+    ui_out_field_string (uiout, NULL, p);
+
+  do_cleanups (back_to);
+}
+
+static void
+free_vector_of_ints (void *xvector)
+{
+  VEC (int) **vector = xvector;
+
+  VEC_free (int, *vector);
+}
+
+static void
+do_nothing (splay_tree_key k)
+{
+}
+
+static void
+free_vector_of_osdata_items (splay_tree_value xvalue)
+{
+  VEC (osdata_item_s) *value = (VEC (osdata_item_s) *) xvalue;
+
+  /* We don't free the items itself, it will be done separately.  */
+  VEC_free (osdata_item_s, value);
+}
+
+static int
+splay_tree_int_comparator (splay_tree_key xa, splay_tree_key xb)
+{
+  int a = xa;
+  int b = xb;
+
+  return a - b;
+}
+
+static void
+free_splay_tree (void *xt)
+{
+  splay_tree t = xt;
+  splay_tree_delete (t);
+}
+
+static void
+list_available_thread_groups (VEC (int) *ids, int recurse)
+{
+  struct osdata *data;
+  struct osdata_item *item;
+  int ix_items;
+
+  /* This keeps a map from integer (pid) to VEC (struct osdata_item *)*
+     The vector contains information about all threads for the given pid.
+     This is assigned an initial value to avoid "may be used uninitialized"
+     warning from gcc.  */
+  splay_tree tree = NULL;
+
+  /* get_osdata will throw if it cannot return data.  */
+  data = get_osdata ("processes");
+  make_cleanup_osdata_free (data);
+
+  if (recurse)
+    {
+      struct osdata *threads = get_osdata ("threads");
+
+      make_cleanup_osdata_free (threads);
+      tree = splay_tree_new (splay_tree_int_comparator,
+                            do_nothing,
+                            free_vector_of_osdata_items);
+      make_cleanup (free_splay_tree, tree);
+
+      for (ix_items = 0;
+          VEC_iterate (osdata_item_s, threads->items,
+                       ix_items, item);
+          ix_items++)
+       {
+         const char *pid = get_osdata_column (item, "pid");
+         int pid_i = strtoul (pid, NULL, 0);
+         VEC (osdata_item_s) *vec = 0;
+
+         splay_tree_node n = splay_tree_lookup (tree, pid_i);
+         if (!n)
+           {
+             VEC_safe_push (osdata_item_s, vec, item);
+             splay_tree_insert (tree, pid_i, (splay_tree_value)vec);
+           }
+         else
+           {
+             vec = (VEC (osdata_item_s) *) n->value;
+             VEC_safe_push (osdata_item_s, vec, item);
+             n->value = (splay_tree_value) vec;
+           }
+       }
+    }
+
+  make_cleanup_ui_out_list_begin_end (uiout, "groups");
+
+  for (ix_items = 0;
+       VEC_iterate (osdata_item_s, data->items,
+                   ix_items, item);
+       ix_items++)
+    {
+      struct cleanup *back_to;
+
+      const char *pid = get_osdata_column (item, "pid");
+      const char *cmd = get_osdata_column (item, "command");
+      const char *user = get_osdata_column (item, "user");
+      const char *cores = get_osdata_column (item, "cores");
+
+      int pid_i = strtoul (pid, NULL, 0);
+
+      /* At present, the target will return all available processes
+        and if information about specific ones was required, we filter
+        undesired processes here.  */
+      if (ids && bsearch (&pid_i, VEC_address (int, ids),
+                         VEC_length (int, ids),
+                         sizeof (int), compare_positive_ints) == NULL)
+       continue;
+
+
+      back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+      ui_out_field_fmt (uiout, "id", "%s", pid);
+      ui_out_field_string (uiout, "type", "process");
+      if (cmd)
+       ui_out_field_string (uiout, "description", cmd);
+      if (user)
+       ui_out_field_string (uiout, "user", user);
+      if (cores)
+       output_cores (uiout, "cores", cores);
+
+      if (recurse)
+       {
+         splay_tree_node n = splay_tree_lookup (tree, pid_i);
+         if (n)
+           {
+             VEC (osdata_item_s) *children = (VEC (osdata_item_s) *) n->value;
+             struct osdata_item *child;
+             int ix_child;
+
+             make_cleanup_ui_out_list_begin_end (uiout, "threads");
+
+             for (ix_child = 0;
+                  VEC_iterate (osdata_item_s, children, ix_child, child);
+                  ++ix_child)
+               {
+                 struct cleanup *back_to_2 =
+                   make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+                 const char *tid = get_osdata_column (child, "tid");
+                 const char *tcore = get_osdata_column (child, "core");
+
+                 ui_out_field_string (uiout, "id", tid);
+                 if (tcore)
+                   ui_out_field_string (uiout, "core", tcore);
+
+                 do_cleanups (back_to_2);
+               }
+           }
+       }
+
+      do_cleanups (back_to);
+    }
+}
+
+void
+mi_cmd_list_thread_groups (char *command, char **argv, int argc)
+{
+  struct cleanup *back_to;
+  int available = 0;
+  int recurse = 0;
+  VEC (int) *ids = 0;
+
+  enum opt
+    {
+      AVAILABLE_OPT, RECURSE_OPT
+    };
+  static struct mi_opt opts[] =
+  {
+    {"-available", AVAILABLE_OPT, 0},
+    {"-recurse", RECURSE_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int optind = 0;
+  char *optarg;
+
+  while (1)
+    {
+      int opt = mi_getopt ("-list-thread-groups", argc, argv, opts,
+                          &optind, &optarg);
+
+      if (opt < 0)
+       break;
+      switch ((enum opt) opt)
+       {
+       case AVAILABLE_OPT:
+         available = 1;
+         break;
+       case RECURSE_OPT:
+         if (strcmp (optarg, "0") == 0)
+           ;
+         else if (strcmp (optarg, "1") == 0)
+           recurse = 1;
+         else
+           error ("only '0' and '1' are valid values for the '--recurse' option");
+         break;
+       }
+    }
+
+  for (; optind < argc; ++optind)
+    {
+      char *end;
+      int inf = strtoul (argv[optind], &end, 0);
+
+      if (*end != '\0')
+       error ("invalid group id '%s'", argv[optind]);
+      VEC_safe_push (int, ids, inf);
+    }
+  if (VEC_length (int, ids) > 1)
+    qsort (VEC_address (int, ids),
+          VEC_length (int, ids),
+          sizeof (int), compare_positive_ints);
+
+  back_to = make_cleanup (free_vector_of_ints, &ids);
+
+  if (available)
+    {
+      list_available_thread_groups (ids, recurse);
+    }
+  else if (VEC_length (int, ids) == 1)
+    {
+      /* Local thread groups, single id. */
+      int pid = *VEC_address (int, ids);
+
+      if (!in_inferior_list (pid))
+       error ("Invalid thread group id '%d'", pid);
+      print_thread_info (uiout, -1, pid);
+    }
   else
-    return MI_CMD_DONE;
+    {
+      struct print_one_inferior_data data;
+
+      data.recurse = recurse;
+      data.inferiors = ids;
+
+      /* Local thread groups.  Either no explicit ids -- and we
+        print everything, or several explicit ids.  In both cases,
+        we print more than one group, and have to use 'groups'
+        as the top-level element.  */
+      make_cleanup_ui_out_list_begin_end (uiout, "groups");
+      update_thread_list ();
+      iterate_over_inferiors (print_one_inferior, &data);
+    }
+
+  do_cleanups (back_to);
 }
 
-enum mi_cmd_result
+void
 mi_cmd_data_list_register_names (char *command, char **argv, int argc)
 {
+  struct gdbarch *gdbarch;
   int regnum, numregs;
   int i;
   struct cleanup *cleanup;
 
   /* Note that the test for a valid register must include checking the
-     REGISTER_NAME because NUM_REGS may be allocated for the union of
-     the register sets within a family of related processors.  In this
-     case, some entries of REGISTER_NAME will change depending upon
-     the particular processor being debugged.  */
+     gdbarch_register_name because gdbarch_num_regs may be allocated for
+     the union of the register sets within a family of related processors.
+     In this case, some entries of gdbarch_register_name will change depending
+     upon the particular processor being debugged.  */
 
-  numregs = NUM_REGS + NUM_PSEUDO_REGS;
+  gdbarch = get_current_arch ();
+  numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 
   cleanup = make_cleanup_ui_out_list_begin_end (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;
           regnum < numregs;
           regnum++)
        {
-         if (REGISTER_NAME (regnum) == NULL
-             || *(REGISTER_NAME (regnum)) == '\0')
+         if (gdbarch_register_name (gdbarch, regnum) == NULL
+             || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
            ui_out_field_string (uiout, NULL, "");
          else
-           ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+           ui_out_field_string (uiout, NULL,
+                                gdbarch_register_name (gdbarch, 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++)
     {
       regnum = atoi (argv[i]);
       if (regnum < 0 || regnum >= numregs)
-       {
-         do_cleanups (cleanup);
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
-      if (REGISTER_NAME (regnum) == NULL
-         || *(REGISTER_NAME (regnum)) == '\0')
+       error ("bad register number");
+
+      if (gdbarch_register_name (gdbarch, regnum) == NULL
+         || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
        ui_out_field_string (uiout, NULL, "");
       else
-       ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
+       ui_out_field_string (uiout, NULL,
+                            gdbarch_register_name (gdbarch, regnum));
     }
   do_cleanups (cleanup);
-  return MI_CMD_DONE;
 }
 
-enum mi_cmd_result
+void
 mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
 {
+  static struct regcache *this_regs = NULL;
+  struct regcache *prev_regs;
+  struct gdbarch *gdbarch;
   int regnum, numregs, changed;
   int i;
   struct cleanup *cleanup;
 
+  /* The last time we visited this function, the current frame's register
+     contents were saved in THIS_REGS.  Move THIS_REGS over to PREV_REGS,
+     and refresh THIS_REGS with the now-current register contents.  */
+
+  prev_regs = this_regs;
+  this_regs = frame_save_as_regcache (get_selected_frame (NULL));
+  cleanup = make_cleanup_regcache_xfree (prev_regs);
+
   /* Note that the test for a valid register must include checking the
-     REGISTER_NAME because NUM_REGS may be allocated for the union of
-     the register sets within a family of related processors.  In this
-     case, some entries of REGISTER_NAME will change depending upon
-     the particular processor being debugged.  */
+     gdbarch_register_name because gdbarch_num_regs may be allocated for
+     the union of the register sets within a family of related processors.
+     In this  case, some entries of gdbarch_register_name will change depending
+     upon the particular processor being debugged.  */
 
-  numregs = NUM_REGS + NUM_PSEUDO_REGS;
+  gdbarch = get_regcache_arch (this_regs);
+  numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 
-  cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changed-registers");
+  make_cleanup_ui_out_list_begin_end (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;
           regnum < numregs;
           regnum++)
        {
-         if (REGISTER_NAME (regnum) == NULL
-             || *(REGISTER_NAME (regnum)) == '\0')
+         if (gdbarch_register_name (gdbarch, regnum) == NULL
+             || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
            continue;
-         changed = register_changed_p (regnum);
+         changed = register_changed_p (regnum, prev_regs, this_regs);
          if (changed < 0)
-           {
-             do_cleanups (cleanup);
-             mi_error_message = xstrprintf ("mi_cmd_data_list_changed_registers: Unable to read register contents.");
-             return MI_CMD_ERROR;
-           }
+           error ("mi_cmd_data_list_changed_registers: Unable to read register contents.");
          else if (changed)
            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++)
     {
       regnum = atoi (argv[i]);
 
       if (regnum >= 0
          && regnum < numregs
-         && REGISTER_NAME (regnum) != NULL
-         && *REGISTER_NAME (regnum) != '\000')
+         && gdbarch_register_name (gdbarch, regnum) != NULL
+         && *gdbarch_register_name (gdbarch, regnum) != '\000')
        {
-         changed = register_changed_p (regnum);
+         changed = register_changed_p (regnum, prev_regs, this_regs);
          if (changed < 0)
-           {
-             do_cleanups (cleanup);
-             mi_error_message = xstrprintf ("mi_cmd_data_list_register_change: Unable to read register contents.");
-             return MI_CMD_ERROR;
-           }
+           error ("mi_cmd_data_list_register_change: Unable to read register contents.");
          else if (changed)
            ui_out_field_int (uiout, NULL, regnum);
        }
       else
-       {
-         do_cleanups (cleanup);
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
+       error ("bad register number");
     }
   do_cleanups (cleanup);
-  return MI_CMD_DONE;
 }
 
 static int
-register_changed_p (int regnum)
+register_changed_p (int regnum, struct regcache *prev_regs,
+                   struct regcache *this_regs)
 {
-  gdb_byte raw_buffer[MAX_REGISTER_SIZE];
-
-  if (! frame_register_read (get_selected_frame (NULL), regnum, raw_buffer))
-    return -1;
+  struct gdbarch *gdbarch = get_regcache_arch (this_regs);
+  gdb_byte prev_buffer[MAX_REGISTER_SIZE];
+  gdb_byte this_buffer[MAX_REGISTER_SIZE];
 
-  if (memcmp (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
-             register_size (current_gdbarch, regnum)) == 0)
+  /* Registers not valid in this frame return count as unchanged.  */
+  if (!regcache_valid_p (this_regs, regnum))
     return 0;
 
-  /* Found a changed register. Return 1. */
+  /* First time through or after gdbarch change consider all registers as
+     changed.  Same for registers not valid in the previous frame.  */
+  if (!prev_regs || get_regcache_arch (prev_regs) != gdbarch
+      || !regcache_valid_p (prev_regs, regnum))
+    return 1;
 
-  memcpy (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
-         register_size (current_gdbarch, regnum));
+  /* Get register contents and compare.  */
+  regcache_cooked_read (prev_regs, regnum, prev_buffer);
+  regcache_cooked_read (this_regs, regnum, this_buffer);
 
-  return 1;
+  return memcmp (prev_buffer, this_buffer,
+                register_size (gdbarch, regnum)) != 0;
 }
 
-/* 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
-   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
    format argumetn there can be a sequence of numbers, indicating which
-   registers to fetch the content of. If the format is the only argument,
-   a list of all the registers with their values is returned. */
-enum mi_cmd_result
+   registers to fetch the content of.  If the format is the only argument,
+   a list of all the registers with their values is returned.  */
+void
 mi_cmd_data_list_register_values (char *command, char **argv, int argc)
 {
-  int regnum, numregs, format, result;
+  struct frame_info *frame;
+  struct gdbarch *gdbarch;
+  int regnum, numregs, format;
   int i;
   struct cleanup *list_cleanup, *tuple_cleanup;
 
   /* Note that the test for a valid register must include checking the
-     REGISTER_NAME because NUM_REGS may be allocated for the union of
-     the register sets within a family of related processors.  In this
-     case, some entries of REGISTER_NAME will change depending upon
-     the particular processor being debugged.  */
-
-  numregs = NUM_REGS + NUM_PSEUDO_REGS;
+     gdbarch_register_name because gdbarch_num_regs may be allocated for
+     the union of the register sets within a family of related processors.
+     In this case, some entries of gdbarch_register_name will change depending
+     upon the particular processor being debugged.  */
 
   if (argc == 0)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
 
   format = (int) argv[0][0];
 
+  frame = get_selected_frame (NULL);
+  gdbarch = get_frame_arch (frame);
+  numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+
   list_cleanup = make_cleanup_ui_out_list_begin_end (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;
           regnum < numregs;
           regnum++)
        {
-         if (REGISTER_NAME (regnum) == NULL
-             || *(REGISTER_NAME (regnum)) == '\0')
+         if (gdbarch_register_name (gdbarch, regnum) == NULL
+             || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
            continue;
          tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
          ui_out_field_int (uiout, "number", regnum);
-         result = get_register (regnum, format);
-         if (result == -1)
-           {
-             do_cleanups (list_cleanup);
-             return MI_CMD_ERROR;
-           }
+         get_register (frame, regnum, format);
          do_cleanups (tuple_cleanup);
        }
     }
 
-  /* Else, list of register #s, just do listed regs */
+  /* Else, list of register #s, just do listed regs */
   for (i = 1; i < argc; i++)
     {
       regnum = atoi (argv[i]);
 
       if (regnum >= 0
          && regnum < numregs
-         && REGISTER_NAME (regnum) != NULL
-         && *REGISTER_NAME (regnum) != '\000')
+         && gdbarch_register_name (gdbarch, regnum) != NULL
+         && *gdbarch_register_name (gdbarch, regnum) != '\000')
        {
          tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
          ui_out_field_int (uiout, "number", regnum);
-         result = get_register (regnum, format);
-         if (result == -1)
-           {
-             do_cleanups (list_cleanup);
-             return MI_CMD_ERROR;
-           }
+         get_register (frame, regnum, format);
          do_cleanups (tuple_cleanup);
        }
       else
-       {
-         do_cleanups (list_cleanup);
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
+       error ("bad register number");
     }
   do_cleanups (list_cleanup);
-  return MI_CMD_DONE;
 }
 
-/* Output one register's contents in the desired format. */
-static int
-get_register (int regnum, int format)
+/* Output one register's contents in the desired format.  */
+static void
+get_register (struct frame_info *frame, int regnum, int format)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte buffer[MAX_REGISTER_SIZE];
   int optim;
   int realnum;
@@ -503,14 +1094,10 @@ get_register (int regnum, int format)
   if (format == 'N')
     format = 0;
 
-  frame_register (get_selected_frame (NULL), regnum, &optim, &lval, &addr,
-                 &realnum, buffer);
+  frame_register (frame, regnum, &optim, &lval, &addr, &realnum, buffer);
 
   if (optim)
-    {
-      mi_error_message = xstrprintf ("Optimized out");
-      return -1;
-    }
+    error ("Optimized out");
 
   if (format == 'r')
     {
@@ -519,10 +1106,11 @@ get_register (int regnum, int format)
 
       strcpy (buf, "0x");
       ptr = buf + 2;
-      for (j = 0; j < register_size (current_gdbarch, regnum); j++)
+      for (j = 0; j < register_size (gdbarch, regnum); j++)
        {
-         int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
-         : register_size (current_gdbarch, regnum) - 1 - j;
+         int idx = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ?
+                   j : register_size (gdbarch, regnum) - 1 - j;
+
          sprintf (ptr, "%02x", (unsigned char) buffer[idx]);
          ptr += 2;
        }
@@ -531,139 +1119,91 @@ get_register (int regnum, int format)
     }
   else
     {
-      val_print (register_type (current_gdbarch, regnum), buffer, 0, 0,
-                stb->stream, format, 1, 0, Val_pretty_default);
+      struct value_print_options opts;
+
+      get_formatted_print_options (&opts, format);
+      opts.deref_ref = 1;
+      val_print (register_type (gdbarch, regnum), buffer, 0, 0,
+                stb->stream, 0, &opts, current_language);
       ui_out_field_stream (uiout, "value", stb);
       ui_out_stream_delete (stb);
     }
-  return 1;
 }
 
 /* Write given values into registers. The registers and values are
-   given as pairs. The corresponding MI command is 
+   given as pairs.  The corresponding MI command is 
    -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]*/
-enum mi_cmd_result
+void
 mi_cmd_data_write_register_values (char *command, char **argv, int argc)
 {
-  int regnum;
-  int i;
-  int numregs;
-  LONGEST value;
+  struct regcache *regcache;
+  struct gdbarch *gdbarch;
+  int numregs, i;
   char format;
 
   /* Note that the test for a valid register must include checking the
-     REGISTER_NAME because NUM_REGS may be allocated for the union of
-     the register sets within a family of related processors.  In this
-     case, some entries of REGISTER_NAME will change depending upon
-     the particular processor being debugged.  */
+     gdbarch_register_name because gdbarch_num_regs may be allocated for
+     the union of the register sets within a family of related processors.
+     In this case, some entries of gdbarch_register_name will change depending
+     upon the particular processor being debugged.  */
 
-  numregs = NUM_REGS + NUM_PSEUDO_REGS;
+  regcache = get_current_regcache ();
+  gdbarch = get_regcache_arch (regcache);
+  numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 
   if (argc == 0)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
 
   format = (int) argv[0][0];
 
   if (!target_has_registers)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: No registers.");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_write_register_values: No registers.");
 
   if (!(argc - 1))
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: No regs and values specified.");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_write_register_values: No regs and values specified.");
 
   if ((argc - 1) % 2)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
 
   for (i = 1; i < argc; i = i + 2)
     {
-      regnum = atoi (argv[i]);
+      int regnum = atoi (argv[i]);
 
-      if (regnum >= 0
-         && regnum < numregs
-         && REGISTER_NAME (regnum) != NULL
-         && *REGISTER_NAME (regnum) != '\000')
+      if (regnum >= 0 && regnum < numregs
+         && gdbarch_register_name (gdbarch, regnum)
+         && *gdbarch_register_name (gdbarch, regnum))
        {
-         void *buffer;
-         struct cleanup *old_chain;
+         LONGEST value;
 
-         /* Get the value as a number */
+         /* Get the value as a number */
          value = parse_and_eval_address (argv[i + 1]);
-         /* Get the value into an array */
-         buffer = xmalloc (DEPRECATED_REGISTER_SIZE);
-         old_chain = make_cleanup (xfree, buffer);
-         store_signed_integer (buffer, DEPRECATED_REGISTER_SIZE, value);
-         /* Write it down */
-         deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (regnum), buffer, register_size (current_gdbarch, regnum));
-         /* Free the buffer.  */
-         do_cleanups (old_chain);
+
+         /* Write it down.  */
+         regcache_cooked_write_signed (regcache, regnum, value);
        }
       else
-       {
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
+       error ("bad register number");
     }
-  return MI_CMD_DONE;
 }
 
-#if 0
-/*This is commented out because we decided it was not useful. I leave
-   it, just in case. ezannoni:1999-12-08 */
-
-/* Assign a value to a variable. The expression argument must be in
-   the form A=2 or "A = 2" (I.e. if there are spaces it needs to be
-   quoted. */
-enum mi_cmd_result
-mi_cmd_data_assign (char *command, char **argv, int argc)
-{
-  struct expression *expr;
-  struct cleanup *old_chain;
-
-  if (argc != 1)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_assign: Usage: -data-assign expression");
-      return MI_CMD_ERROR;
-    }
-
-  /* NOTE what follows is a clone of set_command(). FIXME: ezannoni
-     01-12-1999: Need to decide what to do with this for libgdb purposes. */
-
-  expr = parse_expression (argv[0]);
-  old_chain = make_cleanup (free_current_contents, &expr);
-  evaluate_expression (expr);
-  do_cleanups (old_chain);
-  return MI_CMD_DONE;
-}
-#endif
-
-/* Evaluate the value of the argument. The argument is an
+/* Evaluate the value of the argument.  The argument is an
    expression. If the expression contains spaces it needs to be
-   included in double quotes. */
-enum mi_cmd_result
+   included in double quotes.  */
+void
 mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
 {
   struct expression *expr;
   struct cleanup *old_chain = NULL;
   struct value *val;
   struct ui_stream *stb = NULL;
+  struct value_print_options opts;
 
   stb = ui_out_stream_new (uiout);
 
   if (argc != 1)
     {
-      mi_error_message = xstrprintf ("mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression expression");
-      return MI_CMD_ERROR;
+      ui_out_stream_delete (stb);
+      error ("mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression expression");
     }
 
   expr = parse_expression (argv[0]);
@@ -672,69 +1212,25 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
 
   val = evaluate_expression (expr);
 
-  /* Print the result of the expression evaluation. */
+  /* Print the result of the expression evaluation.  */
+  get_user_print_options (&opts);
+  opts.deref_ref = 0;
   val_print (value_type (val), value_contents (val),
-            value_embedded_offset (val), VALUE_ADDRESS (val),
-            stb->stream, 0, 0, 0, 0);
+            value_embedded_offset (val), value_address (val),
+            stb->stream, 0, &opts, current_language);
 
   ui_out_field_stream (uiout, "value", stb);
   ui_out_stream_delete (stb);
 
   do_cleanups (old_chain);
-
-  return MI_CMD_DONE;
-}
-
-enum mi_cmd_result
-mi_cmd_target_download (char *args, int from_tty)
-{
-  char *run;
-  struct cleanup *old_cleanups = NULL;
-
-  run = xstrprintf ("load %s", args);
-  old_cleanups = make_cleanup (xfree, run);
-  execute_command (run, from_tty);
-
-  do_cleanups (old_cleanups);
-  return MI_CMD_DONE;
-}
-
-/* Connect to the remote target. */
-enum mi_cmd_result
-mi_cmd_target_select (char *args, int from_tty)
-{
-  char *run;
-  struct cleanup *old_cleanups = NULL;
-
-  run = xstrprintf ("target %s", args);
-  old_cleanups = make_cleanup (xfree, run);
-
-  /* target-select is always synchronous.  once the call has returned
-     we know that we are connected. */
-  /* NOTE: At present all targets that are connected are also
-     (implicitly) talking to a halted target.  In the future this may
-     change. */
-  execute_command (run, from_tty);
-
-  do_cleanups (old_cleanups);
-
-  /* Issue the completion message here. */
-  if (last_async_command)
-    fputs_unfiltered (last_async_command, raw_stdout);
-  fputs_unfiltered ("^connected", raw_stdout);
-  mi_out_put (uiout, raw_stdout);
-  mi_out_rewind (uiout);
-  fputs_unfiltered ("\n", raw_stdout);
-  do_exec_cleanups (ALL_CLEANUPS);
-  return MI_CMD_QUIET;
 }
 
 /* DATA-MEMORY-READ:
 
    ADDR: start address of data to be dumped.
-   WORD-FORMAT: a char indicating format for the ``word''. See 
+   WORD-FORMAT: a char indicating format for the ``word''.  See 
    the ``x'' command.
-   WORD-SIZE: size of each ``word''; 1,2,4, or 8 bytes
+   WORD-SIZE: size of each ``word''; 1,2,4, or 8 bytes.
    NR_ROW: Number of rows.
    NR_COL: The number of colums (words per row).
    ASCHAR: (OPTIONAL) Append an ascii character dump to each row.  Use
@@ -748,9 +1244,10 @@ mi_cmd_target_select (char *args, int from_tty)
    Returns: 
    The number of bytes read is SIZE*ROW*COL. */
 
-enum mi_cmd_result
+void
 mi_cmd_data_read_memory (char *command, char **argv, int argc)
 {
+  struct gdbarch *gdbarch = get_current_arch ();
   struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
   CORE_ADDR addr;
   long total_bytes;
@@ -773,13 +1270,14 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
   static struct mi_opt opts[] =
   {
     {"o", OFFSET_OPT, 1},
-    0
+    { 0, 0, 0 }
   };
 
   while (1)
     {
       int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts,
                           &optind, &optarg);
+
       if (opt < 0)
        break;
       switch ((enum opt) opt)
@@ -793,93 +1291,86 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
   argc -= optind;
 
   if (argc < 5 || argc > 6)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR].");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR].");
 
   /* Extract all the arguments. */
 
-  /* Start address of the memory dump. */
+  /* Start address of the memory dump.  */
   addr = parse_and_eval_address (argv[0]) + offset;
-  /* The format character to use when displaying a memory word. See
+  /* The format character to use when displaying a memory word.  See
      the ``x'' command. */
   word_format = argv[1][0];
-  /* The size of the memory word. */
+  /* The size of the memory word.  */
   word_size = atol (argv[2]);
   switch (word_size)
     {
     case 1:
-      word_type = builtin_type_int8;
+      word_type = builtin_type (gdbarch)->builtin_int8;
       word_asize = 'b';
       break;
     case 2:
-      word_type = builtin_type_int16;
+      word_type = builtin_type (gdbarch)->builtin_int16;
       word_asize = 'h';
       break;
     case 4:
-      word_type = builtin_type_int32;
+      word_type = builtin_type (gdbarch)->builtin_int32;
       word_asize = 'w';
       break;
     case 8:
-      word_type = builtin_type_int64;
+      word_type = builtin_type (gdbarch)->builtin_int64;
       word_asize = 'g';
       break;
     default:
-      word_type = builtin_type_int8;
+      word_type = builtin_type (gdbarch)->builtin_int8;
       word_asize = 'b';
     }
-  /* The number of rows */
+  /* The number of rows */
   nr_rows = atol (argv[3]);
   if (nr_rows <= 0)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of rows.");
-      return MI_CMD_ERROR;
-    }
-  /* number of bytes per row. */
+    error ("mi_cmd_data_read_memory: invalid number of rows.");
+
+  /* Number of bytes per row.  */
   nr_cols = atol (argv[4]);
   if (nr_cols <= 0)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of columns.");
-      return MI_CMD_ERROR;
-    }
-  /* The un-printable character when printing ascii. */
+    error ("mi_cmd_data_read_memory: invalid number of columns.");
+
+  /* The un-printable character when printing ascii.  */
   if (argc == 6)
     aschar = *argv[5];
   else
     aschar = 0;
 
-  /* create a buffer and read it in. */
+  /* Create a buffer and read it in.  */
   total_bytes = word_size * nr_rows * nr_cols;
   mbuf = xcalloc (total_bytes, 1);
   make_cleanup (xfree, mbuf);
-  nr_bytes = 0;
-  while (nr_bytes < total_bytes)
-    {
-      int error;
-      long num = target_read_memory_partial (addr + nr_bytes, mbuf + nr_bytes,
-                                            total_bytes - nr_bytes,
-                                            &error);
-      if (num <= 0)
-       break;
-      nr_bytes += num;
-    }
 
-  /* output the header information. */
-  ui_out_field_core_addr (uiout, "addr", addr);
+  /* Dispatch memory reads to the topmost target, not the flattened
+     current_target.  */
+  nr_bytes = target_read_until_error (current_target.beneath,
+                                     TARGET_OBJECT_MEMORY, NULL, mbuf,
+                                     addr, total_bytes);
+  if (nr_bytes <= 0)
+    error ("Unable to read memory.");
+
+  /* Output the header information.  */
+  ui_out_field_core_addr (uiout, "addr", gdbarch, addr);
   ui_out_field_int (uiout, "nr-bytes", nr_bytes);
   ui_out_field_int (uiout, "total-bytes", total_bytes);
-  ui_out_field_core_addr (uiout, "next-row", addr + word_size * nr_cols);
-  ui_out_field_core_addr (uiout, "prev-row", addr - word_size * nr_cols);
-  ui_out_field_core_addr (uiout, "next-page", addr + total_bytes);
-  ui_out_field_core_addr (uiout, "prev-page", addr - total_bytes);
-
-  /* Build the result as a two dimentional table. */
+  ui_out_field_core_addr (uiout, "next-row",
+                         gdbarch, addr + word_size * nr_cols);
+  ui_out_field_core_addr (uiout, "prev-row",
+                         gdbarch, addr - word_size * nr_cols);
+  ui_out_field_core_addr (uiout, "next-page", gdbarch, addr + total_bytes);
+  ui_out_field_core_addr (uiout, "prev-page", gdbarch, addr - total_bytes);
+
+  /* Build the result as a two dimentional table.  */
   {
     struct ui_stream *stream = ui_out_stream_new (uiout);
     struct cleanup *cleanup_list_memory;
     int row;
     int row_byte;
+
     cleanup_list_memory = make_cleanup_ui_out_list_begin_end (uiout, "memory");
     for (row = 0, row_byte = 0;
         row < nr_rows;
@@ -889,10 +1380,13 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
        int col_byte;
        struct cleanup *cleanup_tuple;
        struct cleanup *cleanup_list_data;
+       struct value_print_options opts;
+
        cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-       ui_out_field_core_addr (uiout, "addr", addr + row_byte);
+       ui_out_field_core_addr (uiout, "addr", gdbarch, addr + row_byte);
        /* ui_out_field_core_addr_symbolic (uiout, "saddr", addr + row_byte); */
        cleanup_list_data = make_cleanup_ui_out_list_begin_end (uiout, "data");
+       get_formatted_print_options (&opts, word_format);
        for (col = 0, col_byte = row_byte;
             col < nr_cols;
             col++, col_byte += word_size)
@@ -904,7 +1398,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
            else
              {
                ui_file_rewind (stream->stream);
-               print_scalar_formatted (mbuf + col_byte, word_type, word_format,
+               print_scalar_formatted (mbuf + col_byte, word_type, &opts,
                                        word_asize, stream->stream);
                ui_out_field_stream (uiout, NULL, stream);
              }
@@ -913,6 +1407,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
        if (aschar)
          {
            int byte;
+
            ui_file_rewind (stream->stream);
            for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++)
              {
@@ -935,7 +1430,6 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
     do_cleanups (cleanup_list_memory);
   }
   do_cleanups (cleanups);
-  return MI_CMD_DONE;
 }
 
 /* DATA-MEMORY-WRITE:
@@ -944,24 +1438,26 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
    offset from the beginning of the memory grid row where the cell to
    be written is.
    ADDR: start address of the row in the memory grid where the memory
-   cell is, if OFFSET_COLUMN is specified. Otherwise, the address of
+   cell is, if OFFSET_COLUMN is specified.  Otherwise, the address of
    the location to write to.
-   FORMAT: a char indicating format for the ``word''. See 
+   FORMAT: a char indicating format for the ``word''.  See 
    the ``x'' command.
    WORD_SIZE: size of each ``word''; 1,2,4, or 8 bytes
    VALUE: value to be written into the memory address.
 
    Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE).
 
-   Prints nothing. */
-enum mi_cmd_result
+   Prints nothing.  */
+void
 mi_cmd_data_write_memory (char *command, char **argv, int argc)
 {
+  struct gdbarch *gdbarch = get_current_arch ();
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR addr;
   char word_format;
   long word_size;
   /* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big
-     enough when using a compiler other than GCC. */
+     enough when using a compiler other than GCC.  */
   LONGEST value;
   void *buffer;
   struct cleanup *old_chain;
@@ -975,13 +1471,14 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc)
   static struct mi_opt opts[] =
   {
     {"o", OFFSET_OPT, 1},
-    0
+    { 0, 0, 0 }
   };
 
   while (1)
     {
       int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
                           &optind, &optarg);
+
       if (opt < 0)
        break;
       switch ((enum opt) opt)
@@ -995,110 +1492,192 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc)
   argc -= optind;
 
   if (argc != 4)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
 
-  /* Extract all the arguments. */
-  /* Start address of the memory dump. */
+  /* Extract all the arguments.  */
+  /* Start address of the memory dump.  */
   addr = parse_and_eval_address (argv[0]);
-  /* The format character to use when displaying a memory word. See
-     the ``x'' command. */
+  /* The format character to use when displaying a memory word.  See
+     the ``x'' command.  */
   word_format = argv[1][0];
   /* The size of the memory word. */
   word_size = atol (argv[2]);
 
-  /* Calculate the real address of the write destination. */
+  /* Calculate the real address of the write destination.  */
   addr += (offset * word_size);
 
-  /* Get the value as a number */
+  /* Get the value as a number */
   value = parse_and_eval_address (argv[3]);
-  /* Get the value into an array */
+  /* Get the value into an array */
   buffer = xmalloc (word_size);
   old_chain = make_cleanup (xfree, buffer);
-  store_signed_integer (buffer, word_size, value);
-  /* Write it down to memory */
+  store_signed_integer (buffer, word_size, byte_order, value);
+  /* Write it down to memory */
   write_memory (addr, buffer, word_size);
   /* Free the buffer.  */
   do_cleanups (old_chain);
+}
+
+void
+mi_cmd_enable_timings (char *command, char **argv, int argc)
+{
+  if (argc == 0)
+    do_timings = 1;
+  else if (argc == 1)
+    {
+      if (strcmp (argv[0], "yes") == 0)
+       do_timings = 1;
+      else if (strcmp (argv[0], "no") == 0)
+       do_timings = 0;
+      else
+       goto usage_error;
+    }
+  else
+    goto usage_error;
+    
+  return;
+
+ usage_error:
+  error ("mi_cmd_enable_timings: Usage: %s {yes|no}", command);
+}
+
+void
+mi_cmd_list_features (char *command, char **argv, int argc)
+{
+  if (argc == 0)
+    {
+      struct cleanup *cleanup = NULL;
+
+      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");      
+      ui_out_field_string (uiout, NULL, "frozen-varobjs");
+      ui_out_field_string (uiout, NULL, "pending-breakpoints");
+      ui_out_field_string (uiout, NULL, "thread-info");
+      
+#if HAVE_PYTHON
+      ui_out_field_string (uiout, NULL, "python");
+#endif
+      
+      do_cleanups (cleanup);
+      return;
+    }
+
+  error ("-list-features should be passed no arguments");
+}
+
+void
+mi_cmd_list_target_features (char *command, char **argv, int argc)
+{
+  if (argc == 0)
+    {
+      struct cleanup *cleanup = NULL;
 
-  return MI_CMD_DONE;
+      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");      
+      if (target_can_async_p ())
+       ui_out_field_string (uiout, NULL, "async");
+      
+      do_cleanups (cleanup);
+      return;
+    }
+
+  error ("-list-target-features should be passed no arguments");
+}
+
+void
+mi_cmd_add_inferior (char *command, char **argv, int argc)
+{
+  struct inferior *inf;
+
+  if (argc != 0)
+    error (_("-add-inferior should be passed no arguments"));
+
+  inf = add_inferior_with_spaces ();
+
+  ui_out_field_fmt (uiout, "inferior", "i%d", inf->num);
+}
+
+void
+mi_cmd_remove_inferior (char *command, char **argv, int argc)
+{
+  int id;
+  struct inferior *inf;
+
+  if (argc != 1)
+    error ("-remove-inferior should be passed a single argument");
+
+  if (sscanf (argv[1], "i%d", &id) != 1)
+    error ("the thread group id is syntactically invalid");
+
+  inf = find_inferior_id (id);
+  if (!inf)
+    error ("the specified thread group does not exist");
+
+  delete_inferior_1 (inf, 1 /* silent */);
 }
 
+\f
+
 /* Execute a command within a safe environment.
    Return <0 for error; >=0 for ok.
 
    args->action will tell mi_execute_command what action
-   to perfrom after the given command has executed (display/supress
+   to perfrom after the given command has executed (display/suppress
    prompt, display error). */
 
 static void
 captured_mi_execute_command (struct ui_out *uiout, void *data)
 {
-  struct captured_mi_execute_command_args *args =
-    (struct captured_mi_execute_command_args *) data;
-  struct mi_parse *context = args->command;
+  struct cleanup *cleanup;
+  struct mi_parse *context = (struct mi_parse *) data;
+
+  if (do_timings)
+    current_command_ts = context->cmd_start;
+
+  current_token = xstrdup (context->token);
+  cleanup = make_cleanup (free_current_contents, &current_token);
 
+  running_result_record_printed = 0;
+  mi_proceeded = 0;
   switch (context->op)
     {
-
     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)
        /* FIXME: gdb_???? */
        fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n",
                            context->token, context->command, context->args);
-      /* FIXME: cagney/1999-09-25: Rather than this convoluted
-         condition expression, each function should return an
-         indication of what action is required and then switch on
-         that. */
-      args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
-      args->rc = mi_cmd_execute (context);
-
-      if (!target_can_async_p () || !target_executing)
-       {
-         /* print the result if there were no errors
 
-            Remember that on the way out of executing a command, you have
-            to directly use the mi_interp's uiout, since the command could 
-            have reset the interpreter, in which case the current uiout 
-            will most likely crash in the mi_out_* routines.  */
-         if (args->rc == MI_CMD_DONE)
-           {
-             fputs_unfiltered (context->token, raw_stdout);
-             fputs_unfiltered ("^done", raw_stdout);
-             mi_out_put (uiout, raw_stdout);
-             mi_out_rewind (uiout);
-             fputs_unfiltered ("\n", raw_stdout);
-           }
-         else if (args->rc == MI_CMD_ERROR)
-           {
-             if (mi_error_message)
-               {
-                 fputs_unfiltered (context->token, raw_stdout);
-                 fputs_unfiltered ("^error,msg=\"", raw_stdout);
-                 fputstr_unfiltered (mi_error_message, '"', raw_stdout);
-                 xfree (mi_error_message);
-                 fputs_unfiltered ("\"\n", raw_stdout);
-               }
-             mi_out_rewind (uiout);
-           }
-         else
-           mi_out_rewind (uiout);
-       }
-      else if (sync_execution)
+
+      mi_cmd_execute (context);
+
+      /* Print the result if there were no errors.
+
+        Remember that on the way out of executing a command, you have
+        to directly use the mi_interp's uiout, since the command could 
+        have reset the interpreter, in which case the current uiout 
+        will most likely crash in the mi_out_* routines.  */
+      if (!running_result_record_printed)
        {
-         /* Don't print the prompt. We are executing the target in
-            synchronous mode. */
-         args->action = EXECUTE_COMMAND_SUPRESS_PROMPT;
-         return;
+         fputs_unfiltered (context->token, raw_stdout);
+         /* There's no particularly good reason why target-connect results
+            in not ^done.  Should kill ^connected for MI3.  */
+         fputs_unfiltered (strcmp (context->command, "target-select") == 0
+                           ? "^connected" : "^done", raw_stdout);
+         mi_out_put (uiout, raw_stdout);
+         mi_out_rewind (uiout);
+         mi_print_timing_maybe ();
+         fputs_unfiltered ("\n", raw_stdout);
        }
+      else
+           /* The command does not want anything to be printed.  In that
+              case, the command probably should not have written anything
+              to uiout, but in case it has written something, discard it.  */
+       mi_out_rewind (uiout);
       break;
 
     case CLI_COMMAND:
       {
        char *argv[2];
+
        /* A CLI command was read from the input stream.  */
        /* This "feature" will be removed as soon as we have a
           complete set of mi commands.  */
@@ -1109,27 +1688,31 @@ captured_mi_execute_command (struct ui_out *uiout, void *data)
        argv[1] = context->command;
        mi_cmd_interpreter_exec ("-interpreter-exec", argv, 2);
 
-       /* If we changed interpreters, DON'T print out anything. */
+       /* If we changed interpreters, DON'T print out anything.  */
        if (current_interp_named_p (INTERP_MI)
            || current_interp_named_p (INTERP_MI1)
            || current_interp_named_p (INTERP_MI2)
            || current_interp_named_p (INTERP_MI3))
          {
-           /* print the result */
-           /* FIXME: Check for errors here. */
-           fputs_unfiltered (context->token, raw_stdout);
-           fputs_unfiltered ("^done", raw_stdout);
-           mi_out_put (uiout, raw_stdout);
-           mi_out_rewind (uiout);
-           fputs_unfiltered ("\n", raw_stdout);
-           args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
-           args->rc = MI_CMD_DONE;
+           if (!running_result_record_printed)
+             {
+               fputs_unfiltered (context->token, raw_stdout);
+               fputs_unfiltered ("^done", raw_stdout);
+               mi_out_put (uiout, raw_stdout);
+               mi_out_rewind (uiout);
+               mi_print_timing_maybe ();
+               fputs_unfiltered ("\n", raw_stdout);            
+             }
+           else
+             mi_out_rewind (uiout);
          }
        break;
       }
 
     }
 
+  do_cleanups (cleanup);
+
   return;
 }
 
@@ -1138,120 +1721,192 @@ void
 mi_execute_command (char *cmd, int from_tty)
 {
   struct mi_parse *command;
-  struct captured_mi_execute_command_args args;
-  struct ui_out *saved_uiout = uiout;
 
-  /* This is to handle EOF (^D). We just quit gdb. */
-  /* FIXME: we should call some API function here. */
+  /* This is to handle EOF (^D). We just quit gdb.  */
+  /* FIXME: we should call some API function here.  */
   if (cmd == 0)
     quit_force (NULL, from_tty);
 
+  target_log_command (cmd);
+
   command = mi_parse (cmd);
 
   if (command != NULL)
     {
       struct gdb_exception result;
-      /* FIXME: cagney/1999-11-04: Can this use of catch_exceptions either
-         be pushed even further down or even eliminated? */
-      args.command = command;
-      result = catch_exception (uiout, captured_mi_execute_command, &args,
-                               RETURN_MASK_ALL);
-      exception_print (gdb_stderr, result);
+      ptid_t previous_ptid = inferior_ptid;
 
-      if (args.action == EXECUTE_COMMAND_SUPRESS_PROMPT)
+      if (do_timings)
        {
-         /* The command is executing synchronously.  Bail out early
-            suppressing the finished prompt. */
-         mi_parse_free (command);
-         return;
+         command->cmd_start = (struct mi_timestamp *)
+           xmalloc (sizeof (struct mi_timestamp));
+         timestamp (command->cmd_start);
        }
+
+      result = catch_exception (uiout, captured_mi_execute_command, command,
+                               RETURN_MASK_ALL);
       if (result.reason < 0)
        {
          /* The command execution failed and error() was called
             somewhere.  */
          fputs_unfiltered (command->token, raw_stdout);
          fputs_unfiltered ("^error,msg=\"", raw_stdout);
-         fputstr_unfiltered (result.message, '"', raw_stdout);
+         if (result.message == NULL)
+           fputs_unfiltered ("unknown error", raw_stdout);
+         else
+           fputstr_unfiltered (result.message, '"', raw_stdout);
          fputs_unfiltered ("\"\n", raw_stdout);
          mi_out_rewind (uiout);
        }
+
+      bpstat_do_actions ();
+
+      if (/* The notifications are only output when the top-level
+            interpreter (specified on the command line) is MI.  */      
+         ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ()))
+         /* Don't try report anything if there are no threads -- 
+            the program is dead.  */
+         && thread_count () != 0
+         /* -thread-select explicitly changes thread. If frontend uses that
+            internally, we don't want to emit =thread-selected, since
+            =thread-selected is supposed to indicate user's intentions.  */
+         && strcmp (command->command, "thread-select") != 0)
+       {
+         struct mi_interp *mi = top_level_interpreter_data ();
+         int report_change = 0;
+
+         if (command->thread == -1)
+           {
+             report_change = (!ptid_equal (previous_ptid, null_ptid)
+                              && !ptid_equal (inferior_ptid, previous_ptid)
+                              && !ptid_equal (inferior_ptid, null_ptid));
+           }
+         else if (!ptid_equal (inferior_ptid, null_ptid))
+           {
+             struct thread_info *ti = inferior_thread ();
+
+             report_change = (ti->num != command->thread);
+           }
+
+         if (report_change)
+           {     
+             struct thread_info *ti = inferior_thread ();
+
+             target_terminal_ours ();
+             fprintf_unfiltered (mi->event_channel, 
+                                 "thread-selected,id=\"%d\"",
+                                 ti->num);
+             gdb_flush (mi->event_channel);
+           }
+       }
+
       mi_parse_free (command);
     }
 
   fputs_unfiltered ("(gdb) \n", raw_stdout);
   gdb_flush (raw_stdout);
-  /* print any buffered hook code */
+  /* Print any buffered hook code.  */
   /* ..... */
 }
 
-static enum mi_cmd_result
+static void
 mi_cmd_execute (struct mi_parse *parse)
 {
-  if (parse->cmd->argv_func != NULL
-      || parse->cmd->args_func != NULL)
-    {
-      /* FIXME: We need to save the token because the command executed
-         may be asynchronous and need to print the token again.
-         In the future we can pass the token down to the func
-         and get rid of the last_async_command */
-      /* The problem here is to keep the token around when we launch
-         the target, and we want to interrupt it later on.  The
-         interrupt command will have its own token, but when the
-         target stops, we must display the token corresponding to the
-         last execution command given. So we have another string where
-         we copy the token (previous_async_command), if this was
-         indeed the token of an execution command, and when we stop we
-         print that one. This is possible because the interrupt
-         command, when over, will copy that token back into the
-         default token string (last_async_command). */
-
-      if (target_executing)
-       {
-         if (!previous_async_command)
-           previous_async_command = xstrdup (last_async_command);
-         if (strcmp (parse->command, "exec-interrupt"))
-           {
-             fputs_unfiltered (parse->token, raw_stdout);
-             fputs_unfiltered ("^error,msg=\"", raw_stdout);
-             fputs_unfiltered ("Cannot execute command ", raw_stdout);
-             fputstr_unfiltered (parse->command, '"', raw_stdout);
-             fputs_unfiltered (" while target running", raw_stdout);
-             fputs_unfiltered ("\"\n", raw_stdout);
-             return MI_CMD_ERROR;
-           }
-       }
-      last_async_command = xstrdup (parse->token);
-      make_exec_cleanup (free_current_contents, &last_async_command);
-      /* FIXME: DELETE THIS! */
-      if (parse->cmd->args_func != NULL)
-       return parse->cmd->args_func (parse->args, 0 /*from_tty */ );
-      return parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
+  struct cleanup *cleanup;
+
+  prepare_execute_command ();
+
+  cleanup = make_cleanup (null_cleanup, NULL);
+
+  if (parse->all && parse->thread_group != -1)
+    error (_("Cannot specify --thread-group together with --all"));
+
+  if (parse->all && parse->thread != -1)
+    error (_("Cannot specify --thread together with --all"));
+
+  if (parse->thread_group != -1 && parse->thread != -1)
+    error (_("Cannot specify --thread together with --thread-group"));
+
+  if (parse->frame != -1 && parse->thread == -1)
+    error (_("Cannot specify --frame without --thread"));
+
+  if (parse->thread_group != -1)
+    {
+      struct inferior *inf = find_inferior_id (parse->thread_group);
+      struct thread_info *tp = 0;
+
+      if (!inf)
+       error (_("Invalid thread group for the --thread-group option"));
+
+      set_current_inferior (inf);
+      /* This behaviour means that if --thread-group option identifies
+        an inferior with multiple threads, then a random one will be picked.
+        This is not a problem -- frontend should always provide --thread if
+        it wishes to operate on a specific thread.  */
+      if (inf->pid != 0)
+       tp = any_thread_of_process (inf->pid);
+      switch_to_thread (tp ? tp->ptid : null_ptid);
+      set_current_program_space (inf->pspace);
     }
+
+  if (parse->thread != -1)
+    {
+      struct thread_info *tp = find_thread_id (parse->thread);
+
+      if (!tp)
+       error (_("Invalid thread id: %d"), parse->thread);
+
+      if (is_exited (tp->ptid))
+       error (_("Thread id: %d has terminated"), parse->thread);
+
+      switch_to_thread (tp->ptid);
+    }
+
+  if (parse->frame != -1)
+    {
+      struct frame_info *fid;
+      int frame = parse->frame;
+
+      fid = find_relative_frame (get_current_frame (), &frame);
+      if (frame == 0)
+       /* find_relative_frame was successful */
+       select_frame (fid);
+      else
+       error (_("Invalid frame id: %d"), frame);
+    }
+
+  current_context = parse;
+
+  if (parse->cmd->argv_func != NULL)
+    parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
   else if (parse->cmd->cli.cmd != 0)
     {
       /* FIXME: DELETE THIS. */
-      /* The operation is still implemented by a cli command */
-      /* Must be a synchronous one */
+      /* The operation is still implemented by a cli command */
+      /* Must be a synchronous one */
       mi_execute_cli_command (parse->cmd->cli.cmd, parse->cmd->cli.args_p,
                              parse->args);
-      return MI_CMD_DONE;
     }
   else
     {
-      /* FIXME: DELETE THIS. */
-      fputs_unfiltered (parse->token, raw_stdout);
-      fputs_unfiltered ("^error,msg=\"", raw_stdout);
-      fputs_unfiltered ("Undefined mi command: ", raw_stdout);
-      fputstr_unfiltered (parse->command, '"', raw_stdout);
-      fputs_unfiltered (" (missing implementation)", raw_stdout);
-      fputs_unfiltered ("\"\n", raw_stdout);
-      return MI_CMD_ERROR;
+      /* FIXME: DELETE THIS.  */
+      struct ui_file *stb;
+
+      stb = mem_fileopen ();
+
+      fputs_unfiltered ("Undefined mi command: ", stb);
+      fputstr_unfiltered (parse->command, '"', stb);
+      fputs_unfiltered (" (missing implementation)", stb);
+
+      make_cleanup_ui_file_delete (stb);
+      error_stream (stb);
     }
+  do_cleanups (cleanup);
 }
 
 /* FIXME: This is just a hack so we can get some extra commands going.
-   We don't want to channel things through the CLI, but call libgdb directly */
-/* Use only for synchronous commands */
+   We don't want to channel things through the CLI, but call libgdb directly.
+   Use only for synchronous commands.  */
 
 void
 mi_execute_cli_command (const char *cmd, int args_p, const char *args)
@@ -1260,6 +1915,7 @@ mi_execute_cli_command (const char *cmd, int args_p, const char *args)
     {
       struct cleanup *old_cleanups;
       char *run;
+
       if (args_p)
        run = xstrprintf ("%s %s", cmd, args);
       else
@@ -1275,83 +1931,32 @@ mi_execute_cli_command (const char *cmd, int args_p, const char *args)
     }
 }
 
-enum mi_cmd_result
-mi_execute_async_cli_command (char *mi, char *args, int from_tty)
+void
+mi_execute_async_cli_command (char *cli_command, char **argv, int argc)
 {
   struct cleanup *old_cleanups;
   char *run;
-  char *async_args;
 
   if (target_can_async_p ())
-    {
-      async_args = (char *) xmalloc (strlen (args) + 2);
-      make_exec_cleanup (free, async_args);
-      strcpy (async_args, args);
-      strcat (async_args, "&");
-      run = xstrprintf ("%s %s", mi, async_args);
-      make_exec_cleanup (free, run);
-      add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
-      old_cleanups = NULL;
-    }
+    run = xstrprintf ("%s %s&", cli_command, argc ? *argv : "");
   else
-    {
-      run = xstrprintf ("%s %s", mi, args);
-      old_cleanups = make_cleanup (xfree, run);
-    }
+    run = xstrprintf ("%s %s", cli_command, argc ? *argv : "");
+  old_cleanups = make_cleanup (xfree, run);  
+
+  execute_command ( /*ui */ run, 0 /*from_tty */ );
 
-  if (!target_can_async_p ())
+  if (target_can_async_p ())
     {
-      /* NOTE: For synchronous targets asynchronous behavour is faked by
-         printing out the GDB prompt before we even try to execute the
-         command. */
-      if (last_async_command)
-       fputs_unfiltered (last_async_command, raw_stdout);
-      fputs_unfiltered ("^running\n", raw_stdout);
-      fputs_unfiltered ("(gdb) \n", raw_stdout);
-      gdb_flush (raw_stdout);
+      /* If we're not executing, an exception should have been throw.  */
+      gdb_assert (is_running (inferior_ptid));
+      do_cleanups (old_cleanups);
     }
   else
-    {
-      /* FIXME: cagney/1999-11-29: Printing this message before
-         calling execute_command is wrong.  It should only be printed
-         once gdb has confirmed that it really has managed to send a
-         run command to the target. */
-      if (last_async_command)
-       fputs_unfiltered (last_async_command, raw_stdout);
-      fputs_unfiltered ("^running\n", raw_stdout);
-    }
-
-  execute_command ( /*ui */ run, 0 /*from_tty */ );
-
-  if (!target_can_async_p ())
     {
       /* Do this before doing any printing.  It would appear that some
-         print code leaves garbage around in the buffer. */
+         print code leaves garbage around in the buffer.  */
       do_cleanups (old_cleanups);
-      /* If the target was doing the operation synchronously we fake
-         the stopped message. */
-      if (last_async_command)
-       fputs_unfiltered (last_async_command, raw_stdout);
-      fputs_unfiltered ("*stopped", raw_stdout);
-      mi_out_put (uiout, raw_stdout);
-      mi_out_rewind (uiout);
-      fputs_unfiltered ("\n", raw_stdout);
-      return MI_CMD_QUIET;
     }
-  return MI_CMD_DONE;
-}
-
-void
-mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg)
-{
-  if (last_async_command)
-    fputs_unfiltered (last_async_command, raw_stdout);
-  fputs_unfiltered ("*stopped", raw_stdout);
-  mi_out_put (uiout, raw_stdout);
-  fputs_unfiltered ("\n", raw_stdout);
-  fputs_unfiltered ("(gdb) \n", raw_stdout);
-  gdb_flush (raw_stdout);
-  do_exec_cleanups (ALL_CLEANUPS);
 }
 
 void
@@ -1372,10 +1977,13 @@ mi_load_progress (const char *section_name,
      of this function.  */
   saved_uiout = uiout;
 
-  if (current_interp_named_p (INTERP_MI))
+  if (current_interp_named_p (INTERP_MI)
+      || current_interp_named_p (INTERP_MI2))
     uiout = mi_out_new (2);
   else if (current_interp_named_p (INTERP_MI1))
     uiout = mi_out_new (1);
+  else if (current_interp_named_p (INTERP_MI3))
+    uiout = mi_out_new (3);
   else
     return;
 
@@ -1389,7 +1997,7 @@ mi_load_progress (const char *section_name,
   if (delta.tv_usec < 0)
     {
       delta.tv_sec -= 1;
-      delta.tv_usec += 1000000;
+      delta.tv_usec += 1000000L;
     }
 
   new_section = (previous_sect_name ?
@@ -1397,11 +2005,12 @@ mi_load_progress (const char *section_name,
   if (new_section)
     {
       struct cleanup *cleanup_tuple;
+
       xfree (previous_sect_name);
       previous_sect_name = xstrdup (section_name);
 
-      if (last_async_command)
-       fputs_unfiltered (last_async_command, raw_stdout);
+      if (current_token)
+       fputs_unfiltered (current_token, raw_stdout);
       fputs_unfiltered ("+download", raw_stdout);
       cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
       ui_out_field_string (uiout, "section", section_name);
@@ -1417,10 +2026,11 @@ mi_load_progress (const char *section_name,
       delta.tv_usec >= update_threshold.tv_usec)
     {
       struct cleanup *cleanup_tuple;
+
       last_update.tv_sec = time_now.tv_sec;
       last_update.tv_usec = time_now.tv_usec;
-      if (last_async_command)
-       fputs_unfiltered (last_async_command, raw_stdout);
+      if (current_token)
+       fputs_unfiltered (current_token, raw_stdout);
       fputs_unfiltered ("+download", raw_stdout);
       cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
       ui_out_field_string (uiout, "section", section_name);
@@ -1438,16 +2048,237 @@ mi_load_progress (const char *section_name,
   uiout = saved_uiout;
 }
 
+static void 
+timestamp (struct mi_timestamp *tv)
+  {
+    gettimeofday (&tv->wallclock, NULL);
+#ifdef HAVE_GETRUSAGE
+    getrusage (RUSAGE_SELF, &rusage);
+    tv->utime.tv_sec = rusage.ru_utime.tv_sec;
+    tv->utime.tv_usec = rusage.ru_utime.tv_usec;
+    tv->stime.tv_sec = rusage.ru_stime.tv_sec;
+    tv->stime.tv_usec = rusage.ru_stime.tv_usec;
+#else
+    {
+      long usec = get_run_time ();
+
+      tv->utime.tv_sec = usec/1000000L;
+      tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec;
+      tv->stime.tv_sec = 0;
+      tv->stime.tv_usec = 0;
+    }
+#endif
+  }
+
+static void 
+print_diff_now (struct mi_timestamp *start)
+  {
+    struct mi_timestamp now;
+
+    timestamp (&now);
+    print_diff (start, &now);
+  }
+
+void
+mi_print_timing_maybe (void)
+{
+  /* If the command is -enable-timing then do_timings may be
+     true whilst current_command_ts is not initialized.  */
+  if (do_timings && current_command_ts)
+    print_diff_now (current_command_ts);
+}
+
+static long 
+timeval_diff (struct timeval start, struct timeval end)
+  {
+    return ((end.tv_sec - start.tv_sec) * 1000000L)
+      + (end.tv_usec - start.tv_usec);
+  }
+
+static void 
+print_diff (struct mi_timestamp *start, struct mi_timestamp *end)
+  {
+    fprintf_unfiltered
+      (raw_stdout,
+       ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}", 
+       timeval_diff (start->wallclock, end->wallclock) / 1000000.0, 
+       timeval_diff (start->utime, end->utime) / 1000000.0, 
+       timeval_diff (start->stime, end->stime) / 1000000.0);
+  }
+
+void
+mi_cmd_trace_define_variable (char *command, char **argv, int argc)
+{
+  struct expression *expr;
+  struct cleanup *back_to;
+  LONGEST initval = 0;
+  struct trace_state_variable *tsv;
+  char *name = 0;
+
+  if (argc != 1 && argc != 2)
+    error (_("Usage: -trace-define-variable VARIABLE [VALUE]"));
+
+  expr = parse_expression (argv[0]);
+  back_to = make_cleanup (xfree, expr);
+
+  if (expr->nelts == 3 && expr->elts[0].opcode == OP_INTERNALVAR)
+    {
+      struct internalvar *intvar = expr->elts[1].internalvar;
+
+      if (intvar)
+       name = internalvar_name (intvar);
+    }
+
+  if (!name || *name == '\0')
+    error (_("Invalid name of trace variable"));
+
+  tsv = find_trace_state_variable (name);
+  if (!tsv)
+    tsv = create_trace_state_variable (name);
+
+  if (argc == 2)
+    initval = value_as_long (parse_and_eval (argv[1]));
+
+  tsv->initial_value = initval;
+
+  do_cleanups (back_to);
+}
+
+void
+mi_cmd_trace_list_variables (char *command, char **argv, int argc)
+{
+  if (argc != 0)
+    error (_("-trace-list-variables: no arguments are allowed"));
+
+  tvariables_info_1 ();
+}
+
+void
+mi_cmd_trace_find (char *command, char **argv, int argc)
+{
+  char *mode;
+
+  if (argc == 0)
+    error (_("trace selection mode is required"));
+
+  mode = argv[0];
+
+  if (strcmp (mode, "none") == 0)
+    {
+      tfind_1 (tfind_number, -1, 0, 0, 0);
+      return;
+    }
+
+  if (current_trace_status ()->running)
+    error (_("May not look at trace frames while trace is running."));
+
+  if (strcmp (mode, "frame-number") == 0)
+    {
+      if (argc != 2)
+       error (_("frame number is required"));
+      tfind_1 (tfind_number, atoi (argv[1]), 0, 0, 0);
+    }
+  else if (strcmp (mode, "tracepoint-number") == 0)
+    {
+      if (argc != 2)
+       error (_("tracepoint number is required"));
+      tfind_1 (tfind_tp, atoi (argv[1]), 0, 0, 0);
+    }
+  else if (strcmp (mode, "pc") == 0)
+    {
+      if (argc != 2)
+       error (_("PC is required"));
+      tfind_1 (tfind_pc, 0, parse_and_eval_address (argv[1]), 0, 0);
+    }
+  else if (strcmp (mode, "pc-inside-range") == 0)
+    {
+      if (argc != 3)
+       error (_("Start and end PC are required"));
+      tfind_1 (tfind_range, 0, parse_and_eval_address (argv[1]),
+              parse_and_eval_address (argv[2]), 0);
+    }
+  else if (strcmp (mode, "pc-outside-range") == 0)
+    {
+      if (argc != 3)
+       error (_("Start and end PC are required"));
+      tfind_1 (tfind_outside, 0, parse_and_eval_address (argv[1]),
+              parse_and_eval_address (argv[2]), 0);
+    }
+  else if (strcmp (mode, "line") == 0)
+    {
+      struct symtabs_and_lines sals;
+      struct symtab_and_line sal;
+      static CORE_ADDR start_pc, end_pc;
+      struct cleanup *back_to;
+
+      if (argc != 2)
+       error (_("Line is required"));
+
+      sals = decode_line_spec (argv[1], 1);
+      back_to = make_cleanup (xfree, sals.sals);
+
+      sal = sals.sals[0];
+
+      if (sal.symtab == 0)
+       error (_("Could not find the specified line"));
+
+      if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc))
+       tfind_1 (tfind_range, 0, start_pc, end_pc - 1, 0);
+      else
+       error (_("Could not find the specified line"));
+
+      do_cleanups (back_to);
+    }
+  else
+    error (_("Invalid mode '%s'"), mode);
+
+  if (has_stack_frames () || get_traceframe_number () >= 0)
+    {
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+    }
+}
+
+void
+mi_cmd_trace_save (char *command, char **argv, int argc)
+{
+  int target_saves = 0;
+  char *filename;
+
+  if (argc != 1 && argc != 2)
+    error (_("Usage: -trace-save [-r] filename"));
+
+  if (argc == 2)
+    {
+      filename = argv[1];
+      if (strcmp (argv[0], "-r") == 0)
+       target_saves = 1;
+      else
+       error (_("Invalid option: %s"), argv[0]);
+    }
+  else
+    {
+      filename = argv[0];
+    }
+
+  trace_save (filename, target_saves);
+}
+
+
+void
+mi_cmd_trace_start (char *command, char **argv, int argc)
+{
+  start_tracing ();
+}
+
 void
-mi_setup_architecture_data (void)
+mi_cmd_trace_status (char *command, char **argv, int argc)
 {
-  old_regs = xmalloc ((NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
-  memset (old_regs, 0, (NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
+  trace_status_mi (0);
 }
 
 void
-_initialize_mi_main (void)
+mi_cmd_trace_stop (char *command, char **argv, int argc)
 {
-  DEPRECATED_REGISTER_GDBARCH_SWAP (old_regs);
-  deprecated_register_gdbarch_swap (NULL, 0, mi_setup_architecture_data);
+  stop_tracing ();
+  trace_status_mi (1);
 }
This page took 0.054515 seconds and 4 git commands to generate.