2008-05-03 Pedro Alves <pedro@codesourcery.com>
[binutils-gdb.git] / gdb / mi / mi-interp.c
index 19dbda5d7879b35c3379b67eb00a70a0876d723f..8b0d9091c5b3db495eead22c99681675505510bd 100644 (file)
@@ -1,12 +1,13 @@
 /* MI Interpreter Definitions and Commands for GDB, the GNU debugger.
 
-   Copyright 2002, 2003, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   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,
@@ -15,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdb_string.h"
 #include "inferior.h"
 #include "ui-out.h"
 #include "top.h"
-
+#include "exceptions.h"
 #include "mi-main.h"
 #include "mi-cmds.h"
 #include "mi-out.h"
 #include "mi-console.h"
+#include "observer.h"
+#include "gdbthread.h"
 
 struct mi_interp
 {
@@ -51,12 +52,12 @@ struct mi_interp
 /* These are the interpreter setup, etc. functions for the MI interpreter */
 static void mi_execute_command_wrapper (char *cmd);
 static void mi_command_loop (int mi_version);
-static char *mi_input (char *);
 
 /* These are hooks that we put in place while doing interpreter_exec
    so we can report interesting things that happened "behind the mi's
    back" in this command */
-static int mi_interp_query_hook (const char *ctlstr, va_list ap);
+static int mi_interp_query_hook (const char *ctlstr, va_list ap)
+     ATTR_FORMAT (printf, 1, 0);
 
 static void mi3_command_loop (void);
 static void mi2_command_loop (void);
@@ -65,15 +66,14 @@ static void mi1_command_loop (void);
 static void mi_insert_notify_hooks (void);
 static void mi_remove_notify_hooks (void);
 
+static void mi_new_thread (struct thread_info *t);
+static void mi_thread_exit (struct thread_info *t);
+
 static void *
-mi_interpreter_init (void)
+mi_interpreter_init (int top_level)
 {
   struct mi_interp *mi = XMALLOC (struct mi_interp);
 
-  /* Why is this a part of the mi architecture? */
-
-  mi_setup_architecture_data ();
-
   /* HACK: We need to force stdout/stderr to point at the console.  This avoids
      any potential side effects caused by legacy code that is still
      using the TUI / fputs_unfiltered_hook.  So we set up output channels for
@@ -88,6 +88,12 @@ mi_interpreter_init (void)
   mi->targ = mi_console_file_new (raw_stdout, "@", '"');
   mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
 
+  if (top_level)
+    {
+      observer_attach_new_thread (mi_new_thread);
+      observer_attach_thread_exit (mi_thread_exit);
+    }
+
   return mi;
 }
 
@@ -99,22 +105,19 @@ mi_interpreter_resume (void *data)
 
   gdb_setup_readline ();
 
-  if (event_loop_p)
-    {
-      /* These overwrite some of the initialization done in
-         _intialize_event_loop. */
-      call_readline = gdb_readline2;
-      input_handler = mi_execute_command_wrapper;
-      add_file_handler (input_fd, stdin_event_handler, 0);
-      async_command_editing_p = 0;
-      /* FIXME: This is a total hack for now.  PB's use of the MI implicitly
-         relies on a bug in the async support which allows asynchronous
-         commands to leak through the commmand loop.  The bug involves
-         (but is not limited to) the fact that sync_execution was
-         erroneously initialized to 0.  Duplicate by initializing it
-         thus here... */
-      sync_execution = 0;
-    }
+  /* These overwrite some of the initialization done in
+     _intialize_event_loop.  */
+  call_readline = gdb_readline2;
+  input_handler = mi_execute_command_wrapper;
+  add_file_handler (input_fd, stdin_event_handler, 0);
+  async_command_editing_p = 0;
+  /* FIXME: This is a total hack for now.  PB's use of the MI
+     implicitly relies on a bug in the async support which allows
+     asynchronous commands to leak through the commmand loop.  The bug
+     involves (but is not limited to) the fact that sync_execution was
+     erroneously initialized to 0.  Duplicate by initializing it thus
+     here...  */
+  sync_execution = 0;
 
   gdb_stdout = mi->out;
   /* Route error and log output through the MI */
@@ -122,6 +125,8 @@ mi_interpreter_resume (void *data)
   gdb_stdlog = mi->log;
   /* Route target output through the MI. */
   gdb_stdtarg = mi->targ;
+  /* Route target error through the MI as well. */
+  gdb_stdtargerr = mi->targ;
 
   /* Replace all the hooks that we know about.  There really needs to
      be a better way of doing this... */
@@ -149,13 +154,14 @@ mi_interpreter_suspend (void *data)
   return 1;
 }
 
-static int
+static struct gdb_exception
 mi_interpreter_exec (void *data, const char *command)
 {
+  static struct gdb_exception ok;
   char *tmp = alloca (strlen (command) + 1);
   strcpy (tmp, command);
   mi_execute_command_wrapper (tmp);
-  return 1;
+  return exception_none;
 }
 
 /* Never display the default gdb prompt in mi case.  */
@@ -166,9 +172,11 @@ mi_interpreter_prompt_p (void *data)
 }
 
 static void
-mi_interpreter_exec_continuation (struct continuation_arg *arg)
+mi_interpreter_exec_continuation (struct continuation_arg *arg, int error_p)
 {
   bpstat_do_actions (&stop_bpstat);
+  /* It's not clear what to do in the case of errror -- should we assume that
+     the target is stopped, or that it still runs?  */
   if (!target_executing)
     {
       fputs_unfiltered ("*stopped", raw_stdout);
@@ -176,7 +184,6 @@ mi_interpreter_exec_continuation (struct continuation_arg *arg)
       fputs_unfiltered ("\n", raw_stdout);
       fputs_unfiltered ("(gdb) \n", raw_stdout);
       gdb_flush (raw_stdout);
-      do_exec_cleanups (ALL_CLEANUPS);
     }
   else if (target_can_async_p ())
     {
@@ -188,29 +195,21 @@ enum mi_cmd_result
 mi_cmd_interpreter_exec (char *command, char **argv, int argc)
 {
   struct interp *interp_to_use;
-  enum mi_cmd_result result = MI_CMD_DONE;
   int i;
   struct interp_procs *procs;
+  char *mi_error_message = NULL;
+  struct cleanup *old_chain;
 
   if (argc < 2)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
 
   interp_to_use = interp_lookup (argv[0]);
   if (interp_to_use == NULL)
-    {
-      mi_error_message = xstrprintf ("mi_cmd_interpreter_exec: could not find interpreter \"%s\"", argv[0]);
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_interpreter_exec: could not find interpreter \"%s\"", argv[0]);
 
   if (!interp_exec_p (interp_to_use))
-    {
-      mi_error_message = xstrprintf ("mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
-                                    argv[0]);
-      return MI_CMD_ERROR;
-    }
+    error ("mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
+             argv[0]);
 
   /* Insert the MI out hooks, making sure to also call the interpreter's hooks
      if it has any. */
@@ -220,35 +219,16 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
 
   /* Now run the code... */
 
+  old_chain = make_cleanup (null_cleanup, 0);
   for (i = 1; i < argc; i++)
     {
-      char *buff = NULL;
-      /* Do this in a cleaner way...  We want to force execution to be
-         asynchronous for commands that run the target.  */
-      if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
+      struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
+      if (e.reason < 0)
        {
-         int len = strlen (argv[i]);
-         buff = xmalloc (len + 2);
-         memcpy (buff, argv[i], len);
-         buff[len] = '&';
-         buff[len + 1] = '\0';
-       }
-
-      /* We had to set sync_execution = 0 for the mi (well really for Project
-         Builder's use of the mi - particularly so interrupting would work.
-         But for console commands to work, we need to initialize it to 1 -
-         since that is what the cli expects - before running the command,
-         and then set it back to 0 when we are done. */
-      sync_execution = 1;
-      if (interp_exec (interp_to_use, argv[i]) < 0)
-       {
-         mi_error_message = error_last_message ();
-         result = MI_CMD_ERROR;
+         mi_error_message = xstrdup (e.message);
+         make_cleanup (xfree, mi_error_message);
          break;
        }
-      xfree (buff);
-      do_exec_error_cleanups (ALL_CLEANUPS);
-      sync_execution = 0;
     }
 
   mi_remove_notify_hooks ();
@@ -264,7 +244,10 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
       add_continuation (mi_interpreter_exec_continuation, NULL);
     }
 
-  return result;
+  if (mi_error_message != NULL)
+    error ("%s", mi_error_message);
+  do_cleanups (old_chain);
+  return MI_CMD_DONE;
 }
 
 /*
@@ -320,61 +303,32 @@ mi3_command_loop (void)
 static void
 mi_command_loop (int mi_version)
 {
-#if 0
-  /* HACK: Force stdout/stderr to point at the console.  This avoids
-     any potential side effects caused by legacy code that is still
-     using the TUI / fputs_unfiltered_hook */
-  raw_stdout = stdio_fileopen (stdout);
-  /* Route normal output through the MIx */
-  gdb_stdout = mi_console_file_new (raw_stdout, "~", '"');
-  /* Route error and log output through the MI */
-  gdb_stderr = mi_console_file_new (raw_stdout, "&", '"');
-  gdb_stdlog = gdb_stderr;
-  /* Route target output through the MI. */
-  gdb_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
-  /* HACK: Poke the ui_out table directly.  Should we be creating a
-     mi_out object wired up to the above gdb_stdout / gdb_stderr? */
-  uiout = mi_out_new (mi_version);
-  /* HACK: Override any other interpreter hooks.  We need to create a
-     real event table and pass in that. */
-  deprecated_init_ui_hook = 0;
-  /* deprecated_command_loop_hook = 0; */
-  deprecated_print_frame_info_listing_hook = 0;
-  deprecated_query_hook = 0;
-  deprecated_warning_hook = 0;
-  deprecated_create_breakpoint_hook = 0;
-  deprecated_delete_breakpoint_hook = 0;
-  deprecated_modify_breakpoint_hook = 0;
-  deprecated_interactive_hook = 0;
-  deprecated_registers_changed_hook = 0;
-  deprecated_readline_begin_hook = 0;
-  deprecated_readline_hook = 0;
-  deprecated_readline_end_hook = 0;
-  deprecated_register_changed_hook = 0;
-  deprecated_memory_changed_hook = 0;
-  deprecated_context_hook = 0;
-  deprecated_target_wait_hook = 0;
-  deprecated_call_command_hook = 0;
-  deprecated_error_hook = 0;
-  deprecated_error_begin_hook = 0;
-  deprecated_show_load_progress = mi_load_progress;
-#endif
   /* Turn off 8 bit strings in quoted output.  Any character with the
      high bit set is printed using C's octal format. */
   sevenbit_strings = 1;
   /* Tell the world that we're alive */
   fputs_unfiltered ("(gdb) \n", raw_stdout);
   gdb_flush (raw_stdout);
-  if (!event_loop_p)
-    simplified_command_loop (mi_input, mi_execute_command);
-  else
-    start_event_loop ();
+  start_event_loop ();
+}
+
+static void
+mi_new_thread (struct thread_info *t)
+{
+  struct mi_interp *mi = top_level_interpreter_data ();
+
+  fprintf_unfiltered (mi->event_channel, "thread-created,id=\"%d\"", t->num);
+  gdb_flush (mi->event_channel);
 }
 
-static char *
-mi_input (char *buf)
+static void
+mi_thread_exit (struct thread_info *t)
 {
-  return gdb_readline (NULL);
+  struct mi_interp *mi = top_level_interpreter_data ();
+
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel, "thread-exited,id=\"%d\"", t->num);
+  gdb_flush (mi->event_channel);
 }
 
 extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */