for user breakpoints.
(mi_cmd_break_insert): Only reset event handlers for MI0 and MI1
interpreters.
(mi_cmd_break_watch): Reset uiout output to clear watchpoint
query. This is only used for MI0 and MI1.
* mi-console.h (mi_console_file_new): Add "quote" parameter.
* mi_console.c (struct mi_console_file): Add "quote".
(mi_console_file_new): Add "quote" parameter.
(mi_console_raw_packet): Use the quote character specified in
mi_console_file_new, instead of assuming it is '"'.
* mi-interp.c (mi_event_channel): New channel for event notifications.
(mi_interpreter_init): Make static.
Set event handlers.
(mi_interpreter_resume): Make static.
Deal with MI version bump.
(mi_interpreter_suspend): Make static.
(mi_interpreter_delete): Ditto.
(mi_do_one_event): Ditto.
(mi_cmd_exec_continuation): Ditto.
(mi_interp_query_hook): Ditto.
(mi_interp_read_one_line_hook): Ditto.
(_initialize_mi_interp): Create explicit mi1 interp.
* mi-events.c (notify_event): New helper function.
(mi_create_breakpoint, mi_modify_breakpoint, mi_delete_breakpoint,
mi_create_tracepoint, mi_modify_tracepoint, mi_delete_tracepoint,
mi_architecture_changed): New functions.
* mi.h: Add declarations for mi_create_breakpoint, mi_modify_breakpoint,
mi_delete_breakpoint, mi_create_tracepoint, mi_modify_tracepoint,
mi_delete_tracepoint, mi_architecture_changed, mi_stdout, mi_stderr,
mi_stdtarg, mi_stdlog, and mi_eventchannel.
* mi-main.c (captured_mi_execute_command): Deal with mi version
bump.
(mi_load_progress): Ditto.
* gdbmi.texinfo: Expand notify-async-output to include GDB events.
Update all examples to show breakpoint events and
remove redundant breakpoint info on "-break-insert" and "-break-watch".
The event now supplies everything that is needed.
+2002-06-19 Keith Seitz <keiths@redhat.com>
+
+ * mi-cmd-break.c (breakpoint_notify): Only query the breakpoint
+ for user breakpoints.
+ (mi_cmd_break_insert): Only reset event handlers for MI0 and MI1
+ interpreters.
+ (mi_cmd_break_watch): Reset uiout output to clear watchpoint
+ query. This is only used for MI0 and MI1.
+
+ * mi-console.h (mi_console_file_new): Add "quote" parameter.
+ * mi_console.c (struct mi_console_file): Add "quote".
+ (mi_console_file_new): Add "quote" parameter.
+ (mi_console_raw_packet): Use the quote character specified in
+ mi_console_file_new, instead of assuming it is '"'.
+
+ * mi-interp.c (mi_event_channel): New channel for event notifications.
+ (mi_interpreter_init): Make static.
+ Set event handlers.
+ (mi_interpreter_resume): Make static.
+ Deal with MI version bump.
+ (mi_interpreter_suspend): Make static.
+ (mi_interpreter_delete): Ditto.
+ (mi_do_one_event): Ditto.
+ (mi_cmd_exec_continuation): Ditto.
+ (mi_interp_query_hook): Ditto.
+ (mi_interp_read_one_line_hook): Ditto.
+ (_initialize_mi_interp): Create explicit mi1 interp.
+
+ * mi-events.c (notify_event): New helper function.
+ (mi_create_breakpoint, mi_modify_breakpoint, mi_delete_breakpoint,
+ mi_create_tracepoint, mi_modify_tracepoint, mi_delete_tracepoint,
+ mi_architecture_changed): New functions.
+
+ * mi.h: Add declarations for mi_create_breakpoint, mi_modify_breakpoint,
+ mi_delete_breakpoint, mi_create_tracepoint, mi_modify_tracepoint,
+ mi_delete_tracepoint, mi_architecture_changed, mi_stdout, mi_stderr,
+ mi_stdtarg, mi_stdlog, and mi_eventchannel.
+
+ * mi-main.c (captured_mi_execute_command): Deal with mi version
+ bump.
+ (mi_load_progress): Ditto.
+
+ * gdbmi.texinfo: Expand notify-async-output to include GDB events.
+ Update all examples to show breakpoint events and
+ remove redundant breakpoint info on "-break-insert" and "-break-watch".
+ The event now supplies everything that is needed.
+
2002-05-20 Keith Seitz <keiths@redhat.com>
* mi-main.c (captured_mi_execute_command): Add uiout parameter.
@c @ifinfo
@c This file documents GDB/MI, a Machine Interface to GDB.
-@c Copyright 2000, 2001 Free Software Foundation, Inc.
+@c Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
@c Contributed by Cygnus Solutions.
@c Permission is granted to copy, distribute and/or modify this document
@c @page
@c @vskip 0pt plus 1filll
-@c Copyright @copyright{} 2000, 2001 Free Software Foundation, Inc.
+@c Copyright @copyright{} 2000, 2001, 2002 Free Software Foundation, Inc.
@c Permission is granted to copy, distribute and/or modify this document
@c under the terms of the GNU Free Documentation License, Version 1.1 or
@item
@cindex notify output in @sc{gdb/mi}
-@var{notify-async-output} contains supplementary information that the
-client should handle (e.g., a new breakpoint information). All notify
+@var{notify-async-output} contains supplementary information (events) that the
+client should handle (e.g., a new breakpoint was inserted). All notify
output is prefixed by @samp{=}.
@item
the output received from @sc{gdb/mi}.
@subsubheading Target Stop
-
+@c Ummm... There is no "-stop" command. This assumes async, no?
Here's an example of stopping the inferior process:
@example
@example
-> print 1+2
-<- ~3\n
+<- &"print 1+2\n"
+<- ~"$1 = 3\n"
+<- ^done
<- (@value{GDBP})
@end example
@example
-> -symbol-file xyz.exe
-<- *breakpoint,nr="3",address="0x123",source="a.c:123"
+<- =breakpoint-create,number="3"
+<- ^done
<- (@value{GDBP})
@end example
@example
-> -rubbish
-<- error,"Rubbish not found"
+<- ^error,msg="Undefined MI command: rubbish"
<- (@value{GDBP})
@end example
consequence of @sc{gdb/mi} (e.g., a breakpoint modified) or a result of
target activity (e.g., target stopped).
-The following is a preliminary list of possible out-of-band records.
+The following is a preliminary list of out-of-band records.
@table @code
-@item "*" "stop"
+@item stop
+The inferior stopped.
+@c Need an example!
+
+@item breakpoint-create
+@itemx breakpoint-modify
+@itemx breakpoint-delete
+@itemx tracepoint-create
+@itemx tracepoint-modify
+@itemx tracepoint-delete
+A breakpoint or tracepoint was created, modified, or deleted. In all cases,
+the event will also report the @code{number} of the affected breakpoint/tracepoint:
+@smallexample
+=breakpoint-create,number="1"
+@end smallexample
+
+@item architecture-changed
+This event indicates that @value{GDBN} has changed architectures, and that
+the user interface may need to update certain views that are architecture-dependent,
+such as registers.
+@smallexample
+=architecture-changed
+@end smallexample
@end table
@smallexample
(@value{GDBP})
-break-insert main
-^done,bkpt=@{number="1",addr="0x000100d0",file="hello.c",line="5"@}
+=breakpoint-create,number="1"
+^done
(@value{GDBP})
-break-after 1 3
-~
+=breakpoint-modify,number="1"
^done
(@value{GDBP})
-break-list
@smallexample
(@value{GDBP})
-break-condition 1 1
+=breakpoint-modify,number="1"
^done
(@value{GDBP})
-break-list
@example
(@value{GDBP})
-break-delete 1
+=breakpoint-delete,number="1"
^done
(@value{GDBP})
-break-list
@smallexample
(@value{GDBP})
-break-disable 2
+=breakpoint-modify,number="2"
^done
(@value{GDBP})
-break-list
@smallexample
(@value{GDBP})
-break-enable 2
+=breakpoint-modify,number="2"
^done
(@value{GDBP})
-break-list
expresson.
@end table
-@subsubheading Result
-
-The result is in the form:
-
-@example
- ^done,bkptno="@var{number}",func="@var{funcname}",
- file="@var{filename}",line="@var{lineno}"
-@end example
-
-@noindent
-where @var{number} is the @value{GDBN} number for this breakpoint, @var{funcname}
-is the name of the function where the breakpoint was inserted,
-@var{filename} is the name of the source file which contains this
-function, and @var{lineno} is the source line number within that file.
-
-Note: this format is open to change.
-@c An out-of-band breakpoint instead of part of the result?
-
@subsubheading @value{GDBN} Command
The corresponding @value{GDBN} commands are @samp{break}, @samp{tbreak},
@smallexample
(@value{GDBP})
-break-insert main
-^done,bkpt=@{number="1",addr="0x0001072c",file="recursive2.c",line="4"@}
+=breakpoint-create,number="1"
+^done
(@value{GDBP})
-break-insert -t foo
-^done,bkpt=@{number="2",addr="0x00010774",file="recursive2.c",line="11"@}
+=breakpoint-create,number="2"
+^done
(@value{GDBP})
-break-list
^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
(@value{GDBP})
-break-insert -r foo.*
~int foo(int, int);
-^done,bkpt=@{number="3",addr="0x00010774",file="recursive2.c",line="11"@}
+=breakpoint-create,number="1"
+^done
(@value{GDBP})
@end smallexample
@smallexample
(@value{GDBP})
-break-watch x
-^done,wpt=@{number="2",exp="x"@}
+=breakpoint-create,number="2"
+^done
(@value{GDBP})
-exec-continue
^running
@smallexample
(@value{GDBP})
-break-watch C
-^done,wpt=@{number="5",exp="C"@}
+=breakpoint-create,number="5"
+^done
(@value{GDBP})
-exec-continue
^running
@smallexample
(@value{GDBP})
-break-watch C
-^done,wpt=@{number="2",exp="C"@}
+=breakpoint-create,number="2"
+^done
(@value{GDBP})
-break-list
^done,BreakpointTable=@{nr_rows="2",nr_cols="6",
#include "mi-getopt.h"
#include "gdb-events.h"
#include "gdb.h"
+#include "interps.h"
enum
{
static void
breakpoint_notify (int b)
{
- gdb_breakpoint_query (uiout, b);
+ if (b > 0)
+ gdb_breakpoint_query (uiout, b);
}
error ("mi_cmd_break_insert: Garbage following <location>");
address = argv[optind];
+ /* Save the current event handlers so that we can insert our own. This
+ allows us to capture the breakpoint information as the breakpoint
+ is created. Unfortunately, it also overrides any existing event
+ handlers, so we won't get any event notifications sent out to the
+ client. MI2+ does NOT send breakpoint information with the -break-insert
+ command for this reason. */
+ if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ || gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ old_hooks = set_gdb_event_hooks (&breakpoint_hooks);
+
/* Now we have what we need, let's insert the breakpoint! */
- old_hooks = set_gdb_event_hooks (&breakpoint_hooks);
switch (type)
{
case REG_BP:
internal_error (__FILE__, __LINE__,
"mi_cmd_break_insert: Bad switch.");
}
- set_gdb_event_hooks (old_hooks);
+
+ if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ || gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ set_gdb_event_hooks (old_hooks);
if (rc == GDB_RC_FAIL)
return MI_CMD_CAUGHT_ERROR;
default:
error ("mi_cmd_break_watch: Unknown watchpoint type.");
}
+
+ /* Ugh. This is a hack. mention and print_one_breakpoint in
+ breakpoint.c are so overloaded, that watchpoints and breakpoints
+ cannot use the same printing mechanisms. So for MI2+, we simply
+ rewind MI's uiout so that we can prevent GDB from printing
+ any information about the watchpoint we just inserted. */
+ if (!gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ mi_out_rewind (uiout);
+
return MI_CMD_DONE;
}
struct ui_file *raw;
struct ui_file *buffer;
const char *prefix;
+ char quote;
};
int mi_console_file_magic;
struct ui_file *
mi_console_file_new (struct ui_file *raw,
- const char *prefix)
+ const char *prefix, char quote)
{
struct ui_file *ui_file = ui_file_new ();
struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
mi_console->raw = raw;
mi_console->buffer = mem_fileopen ();
mi_console->prefix = prefix;
+ mi_console->quote = quote;
set_ui_file_fputs (ui_file, mi_console_file_fputs);
set_ui_file_flush (ui_file, mi_console_file_flush);
set_ui_file_data (ui_file, mi_console, mi_console_file_delete);
if (length_buf > 0)
{
fputs_unfiltered (mi_console->prefix, mi_console->raw);
- fputs_unfiltered ("\"", mi_console->raw);
- fputstrn_unfiltered (buf, length_buf, '"', mi_console->raw);
- fputs_unfiltered ("\"\n", mi_console->raw);
+ if (mi_console->quote)
+ {
+ fputs_unfiltered ("\"", mi_console->raw);
+ fputstrn_unfiltered (buf, length_buf, mi_console->quote, mi_console->raw);
+ fputs_unfiltered ("\"\n", mi_console->raw);
+ }
+ else
+ {
+ fputstrn_unfiltered (buf, length_buf, 0, mi_console->raw);
+ fputs_unfiltered ("\n", mi_console->raw);
+ }
gdb_flush (mi_console->raw);
}
}
#ifndef MI_CONSOLE_H
#define MI_CONSOLE_H
-extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix);
+extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix,
+ char quote);
#endif
ui_out_list_end (uiout);
uiout = saved_ui_out;
}
+
+static void
+event_notify (const char *string, ...)
+{
+ va_list args;
+
+ if (!gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ {
+ va_start (args, string);
+ vfprintf_unfiltered (mi_event_channel, string, args);
+ va_end (args);
+ gdb_flush (mi_event_channel);
+ }
+}
+
+/* breakpoint-create,number=bpnum */
+void
+mi_create_breakpoint (int bpnum)
+{
+ event_notify ("breakpoint-create,number=\"%d\"", bpnum);
+}
+
+void
+mi_modify_breakpoint (int bpnum)
+{
+ event_notify ("breakpoint-modify,number=\"%d\"", bpnum);
+}
+
+void
+mi_delete_breakpoint (int bpnum)
+{
+ event_notify ("breakpoint-delete,number=\"%d\"", bpnum);
+}
+
+void
+mi_create_tracepoint (int tpnum)
+{
+ event_notify ("tracepoint-create,number=\"%d\"", tpnum);
+}
+
+void
+mi_modify_tracepoint (int tpnum)
+{
+ event_notify ("tracepoint-modify,number=\"%d\"", tpnum);
+}
+
+void
+mi_delete_tracepoint (int tpnum)
+{
+ event_notify ("tracepoint-delete,number=\"%d\"", tpnum);
+}
+
+void
+mi_architecture_changed (void)
+{
+ event_notify ("architecture-changed");
+}
struct ui_file *mi_stderr;
struct ui_file *mi_stdlog;
struct ui_file *mi_stdtarg;
+struct ui_file *mi_event_channel;
/* This is the interpreter for the mi... */
struct gdb_interpreter *mi0_interp;
+struct gdb_interpreter *mi1_interp;
struct gdb_interpreter *mi_interp;
/* These are the interpreter setup, etc. functions for the MI interpreter */
static void mi_insert_notify_hooks (void);
static void mi_remove_notify_hooks (void);
-int
+static int
mi_interpreter_init (void *data)
{
+ static struct gdb_events handlers;
+
/* Why is this a part of the mi architecture? */
mi_setup_architecture_data ();
this now, and swap them in when we are run. */
raw_stdout = stdio_fileopen (stdout);
- /* Route normal output through the MIx */
- mi_stdout = mi_console_file_new (raw_stdout, "~");
- /* Route error and log output through the MI */
- mi_stderr = mi_console_file_new (raw_stdout, "&");
+
+ /* Create MI channels */
+ mi_stdout = mi_console_file_new (raw_stdout, "~", '"');
+ mi_stderr = mi_console_file_new (raw_stdout, "&", '"');
mi_stdlog = mi_stderr;
- /* Route target output through the MI. */
- mi_stdtarg = mi_console_file_new (raw_stdout, "@");
+ mi_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+ mi_event_channel = mi_console_file_new (raw_stdout, "=", 0);
+
+ /* Add global event handlers */
+ handlers.breakpoint_create = mi_create_breakpoint;
+ handlers.breakpoint_modify = mi_modify_breakpoint;
+ handlers.breakpoint_delete = mi_delete_breakpoint;
+ handlers.tracepoint_create = mi_create_tracepoint;
+ handlers.tracepoint_modify = mi_modify_tracepoint;
+ handlers.tracepoint_delete = mi_delete_tracepoint;
+ handlers.architecture_changed = mi_architecture_changed;
+ set_gdb_event_hooks (&handlers);
return 1;
}
-int
+static int
mi_interpreter_resume (void *data)
{
/* As per hack note in mi_interpreter_init, swap in the output channels... */
/* If we're _the_ interpreter, take control. */
if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
command_loop_hook = mi0_command_loop;
+ else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+ command_loop_hook = mi1_command_loop;
else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI))
command_loop_hook = mi1_command_loop;
else
return 1;
}
-int
+static int
mi_interpreter_suspend (void *data)
{
gdb_disable_readline ();
return 1;
}
-int
+static int
mi_interpreter_delete (void *data)
{
return 1;
}
-int
+static int
mi_interpreter_prompt (void *data, char *new_prompt)
{
return 1;
}
-int
+static int
mi_do_one_event (void *data)
{
return 1;
}
-void
+static void
mi_interpreter_exec_continuation (struct continuation_arg *arg)
{
bpstat_do_actions (&stop_bpstat);
/* 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... */
xfree (buff);
do_exec_error_cleanups (ALL_CLEANUPS);
sync_execution = 0;
-
}
/* Now do the switch... */
query_hook = NULL;
}
-int
+static int
mi_interp_query_hook (const char *ctlstr, va_list ap)
{
return 1;
}
-char *
+static char *
mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
{
static char buff[256];
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, "~");
+ 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_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, "@");
+ 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);
mi_interpreter_prompt /* prompt_proc */
};
+ /* Create MI0 interpreter */
if (mi0_interp == NULL)
{
mi0_interp =
error ("Couldn't add the mi0 interpreter to gdb.\n");
}
+ /* Create MI1 interpreter */
+ if (mi1_interp == NULL)
+ {
+ mi1_interp =
+ gdb_new_interpreter (GDB_INTERPRETER_MI1, NULL, mi_out_new (1),
+ &procs);
+ if (mi1_interp == NULL)
+ error
+ ("Couldn't allocate a new interpreter for the mi1 interpreter\n");
+ if (gdb_add_interpreter (mi1_interp) != 1)
+ error ("Couldn't add the mi1 interpreter to gdb.\n");
+ }
+
+ /* Create MI2 interpreter */
if (mi_interp == NULL)
{
mi_interp =
- gdb_new_interpreter (GDB_INTERPRETER_MI, NULL, mi_out_new (1),
+ gdb_new_interpreter (GDB_INTERPRETER_MI, NULL, mi_out_new (2),
&procs);
if (mi_interp == NULL)
error
/* If we changed interpreters, DON'T print out anything. */
if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI)
- || gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+ || gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ || gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
{
/* print the result */
/* FIXME: Check for errors here. */
mi_parse_free (command);
}
- if (args.rc != MI_CMD_QUIET)
- {
- fputs_unfiltered ("(gdb) \n", raw_stdout);
- gdb_flush (raw_stdout);
- /* print any buffered hook code */
- /* ..... */
- }
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ /* print any buffered hook code */
+ /* ..... */
}
static enum mi_cmd_result
int new_section;
if (!gdb_current_interpreter_is_named (GDB_INTERPRETER_MI)
- && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+ && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+ && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
return;
update_threshold.tv_sec = 0;
#ifndef MI_H
#define MI_H
/* The mi interpreters. */
+struct ui_file;
+struct breakpoint;
struct gdb_interpreter;
extern struct gdb_interpreter *mi_interp;
extern struct gdb_interpreter *mi0_interp;
extern void mi_setup_architecture_data (void);
extern void mi_register_gdbarch_swap (void);
+/* MI's output channels */
+extern struct ui_file *mi_stdout;
+extern struct ui_file *mi_stderr;
+extern struct ui_file *mi_stdlog;
+extern struct ui_file *mi_stdtarg;
+extern struct ui_file *mi_event_channel;
+
/* Events/Hooks */
extern void mi_load_progress (const char *section_name,
unsigned long sent_so_far,
extern void mi_interp_frame_changed_hook (int new_frame_number);
extern void mi_interp_context_hook (int thread_id);
+extern void mi_create_breakpoint (int bpnum);
+extern void mi_modify_breakpoint (int bpnum);
+extern void mi_delete_breakpoint (int bpnum);
+extern void mi_create_tracepoint (int bpnum);
+extern void mi_modify_tracepoint (int bpnum);
+extern void mi_delete_tracepoint (int bpnum);
+extern void mi_architecture_changed (void);
#endif /* MI_H */