diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b3f9c7b..ec5bdbe 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,22 @@
+2017-07-25  Tom Tromey  <tom@tromey.com>
+
+	* tracepoint.c (tvariables_info_1): Use ui_out_emit_table.
+	(info_static_tracepoint_markers_command): Likewise.
+	* solib.c (info_sharedlibrary_command): Use ui_out_emit_table.
+	* skip.c (skip_info): Use ui_out_emit_table.
+	* progspace.c (print_program_space): Use ui_out_emit_table.
+	* osdata.c (info_osdata): Use ui_out_emit_table.
+	* mi/mi-cmd-info.c (mi_cmd_info_ada_exceptions): Use
+	ui_out_emit_table.
+	* linux-thread-db.c (info_auto_load_libthread_db): Use
+	ui_out_emit_table.
+	* inferior.c (print_inferior): Use ui_out_emit_table.
+	* gdb_bfd.c (maintenance_info_bfds): Use ui_out_emit_table.
+	* breakpoint.c (breakpoint_1): Use ui_out_emit_table.
+	* auto-load.c (auto_load_info_scripts): Use ui_out_emit_table.
+	* ada-tasks.c (print_ada_task_info): Use ui_out_emit_table.
+	* ui-out.h (class ui_out_emit_table): New.
+
 2017-07-25  John Baldwin  <jhb@FreeBSD.org>
 
 	* configure.nat: Add "-lkvm" for NetBSD/sparc64 and fix typo.
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index ae43da5..cf43f0e 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -1008,7 +1008,6 @@ print_ada_task_info (struct ui_out *uiout,
   struct ada_tasks_inferior_data *data;
   int taskno, nb_tasks;
   int taskno_arg = 0;
-  struct cleanup *old_chain;
   int nb_columns;
 
   if (ada_build_task_list () == 0)
@@ -1047,8 +1046,7 @@ print_ada_task_info (struct ui_out *uiout,
     nb_tasks = VEC_length (ada_task_info_s, data->task_list);
 
   nb_columns = uiout->is_mi_like_p () ? 8 : 7;
-  old_chain = make_cleanup_ui_out_table_begin_end (uiout, nb_columns,
-						   nb_tasks, "tasks");
+  ui_out_emit_table table_emitter (uiout, nb_columns, nb_tasks, "tasks");
   uiout->table_header (1, ui_left, "current", "");
   uiout->table_header (3, ui_right, "id", "ID");
   uiout->table_header (9, ui_right, "task-id", "TID");
@@ -1143,8 +1141,6 @@ print_ada_task_info (struct ui_out *uiout,
 
       uiout->text ("\n");
     }
-
-  do_cleanups (old_chain);
 }
 
 /* Print a detailed description of the Ada task whose ID is TASKNO_STR
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index 37bf942..75ce828 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -1382,18 +1382,18 @@ auto_load_info_scripts (char *pattern, int from_tty,
   if (nr_scripts > 0 && pattern == auto_load_info_scripts_pattern_nl)
     uiout->text ("\n");
 
-  /* Note: This creates a cleanup to output the table end marker.  */
-  make_cleanup_ui_out_table_begin_end (uiout, 2, nr_scripts,
-				       "AutoLoadedScriptsTable");
+  {
+    ui_out_emit_table table_emitter (uiout, 2, nr_scripts,
+				     "AutoLoadedScriptsTable");
 
-  uiout->table_header (7, ui_left, "loaded", "Loaded");
-  uiout->table_header (70, ui_left, "script", "Script");
-  uiout->table_body ();
+    uiout->table_header (7, ui_left, "loaded", "Loaded");
+    uiout->table_header (70, ui_left, "script", "Script");
+    uiout->table_body ();
 
-  print_scripts (script_files);
-  print_scripts (script_texts);
+    print_scripts (script_files);
+    print_scripts (script_texts);
+  }
 
-  /* Finish up the table before checking for no matching scripts.  */
   do_cleanups (script_chain);
 
   if (nr_scripts == 0)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a848aea..a24cc71 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -6808,7 +6808,6 @@ breakpoint_1 (char *args, int allflag,
   struct breakpoint *b;
   struct bp_location *last_loc = NULL;
   int nr_printable_breakpoints;
-  struct cleanup *bkpttbl_chain;
   struct value_print_options opts;
   int print_address_bits = 0;
   int print_type_col_width = 14;
@@ -6851,48 +6850,43 @@ breakpoint_1 (char *args, int allflag,
 	}
     }
 
-  if (opts.addressprint)
-    bkpttbl_chain 
-      = make_cleanup_ui_out_table_begin_end (uiout, 6,
-					     nr_printable_breakpoints,
-                                             "BreakpointTable");
-  else
-    bkpttbl_chain 
-      = make_cleanup_ui_out_table_begin_end (uiout, 5,
-					     nr_printable_breakpoints,
-                                             "BreakpointTable");
-
-  if (nr_printable_breakpoints > 0)
-    annotate_breakpoints_headers ();
-  if (nr_printable_breakpoints > 0)
-    annotate_field (0);
-  uiout->table_header (7, ui_left, "number", "Num"); /* 1 */
-  if (nr_printable_breakpoints > 0)
-    annotate_field (1);
-  uiout->table_header (print_type_col_width, ui_left, "type", "Type"); /* 2 */
-  if (nr_printable_breakpoints > 0)
-    annotate_field (2);
-  uiout->table_header (4, ui_left, "disp", "Disp"); /* 3 */
-  if (nr_printable_breakpoints > 0)
-    annotate_field (3);
-  uiout->table_header (3, ui_left, "enabled", "Enb"); /* 4 */
-  if (opts.addressprint)
-    {
-      if (nr_printable_breakpoints > 0)
-	annotate_field (4);
-      if (print_address_bits <= 32)
-	uiout->table_header (10, ui_left, "addr", "Address"); /* 5 */
-      else
-	uiout->table_header (18, ui_left, "addr", "Address"); /* 5 */
-    }
-  if (nr_printable_breakpoints > 0)
-    annotate_field (5);
-  uiout->table_header (40, ui_noalign, "what", "What"); /* 6 */
-  uiout->table_body ();
-  if (nr_printable_breakpoints > 0)
-    annotate_breakpoints_table ();
+  {
+    ui_out_emit_table table_emitter (uiout,
+				     opts.addressprint ? 6 : 5,
+				     nr_printable_breakpoints,
+				     "BreakpointTable");
+
+    if (nr_printable_breakpoints > 0)
+      annotate_breakpoints_headers ();
+    if (nr_printable_breakpoints > 0)
+      annotate_field (0);
+    uiout->table_header (7, ui_left, "number", "Num"); /* 1 */
+    if (nr_printable_breakpoints > 0)
+      annotate_field (1);
+    uiout->table_header (print_type_col_width, ui_left, "type", "Type"); /* 2 */
+    if (nr_printable_breakpoints > 0)
+      annotate_field (2);
+    uiout->table_header (4, ui_left, "disp", "Disp"); /* 3 */
+    if (nr_printable_breakpoints > 0)
+      annotate_field (3);
+    uiout->table_header (3, ui_left, "enabled", "Enb"); /* 4 */
+    if (opts.addressprint)
+      {
+	if (nr_printable_breakpoints > 0)
+	  annotate_field (4);
+	if (print_address_bits <= 32)
+	  uiout->table_header (10, ui_left, "addr", "Address"); /* 5 */
+	else
+	  uiout->table_header (18, ui_left, "addr", "Address"); /* 5 */
+      }
+    if (nr_printable_breakpoints > 0)
+      annotate_field (5);
+    uiout->table_header (40, ui_noalign, "what", "What"); /* 6 */
+    uiout->table_body ();
+    if (nr_printable_breakpoints > 0)
+      annotate_breakpoints_table ();
 
-  ALL_BREAKPOINTS (b)
+    ALL_BREAKPOINTS (b)
     {
       QUIT;
       /* If we have a filter, only list the breakpoints it accepts.  */
@@ -6920,8 +6914,7 @@ breakpoint_1 (char *args, int allflag,
       if (allflag || user_breakpoint_p (b))
 	print_one_breakpoint (b, &last_loc, allflag);
     }
-
-  do_cleanups (bkpttbl_chain);
+  }
 
   if (nr_printable_breakpoints == 0)
     {
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 2230127..c0dc191 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -976,18 +976,15 @@ print_one_bfd (void **slot, void *data)
 static void
 maintenance_info_bfds (char *arg, int from_tty)
 {
-  struct cleanup *cleanup;
   struct ui_out *uiout = current_uiout;
 
-  cleanup = make_cleanup_ui_out_table_begin_end (uiout, 3, -1, "bfds");
+  ui_out_emit_table table_emitter (uiout, 3, -1, "bfds");
   uiout->table_header (10, ui_left, "refcount", "Refcount");
   uiout->table_header (18, ui_left, "addr", "Address");
   uiout->table_header (40, ui_left, "filename", "Filename");
 
   uiout->table_body ();
   htab_traverse (all_bfds, print_one_bfd, uiout);
-
-  do_cleanups (cleanup);
 }
 
 /* -Wmissing-prototypes */
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 9fa2dad..8e8e13a 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -534,7 +534,6 @@ static void
 print_inferior (struct ui_out *uiout, char *requested_inferiors)
 {
   struct inferior *inf;
-  struct cleanup *old_chain;
   int inf_count = 0;
 
   /* Compute number of inferiors we will print.  */
@@ -552,8 +551,7 @@ print_inferior (struct ui_out *uiout, char *requested_inferiors)
       return;
     }
 
-  old_chain = make_cleanup_ui_out_table_begin_end (uiout, 4, inf_count,
-						   "inferiors");
+  ui_out_emit_table table_emitter (uiout, 4, inf_count, "inferiors");
   uiout->table_header (1, ui_left, "current", "");
   uiout->table_header (4, ui_left, "number", "Num");
   uiout->table_header (17, ui_left, "target-id", "Description");
@@ -597,8 +595,6 @@ print_inferior (struct ui_out *uiout, char *requested_inferiors)
 
       uiout->text ("\n");
     }
-
-  do_cleanups (old_chain);
 }
 
 static void
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 86254f8..cf68013 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -1623,45 +1623,49 @@ info_auto_load_libthread_db (char *args, int from_tty)
   if (info_count > 0 && args == auto_load_info_scripts_pattern_nl)
     uiout->text ("\n");
 
-  make_cleanup_ui_out_table_begin_end (uiout, 2, unique_filenames,
-				       "LinuxThreadDbTable");
+  {
+    ui_out_emit_table table_emitter (uiout, 2, unique_filenames,
+				     "LinuxThreadDbTable");
 
-  uiout->table_header (max_filename_len, ui_left, "filename", "Filename");
-  uiout->table_header (pids_len, ui_left, "PIDs", "Pids");
-  uiout->table_body ();
+    uiout->table_header (max_filename_len, ui_left, "filename", "Filename");
+    uiout->table_header (pids_len, ui_left, "PIDs", "Pids");
+    uiout->table_body ();
 
-  pids = (char *) xmalloc (max_pids_len + 1);
-  make_cleanup (xfree, pids);
+    pids = (char *) xmalloc (max_pids_len + 1);
+    make_cleanup (xfree, pids);
 
-  /* Note I is incremented inside the cycle, not at its end.  */
-  for (i = 0; i < info_count;)
-    {
-      ui_out_emit_tuple tuple_emitter (uiout, NULL);
-      char *pids_end;
-
-      info = array[i];
-      uiout->field_string ("filename", info->filename);
-      pids_end = pids;
+    /* Note I is incremented inside the cycle, not at its end.  */
+    for (i = 0; i < info_count;)
+      {
+	ui_out_emit_tuple tuple_emitter (uiout, NULL);
+	char *pids_end;
 
-      while (i < info_count && strcmp (info->filename, array[i]->filename) == 0)
-	{
-	  if (pids_end != pids)
-	    {
-	      *pids_end++ = ',';
-	      *pids_end++ = ' ';
-	    }
-	  pids_end += xsnprintf (pids_end, &pids[max_pids_len + 1] - pids_end,
-				 "%u", array[i]->pid);
-	  gdb_assert (pids_end < &pids[max_pids_len + 1]);
+	info = array[i];
+	uiout->field_string ("filename", info->filename);
+	pids_end = pids;
 
-	  i++;
-	}
-      *pids_end = '\0';
+	while (i < info_count && strcmp (info->filename,
+					 array[i]->filename) == 0)
+	  {
+	    if (pids_end != pids)
+	      {
+		*pids_end++ = ',';
+		*pids_end++ = ' ';
+	      }
+	    pids_end += xsnprintf (pids_end,
+				   &pids[max_pids_len + 1] - pids_end,
+				   "%u", array[i]->pid);
+	    gdb_assert (pids_end < &pids[max_pids_len + 1]);
+
+	    i++;
+	  }
+	*pids_end = '\0';
 
-      uiout->field_string ("pids", pids);
+	uiout->field_string ("pids", pids);
 
-      uiout->text ("\n");
-    }
+	uiout->text ("\n");
+      }
+  }
 
   do_cleanups (back_to);
 
diff --git a/gdb/mi/mi-cmd-info.c b/gdb/mi/mi-cmd-info.c
index 7da4f90..fa0d16e 100644
--- a/gdb/mi/mi-cmd-info.c
+++ b/gdb/mi/mi-cmd-info.c
@@ -51,8 +51,9 @@ mi_cmd_info_ada_exceptions (const char *command, char **argv, int argc)
   exceptions = ada_exceptions_list (regexp);
   old_chain = make_cleanup (VEC_cleanup (ada_exc_info), &exceptions);
 
-  make_cleanup_ui_out_table_begin_end
-    (uiout, 2, VEC_length (ada_exc_info, exceptions), "ada-exceptions");
+  ui_out_emit_table table_emitter (uiout, 2,
+				   VEC_length (ada_exc_info, exceptions),
+				   "ada-exceptions");
   uiout->table_header (1, ui_left, "name", "Name");
   uiout->table_header (1, ui_left, "address", "Address");
   uiout->table_body ();
diff --git a/gdb/osdata.c b/gdb/osdata.c
index b9014dd..5458e2f 100644
--- a/gdb/osdata.c
+++ b/gdb/osdata.c
@@ -337,8 +337,7 @@ info_osdata (const char *type)
 	}
     }
 
-  make_cleanup_ui_out_table_begin_end (uiout, ncols, nrows,
-				       "OSDataTable");
+  ui_out_emit_table table_emitter (uiout, ncols, nrows, "OSDataTable");
 
   /* With no columns/items, we just output an empty table, but we
      still output the table.  This matters for MI.  */
diff --git a/gdb/progspace.c b/gdb/progspace.c
index f6602b7..0f3ac81 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -259,7 +259,6 @@ print_program_space (struct ui_out *uiout, int requested)
 {
   struct program_space *pspace;
   int count = 0;
-  struct cleanup *old_chain;
 
   /* Compute number of pspaces we will print.  */
   ALL_PSPACES (pspace)
@@ -273,7 +272,7 @@ print_program_space (struct ui_out *uiout, int requested)
   /* There should always be at least one.  */
   gdb_assert (count > 0);
 
-  old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, count, "pspaces");
+  ui_out_emit_table table_emitter (uiout, 3, count, "pspaces");
   uiout->table_header (1, ui_left, "current", "");
   uiout->table_header (4, ui_left, "id", "Id");
   uiout->table_header (17, ui_left, "exec", "Executable");
@@ -325,8 +324,6 @@ print_program_space (struct ui_out *uiout, int requested)
 
       uiout->text ("\n");
     }
-
-  do_cleanups (old_chain);
 }
 
 /* Boolean test for an already-known program space id.  */
diff --git a/gdb/skip.c b/gdb/skip.c
index e767f83..afa81ec 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -346,7 +346,6 @@ skip_info (char *arg, int from_tty)
   struct skiplist_entry *e;
   int num_printable_entries = 0;
   struct value_print_options opts;
-  struct cleanup *tbl_chain;
 
   get_user_print_options (&opts);
 
@@ -367,9 +366,8 @@ skip_info (char *arg, int from_tty)
       return;
     }
 
-  tbl_chain = make_cleanup_ui_out_table_begin_end (current_uiout, 6,
-						   num_printable_entries,
-						   "SkiplistTable");
+  ui_out_emit_table table_emitter (current_uiout, 6, num_printable_entries,
+				   "SkiplistTable");
 
   current_uiout->table_header (5, ui_left, "number", "Num");   /* 1 */
   current_uiout->table_header (3, ui_left, "enabled", "Enb");  /* 2 */
@@ -411,8 +409,6 @@ skip_info (char *arg, int from_tty)
 
       current_uiout->text ("\n");
     }
-
-  do_cleanups (tbl_chain);
 }
 
 static void
diff --git a/gdb/solib.c b/gdb/solib.c
index 788cf15..a0c21fc 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1045,7 +1045,6 @@ info_sharedlibrary_command (char *pattern, int from_tty)
   int so_missing_debug_info = 0;
   int addr_width;
   int nr_libs;
-  struct cleanup *table_cleanup;
   struct gdbarch *gdbarch = target_gdbarch ();
   struct ui_out *uiout = current_uiout;
 
@@ -1062,8 +1061,8 @@ info_sharedlibrary_command (char *pattern, int from_tty)
 
   update_solib_list (from_tty);
 
-  /* make_cleanup_ui_out_table_begin_end needs to know the number of
-     rows, so we need to make two passes over the libs.  */
+  /* ui_out_emit_table table_emitter needs to know the number of rows,
+     so we need to make two passes over the libs.  */
 
   for (nr_libs = 0, so = so_list_head; so; so = so->next)
     {
@@ -1075,19 +1074,18 @@ info_sharedlibrary_command (char *pattern, int from_tty)
 	}
     }
 
-  table_cleanup =
-    make_cleanup_ui_out_table_begin_end (uiout, 4, nr_libs,
-					 "SharedLibraryTable");
+  {
+    ui_out_emit_table table_emitter (uiout, 4, nr_libs, "SharedLibraryTable");
 
-  /* The "- 1" is because ui_out adds one space between columns.  */
-  uiout->table_header (addr_width - 1, ui_left, "from", "From");
-  uiout->table_header (addr_width - 1, ui_left, "to", "To");
-  uiout->table_header (12 - 1, ui_left, "syms-read", "Syms Read");
-  uiout->table_header (0, ui_noalign, "name", "Shared Object Library");
+    /* The "- 1" is because ui_out adds one space between columns.  */
+    uiout->table_header (addr_width - 1, ui_left, "from", "From");
+    uiout->table_header (addr_width - 1, ui_left, "to", "To");
+    uiout->table_header (12 - 1, ui_left, "syms-read", "Syms Read");
+    uiout->table_header (0, ui_noalign, "name", "Shared Object Library");
 
-  uiout->table_body ();
+    uiout->table_body ();
 
-  ALL_SO_LIBS (so)
+    ALL_SO_LIBS (so)
     {
       if (! so->so_name[0])
 	continue;
@@ -1121,8 +1119,7 @@ info_sharedlibrary_command (char *pattern, int from_tty)
 
       uiout->text ("\n");
     }
-
-  do_cleanups (table_cleanup);
+  }
 
   if (nr_libs == 0)
     {
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 4f2bac5..6721e22 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -482,7 +482,6 @@ tvariables_info_1 (void)
   struct trace_state_variable *tsv;
   int ix;
   int count = 0;
-  struct cleanup *back_to;
   struct ui_out *uiout = current_uiout;
 
   if (VEC_length (tsv_s, tvariables) == 0 && !uiout->is_mi_like_p ())
@@ -496,8 +495,7 @@ tvariables_info_1 (void)
     tsv->value_known = target_get_trace_state_variable_value (tsv->number,
 							      &(tsv->value));
 
-  back_to = make_cleanup_ui_out_table_begin_end (uiout, 3,
-                                                 count, "trace-variables");
+  ui_out_emit_table table_emitter (uiout, 3, count, "trace-variables");
   uiout->table_header (15, ui_left, "name", "Name");
   uiout->table_header (11, ui_left, "initial", "Initial");
   uiout->table_header (11, ui_left, "current", "Current");
@@ -531,8 +529,6 @@ tvariables_info_1 (void)
         uiout->field_string ("current", c);
       uiout->text ("\n");
     }
-
-  do_cleanups (back_to);
 }
 
 /* List all the trace state variables.  */
@@ -3952,9 +3948,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
      don't work without in-process agent, so we don't bother users to type
      `set agent on' when to use static tracepoint.  */
 
-  old_chain
-    = make_cleanup_ui_out_table_begin_end (uiout, 5, -1,
-					   "StaticTracepointMarkersTable");
+  ui_out_emit_table table_emitter (uiout, 5, -1,
+				   "StaticTracepointMarkersTable");
 
   uiout->table_header (7, ui_left, "counter", "Cnt");
 
@@ -3970,7 +3965,7 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
   uiout->table_body ();
 
   markers = target_static_tracepoint_markers_by_strid (NULL);
-  make_cleanup (VEC_cleanup (static_tracepoint_marker_p), &markers);
+  old_chain = make_cleanup (VEC_cleanup (static_tracepoint_marker_p), &markers);
 
   for (i = 0;
        VEC_iterate (static_tracepoint_marker_p,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 9278cab..2293f26 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -220,4 +220,31 @@ private:
 typedef ui_out_emit_type<ui_out_type_tuple> ui_out_emit_tuple;
 typedef ui_out_emit_type<ui_out_type_list> ui_out_emit_list;
 
+/* This is similar to make_cleanup_ui_out_table_begin_end, but written
+   as an RAII class.  */
+class ui_out_emit_table
+{
+public:
+
+  ui_out_emit_table (struct ui_out *uiout, int nr_cols, int nr_rows,
+		     const char *tblid)
+
+    : m_uiout (uiout)
+  {
+    m_uiout->table_begin (nr_cols, nr_rows, tblid);
+  }
+
+  ~ui_out_emit_table ()
+  {
+    m_uiout->table_end ();
+  }
+
+  ui_out_emit_table (const ui_out_emit_table &) = delete;
+  ui_out_emit_table &operator= (const ui_out_emit_table &) = delete;
+
+private:
+
+  struct ui_out *m_uiout;
+};
+
 #endif /* UI_OUT_H */
