2010-05-17 Michael Snyder <msnyder@vmware.com>
[deliverable/binutils-gdb.git] / gdb / mi / mi-main.c
index 1193b0c2042cced1181ce9e2bd5be1b2bcd52e96..c9472ed240afeaecec6d906bb15ba5d1ff37e6c9 100644 (file)
@@ -1,6 +1,6 @@
 /* MI Command Set.
 
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
+   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.  */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "target.h"
 #include "inferior.h"
 #include "gdb_string.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>
@@ -63,29 +69,6 @@ enum
     FROM_TTY = 0
   };
 
-/* Enumerations of the actions that may result from calling
-   captured_mi_execute_command.  */
-
-enum captured_mi_execute_command_actions
-  {
-    EXECUTE_COMMAND_DISPLAY_PROMPT,
-    EXECUTE_COMMAND_SUPRESS_PROMPT
-  };
-
-/* 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;
-
-  /* What action to perform when the call is finished (output).  */
-  enum captured_mi_execute_command_actions action;
-
-  /* The command context to be executed (input).  */
-  struct mi_parse *command;
-};
-
 int mi_debug_p;
 struct ui_file *raw_stdout;
 
@@ -95,23 +78,28 @@ static struct mi_timestamp *current_command_ts;
 
 static int do_timings = 0;
 
-/* The token of the last asynchronous command.  */
-static char *last_async_command;
-static char *previous_async_command;
-char *mi_error_message;
+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;
+
+int running_result_record_printed = 1;
+
+/* 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_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
-
+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 int get_register (int regnum, int format);
+static void get_register (struct frame_info *, int regnum, int format);
 
 /* Command implementations.  FIXME: Is this libgdb?  No.  This is the MI
    layer that calls libgdb.  Any operation used in the below should be
@@ -122,77 +110,78 @@ static void timestamp (struct mi_timestamp *tv);
 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);
+  if (current_token)
+    fputs_unfiltered (current_token, raw_stdout);
   fputs_unfiltered ("^exit\n", raw_stdout);
   mi_out_put (uiout, raw_stdout);
+  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);
+  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);
+  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);
+  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);
+  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);
+  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);
+    return_command (*argv, 0);
   else
     /* Call return_command with from_tty argument equal to 0 so as to
        avoid being queried.  */
@@ -201,15 +190,136 @@ mi_cmd_exec_return (char *args, int from_tty)
   /* Because we have called return_command with from_tty = 0, we need
      to print the frame here.  */
   print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS);
-
-  return MI_CMD_DONE;
 }
 
-enum mi_cmd_result
-mi_cmd_exec_continue (char *args, int from_tty)
+void
+mi_cmd_exec_jump (char *args, char **argv, int argc)
 {
   /* FIXME: Should call a libgdb function, not a cli wrapper.  */
-  return mi_execute_async_cli_command ("continue", args, from_tty);
+  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;
+}
+
+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);
+}
+
+void
+mi_cmd_exec_continue (char *command, char **argv, int argc)
+{
+  if (argc > 0 && strcmp (argv[0], "--reverse") == 0)
+    exec_reverse_continue (argv + 1, argc - 1);
+  else
+    exec_continue (argv, argc);
+}
+
+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
@@ -217,70 +327,545 @@ mi_cmd_exec_continue (char *args, int from_tty)
    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)
+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;
+    }
+
+  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);
     }
-  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;
 }
 
-enum mi_cmd_result
-mi_cmd_thread_select (char *command, char **argv, int argc)
+static int
+run_one_inferior (struct inferior *inf, void *arg)
 {
-  enum gdb_rc rc;
+  if (inf->pid != 0)
+    {
+      if (inf->pid != ptid_get_pid (inferior_ptid))
+       {
+         struct thread_info *tp;
 
-  if (argc != 1)
+         tp = any_thread_of_process (inf->pid);
+         if (!tp)
+           error (_("Inferior has no threads."));
+
+         switch_to_thread (tp->ptid);
+       }
+    }
+  else
     {
-      mi_error_message = xstrprintf ("mi_cmd_thread_select: USAGE: threadnum.");
-      return MI_CMD_ERROR;
+      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
-    rc = gdb_thread_select (uiout, argv[0], &mi_error_message);
+    {
+      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;
+}
+
+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)
-    return MI_CMD_ERROR;
-  else
-    return MI_CMD_DONE;
+    {
+      make_cleanup (xfree, mi_error_message);
+      error ("%s", mi_error_message);
+    }
 }
 
-enum mi_cmd_result
+void
 mi_cmd_thread_list_ids (char *command, char **argv, int argc)
 {
   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;
@@ -291,8 +876,8 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc)
      In this case, some entries of gdbarch_register_name will change depending
      upon the particular processor being debugged.  */
 
-  numregs = gdbarch_num_regs (current_gdbarch)
-           + gdbarch_num_pseudo_regs (current_gdbarch);
+  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");
 
@@ -302,13 +887,12 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc)
           regnum < numregs;
           regnum++)
        {
-         if (gdbarch_register_name (current_gdbarch, regnum) == NULL
-             || *(gdbarch_register_name (current_gdbarch, 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,
-                                gdbarch_register_name
-                                  (current_gdbarch, regnum));
+                                gdbarch_register_name (gdbarch, regnum));
        }
     }
 
@@ -317,27 +901,24 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc)
     {
       regnum = atoi (argv[i]);
       if (regnum < 0 || regnum >= numregs)
-       {
-         do_cleanups (cleanup);
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
-      if (gdbarch_register_name (current_gdbarch, regnum) == NULL
-         || *(gdbarch_register_name (current_gdbarch, 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,
-                            gdbarch_register_name (current_gdbarch, regnum));
+                            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;
@@ -356,8 +937,8 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
      In this  case, some entries of gdbarch_register_name will change depending
      upon the particular processor being debugged.  */
 
-  numregs = gdbarch_num_regs (current_gdbarch)
-           + gdbarch_num_pseudo_regs (current_gdbarch);
+  gdbarch = get_regcache_arch (this_regs);
+  numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 
   make_cleanup_ui_out_list_begin_end (uiout, "changed-registers");
 
@@ -367,16 +948,12 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
           regnum < numregs;
           regnum++)
        {
-         if (gdbarch_register_name (current_gdbarch, regnum) == NULL
-             || *(gdbarch_register_name (current_gdbarch, regnum)) == '\0')
+         if (gdbarch_register_name (gdbarch, regnum) == NULL
+             || *(gdbarch_register_name (gdbarch, regnum)) == '\0')
            continue;
          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);
        }
@@ -389,28 +966,19 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
 
       if (regnum >= 0
          && regnum < numregs
-         && gdbarch_register_name (current_gdbarch, regnum) != NULL
-         && *gdbarch_register_name (current_gdbarch, regnum) != '\000')
+         && gdbarch_register_name (gdbarch, regnum) != NULL
+         && *gdbarch_register_name (gdbarch, regnum) != '\000')
        {
          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
@@ -446,10 +1014,12 @@ register_changed_p (int regnum, struct regcache *prev_regs,
    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
+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;
 
@@ -459,17 +1029,15 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc)
      In this case, some entries of gdbarch_register_name will change depending
      upon the particular processor being debugged.  */
 
-  numregs = gdbarch_num_regs (current_gdbarch)
-           + gdbarch_num_pseudo_regs (current_gdbarch);
-
   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.  */
@@ -478,17 +1046,12 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc)
           regnum < numregs;
           regnum++)
        {
-         if (gdbarch_register_name (current_gdbarch, regnum) == NULL
-             || *(gdbarch_register_name (current_gdbarch, 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);
        }
     }
@@ -500,34 +1063,25 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc)
 
       if (regnum >= 0
          && regnum < numregs
-         && gdbarch_register_name (current_gdbarch, regnum) != NULL
-         && *gdbarch_register_name (current_gdbarch, 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)
+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;
@@ -540,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')
     {
@@ -556,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 = gdbarch_byte_order (current_gdbarch) == 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;
        }
@@ -568,20 +1119,25 @@ 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 
    -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)
 {
+  struct regcache *regcache;
+  struct gdbarch *gdbarch;
   int numregs, i;
   char format;
 
@@ -591,42 +1147,31 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc)
      In this case, some entries of gdbarch_register_name will change depending
      upon the particular processor being debugged.  */
 
-  numregs = gdbarch_num_regs (current_gdbarch)
-           + gdbarch_num_pseudo_regs (current_gdbarch);
+  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)
     {
       int regnum = atoi (argv[i]);
 
       if (regnum >= 0 && regnum < numregs
-         && gdbarch_register_name (current_gdbarch, regnum)
-         && *gdbarch_register_name (current_gdbarch, regnum))
+         && gdbarch_register_name (gdbarch, regnum)
+         && *gdbarch_register_name (gdbarch, regnum))
        {
          LONGEST value;
 
@@ -634,64 +1179,31 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc)
          value = parse_and_eval_address (argv[i + 1]);
 
          /* Write it down.  */
-         regcache_cooked_write_signed (current_regcache, regnum, value);
+         regcache_cooked_write_signed (regcache, regnum, value);
        }
       else
-       {
-         mi_error_message = xstrprintf ("bad register number");
-         return MI_CMD_ERROR;
-       }
-    }
-  return MI_CMD_DONE;
-}
-
-#if 0
-/* This is commented out because we decided it was not useful.  I leave
-   it, just in case.  ezannoni:1999-12-08 */
-
-/* Assign a value to a variable.  The expression argument must be in
-   the form A=2 or "A = 2" i.e. if there are spaces it needs to be
-   quoted.  */
-enum mi_cmd_result
-mi_cmd_data_assign (char *command, char **argv, int argc)
-{
-  struct expression *expr;
-  struct cleanup *old_chain;
-
-  if (argc != 1)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_data_assign: Usage: -data-assign expression");
-      return MI_CMD_ERROR;
+       error ("bad register number");
     }
-
-  /* NOTE what follows is a clone of set_command().  FIXME: ezannoni
-     01-12-1999: Need to decide what to do with this for libgdb purposes.  */
-
-  expr = parse_expression (argv[0]);
-  old_chain = make_cleanup (free_current_contents, &expr);
-  evaluate_expression (expr);
-  do_cleanups (old_chain);
-  return MI_CMD_DONE;
 }
-#endif
 
 /* Evaluate the value of the argument.  The argument is an
    expression. If the expression contains spaces it needs to be
    included in double quotes.  */
-enum mi_cmd_result
+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]);
@@ -701,60 +1213,16 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
   val = evaluate_expression (expr);
 
   /* 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:
@@ -776,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;
@@ -808,6 +1277,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
     {
       int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts,
                           &optind, &optarg);
+
       if (opt < 0)
        break;
       switch ((enum opt) opt)
@@ -821,10 +1291,7 @@ 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. */
 
@@ -838,39 +1305,35 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
   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.  */
   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;
-    }
+    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;
-    }
+    error ("mi_cmd_data_read_memory: invalid number of columns.");
+
   /* The un-printable character when printing ascii.  */
   if (argc == 6)
     aschar = *argv[5];
@@ -882,23 +1345,24 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
   mbuf = xcalloc (total_bytes, 1);
   make_cleanup (xfree, mbuf);
 
-  nr_bytes = target_read (&current_target, TARGET_OBJECT_MEMORY, NULL,
-                         mbuf, addr, total_bytes);
+  /* 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)
-    {
-      do_cleanups (cleanups);
-      mi_error_message = xstrdup ("Unable to read memory.");
-      return MI_CMD_ERROR;
-    }
+    error ("Unable to read memory.");
 
   /* Output the header information.  */
-  ui_out_field_core_addr (uiout, "addr", addr);
+  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);
+  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.  */
   {
@@ -906,6 +1370,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
     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;
@@ -915,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)
@@ -930,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);
              }
@@ -939,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++)
              {
@@ -961,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:
@@ -980,9 +1448,11 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
    Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE).
 
    Prints nothing.  */
-enum mi_cmd_result
+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;
@@ -1008,6 +1478,7 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc)
     {
       int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
                           &optind, &optarg);
+
       if (opt < 0)
        break;
       switch ((enum opt) opt)
@@ -1021,10 +1492,7 @@ 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.  */
@@ -1043,16 +1511,14 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc)
   /* Get the value into an array.  */
   buffer = xmalloc (word_size);
   old_chain = make_cleanup (xfree, buffer);
-  store_signed_integer (buffer, word_size, value);
+  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);
-
-  return MI_CMD_DONE;
 }
 
-enum mi_cmd_result
+void
 mi_cmd_enable_timings (char *command, char **argv, int argc)
 {
   if (argc == 0)
@@ -1069,99 +1535,149 @@ mi_cmd_enable_timings (char *command, char **argv, int argc)
   else
     goto usage_error;
     
-  return MI_CMD_DONE;
+  return;
 
  usage_error:
   error ("mi_cmd_enable_timings: Usage: %s {yes|no}", command);
-  return MI_CMD_ERROR;
 }
 
+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;
+
+      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;
 
-  struct mi_timestamp cmd_finished;
+  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.  */
       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;
-
-      if (do_timings)
-       current_command_ts = context->cmd_start;
 
-      args->rc = mi_cmd_execute (context);
 
-      if (do_timings)
-          timestamp (&cmd_finished);
+      mi_cmd_execute (context);
 
-      if (!target_can_async_p () || !target_executing)
-       {
-         /* Print the result if there were no errors.
+      /* 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);
-             /* Have to check cmd_start, since the command could be
-                -enable-timings.  */
-             if (do_timings && context->cmd_start)
-                 print_diff (context->cmd_start, &cmd_finished);
-             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)
+        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.  */
@@ -1170,7 +1686,7 @@ captured_mi_execute_command (struct ui_out *uiout, void *data)
        /* Call the "console" interpreter.  */
        argv[0] = "console";
        argv[1] = context->command;
-       args->rc = mi_cmd_interpreter_exec ("-interpreter-exec", argv, 2);
+       mi_cmd_interpreter_exec ("-interpreter-exec", argv, 2);
 
        /* If we changed interpreters, DON'T print out anything.  */
        if (current_interp_named_p (INTERP_MI)
@@ -1178,26 +1694,14 @@ captured_mi_execute_command (struct ui_out *uiout, void *data)
            || current_interp_named_p (INTERP_MI2)
            || current_interp_named_p (INTERP_MI3))
          {
-           if (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);
-               fputs_unfiltered ("\n", raw_stdout);
-               args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
-             }
-           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);
+               mi_print_timing_maybe ();
+               fputs_unfiltered ("\n", raw_stdout);            
              }
            else
              mi_out_rewind (uiout);
@@ -1207,6 +1711,8 @@ captured_mi_execute_command (struct ui_out *uiout, void *data)
 
     }
 
+  do_cleanups (cleanup);
+
   return;
 }
 
@@ -1215,19 +1721,20 @@ 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.  */
   if (cmd == 0)
     quit_force (NULL, from_tty);
 
+  target_log_command (cmd);
+
   command = mi_parse (cmd);
 
   if (command != NULL)
     {
       struct gdb_exception result;
+      ptid_t previous_ptid = inferior_ptid;
 
       if (do_timings)
        {
@@ -1236,20 +1743,8 @@ mi_execute_command (char *cmd, int from_tty)
          timestamp (command->cmd_start);
        }
 
-      /* 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,
+      result = catch_exception (uiout, captured_mi_execute_command, command,
                                RETURN_MASK_ALL);
-      exception_print (gdb_stderr, result);
-
-      if (args.action == EXECUTE_COMMAND_SUPRESS_PROMPT)
-       {
-         /* The command is executing synchronously.  Bail out early
-            suppressing the finished prompt.  */
-         mi_parse_free (command);
-         return;
-       }
       if (result.reason < 0)
        {
          /* The command execution failed and error() was called
@@ -1259,10 +1754,52 @@ mi_execute_command (char *cmd, int from_tty)
          if (result.message == NULL)
            fputs_unfiltered ("unknown error", raw_stdout);
          else
-             fputstr_unfiltered (result.message, '"', raw_stdout);
+           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);
     }
 
@@ -1272,51 +1809,76 @@ mi_execute_command (char *cmd, int from_tty)
   /* ..... */
 }
 
-static enum mi_cmd_result
+static void
 mi_cmd_execute (struct mi_parse *parse)
 {
-  free_all_values ();
-
-  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. */
@@ -1324,19 +1886,22 @@ mi_cmd_execute (struct mi_parse *parse)
       /* 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;
+      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.
@@ -1350,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
@@ -1365,85 +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.  */
       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);
-      if (do_timings)
-       print_diff_now (current_command_ts);
-      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
@@ -1464,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;
 
@@ -1489,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);
@@ -1509,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);
@@ -1533,7 +2051,6 @@ mi_load_progress (const char *section_name,
 static void 
 timestamp (struct mi_timestamp *tv)
   {
-    long usec;
     gettimeofday (&tv->wallclock, NULL);
 #ifdef HAVE_GETRUSAGE
     getrusage (RUSAGE_SELF, &rusage);
@@ -1542,11 +2059,14 @@ timestamp (struct mi_timestamp *tv)
     tv->stime.tv_sec = rusage.ru_stime.tv_sec;
     tv->stime.tv_usec = rusage.ru_stime.tv_usec;
 #else
-    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;
+    {
+      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
   }
 
@@ -1554,10 +2074,20 @@ 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)
   {
@@ -1575,3 +2105,180 @@ print_diff (struct mi_timestamp *start, struct mi_timestamp *end)
        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_cmd_trace_status (char *command, char **argv, int argc)
+{
+  trace_status_mi (0);
+}
+
+void
+mi_cmd_trace_stop (char *command, char **argv, int argc)
+{
+  stop_tracing ();
+  trace_status_mi (1);
+}
This page took 0.051858 seconds and 4 git commands to generate.