This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: MI handshaking
On Thu, Nov 04, 2004 at 11:23:11PM +0200, Eli Zaretskii wrote:
> > Date: Thu, 4 Nov 2004 14:57:01 -0500
> > From: Bob Rossi <bob@brasko.net>
> >
> > The one question I have is, should the documentation for this be in the
> > MI output syntax? or should there me a new field called
> > MI handshaking syntax?
>
> I'd prefer a new subsection right at the beginning of the GDB/MI
> description in the manual. That way, someone who designs a front end
> will see this stuff when she begins reading the docs.
Here is the new patch, with the doco sections.
Does anyone care if the output of the handshaking starts with a special
char like '~' or something? Or should I leave it the way it is below?
$ ./gdb/gdb -i=mi
handshake={stable_protocols={mi2}}
~"GNU gdb 6.3.50_2004-11-05-cvs\n"
~"Copyright 2004 Free Software Foundation, Inc.\n"
Any suggestions?
Thanks,
Bob Rossi
Index: gdb/interps.c
===================================================================
RCS file: /cvs/src/src/gdb/interps.c,v
retrieving revision 1.8
diff -w -u -r1.8 interps.c
--- gdb/interps.c 13 Sep 2004 18:26:30 -0000 1.8
+++ gdb/interps.c 5 Nov 2004 16:36:28 -0000
@@ -68,6 +68,8 @@
const struct interp_procs *procs;
int quiet_p;
+
+ interp_handshake_ftype *handshake;
};
/* Functions local to this file. */
@@ -90,7 +92,7 @@
interpreter. */
struct interp *
interp_new (const char *name, void *data, struct ui_out *uiout,
- const struct interp_procs *procs)
+ const struct interp_procs *procs, interp_handshake_ftype *handshake)
{
struct interp *new_interp;
@@ -102,6 +104,7 @@
new_interp->quiet_p = 0;
new_interp->procs = procs;
new_interp->inited = 0;
+ new_interp->handshake = handshake;
return new_interp;
}
@@ -239,6 +242,22 @@
return current_interpreter->interpreter_out;
}
+int
+interp_can_handshake (struct interp *interp)
+{
+ if (interp != NULL)
+ if (interp->handshake)
+ return 1;
+
+ return 0;
+}
+
+struct interp *
+interp_handshake (struct interp *interp)
+{
+ return interp_lookup (interp->handshake (gdb_stdout, gdb_stdin));
+}
+
/* Returns true if the current interp is the passed in name. */
int
current_interp_named_p (const char *interp_name)
Index: gdb/interps.h
===================================================================
RCS file: /cvs/src/src/gdb/interps.h,v
retrieving revision 1.6
diff -w -u -r1.6 interps.h
--- gdb/interps.h 18 Feb 2004 19:01:36 -0000 1.6
+++ gdb/interps.h 5 Nov 2004 16:36:28 -0000
@@ -40,6 +40,7 @@
typedef int (interp_prompt_p_ftype) (void *data);
typedef int (interp_exec_ftype) (void *data, const char *command);
typedef void (interp_command_loop_ftype) (void *data);
+typedef const char *(interp_handshake_ftype) (struct ui_file *gdb_stdout, struct ui_file *gdb_stdin);
struct interp_procs
{
@@ -53,11 +54,14 @@
extern struct interp *interp_new (const char *name, void *data,
struct ui_out *uiout,
- const struct interp_procs *procs);
+ const struct interp_procs *procs,
+ interp_handshake_ftype *handshake);
extern void interp_add (struct interp *interp);
extern int interp_set (struct interp *interp);
extern struct interp *interp_lookup (const char *name);
extern struct ui_out *interp_ui_out (struct interp *interp);
+extern int interp_can_handshake (struct interp *interp);
+extern struct interp *interp_handshake (struct interp *interp);
extern int current_interp_named_p (const char *name);
extern int current_interp_display_prompt_p (void);
Index: gdb/main.c
===================================================================
RCS file: /cvs/src/src/gdb/main.c,v
retrieving revision 1.44
diff -w -u -r1.44 main.c
--- gdb/main.c 10 Aug 2004 22:36:39 -0000 1.44
+++ gdb/main.c 5 Nov 2004 16:36:28 -0000
@@ -561,8 +561,13 @@
{
/* Find it. */
struct interp *interp = interp_lookup (interpreter_p);
+
+ if (interp && interp_can_handshake (interp))
+ interp = interp_handshake (interp);
+
if (interp == NULL)
error ("Interpreter `%s' unrecognized", interpreter_p);
+
/* Install it. */
if (!interp_set (interp))
{
Index: gdb/cli/cli-interp.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-interp.c,v
retrieving revision 1.4
diff -w -u -r1.4 cli-interp.c
--- gdb/cli/cli-interp.c 3 Jul 2003 14:49:26 -0000 1.4
+++ gdb/cli/cli-interp.c 5 Nov 2004 16:36:29 -0000
@@ -151,7 +151,7 @@
/* Create a default uiout builder for the CLI. */
cli_uiout = cli_out_new (gdb_stdout);
- cli_interp = interp_new (INTERP_CONSOLE, NULL, cli_uiout, &procs);
+ cli_interp = interp_new (INTERP_CONSOLE, NULL, cli_uiout, &procs, NULL);
interp_add (cli_interp);
}
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.222
diff -w -u -r1.222 gdb.texinfo
--- gdb/doc/gdb.texinfo 23 Oct 2004 15:05:29 -0000 1.222
+++ gdb/doc/gdb.texinfo 5 Nov 2004 16:36:41 -0000
@@ -14997,6 +14997,7 @@
@menu
* GDB/MI Command Syntax::
* GDB/MI Compatibility with CLI::
+* GDB/MI Handshaking Interface::
* GDB/MI Output Records::
* GDB/MI Command Description Format::
* GDB/MI Breakpoint Table Commands::
@@ -15021,11 +15022,50 @@
@section @sc{gdb/mi} Command Syntax
@menu
+* GDB/MI Handshaking Syntax::
* GDB/MI Input Syntax::
* GDB/MI Output Syntax::
* GDB/MI Simple Examples::
@end menu
+@node GDB/MI Handshaking Syntax
+@subsection @sc{gdb/mi} Handshaking Syntax
+
+@cindex handshaking syntax for @sc{gdb/mi}
+@cindex @sc{gdb/mi}, handshaking syntax
+@table @code
+@item @var{handshake_output} @expansion{}
+@code{"handshake=@{stable_protocols=@{" @var{mi-protocol-list}
+"@}" @var{nl}}
+
+@item @var{mi-protocol-list} @expansion{}
+@code{ epsilon | @var{mi-protocol} | @var{mi-protocol-list} "," @var{mi-protocol} }
+
+@item @var{mi-protocol} @expansion{}
+@code{ "mi" @var{token} }
+
+@item @var{token} @expansion{}
+"any sequence of digits"
+
+@item @var{nl} @expansion{}
+@code{CR | CR-LF}
+@end table
+
+@noindent
+Notes:
+
+@itemize @bullet
+@item
+If only one stable @sc{mi} protocol is supported by a particular release of
+@value{GDBN}, then that release is used and the caller does not have to
+do anything.
+
+@item
+If there is more than one stable @sc{mi} protocol supported by a particular
+release of @value{GDBN}, then the caller has to specify which version of the
+@sc{mi} protocol it wants @value{GDBN} to communicate with.
+@end itemize
+
@node GDB/MI Input Syntax
@subsection @sc{gdb/mi} Input Syntax
@@ -15111,6 +15151,9 @@
@var{token}.
@table @code
+@item @var{output-list} @expansion{}
+@code{@var{output} | @var{output-list} @var{output}}
+
@item @var{output} @expansion{}
@code{( @var{out-of-band-record} )* [ @var{result-record} ] "(@value{GDBP})" @var{nl}}
@@ -15314,6 +15357,38 @@
an un-supported hybrid of @sc{gdb/mi} and CLI output.
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@node GDB/MI Handshaking Interface
+@section @sc{gdb/mi} Handshaking Interface
+
+@cindex @sc{gdb/mi}, handshaking interface
+@value{GDBN} is capable of speaking several MI protocols at a time. This
+interface is intended to help developers understand what version of the MI
+protocol that a particular @value{GDBN} is going to communicate with.
+
+It is possible to start the @sc{gdb/mi} interpreter using -i=mi1, -i=mi2, or
+simply with -i=mi. If a front end starts @value{GDBN} with -i=miN it will
+bypass the handshaking mode and will go directly into the version of the MI
+that it requested. However, if @value{GDBN} is started with the -i=mi flag,
+then this tells @value{GDBN} to go into it's handshaking mode with the
+client to determine the correct MI protocol to communicate with.
+
+@value{GDBN} will output all of the stable versions of the MI protocol that
+it supports. The term "stable MI protocol" simply means that the protocol
+was tested when this particular release was made. Protocols that are no longer
+tested in the @value{GDBN} testsuite will not be considered a stable release.
+If the caller still wishes to communicate with @value{GDBN} using one of these
+untested protocols, they could simply try to invoke @value{GDBN} with -i=miN,
+where N is version they wish to communicate with.
+
+@value{GDBN} will output all of the stable MI versions that it supports.
+If a specific version of @value{GDBN} speaks only one stable MI protocol than
+it will begin communicating with that version of the protocol. The front end
+has no way to change this version. However, if @value{GDBN} speaks several
+versions of the MI protocol, than it will output a list of these protocols
+and the front end then has to choose the version that it wants @value{GDBN}
+to communicate with.
+
+@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@node GDB/MI Output Records
@section @sc{gdb/mi} Output Records
Index: gdb/mi/mi-interp.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-interp.c,v
retrieving revision 1.11
diff -w -u -r1.11 mi-interp.c
--- gdb/mi/mi-interp.c 13 Sep 2004 18:26:31 -0000 1.11
+++ gdb/mi/mi-interp.c 5 Nov 2004 16:36:42 -0000
@@ -364,6 +364,66 @@
start_event_loop ();
}
+/* The latest stable mi version that is being tested.
+ There could potentially be several versions of MI that are stable
+ at a time. */
+static const int stable_mi_versions[] =
+{
+ 2,
+ 0
+};
+
+/* Allows MI and the front end to agree on an MI protocol.
+
+ All of the stable MI versions are currently printed. If there is more
+ than one stable MI version, than it is expected the user will write
+ back the version they want to communicate with.
+
+ Returns the MI version string the user requested, or if there is only
+ one version, that string is returned. */
+static const char *mi_handshake (struct ui_file *gdb_stdout,
+ struct ui_file *gdb_stdin)
+{
+ static char mi_buf[32];
+ int i;
+
+ if (!gdb_stdout || !gdb_stdin)
+ return NULL;
+
+ /* Output the header, can't use mi_out stuff because no mi has
+ been chosen and initialized yet. */
+ fprintf_unfiltered ( gdb_stdout, "handshake={stable_protocols={" );
+
+ /* Output all the stable versions */
+ for (i = 0; stable_mi_versions[i] != 0; ++i )
+ {
+ if (i > 0)
+ fprintf_unfiltered (gdb_stdout, ",");
+
+ fprintf_unfiltered (gdb_stdout, "mi%d", stable_mi_versions[i] );
+ }
+
+ fprintf_unfiltered ( gdb_stdout, "}}\n" );
+
+ /* If there was more than one stable version outputted, ask the front
+ end which one it should use */
+ if ( i > 1 )
+ {
+ int size;
+ size = ui_file_read ( gdb_stdin, mi_buf, 31 );
+ mi_buf[size--] = 0; /* null terminate, and remove new line */
+ while ( size >= 0 && (mi_buf[size] == '\n' || mi_buf[size] == '\r') )
+ mi_buf[size--] = 0;
+
+ /* The mi option is not valid in this mode. */
+ if ( strcmp ( mi_buf, "mi" ) == 0 )
+ return NULL;
+ } else
+ sprintf ( mi_buf, "mi%d", stable_mi_versions[0] );
+
+ return mi_buf;
+}
+
extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
void
@@ -379,11 +439,11 @@
};
/* The various interpreter levels. */
- interp_add (interp_new (INTERP_MI1, NULL, mi_out_new (1), &procs));
- interp_add (interp_new (INTERP_MI2, NULL, mi_out_new (2), &procs));
- interp_add (interp_new (INTERP_MI3, NULL, mi_out_new (3), &procs));
+ interp_add (interp_new (INTERP_MI1, NULL, mi_out_new (1), &procs, NULL));
+ interp_add (interp_new (INTERP_MI2, NULL, mi_out_new (2), &procs, NULL));
+ interp_add (interp_new (INTERP_MI3, NULL, mi_out_new (3), &procs, NULL));
/* "mi" selects the most recent released version. "mi2" was
released as part of GDB 6.0. */
- interp_add (interp_new (INTERP_MI, NULL, mi_out_new (2), &procs));
+ interp_add (interp_new (INTERP_MI, NULL, mi_out_new (stable_mi_versions[0]), &procs, mi_handshake));
}
Index: gdb/tui/tui-interp.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-interp.c,v
retrieving revision 1.5
diff -w -u -r1.5 tui-interp.c
--- gdb/tui/tui-interp.c 7 Feb 2004 04:40:36 -0000 1.5
+++ gdb/tui/tui-interp.c 5 Nov 2004 16:36:43 -0000
@@ -198,7 +198,7 @@
/* Create a default uiout builder for the TUI. */
tui_out = tui_out_new (gdb_stdout);
- interp_add (interp_new ("tui", NULL, tui_out, &procs));
+ interp_add (interp_new ("tui", NULL, tui_out, &procs, NULL));
if (interpreter_p && strcmp (interpreter_p, "tui") == 0)
tui_start_enabled = 1;