X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmi%2Fmi-interp.c;h=65c1b4f49fafb5da3ba1ff05616a9026b4e3982e;hb=c86cf029308edd78d12d1bb67a1d4ae1c14a9155;hp=7166f946974589a1dd3105c6f497f39793378d70;hpb=6b1b7650d16705f3ea52681cf30798e91546de78;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index 7166f94697..65c1b4f49f 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -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, 2009 + 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 . */ #include "defs.h" #include "gdb_string.h" @@ -32,21 +31,10 @@ #include "mi-cmds.h" #include "mi-out.h" #include "mi-console.h" - -struct mi_interp -{ - /* MI's output channels */ - struct ui_file *out; - struct ui_file *err; - struct ui_file *log; - struct ui_file *targ; - struct ui_file *event_channel; - - /* This is the interpreter for the mi... */ - struct interp *mi2_interp; - struct interp *mi1_interp; - struct interp *mi_interp; -}; +#include "mi-common.h" +#include "observer.h" +#include "gdbthread.h" +#include "solist.h" /* These are the interpreter setup, etc. functions for the MI interpreter */ static void mi_execute_command_wrapper (char *cmd); @@ -55,7 +43,8 @@ static void mi_command_loop (int mi_version); /* 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); @@ -63,16 +52,21 @@ static void mi1_command_loop (void); static void mi_insert_notify_hooks (void); static void mi_remove_notify_hooks (void); +static void mi_on_normal_stop (struct bpstats *bs, int print_frame); + +static void mi_new_thread (struct thread_info *t); +static void mi_thread_exit (struct thread_info *t); +static void mi_new_inferior (int pid); +static void mi_inferior_exit (int pid); +static void mi_on_resume (ptid_t ptid); +static void mi_solib_loaded (struct so_list *solib); +static void mi_solib_unloaded (struct so_list *solib); 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 @@ -87,6 +81,18 @@ 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); + observer_attach_new_inferior (mi_new_inferior); + observer_attach_inferior_exit (mi_inferior_exit); + observer_attach_normal_stop (mi_on_normal_stop); + observer_attach_target_resumed (mi_on_resume); + observer_attach_solib_loaded (mi_solib_loaded); + observer_attach_solib_unloaded (mi_solib_unloaded); + } + return mi; } @@ -118,6 +124,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... */ @@ -145,10 +153,10 @@ mi_interpreter_suspend (void *data) return 1; } -static struct exception +static struct gdb_exception mi_interpreter_exec (void *data, const char *command) { - static struct exception ok; + static struct gdb_exception ok; char *tmp = alloca (strlen (command) + 1); strcpy (tmp, command); mi_execute_command_wrapper (tmp); @@ -162,52 +170,25 @@ mi_interpreter_prompt_p (void *data) return 0; } -static void -mi_interpreter_exec_continuation (struct continuation_arg *arg) -{ - bpstat_do_actions (&stop_bpstat); - if (!target_executing) - { - 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); - } - else if (target_can_async_p ()) - { - add_continuation (mi_interpreter_exec_continuation, NULL); - } -} - -enum mi_cmd_result +void 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. */ @@ -217,54 +198,23 @@ 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'; + mi_error_message = xstrdup (e.message); + make_cleanup (xfree, mi_error_message); + break; } - - /* 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; - { - struct exception e = interp_exec (interp_to_use, argv[i]); - if (e.reason < 0) - { - mi_error_message = xstrdup (e.message); - result = MI_CMD_ERROR; - break; - } - } - xfree (buff); - do_exec_error_cleanups (ALL_CLEANUPS); - sync_execution = 0; } mi_remove_notify_hooks (); - /* Okay, now let's see if the command set the inferior going... - Tricky point - have to do this AFTER resetting the interpreter, since - changing the interpreter will clear out all the continuations for - that interpreter... */ - - if (target_can_async_p () && target_executing) - { - fputs_unfiltered ("^running\n", raw_stdout); - add_continuation (mi_interpreter_exec_continuation, NULL); - } - - return result; + if (mi_error_message != NULL) + error ("%s", mi_error_message); + do_cleanups (old_chain); } /* @@ -320,45 +270,6 @@ 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; @@ -368,6 +279,165 @@ mi_command_loop (int mi_version) 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\",group-id=\"%d\"", + t->num, t->ptid.pid); + gdb_flush (mi->event_channel); +} + +static void +mi_thread_exit (struct thread_info *t) +{ + struct mi_interp *mi = top_level_interpreter_data (); + target_terminal_ours (); + fprintf_unfiltered (mi->event_channel, + "thread-exited,id=\"%d\",group-id=\"%d\"", + t->num,t->ptid.pid); + gdb_flush (mi->event_channel); +} + +static void +mi_new_inferior (int pid) +{ + struct mi_interp *mi = top_level_interpreter_data (); + target_terminal_ours (); + fprintf_unfiltered (mi->event_channel, "thread-group-created,id=\"%d\"", + pid); + gdb_flush (mi->event_channel); +} + +static void +mi_inferior_exit (int pid) +{ + struct mi_interp *mi = top_level_interpreter_data (); + target_terminal_ours (); + fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=\"%d\"", + pid); + gdb_flush (mi->event_channel); +} + +static void +mi_on_normal_stop (struct bpstats *bs, int print_frame) +{ + /* Since this can be called when CLI command is executing, + using cli interpreter, be sure to use MI uiout for output, + not the current one. */ + struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); + struct mi_interp *mi = top_level_interpreter_data (); + + if (print_frame) + { + if (uiout != mi_uiout) + { + /* The normal_stop function has printed frame information into + CLI uiout, or some other non-MI uiout. There's no way we + can extract proper fields from random uiout object, so we print + the frame again. In practice, this can only happen when running + a CLI command in MI. */ + struct ui_out *saved_uiout = uiout; + uiout = mi_uiout; + print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC); + uiout = saved_uiout; + } + + ui_out_field_int (mi_uiout, "thread-id", + pid_to_thread_id (inferior_ptid)); + if (non_stop) + { + struct cleanup *back_to = make_cleanup_ui_out_list_begin_end + (mi_uiout, "stopped-threads"); + ui_out_field_int (mi_uiout, NULL, + pid_to_thread_id (inferior_ptid)); + do_cleanups (back_to); + } + else + ui_out_field_string (mi_uiout, "stopped-threads", "all"); + } + + fputs_unfiltered ("*stopped", raw_stdout); + mi_out_put (mi_uiout, raw_stdout); + mi_out_rewind (mi_uiout); + fputs_unfiltered ("\n", raw_stdout); + gdb_flush (raw_stdout); +} + +static void +mi_on_resume (ptid_t ptid) +{ + /* To cater for older frontends, emit ^running, but do it only once + per each command. We do it here, since at this point we know + that the target was successfully resumed, and in non-async mode, + we won't return back to MI interpreter code until the target + is done running, so delaying the output of "^running" until then + will make it impossible for frontend to know what's going on. + + In future (MI3), we'll be outputting "^done" here. */ + if (!running_result_record_printed) + { + if (current_token) + fputs_unfiltered (current_token, raw_stdout); + fputs_unfiltered ("^running\n", raw_stdout); + } + + if (PIDGET (ptid) == -1) + fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n"); + else if (thread_count () == 0) + { + /* This is a target where for single-threaded programs the thread + table has zero threads. Don't print any thread-id field. */ + fprintf_unfiltered (raw_stdout, "*running\n"); + } + else + { + struct thread_info *ti = find_thread_pid (ptid); + gdb_assert (ti); + fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n", ti->num); + } + + if (!running_result_record_printed) + { + running_result_record_printed = 1; + /* This is what gdb used to do historically -- printing prompt even if + it cannot actually accept any input. This will be surely removed + for MI3, and may be removed even earler. */ + /* FIXME: review the use of target_is_async_p here -- is that + what we want? */ + if (!target_is_async_p ()) + fputs_unfiltered ("(gdb) \n", raw_stdout); + } + gdb_flush (raw_stdout); +} + +static void +mi_solib_loaded (struct so_list *solib) +{ + struct mi_interp *mi = top_level_interpreter_data (); + target_terminal_ours (); + fprintf_unfiltered (mi->event_channel, + "library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded=\"%d\"", + solib->so_original_name, solib->so_original_name, + solib->so_name, solib->symbols_loaded); + gdb_flush (mi->event_channel); +} + +static void +mi_solib_unloaded (struct so_list *solib) +{ + struct mi_interp *mi = top_level_interpreter_data (); + target_terminal_ours (); + fprintf_unfiltered (mi->event_channel, + "library-unloaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\"", + solib->so_original_name, solib->so_original_name, + solib->so_name); + gdb_flush (mi->event_channel); +} + + extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ void