[v2,24/25] Add new command to create extra console/mi UI channels

Message ID 1458573675-15478-25-git-send-email-palves@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves March 21, 2016, 3:21 p.m. UTC
  With all the previous plumbing in place, it's now easy to add a
command that actually creates a new console/mi UI.

The intended use case is to make it possible and easy for MI frontends
to provide a fully featured GDB console to users, with readline
support, command line editing, history, etc., just like if gdb was
started on the command line.  Currently MI frontends have to try to
implement all of that theirselves and make use of "-interpreter-exec
console ...", which is far from perfect.  If you ever tried Eclipse's
gdb console window, you'll know what I mean...

Instead of trying to multiplex console through MI, this command let's
just leverage all the built in readline/editing support already inside
gdb.

The plan is for the MI frontend to start GDB in regular console mode,
running inside a terminal emulator widget embedded in Eclipse (which
already exists, for supporting the shell widget; other frontends have
similar widgets), and then tell GDB to run a full MI interpreter on an
extra / separate side channel, independent of the console.

My original prototype planned to do things the other way around --
start GDB in MI mode, and then start an extra CLI console on separate
tty.  I handed over that prototype to Marc Khouzam @ Eclipse CDT, and
after experimentation and discussion, we ended up concluding that
starting GDB in CLI mode instead was both easier and actually also
supported an interesting use case -- connect an Eclipse frontend to a
GDB that is already running outside Eclipse.

The current usage is "new-ui <interpreter> <tty>".

E.g., on a terminal run this scriplet:

 $ cat gdb-client
 #!/bin/bash

 reset
 tty
 tail -f /dev/null

 $ gdb-client
 /dev/pts/15

Now run gdb on another terminal, and tell it to start a MI interpreter
on the tty of the other terminal:

 ...
 (gdb) new-ui mi /dev/pts/15
 New UI allocated

Now back to the the gdb-client terminal, we'll get an MI prompt, ready
for MI input:

 /dev/pts/15
 =thread-group-added,id="i1"
 (gdb)

You can also start a new UI running a CLI, with:

 (gdb) new-ui console /dev/pts/15

Though note that this console won't support readline command editing
(yet).  It works as if "set editing off" was entered.

Starting more than one MI UI is probably very broken, because there
are still globals in the MI code that should be made per UI.  Should
be trivial to fix, though much lower priority than getting one MI
working.
---
 gdb/interps.c | 15 +++++++++++-
 gdb/interps.h |  5 ++++
 gdb/main.c    | 12 +---------
 gdb/top.c     | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 12 deletions(-)
  

Comments

Eli Zaretskii March 21, 2016, 4:30 p.m. UTC | #1
> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 21 Mar 2016 15:21:14 +0000
> 
> With all the previous plumbing in place, it's now easy to add a
> command that actually creates a new console/mi UI.

Shouldn't this (and other related) code be conditional of PTYs being
supported?  Otherwise, this is just useless baggage, right?

Thanks.
  
Pedro Alves March 21, 2016, 4:51 p.m. UTC | #2
Hi Eli,

On 03/21/2016 04:30 PM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Date: Mon, 21 Mar 2016 15:21:14 +0000
>>
>> With all the previous plumbing in place, it's now easy to add a
>> command that actually creates a new console/mi UI.
> 
> Shouldn't this (and other related) code be conditional of PTYs being
> supported?  Otherwise, this is just useless baggage, right?

Actually this should all work on Windows too, for example.

MI doesn't really need a PTY, so even though currently the command's
online help and git logs say usage is "new-ui INTERP TTY", that TTY part
could actually be the name of any bidirectional stream.

E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
I think it should work to pass a console name, or a bidirectional
named pipe path, though I haven't tried it.

If necessary, it would also be easy to extend the command to support
separate streams for in/out/err, like, e.g.:

 (gdb) new-ui INTERP IN OUT ERR

And then it'd be possible to open a new MI channel through
unidirectional named pipes, regular files, etc. too.

Thanks,
Pedro Alves
  
Eli Zaretskii March 21, 2016, 5:11 p.m. UTC | #3
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 21 Mar 2016 16:51:21 +0000
> 
> > Shouldn't this (and other related) code be conditional of PTYs being
> > supported?  Otherwise, this is just useless baggage, right?
> 
> Actually this should all work on Windows too, for example.

Are you sure?  The code does this, for example:

> +static FILE *
> +open_stream (const char *name)
> +{
> +  int fd;
> +
> +  fd = open (name, O_RDWR | O_NOCTTY);
> +  if (fd < 0)
> +    perror_with_name  (_("opening terminal failed"));
> +
> +  return fdopen (fd, "w+");
> +}

How do you expect this to work on Windows?  For starters, O_NOCTTY is
not supported.  And what would you use for 'name' here?  More
importantly, each Windows process can have only one console at a time,
AFAIK.

Am I missing something?

> MI doesn't really need a PTY, so even though currently the command's
> online help and git logs say usage is "new-ui INTERP TTY", that TTY part
> could actually be the name of any bidirectional stream.
> 
> E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
> I think it should work to pass a console name, or a bidirectional
> named pipe path, though I haven't tried it.

There are no Unix domain sockets on Windows, AFAIK.  As for a console
name, see above.

> If necessary, it would also be easy to extend the command to support
> separate streams for in/out/err, like, e.g.:
> 
>  (gdb) new-ui INTERP IN OUT ERR
> 
> And then it'd be possible to open a new MI channel through
> unidirectional named pipes, regular files, etc. too.

But doesn't readline need a console-compatible device?  PTYs pass the
isatty test, but pipes and regular files fail it, so will readline at
all work?

I have a dreadful feeling that I'm missing something very important
here, because I'm sure I don't tell anything you don't already know.
  
Pedro Alves March 21, 2016, 5:57 p.m. UTC | #4
On 03/21/2016 05:11 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <palves@redhat.com>
>> Date: Mon, 21 Mar 2016 16:51:21 +0000
>>
>>> Shouldn't this (and other related) code be conditional of PTYs being
>>> supported?  Otherwise, this is just useless baggage, right?
>>
>> Actually this should all work on Windows too, for example.
> 
> Are you sure?  The code does this, for example:
> 
>> +static FILE *
>> +open_stream (const char *name)
>> +{
>> +  int fd;
>> +
>> +  fd = open (name, O_RDWR | O_NOCTTY);
>> +  if (fd < 0)
>> +    perror_with_name  (_("opening terminal failed"));
>> +
>> +  return fdopen (fd, "w+");
>> +}
> 
> How do you expect this to work on Windows?  For starters, O_NOCTTY is
> not supported. 

I thought I had tried building this on Windows, looks like not.
I was misled by this bit in windows-nat.c:

      tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);

but I see now that that's Cygwin only.

inflow.c has this at the top:

#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif

guess I'll do the same here.

> And what would you use for 'name' here?  More
> importantly, each Windows process can have only one console at a time,
> AFAIK.
> 
> Am I missing something?

Hmm, I thought you could create multiple Windows consoles in a process,
but I now see you can't unless you detach from the previous console:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682528%28v=vs.85%29.aspx

I imagine it should be possible to start GDB in MI mode, with
no console attached, and then do "new-ui console con1:" and have
gdb attach to that console.  Since there'd be only one CLI instance
inside gdb when run like this, we could support line editing / readline 
on this secondary UI, though we don't, not yet.  That would require 
more work, on GNU/Linux too.  FAOD, it does work to start gdb in MI and
create a secondary CLI UI, but it'll not have readline active (it works
as if you started gdb with isatty(0)==0, or with "set editing off").

But the way I see it working is that the frontend creates a bidirectional
named pipe, with CreateNamedPipe(PIPE_ACCESS_DUPLEX), for MI communication.
Then it starts GDB in console mode, attached to a real console window
embedded in the frontend's GUI (*) and tells gdb to open the MI ui on the
named pipe.  Like:

 $ gdb -q -ex "new-ui mi \\.\pipe\pipename"

I _think_ that should work, but it's been years since I did
anything closely related on Windows.

* - years ago when I had to use Windows on a regular basis, I used
the Console2 program, which has multiple console windows, though
I don't know exact details of how.  Maybe some multi-process trick.

> 
>> MI doesn't really need a PTY, so even though currently the command's
>> online help and git logs say usage is "new-ui INTERP TTY", that TTY part
>> could actually be the name of any bidirectional stream.
>>
>> E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
>> I think it should work to pass a console name, or a bidirectional
>> named pipe path, though I haven't tried it.
> 
> There are no Unix domain sockets on Windows, AFAIK.  As for a console
> name, see above.

There are bidirectional named pipes though.

> 
>> If necessary, it would also be easy to extend the command to support
>> separate streams for in/out/err, like, e.g.:
>>
>>   (gdb) new-ui INTERP IN OUT ERR
>>
>> And then it'd be possible to open a new MI channel through
>> unidirectional named pipes, regular files, etc. too.
> 
> But doesn't readline need a console-compatible device?  PTYs pass the
> isatty test, but pipes and regular files fail it, so will readline at
> all work?

You'll normally be specifying "MI" as INTERP, which does not need to
 use readline at all.  So as mentioned above, a frontend first starts GDB
in console mode, with stdin/stdout/stderr associated with a PTY/console,
and then opens a secondary ui with "new-ui" for MI.  And this MI ui does
_not_ need to pass the isatty test, as MI does not really need a terminal
for anything.

> I have a dreadful feeling that I'm missing something very important
> here, because I'm sure I don't tell anything you don't already know.

Thanks,
Pedro Alves
  
Pedro Alves May 26, 2016, 11:43 a.m. UTC | #5
On 03/21/2016 05:57 PM, Pedro Alves wrote:
> On 03/21/2016 05:11 PM, Eli Zaretskii wrote:

> 
>>
>>> If necessary, it would also be easy to extend the command to support
>>> separate streams for in/out/err, like, e.g.:
>>>
>>>   (gdb) new-ui INTERP IN OUT ERR
>>>
>>> And then it'd be possible to open a new MI channel through
>>> unidirectional named pipes, regular files, etc. too.
>>
>> But doesn't readline need a console-compatible device?  PTYs pass the
>> isatty test, but pipes and regular files fail it, so will readline at
>> all work?
> 
> You'll normally be specifying "MI" as INTERP, which does not need to
>  use readline at all.  So as mentioned above, a frontend first starts GDB
> in console mode, with stdin/stdout/stderr associated with a PTY/console,
> and then opens a secondary ui with "new-ui" for MI.  And this MI ui does
> _not_ need to pass the isatty test, as MI does not really need a terminal
> for anything.
> 

I've been thinking a bit on how to make this all work on Windows,
with Eclipse, and my current thinking is that instead of some hack to 
embed a native console window inside the GUI, better would be to reuse 
the same Eclipse terminal emulator widget, and coax gdb
to send the right terminal escape sequences for cursor movement
and character placement as a Unix gdb would.

Instead of a pty, that terminal widget would be backed by a bidirectional
named pipe.  Cygwin ptys use that behind the scenes as well.

So in the end, GDB would be running with input/output connected to a
named pipe, and we'd need to force gdb and ncurses to believe that
that is a terminal.

I'm aware that GNU ncurses, has a concept of "drivers", and it
has a driver for real windows consoles ("win32con") and that is
the default.  AFAIK, the way to select the driver is to set
the TERM env var.

So in theory, all one would need to do is to set the TERM env
var to vt100, xterm, or some such to force the right driver.

The problems will probably be around isatty checks in
readline and ncurses, as you suggested.

There may also be #ifdef WIN32 bits in those libraries that
are #ifdef-ing out code that we'll need, assuming terminal == console,
though I haven't really checked.

The isatty problem looks very much like the problem a native Windows/mingw
program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
See, e.g.,:

  http://www.spinics.net/lists/git/msg274348.html

So I think it should be possible to make it work on Windows, and I
think it's the right way forward, though some further
ncurses/readline/gdb patching might be in order.

So it looks like if you get native Windows GDB (readline/ncurses)
behaving correctly (history, completion, etc.) when run on a Cygwin
terminal, then from within Eclipse or any other GUI, it would
work as well.

BTW, while investigating this, I found that since some recent
update to Windows 10, Windows consoles now supports ansi/vt100
escape sequences, finally:

 http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements

This further reinforces to me the idea of using ansi escapes on
Windows Eclipse/gdb too.

Thanks,
Pedro Alves
  
Eli Zaretskii May 26, 2016, 3:46 p.m. UTC | #6
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 26 May 2016 12:43:01 +0100
> 
> I've been thinking a bit on how to make this all work on Windows,
> with Eclipse, and my current thinking is that instead of some hack to 
> embed a native console window inside the GUI, better would be to reuse 
> the same Eclipse terminal emulator widget, and coax gdb
> to send the right terminal escape sequences for cursor movement
> and character placement as a Unix gdb would.

Sorry, I know nothing about this "Eclipse terminal emulator widget".

In any case, this is Eclipse-specific, right?

> So in the end, GDB would be running with input/output connected to a
> named pipe, and we'd need to force gdb and ncurses to believe that
> that is a terminal.

I'm quite sure this would be a lot of work.

> I'm aware that GNU ncurses, has a concept of "drivers", and it
> has a driver for real windows consoles ("win32con") and that is
> the default.  AFAIK, the way to select the driver is to set
> the TERM env var.

To select a different driver?  Yes, the default is only used if TERM
is unset.

> The problems will probably be around isatty checks in
> readline and ncurses, as you suggested.
> 
> There may also be #ifdef WIN32 bits in those libraries that
> are #ifdef-ing out code that we'll need, assuming terminal == console,
> though I haven't really checked.

Right.

> The isatty problem looks very much like the problem a native Windows/mingw
> program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
> Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
> See, e.g.,:
> 
>   http://www.spinics.net/lists/git/msg274348.html

Cygwin also owns the libc it uses, so it's easy to work around the
related problems.  MinGW cannot do that easily.

> BTW, while investigating this, I found that since some recent
> update to Windows 10, Windows consoles now supports ansi/vt100
> escape sequences, finally:
> 
>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
> 
> This further reinforces to me the idea of using ansi escapes on
> Windows Eclipse/gdb too.

Not sure how that is related, since the emulator is not a console for
the program that runs on it.
  
Pedro Alves May 26, 2016, 4:03 p.m. UTC | #7
On 05/26/2016 04:46 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <palves@redhat.com>
>> Date: Thu, 26 May 2016 12:43:01 +0100
>>
>> I've been thinking a bit on how to make this all work on Windows,
>> with Eclipse, and my current thinking is that instead of some hack to 
>> embed a native console window inside the GUI, better would be to reuse 
>> the same Eclipse terminal emulator widget, and coax gdb
>> to send the right terminal escape sequences for cursor movement
>> and character placement as a Unix gdb would.
> 
> Sorry, I know nothing about this "Eclipse terminal emulator widget".

Just think of it as a terminal emulator, like xterm or any other.

> 
> In any case, this is Eclipse-specific, right?

Other frontends will probably follow the same approach.

>> The problems will probably be around isatty checks in
>> readline and ncurses, as you suggested.
>>
>> There may also be #ifdef WIN32 bits in those libraries that
>> are #ifdef-ing out code that we'll need, assuming terminal == console,
>> though I haven't really checked.
> 
> Right.
> 
>> The isatty problem looks very much like the problem a native Windows/mingw
>> program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
>> Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
>> See, e.g.,:
>>
>>   http://www.spinics.net/lists/git/msg274348.html
> 
> Cygwin also owns the libc it uses, so it's easy to work around the
> related problems.  MinGW cannot do that easily.

I think you misunderstand.  That patch is against a native mingw program
(git mingw port).  The patch is a clever hack that makes msvcrt's "isatty"
return true when input/output is connected to a named pipe that has a name
that is recognized as being a MSYS pty.

> 
>> BTW, while investigating this, I found that since some recent
>> update to Windows 10, Windows consoles now supports ansi/vt100
>> escape sequences, finally:
>>
>>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
>>
>> This further reinforces to me the idea of using ansi escapes on
>> Windows Eclipse/gdb too.
> 
> Not sure how that is related, since the emulator is not a console for
> the program that runs on it.

I mean that going forward, with that, it won't sound so strange for 
native Windows console applications to output ansi escape sequences
instead of using the console APIs to control cursor positioning, etc.

Thanks,
Pedro Alves
  
Eli Zaretskii May 26, 2016, 4:36 p.m. UTC | #8
> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 26 May 2016 17:03:33 +0100
> 
> >> BTW, while investigating this, I found that since some recent
> >> update to Windows 10, Windows consoles now supports ansi/vt100
> >> escape sequences, finally:
> >>
> >>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
> >>
> >> This further reinforces to me the idea of using ansi escapes on
> >> Windows Eclipse/gdb too.
> > 
> > Not sure how that is related, since the emulator is not a console for
> > the program that runs on it.
> 
> I mean that going forward, with that, it won't sound so strange for 
> native Windows console applications to output ansi escape sequences
> instead of using the console APIs to control cursor positioning, etc.

Perhaps in 5 or 10 years, when previous Windows versions are no longer
important.  But not until then, IMO.  (My main development machine
still runs XPSP3, FWIW.)
  
Pedro Alves May 26, 2016, 4:41 p.m. UTC | #9
On 05/26/2016 05:36 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org

>> I mean that going forward, with that, it won't sound so strange for 
>> native Windows console applications to output ansi escape sequences
>> instead of using the console APIs to control cursor positioning, etc.
> 
> Perhaps in 5 or 10 years, when previous Windows versions are no longer
> important.  But not until then, IMO.  (My main development machine
> still runs XPSP3, FWIW.)

Yeah, agreed.  I don't see it as the default any time soon, but rather 
an option that once sounded foreign/alien in the Windows world,
and will now will start sounding normal.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/interps.c b/gdb/interps.c
index 90d0de8..c9de292 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -291,6 +291,19 @@  interp_lookup (const char *name)
   return NULL;
 }
 
+void
+set_top_level_interpreter (const char *name)
+{
+  /* Find it.  */
+  struct interp *interp = interp_lookup (name);
+
+  if (interp == NULL)
+    error (_("Interpreter `%s' unrecognized"), name);
+  /* Install it.  */
+  if (!interp_set (interp, 1))
+    error (_("Interpreter `%s' failed to initialize."), name);
+}
+
 /* Returns the current interpreter.  */
 
 struct ui_out *
@@ -523,7 +536,7 @@  interpreter_exec_cmd (char *args, int from_tty)
 }
 
 /* List the possible interpreters which could complete the given text.  */
-static VEC (char_ptr) *
+VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
diff --git a/gdb/interps.h b/gdb/interps.h
index 6d8930f..3f9f010 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -86,6 +86,7 @@  extern struct interp *interp_new (const char *name,
 extern void interp_add (struct interp *interp);
 extern int interp_set (struct interp *interp, int top_level);
 extern struct interp *interp_lookup (const char *name);
+extern void set_top_level_interpreter (const char *name);
 extern struct ui_out *interp_ui_out (struct interp *interp);
 extern void *interp_data (struct interp *interp);
 extern const char *interp_name (struct interp *interp);
@@ -119,6 +120,10 @@  extern int interp_supports_command_editing (struct interp *interp);
    chance to e.g., print a prompt.  */
 extern void interp_pre_command_loop (struct interp *interp);
 
+extern VEC (char_ptr) *interpreter_completer (struct cmd_list_element *ignore,
+					      const char *text,
+					      const char *word);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE		"console"
 #define INTERP_MI1             "mi1"
diff --git a/gdb/main.c b/gdb/main.c
index 95578e4..a982752 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -962,17 +962,7 @@  captured_main (void *data)
 
   /* Install the default UI.  All the interpreters should have had a
      look at things by now.  Initialize the default interpreter.  */
-
-  {
-    /* Find it.  */
-    struct interp *interp = interp_lookup (interpreter_p);
-
-    if (interp == NULL)
-      error (_("Interpreter `%s' unrecognized"), interpreter_p);
-    /* Install it.  */
-    if (!interp_set (interp, 1))
-      error (_("Interpreter `%s' failed to initialize."), interpreter_p);
-  }
+  set_top_level_interpreter (interpreter_p);
 
   /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets
      GDB retain the old MI1 interpreter startup behavior.  Output the
diff --git a/gdb/top.c b/gdb/top.c
index 7d6d7cb..d74af46 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -313,6 +313,75 @@  delete_ui (struct ui *todel)
   free_ui (ui);
 }
 
+static FILE *
+open_stream (const char *name)
+{
+  int fd;
+
+  fd = open (name, O_RDWR | O_NOCTTY);
+  if (fd < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  return fdopen (fd, "w+");
+}
+
+static void
+new_ui_command (char *args, int from_tty)
+{
+  struct ui *ui;
+  struct interp *interp;
+  FILE *stream[3] = { NULL, NULL, NULL };
+  int i;
+  int res;
+  int argc;
+  char **argv;
+  const char *interpreter_name;
+  const char *tty_name;
+  struct cleanup *back_to;
+  struct cleanup *streams_chain;
+
+  argv = gdb_buildargv (args);
+  back_to = make_cleanup_freeargv (argv);
+
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  if (argc < 2)
+    error (_("usage: new-ui <interpreter> <tty>"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  streams_chain = make_cleanup (null_cleanup, NULL);
+
+  /* Open specified terminal, once for each of
+     stdin/stdout/stderr.  */
+  for (i = 0; i < 3; i++)
+    {
+      stream[i] = open_stream (tty_name);
+      make_cleanup_fclose (stream[i]);
+    }
+
+  ui = new_ui (stream[0], stream[1], stream[2]);
+
+  discard_cleanups (streams_chain);
+
+  initialize_stdin_serial (ui);
+  ui->async = 1;
+
+  make_cleanup (restore_ui_cleanup, current_ui);
+  current_ui = ui;
+
+  set_top_level_interpreter (interpreter_name);
+
+  interp_pre_command_loop (top_level_interpreter ());
+
+  /* This restores the previous UI.  */
+  do_cleanups (back_to);
+
+  printf_unfiltered ("New UI allocated\n");
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
@@ -1878,6 +1947,8 @@  set_history_filename (char *args, int from_tty, struct cmd_list_element *c)
 static void
 init_main (void)
 {
+  struct cmd_list_element *c;
+
   /* Initialize the prompt to a simple "(gdb) " prompt or to whatever
      the DEFAULT_PROMPT is.  */
   set_prompt (DEFAULT_PROMPT);
@@ -2001,6 +2072,12 @@  When set, GDB uses the specified path to search for data files."),
                            set_gdb_datadir, show_gdb_datadir,
                            &setlist,
                            &showlist);
+
+  c = add_cmd ("new-ui", class_support, new_ui_command, _("\
+Create a new UI.  It takes two arguments:\n\
+The first argument is the name of the interpreter to run.\n\
+The second argument is the terminal the UI runs on.\n"), &cmdlist);
+  set_cmd_completer (c, interpreter_completer);
 }
 
 void