Index: gdb/mi/mi-interp.c |
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c |
index c9cd24d676a850f35982cccaeb9a1168b88e630e..b48713676e12470b69e7a8bedca3d4fdd694e09b 100644 |
--- a/gdb/mi/mi-interp.c |
+++ b/gdb/mi/mi-interp.c |
@@ -36,15 +36,19 @@ |
#include "solist.h" |
#include "gdb.h" |
-/* These are the interpreter setup, etc. functions for the MI interpreter */ |
+/* These are the interpreter setup, etc. functions for the MI |
+ interpreter. */ |
+ |
static void mi_execute_command_wrapper (char *cmd); |
+static void mi_execute_command_input_handler (char *cmd); |
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 */ |
+ 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) |
- ATTRIBUTE_PRINTF (1, 0); |
+ ATTRIBUTE_PRINTF (1, 0); |
static void mi3_command_loop (void); |
static void mi2_command_loop (void); |
@@ -77,14 +81,15 @@ mi_interpreter_init (struct interp *interp, int top_level) |
const char *name; |
int mi_version; |
- /* 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 |
- this now, and swap them in when we are run. */ |
+ /* Assign the output channel created at startup to its own global, |
+ so that we can create a console channel that encapsulates and |
+ prefixes all gdb_output-type bits coming from the rest of the |
+ debugger. */ |
- raw_stdout = stdio_fileopen (stdout); |
+ raw_stdout = gdb_stdout; |
- /* Create MI channels */ |
+ /* Create MI console channels, each with a different prefix so they |
+ can be distinguished. */ |
mi->out = mi_console_file_new (raw_stdout, "~", '"'); |
mi->err = mi_console_file_new (raw_stdout, "&", '"'); |
mi->log = mi->err; |
@@ -124,9 +129,10 @@ mi_interpreter_init (struct interp *interp, int top_level) |
observer_attach_breakpoint_deleted (mi_breakpoint_deleted); |
observer_attach_breakpoint_modified (mi_breakpoint_modified); |
- /* The initial inferior is created before this function is called, so we |
- need to report it explicitly. Use iteration in case future version |
- of GDB creates more than one inferior up-front. */ |
+ /* The initial inferior is created before this function is |
+ called, so we need to report it explicitly. Use iteration in |
+ case future version of GDB creates more than one inferior |
+ up-front. */ |
iterate_over_inferiors (report_initial_inferior, mi); |
} |
@@ -138,13 +144,14 @@ mi_interpreter_resume (void *data) |
{ |
struct mi_interp *mi = data; |
- /* As per hack note in mi_interpreter_init, swap in the output channels... */ |
+ /* As per hack note in mi_interpreter_init, swap in the output |
+ channels... */ |
gdb_setup_readline (); |
/* These overwrite some of the initialization done in |
_intialize_event_loop. */ |
call_readline = gdb_readline2; |
- input_handler = mi_execute_command_wrapper; |
+ input_handler = mi_execute_command_input_handler; |
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 |
@@ -156,12 +163,12 @@ mi_interpreter_resume (void *data) |
sync_execution = 0; |
gdb_stdout = mi->out; |
- /* Route error and log output through the MI */ |
+ /* Route error and log output through the MI. */ |
gdb_stderr = mi->err; |
gdb_stdlog = mi->log; |
- /* Route target output through the MI. */ |
+ /* Route target output through the MI. */ |
gdb_stdtarg = mi->targ; |
- /* Route target error through the MI as well. */ |
+ /* Route target error through the MI as well. */ |
gdb_stdtargerr = mi->targ; |
/* Replace all the hooks that we know about. There really needs to |
@@ -170,7 +177,7 @@ mi_interpreter_resume (void *data) |
deprecated_show_load_progress = mi_load_progress; |
- /* If we're _the_ interpreter, take control. */ |
+ /* If we're _the_ interpreter, take control. */ |
if (current_interp_named_p (INTERP_MI1)) |
deprecated_command_loop_hook = mi1_command_loop; |
else if (current_interp_named_p (INTERP_MI2)) |
@@ -200,7 +207,8 @@ mi_interpreter_exec (void *data, const char *command) |
return exception_none; |
} |
-/* Never display the default gdb prompt in mi case. */ |
+/* Never display the default GDB prompt in MI case. */ |
+ |
static int |
mi_interpreter_prompt_p (void *data) |
{ |
@@ -229,13 +237,14 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) |
"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. */ |
- /* KRS: We shouldn't need this... Events should be installed and they should |
- just ALWAYS fire something out down the MI channel... */ |
+ /* Insert the MI out hooks, making sure to also call the |
+ interpreter's hooks if it has any. */ |
+ /* KRS: We shouldn't need this... Events should be installed and |
+ they should just ALWAYS fire something out down the MI |
+ channel. */ |
mi_insert_notify_hooks (); |
- /* Now run the code... */ |
+ /* Now run the code. */ |
old_chain = make_cleanup (null_cleanup, 0); |
for (i = 1; i < argc; i++) |
@@ -257,14 +266,12 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc) |
do_cleanups (old_chain); |
} |
-/* |
- * mi_insert_notify_hooks - This inserts a number of hooks that are |
- * meant to produce async-notify ("=") MI messages while running |
- * commands in another interpreter using mi_interpreter_exec. The |
- * canonical use for this is to allow access to the gdb CLI |
- * interpreter from within the MI, while still producing MI style |
- * output when actions in the CLI command change gdb's state. |
-*/ |
+/* This inserts a number of hooks that are meant to produce |
+ async-notify ("=") MI messages while running commands in another |
+ interpreter using mi_interpreter_exec. The canonical use for this |
+ is to allow access to the gdb CLI interpreter from within the MI, |
+ while still producing MI style output when actions in the CLI |
+ command change GDB's state. */ |
static void |
mi_insert_notify_hooks (void) |
@@ -290,6 +297,17 @@ mi_execute_command_wrapper (char *cmd) |
mi_execute_command (cmd, stdin == instream); |
} |
+/* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER. */ |
+ |
+static void |
+mi_execute_command_input_handler (char *cmd) |
+{ |
+ mi_execute_command_wrapper (cmd); |
+ |
+ fputs_unfiltered ("(gdb) \n", raw_stdout); |
+ gdb_flush (raw_stdout); |
+} |
+ |
static void |
mi1_command_loop (void) |
{ |
@@ -312,11 +330,13 @@ static void |
mi_command_loop (int mi_version) |
{ |
/* Turn off 8 bit strings in quoted output. Any character with the |
- high bit set is printed using C's octal format. */ |
+ high bit set is printed using C's octal format. */ |
sevenbit_strings = 1; |
- /* Tell the world that we're alive */ |
+ |
+ /* Tell the world that we're alive. */ |
fputs_unfiltered ("(gdb) \n", raw_stdout); |
gdb_flush (raw_stdout); |
+ |
start_event_loop (); |
} |
@@ -420,11 +440,11 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame) |
if (current_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. */ |
+ /* 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 = current_uiout; |
struct target_waitstatus last; |
ptid_t last_ptid; |
@@ -483,15 +503,17 @@ mi_about_to_proceed (void) |
/* When non-zero, no MI notifications will be emitted in |
response to breakpoint change observers. */ |
+ |
int mi_suppress_breakpoint_notifications = 0; |
/* Emit notification about a created breakpoint. */ |
+ |
static void |
mi_breakpoint_created (struct breakpoint *b) |
{ |
struct mi_interp *mi = top_level_interpreter_data (); |
struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); |
- struct gdb_exception e; |
+ volatile struct gdb_exception e; |
if (mi_suppress_breakpoint_notifications) |
return; |
@@ -503,12 +525,12 @@ mi_breakpoint_created (struct breakpoint *b) |
fprintf_unfiltered (mi->event_channel, |
"breakpoint-created"); |
/* We want the output from gdb_breakpoint_query to go to |
- mi->event_channel. One approach would be to just |
- call gdb_breakpoint_query, and then use mi_out_put to |
- send the current content of mi_outout into mi->event_channel. |
- However, that will break if anything is output to mi_uiout |
- prior the calling the breakpoint_created notifications. |
- So, we use ui_out_redirect. */ |
+ mi->event_channel. One approach would be to just call |
+ gdb_breakpoint_query, and then use mi_out_put to send the current |
+ content of mi_outout into mi->event_channel. However, that will |
+ break if anything is output to mi_uiout prior to calling the |
+ breakpoint_created notifications. So, we use |
+ ui_out_redirect. */ |
ui_out_redirect (mi_uiout, mi->event_channel); |
TRY_CATCH (e, RETURN_MASK_ERROR) |
gdb_breakpoint_query (mi_uiout, b->number, NULL); |
@@ -518,6 +540,7 @@ mi_breakpoint_created (struct breakpoint *b) |
} |
/* Emit notification about deleted breakpoint. */ |
+ |
static void |
mi_breakpoint_deleted (struct breakpoint *b) |
{ |
@@ -538,12 +561,13 @@ mi_breakpoint_deleted (struct breakpoint *b) |
} |
/* Emit notification about modified breakpoint. */ |
+ |
static void |
mi_breakpoint_modified (struct breakpoint *b) |
{ |
struct mi_interp *mi = top_level_interpreter_data (); |
struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ()); |
- struct gdb_exception e; |
+ volatile struct gdb_exception e; |
if (mi_suppress_breakpoint_notifications) |
return; |
@@ -555,12 +579,12 @@ mi_breakpoint_modified (struct breakpoint *b) |
fprintf_unfiltered (mi->event_channel, |
"breakpoint-modified"); |
/* We want the output from gdb_breakpoint_query to go to |
- mi->event_channel. One approach would be to just |
- call gdb_breakpoint_query, and then use mi_out_put to |
- send the current content of mi_outout into mi->event_channel. |
- However, that will break if anything is output to mi_uiout |
- prior the calling the breakpoint_created notifications. |
- So, we use ui_out_redirect. */ |
+ mi->event_channel. One approach would be to just call |
+ gdb_breakpoint_query, and then use mi_out_put to send the current |
+ content of mi_outout into mi->event_channel. However, that will |
+ break if anything is output to mi_uiout prior to calling the |
+ breakpoint_created notifications. So, we use |
+ ui_out_redirect. */ |
ui_out_redirect (mi_uiout, mi->event_channel); |
TRY_CATCH (e, RETURN_MASK_ERROR) |
gdb_breakpoint_query (mi_uiout, b->number, NULL); |
@@ -569,7 +593,6 @@ mi_breakpoint_modified (struct breakpoint *b) |
gdb_flush (mi->event_channel); |
} |
- |
static int |
mi_output_running_pid (struct thread_info *info, void *arg) |
{ |
@@ -732,20 +755,69 @@ mi_ui_out (struct interp *interp) |
return mi->uiout; |
} |
+/* Save the original value of raw_stdout here when logging, so we can |
+ restore correctly when done. */ |
+ |
+static struct ui_file *saved_raw_stdout; |
+ |
+/* Do MI-specific logging actions; save raw_stdout, and change all |
+ the consoles to use the supplied ui-file(s). */ |
+ |
+static int |
+mi_set_logging (struct interp *interp, int start_log, |
+ struct ui_file *out, struct ui_file *logfile) |
+{ |
+ struct mi_interp *mi = interp_data (interp); |
+ |
+ if (!mi) |
+ return 0; |
+ |
+ if (start_log) |
+ { |
+ /* The tee created already is based on gdb_stdout, which for MI |
+ is a console and so we end up in an infinite loop of console |
+ writing to ui_file writing to console etc. So discard the |
+ existing tee (it hasn't been used yet, and MI won't ever use |
+ it), and create one based on raw_stdout instead. */ |
+ if (logfile) |
+ { |
+ ui_file_delete (out); |
+ out = tee_file_new (raw_stdout, 0, logfile, 0); |
+ } |
+ |
+ saved_raw_stdout = raw_stdout; |
+ raw_stdout = out; |
+ } |
+ else |
+ { |
+ raw_stdout = saved_raw_stdout; |
+ saved_raw_stdout = NULL; |
+ } |
+ |
+ mi_console_set_raw (mi->out, raw_stdout); |
+ mi_console_set_raw (mi->err, raw_stdout); |
+ mi_console_set_raw (mi->log, raw_stdout); |
+ mi_console_set_raw (mi->targ, raw_stdout); |
+ mi_console_set_raw (mi->event_channel, raw_stdout); |
+ |
+ return 1; |
+} |
+ |
extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */ |
void |
_initialize_mi_interp (void) |
{ |
static const struct interp_procs procs = |
- { |
- mi_interpreter_init, /* init_proc */ |
- mi_interpreter_resume, /* resume_proc */ |
- mi_interpreter_suspend, /* suspend_proc */ |
- mi_interpreter_exec, /* exec_proc */ |
- mi_interpreter_prompt_p, /* prompt_proc_p */ |
- mi_ui_out /* ui_out_proc */ |
- }; |
+ { |
+ mi_interpreter_init, /* init_proc */ |
+ mi_interpreter_resume, /* resume_proc */ |
+ mi_interpreter_suspend, /* suspend_proc */ |
+ mi_interpreter_exec, /* exec_proc */ |
+ mi_interpreter_prompt_p, /* prompt_proc_p */ |
+ mi_ui_out, /* ui_out_proc */ |
+ mi_set_logging /* set_logging_proc */ |
+ }; |
/* The various interpreter levels. */ |
interp_add (interp_new (INTERP_MI1, &procs)); |