[RFA,7/8] Add truncate_repeat_arguments function

Message ID 2c331d73-d982-97c4-cf85-4f98789d6f27@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves Nov. 7, 2017, 2:35 p.m. UTC
  On 10/18/2017 04:47 AM, Tom Tromey wrote:
>>>>>> "Yao" == Yao Qi <qiyaoltc@gmail.com> writes:
> 
> Yao> This global variable worries me a little bit.  Is it possible that
> Yao> different part of GDB request to execute the repeatable commands?  For
> Yao> example, CLI and MI issues command, or different UIs issue command.
> 
> It's hard to reason about, I agree.
> 
> I think commands can either be run via "cmd_func", or by calling the
> command function directly.
> 
> Direct calls can be directly audited -- and none of the callers of the
> new set_repeat_arguments function are called this way.
> 
> There are also not many calls to cmd_func; and at least when I look at
> these (I encourage you to check my work), I think only execute_command
> can possibly call a command that calls set_repeat_arguments.
> 
> Since execute_command uses a scoped_restore to save and restore this
> global, I think this must be ok.
> 
> It does seem a bit fragile.  For example, I'd recommend not adding new
> callers of set_repeat_arguments.  I'm open to suggestions for another
> way to approach this.

I think an unanswered question is whether the cases of two different
UIs or interpreters running a command that calls set_repeat_arguments
are handled correctly (for some definition of correctly).

Two UIs means doing something like:
  gdb -ex "new-ui console /dev/pts/56"
or:
  gdb -ex "new-ui mi /dev/pts/56"

and then typing "list foo" in main UI and then just "<ret>"
in the extra UI.

while two interpreters means something like:

  $ gdb -i=mi
  (gdb)
  -interpreter-exec console "CLI COMMAND"
  -equivalent-mi-command

I'm not sure there's any MI command that calls into
the commands that set repeat arguments.

For for different UIs: currently, while each UI has its own line buffer,
saved_command_line is still global.  I.e., the variable that holds the
command line that is passed to the command functions.  That means that if you
type a command in one UI, and then type "<ret>" in a second UI, the
second UI repeats the command typed in the first UI.  I don't recall a
good reason for that, other than "we can improve things incrementally on
top of the initial support for multiple UIs" and "one console and one
MI is the main use case".

I think this patch doesn't affect things here.  Even if we make
saved_command_line per-UI, it seems like repeat_arguments can still be
a global, since it's only used within the scope of a single execute_command
call.   It could be made per-UI too, though it wouldn't make much of a
difference, I think.

To expand a bit: It's entirely possible that execute_command ends up doing
another execute_command inside.  For example when running a GDB script.
And it's plausible that the nested execute_command runs in a different UI from
the one that started the script.  E.g., if a breakpoint is hit, and that
breakpoint has commands -- currently all run control events are always run with
the main UI as current UI, while the script that started the target running
could have been invoked from a different UI.   Actually, I noticed that
breakpoint commands aren't (they're run in inferior_event_handler, while
it's fetch_inferior_event that sets the current UI to the main UI right
at the top), which seems like a bug to me.  But in any case,
breakpoint commands run with from_tty == 0, so shouldn't be affected.

So I think the patch is OK.

BTW, while writing the above, I spent a bit playing with actually 
making saved_command_line be per-UI, and then also the
"list", "x", and "show command" global state.  Playing with 

  gdb -ex "new-ui console TTY" --args ./gdb

it seems to work nicely and intuitively.  See attached
(untested) patch.  I've pushed it to the 
users/palves/per_ui_repeat branch on sourceware too.
(And what I was trying to determine: ) it doesn't look
like your patch would affect doing this.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 7377189..1e84fdf 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -634,8 +634,8 @@  command_line_append_input_line (struct buffer *cmd_line_buffer, char *rl)
    If REPEAT, handle command repetitions:
 
      - If the input command line is NOT empty, the command returned is
-       copied into the global 'saved_command_line' var so that it can
-       be repeated later.
+       copied into the 'ui->saved_command_line' var so that it can be
+       repeated later.
 
      - OTOH, if the input command line IS empty, return the previously
        saved command instead of the empty input line.
@@ -671,9 +671,9 @@  handle_line_of_input (struct buffer *cmd_line_buffer,
 #define SERVER_COMMAND_PREFIX "server "
   if (startswith (cmd, SERVER_COMMAND_PREFIX))
     {
-      /* Note that we don't set `saved_command_line'.  Between this
-         and the check in dont_repeat, this insures that repeating
-         will still do the right thing.  */
+      /* Note that we don't set `ui->saved_command_line'.  Between
+         this and the check in dont_repeat, this insures that
+         repeating will still do the right thing.  */
       return cmd + strlen (SERVER_COMMAND_PREFIX);
     }
 
@@ -713,7 +713,7 @@  handle_line_of_input (struct buffer *cmd_line_buffer,
   for (p1 = cmd; *p1 == ' ' || *p1 == '\t'; p1++)
     ;
   if (repeat && *p1 == '\0')
-    return saved_command_line;
+    return ui->saved_command_line;
 
   /* Add command to history if appropriate.  Note: lines consisting
      solely of comments are also added to the command history.  This
@@ -728,9 +728,9 @@  handle_line_of_input (struct buffer *cmd_line_buffer,
   /* Save into global buffer if appropriate.  */
   if (repeat)
     {
-      xfree (saved_command_line);
-      saved_command_line = xstrdup (cmd);
-      return saved_command_line;
+      xfree (ui->saved_command_line);
+      ui->saved_command_line = xstrdup (cmd);
+      return ui->saved_command_line;
     }
   else
     return cmd;
diff --git a/gdb/main.c b/gdb/main.c
index 835ae24..8fae552 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -522,8 +522,6 @@  captured_main_1 (struct captured_main_args *context)
   notice_open_fds ();
   save_original_signals_state ();
 
-  saved_command_line = (char *) xstrdup ("");
-
 #ifdef __MINGW32__
   /* Ensure stderr is unbuffered.  A Cygwin pty or pipe is implemented
      as a Windows pipe, and Windows buffers on pipes.  */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 017c7be..ec54658 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -49,37 +49,50 @@ 
 #include "format.h"
 #include "source.h"
 #include "common/byte-vector.h"
+#include "top.h"
 
 #ifdef TUI
 #include "tui/tui.h"		/* For tui_active et al.   */
 #endif
 
-/* Last specified output format.  */
+struct current_printcmd_info
+{
+  /* Last specified output format.  */
+  char last_format = 0;
 
-static char last_format = 0;
+  /* Last specified examination size.  'b', 'h', 'w' or `q'.  */
+  char last_size = 'w';
 
-/* Last specified examination size.  'b', 'h', 'w' or `q'.  */
+  /* Default address to examine next, and associated architecture.  */
+  struct gdbarch *next_gdbarch;
+  CORE_ADDR next_address;
 
-static char last_size = 'w';
+  /* Last address examined.  */
+  CORE_ADDR last_examine_address;
 
-/* Default address to examine next, and associated architecture.  */
+  /* Contents of last address examined.  This is not valid past the
+     end of the `x' command!  */
+  struct value *last_examine_value;
+};
 
-static struct gdbarch *next_gdbarch;
-static CORE_ADDR next_address;
+static current_printcmd_info &
+get_current_printcmd_info ()
+{
+  if (current_ui->curr_printcmd_info == NULL)
+    current_ui->curr_printcmd_info = new current_printcmd_info ();
+  return *current_ui->curr_printcmd_info;
+}
+
+void
+delete_current_printcmd_info (struct ui *ui)
+{
+  delete ui->curr_printcmd_info;
+}
 
 /* Number of delay instructions following current disassembled insn.  */
 
 static int branch_delay_insns;
 
-/* Last address examined.  */
-
-static CORE_ADDR last_examine_address;
-
-/* Contents of last address examined.
-   This is not valid past the end of the `x' command!  */
-
-static struct value *last_examine_value;
-
 /* Largest offset between a symbolic value and an address, that will be
    printed as `0x1234 <symbol+offset>'.  */
 
@@ -279,8 +292,10 @@  print_formatted (struct value *val, int size,
   struct type *type = check_typedef (value_type (val));
   int len = TYPE_LENGTH (type);
 
+  current_printcmd_info &ci = get_current_printcmd_info ();
+
   if (VALUE_LVAL (val) == lval_memory)
-    next_address = value_address (val) + len;
+    ci.next_address = value_address (val) + len;
 
   if (size)
     {
@@ -290,20 +305,20 @@  print_formatted (struct value *val, int size,
 	  {
 	    struct type *elttype = value_type (val);
 
-	    next_address = (value_address (val)
-			    + val_print_string (elttype, NULL,
-						value_address (val), -1,
-						stream, options) * len);
+	    ci.next_address = (value_address (val)
+			       + val_print_string (elttype, NULL,
+						   value_address (val), -1,
+						   stream, options) * len);
 	  }
 	  return;
 
 	case 'i':
 	  /* We often wrap here if there are long symbolic names.  */
 	  wrap_here ("    ");
-	  next_address = (value_address (val)
-			  + gdb_print_insn (get_type_arch (type),
-					    value_address (val), stream,
-					    &branch_delay_insns));
+	  ci.next_address = (value_address (val)
+			     + gdb_print_insn (get_type_arch (type),
+					       value_address (val), stream,
+					       &branch_delay_insns));
 	  return;
 	}
     }
@@ -500,10 +515,13 @@  set_next_address (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
   struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
 
-  next_gdbarch = gdbarch;
-  next_address = addr;
+  current_printcmd_info &ci = get_current_printcmd_info ();
 
-  /* Make address available to the user as $_.  */
+  ci.next_gdbarch = gdbarch;
+  ci.next_address = addr;
+
+  /* Make address available to the user as $_.  FIXME: should instead
+     be a computed val, so that it works Per-UI.  */
   set_internalvar (lookup_internalvar ("_"),
 		   value_from_pointer (ptr_type, addr));
 }
@@ -976,8 +994,11 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
   format = fmt.format;
   size = fmt.size;
   count = fmt.count;
-  next_gdbarch = gdbarch;
-  next_address = addr;
+
+  current_printcmd_info &ci = get_current_printcmd_info ();
+
+  ci.next_gdbarch = gdbarch;
+  ci.next_address = addr;
 
   /* Instruction format implies fetch single bytes
      regardless of the specified size.
@@ -989,11 +1010,11 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
   if (size == 'a')
     {
       /* Pick the appropriate size for an address.  */
-      if (gdbarch_ptr_bit (next_gdbarch) == 64)
+      if (gdbarch_ptr_bit (ci.next_gdbarch) == 64)
 	size = 'g';
-      else if (gdbarch_ptr_bit (next_gdbarch) == 32)
+      else if (gdbarch_ptr_bit (ci.next_gdbarch) == 32)
 	size = 'w';
-      else if (gdbarch_ptr_bit (next_gdbarch) == 16)
+      else if (gdbarch_ptr_bit (ci.next_gdbarch) == 16)
 	size = 'h';
       else
 	/* Bad value for gdbarch_ptr_bit.  */
@@ -1002,13 +1023,13 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
     }
 
   if (size == 'b')
-    val_type = builtin_type (next_gdbarch)->builtin_int8;
+    val_type = builtin_type (ci.next_gdbarch)->builtin_int8;
   else if (size == 'h')
-    val_type = builtin_type (next_gdbarch)->builtin_int16;
+    val_type = builtin_type (ci.next_gdbarch)->builtin_int16;
   else if (size == 'w')
-    val_type = builtin_type (next_gdbarch)->builtin_int32;
+    val_type = builtin_type (ci.next_gdbarch)->builtin_int32;
   else if (size == 'g')
-    val_type = builtin_type (next_gdbarch)->builtin_int64;
+    val_type = builtin_type (ci.next_gdbarch)->builtin_int64;
 
   if (format == 's')
     {
@@ -1017,9 +1038,9 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
       /* Search for "char16_t"  or "char32_t" types or fall back to 8-bit char
 	 if type is not found.  */
       if (size == 'h')
-	char_type = builtin_type (next_gdbarch)->builtin_char16;
+	char_type = builtin_type (ci.next_gdbarch)->builtin_char16;
       else if (size == 'w')
-	char_type = builtin_type (next_gdbarch)->builtin_char32;
+	char_type = builtin_type (ci.next_gdbarch)->builtin_char32;
       if (char_type)
         val_type = char_type;
       else
@@ -1028,7 +1049,7 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
 	    warning (_("Unable to display strings with "
 		       "size '%c', using 'b' instead."), size);
 	  size = 'b';
-	  val_type = builtin_type (next_gdbarch)->builtin_int8;
+	  val_type = builtin_type (ci.next_gdbarch)->builtin_int8;
         }
     }
 
@@ -1051,26 +1072,26 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
       count = -count;
       if (format == 'i')
         {
-          next_address = find_instruction_backward (gdbarch, addr, count,
-                                                    &count);
+          ci.next_address = find_instruction_backward (gdbarch, addr, count,
+						       &count);
         }
       else if (format == 's')
         {
-          next_address = find_string_backward (gdbarch, addr, count,
-                                               TYPE_LENGTH (val_type),
-                                               &opts, &count);
+          ci.next_address = find_string_backward (gdbarch, addr, count,
+						  TYPE_LENGTH (val_type),
+						  &opts, &count);
         }
       else
         {
-          next_address = addr - count * TYPE_LENGTH (val_type);
+          ci.next_address = addr - count * TYPE_LENGTH (val_type);
         }
 
       /* The following call to print_formatted updates next_address in every
          iteration.  In backward case, we store the start address here
          and update next_address with it before exiting the function.  */
       addr_rewound = (format == 's'
-                      ? next_address - TYPE_LENGTH (val_type)
-                      : next_address);
+                      ? ci.next_address - TYPE_LENGTH (val_type)
+                      : ci.next_address);
       need_to_update_next_address = 1;
     }
 
@@ -1081,8 +1102,8 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
     {
       QUIT;
       if (format == 'i')
-	fputs_filtered (pc_prefix (next_address), gdb_stdout);
-      print_address (next_gdbarch, next_address, gdb_stdout);
+	fputs_filtered (pc_prefix (ci.next_address), gdb_stdout);
+      print_address (ci.next_gdbarch, ci.next_address, gdb_stdout);
       printf_filtered (":");
       for (i = maxelts;
 	   i > 0 && count > 0;
@@ -1091,10 +1112,10 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
 	  printf_filtered ("\t");
 	  /* Note that print_formatted sets next_address for the next
 	     object.  */
-	  last_examine_address = next_address;
+	  ci.last_examine_address = ci.next_address;
 
-	  if (last_examine_value)
-	    value_free (last_examine_value);
+	  if (ci.last_examine_value)
+	    value_free (ci.last_examine_value);
 
 	  /* The value to be displayed is not fetched greedily.
 	     Instead, to avoid the possibility of a fetched value not
@@ -1105,12 +1126,12 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
 	     the disassembler be modified so that LAST_EXAMINE_VALUE
 	     is left with the byte sequence from the last complete
 	     instruction fetched from memory?  */
-	  last_examine_value = value_at_lazy (val_type, next_address);
+	  ci.last_examine_value = value_at_lazy (val_type, ci.next_address);
 
-	  if (last_examine_value)
-	    release_value (last_examine_value);
+	  if (ci.last_examine_value)
+	    release_value (ci.last_examine_value);
 
-	  print_formatted (last_examine_value, size, &opts, gdb_stdout);
+	  print_formatted (ci.last_examine_value, size, &opts, gdb_stdout);
 
 	  /* Display any branch delay slots following the final insn.  */
 	  if (format == 'i' && count == 1)
@@ -1121,7 +1142,7 @@  do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
     }
 
   if (need_to_update_next_address)
-    next_address = addr_rewound;
+    ci.next_address = addr_rewound;
 }
 
 static void
@@ -1149,9 +1170,12 @@  print_command_parse_format (const char **expp, const char *cmdname,
   if (exp && *exp == '/')
     {
       exp++;
-      *fmtp = decode_format (&exp, last_format, 0);
+
+      current_printcmd_info &ci = get_current_printcmd_info ();
+
+      *fmtp = decode_format (&exp, ci.last_format, 0);
       validate_format (*fmtp, cmdname);
-      last_format = fmtp->format;
+      ci.last_format = fmtp->format;
     }
   else
     {
@@ -1624,8 +1648,10 @@  x_command (char *exp, int from_tty)
   struct format_data fmt;
   struct value *val;
 
-  fmt.format = last_format ? last_format : 'x';
-  fmt.size = last_size;
+  current_printcmd_info &ci = get_current_printcmd_info ();
+
+  fmt.format = ci.last_format ? ci.last_format : 'x';
+  fmt.size = ci.last_size;
   fmt.count = 1;
   fmt.raw = 0;
 
@@ -1633,7 +1659,7 @@  x_command (char *exp, int from_tty)
     {
       const char *tmp = exp + 1;
 
-      fmt = decode_format (&tmp, last_format, last_size);
+      fmt = decode_format (&tmp, ci.last_format, ci.last_size);
       exp = (char *) tmp;
     }
 
@@ -1655,45 +1681,45 @@  x_command (char *exp, int from_tty)
       if (/* last_format == 'i'  && */ 
 	  TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC
 	   && VALUE_LVAL (val) == lval_memory)
-	next_address = value_address (val);
+	ci.next_address = value_address (val);
       else
-	next_address = value_as_address (val);
+	ci.next_address = value_as_address (val);
 
-      next_gdbarch = expr->gdbarch;
+      ci.next_gdbarch = expr->gdbarch;
     }
 
-  if (!next_gdbarch)
+  if (!ci.next_gdbarch)
     error_no_arg (_("starting display address"));
 
-  do_examine (fmt, next_gdbarch, next_address);
+  do_examine (fmt, ci.next_gdbarch, ci.next_address);
 
   /* If the examine succeeds, we remember its size and format for next
      time.  Set last_size to 'b' for strings.  */
   if (fmt.format == 's')
-    last_size = 'b';
+    ci.last_size = 'b';
   else
-    last_size = fmt.size;
-  last_format = fmt.format;
+    ci.last_size = fmt.size;
+  ci.last_format = fmt.format;
 
   /* Set a couple of internal variables if appropriate.  */
-  if (last_examine_value)
+  if (ci.last_examine_value)
     {
       /* Make last address examined available to the user as $_.  Use
          the correct pointer type.  */
       struct type *pointer_type
-	= lookup_pointer_type (value_type (last_examine_value));
+	= lookup_pointer_type (value_type (ci.last_examine_value));
       set_internalvar (lookup_internalvar ("_"),
 		       value_from_pointer (pointer_type,
-					   last_examine_address));
+					   ci.last_examine_address));
 
       /* Make contents of last address examined available to the user
 	 as $__.  If the last value has not been fetched from memory
 	 then don't fetch it now; instead mark it by voiding the $__
 	 variable.  */
-      if (value_lazy (last_examine_value))
+      if (value_lazy (ci.last_examine_value))
 	clear_internalvar (lookup_internalvar ("__"));
       else
-	set_internalvar (lookup_internalvar ("__"), last_examine_value);
+	set_internalvar (lookup_internalvar ("__"), ci.last_examine_value);
     }
 }
 
diff --git a/gdb/source.c b/gdb/source.c
index aa672fd..61a3634 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -44,6 +44,7 @@ 
 #include "readline/readline.h"
 #include "common/enum-flags.h"
 #include <algorithm>
+#include "top.h"
 
 #define OPEN_MODE (O_RDONLY | O_BINARY)
 #define FDOPEN_MODE FOPEN_RB
@@ -76,15 +77,45 @@  struct substitute_path_rule
 
 static struct substitute_path_rule *substitute_path_rules = NULL;
 
-/* Symtab of default file for listing lines of.  */
+struct current_source_info
+{
+  /* Symtab of default file for listing lines of.  */
+  symtab *current_source_symtab = NULL;
+
+  /* Default next line to list.  */
+  int current_source_line = 0;
 
-static struct symtab *current_source_symtab;
+  program_space *current_source_pspace = NULL;
 
-/* Default next line to list.  */
+  /* Line number of last line printed.  Default for various commands.
+     source_line is usually, but not always, the same as this.  */
+  int last_line_listed;
 
-static int current_source_line;
+  /* First line number listed by last listing command.  If 0, then no
+     source lines have yet been listed since the last time the current
+     source line was changed.  */
+  int first_line_listed;
 
-static struct program_space *current_source_pspace;
+  /* Saves the name of the last source file visited and a possible
+     error code.  Used to prevent repeating annoying "No such file or
+     directories" msgs.  */
+  struct symtab *last_source_visited = NULL;
+  int last_source_error = 0;
+};
+
+static current_source_info &
+get_current_source_info ()
+{
+  if (current_ui->curr_source_info == NULL)
+    current_ui->curr_source_info = new current_source_info ();
+  return *current_ui->curr_source_info;
+}
+
+void
+delete_current_source_info (struct ui *ui)
+{
+  delete ui->curr_source_info;
+}
 
 /* Default number of lines to print with commands like "list".
    This is based on guessing how many long (i.e. more than chars_per_line
@@ -123,23 +154,8 @@  show_filename_display_string (struct ui_file *file, int from_tty,
 {
   fprintf_filtered (file, _("Filenames are displayed as \"%s\".\n"), value);
 }
- 
-/* Line number of last line printed.  Default for various commands.
-   current_source_line is usually, but not always, the same as this.  */
-
-static int last_line_listed;
-
-/* First line number listed by last listing command.  If 0, then no
-   source lines have yet been listed since the last time the current
-   source line was changed.  */
-
-static int first_line_listed;
 
-/* Saves the name of the last source file visited and a possible error code.
-   Used to prevent repeating annoying "No such file or directories" msgs.  */
 
-static struct symtab *last_source_visited = NULL;
-static int last_source_error = 0;
 
 /* Return the first line listed by print_source_lines.
    Used by command interpreters to request listing from
@@ -148,7 +164,9 @@  static int last_source_error = 0;
 int
 get_first_line_listed (void)
 {
-  return first_line_listed;
+  current_source_info &si = get_current_source_info ();
+
+  return si.first_line_listed;
 }
 
 /* Clear line listed range.  This makes the next "list" center the
@@ -157,8 +175,10 @@  get_first_line_listed (void)
 static void
 clear_lines_listed_range (void)
 {
-  first_line_listed = 0;
-  last_line_listed = 0;
+  current_source_info &si = get_current_source_info ();
+
+  si.first_line_listed = 0;
+  si.last_line_listed = 0;
 }
 
 /* Return the default number of lines to print with commands like the
@@ -180,12 +200,14 @@  get_current_source_symtab_and_line (void)
 {
   symtab_and_line cursal;
 
-  cursal.pspace = current_source_pspace;
-  cursal.symtab = current_source_symtab;
-  cursal.line = current_source_line;
+  current_source_info &si = get_current_source_info ();
+
+  cursal.pspace = si.current_source_pspace;
+  cursal.symtab = si.current_source_symtab;
+  cursal.line = si.current_source_line;
   cursal.pc = 0;
   cursal.end = 0;
-  
+
   return cursal;
 }
 
@@ -203,8 +225,9 @@  set_default_source_symtab_and_line (void)
   if (!have_full_symbols () && !have_partial_symbols ())
     error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  current_source_info &si = get_current_source_info ();
   /* Pull in a current source symtab if necessary.  */
-  if (current_source_symtab == 0)
+  if (si.current_source_symtab == NULL)
     select_source_symtab (0);
 }
 
@@ -218,15 +241,17 @@  set_current_source_symtab_and_line (const symtab_and_line &sal)
 {
   symtab_and_line cursal;
 
-  cursal.pspace = current_source_pspace;
-  cursal.symtab = current_source_symtab;
-  cursal.line = current_source_line;
+  current_source_info &si = get_current_source_info ();
+
+  cursal.pspace = si.current_source_pspace;
+  cursal.symtab = si.current_source_symtab;
+  cursal.line = si.current_source_line;
   cursal.pc = 0;
   cursal.end = 0;
 
-  current_source_pspace = sal.pspace;
-  current_source_symtab = sal.symtab;
-  current_source_line = sal.line;
+  si.current_source_pspace = sal.pspace;
+  si.current_source_symtab = sal.symtab;
+  si.current_source_line = sal.line;
 
   /* Force the next "list" to center around the current line.  */
   clear_lines_listed_range ();
@@ -239,8 +264,10 @@  set_current_source_symtab_and_line (const symtab_and_line &sal)
 void
 clear_current_source_symtab_and_line (void)
 {
-  current_source_symtab = 0;
-  current_source_line = 0;
+  current_source_info &si = get_current_source_info ();
+
+  si.current_source_symtab = NULL;
+  si.current_source_line = 0;
 }
 
 /* Set the source file default for the "list" command to be S.
@@ -257,15 +284,17 @@  select_source_symtab (struct symtab *s)
   struct objfile *ofp;
   struct compunit_symtab *cu;
 
+  current_source_info &si = get_current_source_info ();
+
   if (s)
     {
-      current_source_symtab = s;
-      current_source_line = 1;
-      current_source_pspace = SYMTAB_PSPACE (s);
+      si.current_source_symtab = s;
+      si.current_source_line = 1;
+      si.current_source_pspace = SYMTAB_PSPACE (s);
       return;
     }
 
-  if (current_source_symtab)
+  if (si.current_source_symtab != NULL)
     return;
 
   /* Make the default place to list be the function `main'
@@ -276,17 +305,17 @@  select_source_symtab (struct symtab *s)
 	= decode_line_with_current_source (main_name (),
 					   DECODE_LINE_FUNFIRSTLINE);
       const symtab_and_line &sal = sals[0];
-      current_source_pspace = sal.pspace;
-      current_source_symtab = sal.symtab;
-      current_source_line = std::max (sal.line - (lines_to_list - 1), 1);
-      if (current_source_symtab)
+      si.current_source_pspace = sal.pspace;
+      si.current_source_symtab = sal.symtab;
+      si.current_source_line = std::max (sal.line - (lines_to_list - 1), 1);
+      if (si.current_source_symtab != NULL)
 	return;
     }
 
   /* Alright; find the last file in the symtab list (ignoring .h's
      and namespace symtabs).  */
 
-  current_source_line = 1;
+  si.current_source_line = 1;
 
   ALL_FILETABS (ofp, cu, s)
     {
@@ -296,12 +325,12 @@  select_source_symtab (struct symtab *s)
       if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
 			|| strcmp (name, "<<C++-namespaces>>") == 0)))
 	{
-	  current_source_pspace = current_program_space;
-	  current_source_symtab = s;
+	  si.current_source_pspace = current_program_space;
+	  si.current_source_symtab = s;
 	}
     }
 
-  if (current_source_symtab)
+  if (si.current_source_symtab != NULL)
     return;
 
   ALL_OBJFILES (ofp)
@@ -309,9 +338,9 @@  select_source_symtab (struct symtab *s)
     if (ofp->sf)
       s = ofp->sf->qf->find_last_source_symtab (ofp);
     if (s)
-      current_source_symtab = s;
+      si.current_source_symtab = s;
   }
-  if (current_source_symtab)
+  if (si.current_source_symtab != NULL)
     return;
 
   error (_("Can't find a default source file"));
@@ -403,7 +432,12 @@  forget_cached_source_info (void)
       forget_cached_source_info_for_objfile (objfile);
     }
 
-  last_source_visited = NULL;
+  struct ui *ui;
+  ALL_UIS (ui)
+    {
+      if (ui->curr_source_info != NULL)
+	ui->curr_source_info->last_source_visited = NULL;
+    }
 }
 
 void
@@ -645,7 +679,8 @@  add_path (char *dirname, char **which_path, int parse_separators)
 static void
 info_source_command (char *ignore, int from_tty)
 {
-  struct symtab *s = current_source_symtab;
+  current_source_info &si = get_current_source_info ();
+  struct symtab *s = si.current_source_symtab;
   struct compunit_symtab *cust;
 
   if (!s)
@@ -1312,8 +1347,9 @@  identify_source_line (struct symtab *s, int line, int mid_statement,
   annotate_source (s->fullname, line, s->line_charpos[line - 1],
 		   mid_statement, get_objfile_arch (SYMTAB_OBJFILE (s)), pc);
 
-  current_source_line = line;
-  current_source_symtab = s;
+  current_source_info &si = get_current_source_info ();
+  si.current_source_line = line;
+  si.current_source_symtab = s;
   clear_lines_listed_range ();
   return 1;
 }
@@ -1333,36 +1369,37 @@  print_source_lines_base (struct symtab *s, int line, int stopline,
   struct ui_out *uiout = current_uiout;
 
   /* Regardless of whether we can open the file, set current_source_symtab.  */
-  current_source_symtab = s;
-  current_source_line = line;
-  first_line_listed = line;
+  current_source_info &si = get_current_source_info ();
+  si.current_source_symtab = s;
+  si.current_source_line = line;
+  si.first_line_listed = line;
 
   /* If printing of source lines is disabled, just print file and line
      number.  */
   if (uiout->test_flags (ui_source_list))
     {
       /* Only prints "No such file or directory" once.  */
-      if ((s != last_source_visited) || (!last_source_error))
+      if ((s != si.last_source_visited) || (!si.last_source_error))
 	{
-	  last_source_visited = s;
+	  si.last_source_visited = s;
 	  desc = open_source_file (s);
 	}
       else
 	{
-	  desc = last_source_error;
+	  desc = si.last_source_error;
 	  flags |= PRINT_SOURCE_LINES_NOERROR;
 	}
     }
   else
     {
-      desc = last_source_error;
+      desc = si.last_source_error;
       flags |= PRINT_SOURCE_LINES_NOERROR;
       noprint = 1;
     }
 
   if (desc < 0 || noprint)
     {
-      last_source_error = desc;
+      si.last_source_error = desc;
 
       if (!(flags & PRINT_SOURCE_LINES_NOERROR))
 	{
@@ -1404,7 +1441,7 @@  print_source_lines_base (struct symtab *s, int line, int stopline,
       return;
     }
 
-  last_source_error = 0;
+  si.last_source_error = 0;
 
   if (s->line_charpos == 0)
     find_source_lines (s, desc);
@@ -1432,13 +1469,13 @@  print_source_lines_base (struct symtab *s, int line, int stopline,
       c = fgetc (stream.get ());
       if (c == EOF)
 	break;
-      last_line_listed = current_source_line;
+      si.last_line_listed = si.current_source_line;
       if (flags & PRINT_SOURCE_LINES_FILENAME)
         {
           uiout->text (symtab_to_filename_for_display (s));
           uiout->text (":");
         }
-      xsnprintf (buf, sizeof (buf), "%d\t", current_source_line++);
+      xsnprintf (buf, sizeof (buf), "%d\t", si.current_source_line++);
       uiout->text (buf);
       do
 	{
@@ -1492,14 +1529,16 @@  info_line_command (char *arg, int from_tty)
   symtab_and_line curr_sal;
   gdb::array_view<symtab_and_line> sals;
 
+  current_source_info &si = get_current_source_info ();
+
   if (arg == 0)
     {
-      curr_sal.symtab = current_source_symtab;
+      curr_sal.symtab = si.current_source_symtab;
       curr_sal.pspace = current_program_space;
-      if (last_line_listed != 0)
-	curr_sal.line = last_line_listed;
+      if (si.last_line_listed != 0)
+	curr_sal.line = si.last_line_listed;
       else
-	curr_sal.line = current_source_line;
+	curr_sal.line = si.current_source_line;
 
       sals = curr_sal;
     }
@@ -1572,7 +1611,7 @@  info_line_command (char *arg, int from_tty)
 	  set_next_address (gdbarch, start_pc);
 
 	  /* Repeating "info line" should do the following line.  */
-	  last_line_listed = sal.line + 1;
+	  si.last_line_listed = sal.line + 1;
 
 	  /* If this is the only line, show the source code.  If it could
 	     not find the file, don't do anything special.  */
@@ -1599,28 +1638,30 @@  forward_search_command (char *regex, int from_tty)
   char *msg;
   struct cleanup *cleanups;
 
-  line = last_line_listed + 1;
+  current_source_info &si = get_current_source_info ();
+
+  line = si.last_line_listed + 1;
 
   msg = (char *) re_comp (regex);
   if (msg)
     error (("%s"), msg);
 
-  if (current_source_symtab == 0)
+  if (si.current_source_symtab == 0)
     select_source_symtab (0);
 
-  desc = open_source_file (current_source_symtab);
+  desc = open_source_file (si.current_source_symtab);
   if (desc < 0)
-    perror_with_name (symtab_to_filename_for_display (current_source_symtab));
+    perror_with_name (symtab_to_filename_for_display (si.current_source_symtab));
   cleanups = make_cleanup_close (desc);
 
-  if (current_source_symtab->line_charpos == 0)
-    find_source_lines (current_source_symtab, desc);
+  if (si.current_source_symtab->line_charpos == 0)
+    find_source_lines (si.current_source_symtab, desc);
 
-  if (line < 1 || line > current_source_symtab->nlines)
+  if (line < 1 || line > si.current_source_symtab->nlines)
     error (_("Expression not found"));
 
-  if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
-    perror_with_name (symtab_to_filename_for_display (current_source_symtab));
+  if (lseek (desc, si.current_source_symtab->line_charpos[line - 1], 0) < 0)
+    perror_with_name (symtab_to_filename_for_display (si.current_source_symtab));
 
   discard_cleanups (cleanups);
   gdb_file_up stream (fdopen (desc, FDOPEN_MODE));
@@ -1664,9 +1705,9 @@  forward_search_command (char *regex, int from_tty)
       if (re_exec (buf) > 0)
 	{
 	  /* Match!  */
-	  print_source_lines (current_source_symtab, line, line + 1, 0);
+	  print_source_lines (si.current_source_symtab, line, line + 1, 0);
 	  set_internalvar_integer (lookup_internalvar ("_"), line);
-	  current_source_line = std::max (line - lines_to_list / 2, 1);
+	  si.current_source_line = std::max (line - lines_to_list / 2, 1);
 	  return;
 	}
       line++;
@@ -1684,28 +1725,30 @@  reverse_search_command (char *regex, int from_tty)
   char *msg;
   struct cleanup *cleanups;
 
-  line = last_line_listed - 1;
+  current_source_info &si = get_current_source_info ();
+
+  line = si.last_line_listed - 1;
 
   msg = (char *) re_comp (regex);
   if (msg)
     error (("%s"), msg);
 
-  if (current_source_symtab == 0)
+  if (si.current_source_symtab == 0)
     select_source_symtab (0);
 
-  desc = open_source_file (current_source_symtab);
+  desc = open_source_file (si.current_source_symtab);
   if (desc < 0)
-    perror_with_name (symtab_to_filename_for_display (current_source_symtab));
+    perror_with_name (symtab_to_filename_for_display (si.current_source_symtab));
   cleanups = make_cleanup_close (desc);
 
-  if (current_source_symtab->line_charpos == 0)
-    find_source_lines (current_source_symtab, desc);
+  if (si.current_source_symtab->line_charpos == 0)
+    find_source_lines (si.current_source_symtab, desc);
 
-  if (line < 1 || line > current_source_symtab->nlines)
+  if (line < 1 || line > si.current_source_symtab->nlines)
     error (_("Expression not found"));
 
-  if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
-    perror_with_name (symtab_to_filename_for_display (current_source_symtab));
+  if (lseek (desc, si.current_source_symtab->line_charpos[line - 1], 0) < 0)
+    perror_with_name (symtab_to_filename_for_display (si.current_source_symtab));
 
   discard_cleanups (cleanups);
   gdb_file_up stream (fdopen (desc, FDOPEN_MODE));
@@ -1738,18 +1781,18 @@  reverse_search_command (char *regex, int from_tty)
       if (re_exec (buf) > 0)
 	{
 	  /* Match!  */
-	  print_source_lines (current_source_symtab, line, line + 1, 0);
+	  print_source_lines (si.current_source_symtab, line, line + 1, 0);
 	  set_internalvar_integer (lookup_internalvar ("_"), line);
-	  current_source_line = std::max (line - lines_to_list / 2, 1);
+	  si.current_source_line = std::max (line - lines_to_list / 2, 1);
 	  return;
 	}
       line--;
       if (fseek (stream.get (),
-		 current_source_symtab->line_charpos[line - 1], 0) < 0)
+		 si.current_source_symtab->line_charpos[line - 1], 0) < 0)
 	{
 	  const char *filename;
 
-	  filename = symtab_to_filename_for_display (current_source_symtab);
+	  filename = symtab_to_filename_for_display (si.current_source_symtab);
 	  perror_with_name (filename);
 	}
     }
@@ -1974,7 +2017,6 @@  _initialize_source (void)
 {
   struct cmd_list_element *c;
 
-  current_source_symtab = 0;
   init_source_path ();
 
   /* The intention is to use POSIX Basic Regular Expressions.
diff --git a/gdb/top.c b/gdb/top.c
index f006c66..3919203 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -132,10 +132,6 @@  show_confirm (struct ui_file *file, int from_tty,
 
 char *current_directory;
 
-/* The last command line executed on the console.  Used for command
-   repetitions.  */
-char *saved_command_line;
-
 /* Nonzero if the current command is modified by "server ".  This
    affects things like recording into the command history, commands
    repeating on RETURN, etc.  This is so a user interface (emacs, GUI,
@@ -251,6 +247,7 @@  static int highest_ui_num;
 ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_)
   : next (nullptr),
     num (++highest_ui_num),
+    saved_command_line (xstrdup ("")),
     call_readline (nullptr),
     input_handler (nullptr),
     command_editing (0),
@@ -301,6 +298,10 @@  ui::~ui ()
   else
     ui_list = next;
 
+  delete_current_printcmd_info (this);
+  delete_current_source_info (this);
+  delete_current_top_info (this);
+
   delete m_gdb_stdin;
   delete m_gdb_stdout;
   delete m_gdb_stderr;
@@ -675,7 +676,10 @@  dont_repeat (void)
      thing read from stdin in line and don't want to delete it.  Null
      lines won't repeat here in any case.  */
   if (ui->instream == ui->stdin_stream)
-    *saved_command_line = 0;
+    {
+      xfree (ui->saved_command_line);
+      ui->saved_command_line = NULL;
+    }
 }
 
 /* Prevent dont_repeat from working, and return a cleanup that
@@ -1659,11 +1663,33 @@  dont_repeat_command (char *ignored, int from_tty)
 {
   /* Can't call dont_repeat here because we're not necessarily reading
      from stdin.  */
-  *saved_command_line = 0;
+  xfree (current_ui->saved_command_line);
+  current_ui->saved_command_line = NULL;
 }
 
 /* Functions to manipulate command line editing control variables.  */
 
+struct current_top_info
+{
+  /* Number of the history entry which we are planning to display
+     next in "show commands".  Relative to history_base.  */
+  int num = 0;
+};
+
+static current_top_info &
+get_current_top_info ()
+{
+  if (current_ui->curr_top_info == NULL)
+    current_ui->curr_top_info = new current_top_info ();
+  return *current_ui->curr_top_info;
+}
+
+void
+delete_current_top_info (struct ui *ui)
+{
+  delete ui->curr_top_info;
+}
+
 /* Number of commands to print in each call to show_commands.  */
 #define Hist_print 10
 void
@@ -1672,9 +1698,7 @@  show_commands (char *args, int from_tty)
   /* Index for history commands.  Relative to history_base.  */
   int offset;
 
-  /* Number of the history entry which we are planning to display next.
-     Relative to history_base.  */
-  static int num = 0;
+  current_top_info &ci = get_current_top_info ();
 
   /* Print out some of the commands from the command history.  */
 
@@ -1685,28 +1709,28 @@  show_commands (char *args, int from_tty)
 	;
       else
 	/* "info editing <exp>" should print around command number <exp>.  */
-	num = (parse_and_eval_long (args) - history_base) - Hist_print / 2;
+	ci.num = (parse_and_eval_long (args) - history_base) - Hist_print / 2;
     }
   /* "show commands" means print the last Hist_print commands.  */
   else
     {
-      num = history_length - Hist_print;
+      ci.num = history_length - Hist_print;
     }
 
-  if (num < 0)
-    num = 0;
+  if (ci.num < 0)
+    ci.num = 0;
 
   /* If there are at least Hist_print commands, we want to display the last
      Hist_print rather than, say, the last 6.  */
-  if (history_length - num < Hist_print)
+  if (history_length - ci.num < Hist_print)
     {
-      num = history_length - Hist_print;
-      if (num < 0)
-	num = 0;
+      ci.num = history_length - Hist_print;
+      if (ci.num < 0)
+	ci.num = 0;
     }
 
-  for (offset = num;
-       offset < num + Hist_print && offset < history_length;
+  for (offset = ci.num;
+       offset < ci.num + Hist_print && offset < history_length;
        offset++)
     {
       printf_filtered ("%5d  %s\n", history_base + offset,
@@ -1715,7 +1739,7 @@  show_commands (char *args, int from_tty)
 
   /* The next command we want to display is the next one that we haven't
      displayed yet.  */
-  num += Hist_print;
+  ci.num += Hist_print;
 
   /* If the user repeats this command with return, it should do what
      "show commands +" does.  This is unnecessary if arg is null,
diff --git a/gdb/top.h b/gdb/top.h
index ab65ddb..94822772 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -71,6 +71,10 @@  struct ui
      input until we have a whole command line.  */
   struct buffer line_buffer;
 
+  /* The last command line executed on the console.  Used for command
+     repetitions.  */
+  char *saved_command_line;
+
   /* The callback used by the event loop whenever an event is detected
      on the UI's input file descriptor.  This function incrementally
      builds a buffer where it accumulates the line read up to the
@@ -130,6 +134,15 @@  struct ui
   /* See enum prompt_state's description.  */
   enum prompt_state prompt_state;
 
+  /* Per-UI info for printcmd.c.  Initialized on demand.  */
+  struct current_printcmd_info *curr_printcmd_info = NULL;
+
+  /* Per-UI info for source.c.  Initialized on demand.  */
+  struct current_source_info *curr_source_info = NULL;
+
+  /* Per-UI info for top.c.  Initialized on demand.  */
+  struct current_top_info *curr_top_info = NULL;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -217,7 +230,6 @@  extern void ui_register_input_event_handler (struct ui *ui);
 extern void ui_unregister_input_event_handler (struct ui *ui);
 
 /* From top.c.  */
-extern char *saved_command_line;
 extern int confirm;
 extern int inhibit_gdbinit;
 extern const char gdbinit[];
@@ -234,6 +246,11 @@  extern void quit_command (char *, int);
 extern void quit_cover (void);
 extern void execute_command (char *, int);
 
+/* Delete the per-UI info of UI.  */
+extern void delete_current_printcmd_info (struct ui *ui);
+extern void delete_current_source_info (struct ui *ui);
+extern void delete_current_top_info (struct ui *ui);
+
 /* If the interpreter is in sync mode (we're running a user command's
    list, running command hooks or similars), and we just ran a
    synchronous command that started the target, wait for that command