Change target_read_string to use unique_xmalloc_ptr
[deliverable/binutils-gdb.git] / gdb / target.c
index 359bf0dec9ba9376bd2814500e64539543a439ae..b9b2e757dd5594d079270cdfdaaf712cdfe9c7e3 100644 (file)
@@ -1,6 +1,6 @@
 /* Select target systems and architectures at runtime for GDB.
 
-   Copyright (C) 1990-2017 Free Software Foundation, Inc.
+   Copyright (C) 1990-2018 Free Software Foundation, Inc.
 
    Contributed by Cygnus Support.
 
@@ -46,8 +46,8 @@
 #include "top.h"
 #include "event-top.h"
 #include <algorithm>
-
-static void target_info (char *, int);
+#include "byte-vector.h"
+#include "terminal.h"
 
 static void generic_tls_error (void) ATTRIBUTE_NORETURN;
 
@@ -89,9 +89,7 @@ static int return_zero (struct target_ops *);
 
 static int return_zero_has_execution (struct target_ops *, ptid_t);
 
-static void target_command (char *, int);
-
-static struct target_ops *find_default_run_target (char *);
+static struct target_ops *find_default_run_target (const char *);
 
 static struct gdbarch *default_thread_architecture (struct target_ops *ops,
                                                    ptid_t ptid);
@@ -103,7 +101,7 @@ static int dummy_find_memory_regions (struct target_ops *self,
 static char *dummy_make_corefile_notes (struct target_ops *self,
                                        bfd *ignore1, int *ignore2);
 
-static char *default_pid_to_str (struct target_ops *ops, ptid_t ptid);
+static const char *default_pid_to_str (struct target_ops *ops, ptid_t ptid);
 
 static enum exec_direction_kind default_execution_direction
     (struct target_ops *self);
@@ -170,7 +168,7 @@ int may_stop = 1;
 static unsigned int targetdebug = 0;
 
 static void
-set_targetdebug  (char *args, int from_tty, struct cmd_list_element *c)
+set_targetdebug  (const char *args, int from_tty, struct cmd_list_element *c)
 {
   update_current_target ();
 }
@@ -187,7 +185,7 @@ static void setup_target_debug (void);
 /* The user just typed 'target' without the name of a target.  */
 
 static void
-target_command (char *arg, int from_tty)
+target_command (const char *arg, int from_tty)
 {
   fputs_filtered ("Argument required (target name).  Try `help target'\n",
                  gdb_stdout);
@@ -348,7 +346,7 @@ complete_target_initialization (struct target_ops *t)
 /* This is used to implement the various target commands.  */
 
 static void
-open_target (char *args, int from_tty, struct cmd_list_element *command)
+open_target (const char *args, int from_tty, struct cmd_list_element *command)
 {
   struct target_ops *ops = (struct target_ops *) get_cmd_context (command);
 
@@ -385,7 +383,7 @@ Remaining arguments are interpreted by the target protocol.  For more\n\
 information on the arguments for a particular protocol, type\n\
 `help target ' followed by the protocol name."),
                    &targetlist, "target ", 0, &cmdlist);
-  c = add_cmd (t->to_shortname, no_class, NULL, t->to_doc, &targetlist);
+  c = add_cmd (t->to_shortname, no_class, t->to_doc, &targetlist);
   set_cmd_sfunc (c, open_target);
   set_cmd_context (c, t);
   if (completer != NULL)
@@ -403,14 +401,14 @@ add_target (struct target_ops *t)
 /* See target.h.  */
 
 void
-add_deprecated_target_alias (struct target_ops *t, char *alias)
+add_deprecated_target_alias (struct target_ops *t, const char *alias)
 {
   struct cmd_list_element *c;
   char *alt;
 
   /* If we use add_alias_cmd, here, we do not get the deprecated warning,
      see PR cli/15104.  */
-  c = add_cmd (alias, no_class, NULL, t->to_doc, &targetlist);
+  c = add_cmd (alias, no_class, t->to_doc, &targetlist);
   set_cmd_sfunc (c, open_target);
   set_cmd_context (c, t);
   alt = xstrprintf ("target %s", t->to_shortname);
@@ -432,53 +430,25 @@ target_load (const char *arg, int from_tty)
   (*current_target.to_load) (&current_target, arg, from_tty);
 }
 
-/* Possible terminal states.  */
-
-enum terminal_state
-  {
-    /* The inferior's terminal settings are in effect.  */
-    terminal_is_inferior = 0,
+/* Define it.  */
 
-    /* Some of our terminal settings are in effect, enough to get
-       proper output.  */
-    terminal_is_ours_for_output = 1,
+target_terminal_state target_terminal::m_terminal_state
+  = target_terminal_state::is_ours;
 
-    /* Our terminal settings are in effect, for output and input.  */
-    terminal_is_ours = 2
-  };
-
-static enum terminal_state terminal_state = terminal_is_ours;
-
-/* See target.h.  */
+/* See target/target.h.  */
 
 void
-target_terminal_init (void)
+target_terminal::init (void)
 {
   (*current_target.to_terminal_init) (&current_target);
 
-  terminal_state = terminal_is_ours;
-}
-
-/* See target.h.  */
-
-int
-target_terminal_is_inferior (void)
-{
-  return (terminal_state == terminal_is_inferior);
+  m_terminal_state = target_terminal_state::is_ours;
 }
 
-/* See target.h.  */
-
-int
-target_terminal_is_ours (void)
-{
-  return (terminal_state == terminal_is_ours);
-}
-
-/* See target.h.  */
+/* See target/target.h.  */
 
 void
-target_terminal_inferior (void)
+target_terminal::inferior (void)
 {
   struct ui *ui = current_ui;
 
@@ -489,18 +459,23 @@ target_terminal_inferior (void)
 
   /* Since we always run the inferior in the main console (unless "set
      inferior-tty" is in effect), when some UI other than the main one
-     calls target_terminal_inferior/target_terminal_inferior, then we
-     leave the main UI's terminal settings as is.  */
+     calls target_terminal::inferior, then we leave the main UI's
+     terminal settings as is.  */
   if (ui != main_ui)
     return;
 
-  if (terminal_state == terminal_is_inferior)
-    return;
-
   /* If GDB is resuming the inferior in the foreground, install
      inferior's terminal modes.  */
-  (*current_target.to_terminal_inferior) (&current_target);
-  terminal_state = terminal_is_inferior;
+
+  struct inferior *inf = current_inferior ();
+
+  if (inf->terminal_state != target_terminal_state::is_inferior)
+    {
+      (*current_target.to_terminal_inferior) (&current_target);
+      inf->terminal_state = target_terminal_state::is_inferior;
+    }
+
+  m_terminal_state = target_terminal_state::is_inferior;
 
   /* If the user hit C-c before, pretend that it was hit right
      here.  */
@@ -508,39 +483,130 @@ target_terminal_inferior (void)
     target_pass_ctrlc ();
 }
 
-/* See target.h.  */
+/* See target/target.h.  */
 
 void
-target_terminal_ours (void)
+target_terminal::restore_inferior (void)
 {
   struct ui *ui = current_ui;
 
-  /* See target_terminal_inferior.  */
+  /* See target_terminal::inferior().  */
+  if (ui->prompt_state != PROMPT_BLOCKED || ui != main_ui)
+    return;
+
+  /* Restore the terminal settings of inferiors that were in the
+     foreground but are now ours_for_output due to a temporary
+     target_target::ours_for_output() call.  */
+
+  {
+    scoped_restore_current_inferior restore_inferior;
+    struct inferior *inf;
+
+    ALL_INFERIORS (inf)
+      {
+       if (inf->terminal_state == target_terminal_state::is_ours_for_output)
+         {
+           set_current_inferior (inf);
+           (*current_target.to_terminal_inferior) (&current_target);
+           inf->terminal_state = target_terminal_state::is_inferior;
+         }
+      }
+  }
+
+  m_terminal_state = target_terminal_state::is_inferior;
+
+  /* If the user hit C-c before, pretend that it was hit right
+     here.  */
+  if (check_quit_flag ())
+    target_pass_ctrlc ();
+}
+
+/* Switch terminal state to DESIRED_STATE, either is_ours, or
+   is_ours_for_output.  */
+
+static void
+target_terminal_is_ours_kind (target_terminal_state desired_state)
+{
+  scoped_restore_current_inferior restore_inferior;
+  struct inferior *inf;
+
+  /* Must do this in two passes.  First, have all inferiors save the
+     current terminal settings.  Then, after all inferiors have add a
+     chance to safely save the terminal settings, restore GDB's
+     terminal settings.  */
+
+  ALL_INFERIORS (inf)
+    {
+      if (inf->terminal_state == target_terminal_state::is_inferior)
+       {
+         set_current_inferior (inf);
+         (*current_target.to_terminal_save_inferior) (&current_target);
+       }
+    }
+
+  ALL_INFERIORS (inf)
+    {
+      /* Note we don't check is_inferior here like above because we
+        need to handle 'is_ours_for_output -> is_ours' too.  Careful
+        to never transition from 'is_ours' to 'is_ours_for_output',
+        though.  */
+      if (inf->terminal_state != target_terminal_state::is_ours
+         && inf->terminal_state != desired_state)
+       {
+         set_current_inferior (inf);
+         if (desired_state == target_terminal_state::is_ours)
+           (*current_target.to_terminal_ours) (&current_target);
+         else if (desired_state == target_terminal_state::is_ours_for_output)
+           (*current_target.to_terminal_ours_for_output) (&current_target);
+         else
+           gdb_assert_not_reached ("unhandled desired state");
+         inf->terminal_state = desired_state;
+       }
+    }
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal::ours ()
+{
+  struct ui *ui = current_ui;
+
+  /* See target_terminal::inferior.  */
   if (ui != main_ui)
     return;
 
-  if (terminal_state == terminal_is_ours)
+  if (m_terminal_state == target_terminal_state::is_ours)
     return;
 
-  (*current_target.to_terminal_ours) (&current_target);
-  terminal_state = terminal_is_ours;
+  target_terminal_is_ours_kind (target_terminal_state::is_ours);
+  m_terminal_state = target_terminal_state::is_ours;
 }
 
-/* See target.h.  */
+/* See target/target.h.  */
 
 void
-target_terminal_ours_for_output (void)
+target_terminal::ours_for_output ()
 {
   struct ui *ui = current_ui;
 
-  /* See target_terminal_inferior.  */
+  /* See target_terminal::inferior.  */
   if (ui != main_ui)
     return;
 
-  if (terminal_state != terminal_is_inferior)
+  if (!target_terminal::is_inferior ())
     return;
-  (*current_target.to_terminal_ours_for_output) (&current_target);
-  terminal_state = terminal_is_ours_for_output;
+
+  target_terminal_is_ours_kind (target_terminal_state::is_ours_for_output);
+  target_terminal::m_terminal_state = target_terminal_state::is_ours_for_output;
+}
+
+/* See target/target.h.  */
+
+void
+target_terminal::info (const char *arg, int from_tty)
+{
+  (*current_target.to_terminal_info) (&current_target, arg, from_tty);
 }
 
 /* See target.h.  */
@@ -560,40 +626,6 @@ target_supports_terminal_ours (void)
   return 0;
 }
 
-/* Restore the terminal to its previous state (helper for
-   make_cleanup_restore_target_terminal). */
-
-static void
-cleanup_restore_target_terminal (void *arg)
-{
-  enum terminal_state *previous_state = (enum terminal_state *) arg;
-
-  switch (*previous_state)
-    {
-    case terminal_is_ours:
-      target_terminal_ours ();
-      break;
-    case terminal_is_ours_for_output:
-      target_terminal_ours_for_output ();
-      break;
-    case terminal_is_inferior:
-      target_terminal_inferior ();
-      break;
-    }
-}
-
-/* See target.h. */
-
-struct cleanup *
-make_cleanup_restore_target_terminal (void)
-{
-  enum terminal_state *ts = XNEW (enum terminal_state);
-
-  *ts = terminal_state;
-
-  return make_cleanup_dtor (cleanup_restore_target_terminal, ts, xfree);
-}
-
 static void
 tcomplain (void)
 {
@@ -961,7 +993,8 @@ target_xfer_status_to_string (enum target_xfer_status status)
    read.  */
 
 int
-target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop)
+target_read_string (CORE_ADDR memaddr, gdb::unique_xmalloc_ptr<char> *string,
+                   int len, int *errnop)
 {
   int tlen, offset, i;
   gdb_byte buf[4];
@@ -1021,7 +1054,7 @@ target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop)
       nbytes_read += tlen;
     }
 done:
-  *string = buffer;
+  string->reset (buffer);
   if (errnop != NULL)
     *errnop = errcode;
   return nbytes_read;
@@ -1271,6 +1304,8 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
   if (len == 0)
     return TARGET_XFER_EOF;
 
+  memaddr = address_significant (target_gdbarch (), memaddr);
+
   /* Fill in READBUF with breakpoint shadows, or WRITEBUF with
      breakpoint insns, thus hiding out from higher layers whether
      there are software breakpoints inserted in the code stream.  */
@@ -1284,9 +1319,6 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
     }
   else
     {
-      gdb_byte *buf;
-      struct cleanup *old_chain;
-
       /* A large write request is likely to be partially satisfied
         by memory_xfer_partial_1.  We will continually malloc
         and free a copy of the entire write request for breakpoint
@@ -1295,34 +1327,19 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
         to mitigate this.  */
       len = std::min (ops->to_get_memory_xfer_limit (ops), len);
 
-      buf = (gdb_byte *) xmalloc (len);
-      old_chain = make_cleanup (xfree, buf);
-      memcpy (buf, writebuf, len);
-
-      breakpoint_xfer_memory (NULL, buf, writebuf, memaddr, len);
-      res = memory_xfer_partial_1 (ops, object, NULL, buf, memaddr, len,
+      gdb::byte_vector buf (writebuf, writebuf + len);
+      breakpoint_xfer_memory (NULL, buf.data (), writebuf, memaddr, len);
+      res = memory_xfer_partial_1 (ops, object, NULL, buf.data (), memaddr, len,
                                   xfered_len);
-
-      do_cleanups (old_chain);
     }
 
   return res;
 }
 
-static void
-restore_show_memory_breakpoints (void *arg)
+scoped_restore_tmpl<int>
+make_scoped_restore_show_memory_breakpoints (int show)
 {
-  show_memory_breakpoints = (uintptr_t) arg;
-}
-
-struct cleanup *
-make_show_memory_breakpoints_cleanup (int show)
-{
-  int current = show_memory_breakpoints;
-
-  show_memory_breakpoints = show;
-  return make_cleanup (restore_show_memory_breakpoints,
-                      (void *) (uintptr_t) current);
+  return make_scoped_restore (&show_memory_breakpoints, show);
 }
 
 /* For docs see target.h, to_xfer_partial.  */
@@ -1552,34 +1569,31 @@ target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len)
 
 /* Fetch the target's memory map.  */
 
-VEC(mem_region_s) *
+std::vector<mem_region>
 target_memory_map (void)
 {
-  VEC(mem_region_s) *result;
-  struct mem_region *last_one, *this_one;
-  int ix;
-  result = current_target.to_memory_map (&current_target);
-  if (result == NULL)
-    return NULL;
+  std::vector<mem_region> result
+    = current_target.to_memory_map (&current_target);
+  if (result.empty ())
+    return result;
 
-  qsort (VEC_address (mem_region_s, result),
-        VEC_length (mem_region_s, result),
-        sizeof (struct mem_region), mem_region_cmp);
+  std::sort (result.begin (), result.end ());
 
   /* Check that regions do not overlap.  Simultaneously assign
      a numbering for the "mem" commands to use to refer to
      each region.  */
-  last_one = NULL;
-  for (ix = 0; VEC_iterate (mem_region_s, result, ix, this_one); ix++)
+  mem_region *last_one = NULL;
+  for (size_t ix = 0; ix < result.size (); ix++)
     {
+      mem_region *this_one = &result[ix];
       this_one->number = ix;
 
-      if (last_one && last_one->hi > this_one->lo)
+      if (last_one != NULL && last_one->hi > this_one->lo)
        {
          warning (_("Overlapping regions in memory map: ignoring"));
-         VEC_free (mem_region_s, result);
-         return NULL;
+         return std::vector<mem_region> ();
        }
+
       last_one = this_one;
     }
 
@@ -1701,43 +1715,37 @@ static void
 read_whatever_is_readable (struct target_ops *ops,
                           const ULONGEST begin, const ULONGEST end,
                           int unit_size,
-                          VEC(memory_read_result_s) **result)
+                          std::vector<memory_read_result> *result)
 {
-  gdb_byte *buf = (gdb_byte *) xmalloc (end - begin);
   ULONGEST current_begin = begin;
   ULONGEST current_end = end;
   int forward;
-  memory_read_result_s r;
   ULONGEST xfered_len;
 
   /* If we previously failed to read 1 byte, nothing can be done here.  */
   if (end - begin <= 1)
-    {
-      xfree (buf);
-      return;
-    }
+    return;
+
+  gdb::unique_xmalloc_ptr<gdb_byte> buf ((gdb_byte *) xmalloc (end - begin));
 
   /* Check that either first or the last byte is readable, and give up
      if not.  This heuristic is meant to permit reading accessible memory
      at the boundary of accessible region.  */
   if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
-                          buf, begin, 1, &xfered_len) == TARGET_XFER_OK)
+                          buf.get (), begin, 1, &xfered_len) == TARGET_XFER_OK)
     {
       forward = 1;
       ++current_begin;
     }
   else if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
-                               buf + (end - begin) - 1, end - 1, 1,
+                               buf.get () + (end - begin) - 1, end - 1, 1,
                                &xfered_len) == TARGET_XFER_OK)
     {
       forward = 0;
       --current_end;
     }
   else
-    {
-      xfree (buf);
-      return;
-    }
+    return;
 
   /* Loop invariant is that the [current_begin, current_end) was previously
      found to be not readable as a whole.
@@ -1767,7 +1775,7 @@ read_whatever_is_readable (struct target_ops *ops,
        }
 
       xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL,
-                         buf + (first_half_begin - begin) * unit_size,
+                         buf.get () + (first_half_begin - begin) * unit_size,
                          first_half_begin,
                          first_half_end - first_half_begin);
 
@@ -1794,47 +1802,27 @@ read_whatever_is_readable (struct target_ops *ops,
   if (forward)
     {
       /* The [begin, current_begin) range has been read.  */
-      r.begin = begin;
-      r.end = current_begin;
-      r.data = buf;
+      result->emplace_back (begin, current_end, std::move (buf));
     }
   else
     {
       /* The [current_end, end) range has been read.  */
       LONGEST region_len = end - current_end;
 
-      r.data = (gdb_byte *) xmalloc (region_len * unit_size);
-      memcpy (r.data, buf + (current_end - begin) * unit_size,
+      gdb::unique_xmalloc_ptr<gdb_byte> data
+       ((gdb_byte *) xmalloc (region_len * unit_size));
+      memcpy (data.get (), buf.get () + (current_end - begin) * unit_size,
              region_len * unit_size);
-      r.begin = current_end;
-      r.end = end;
-      xfree (buf);
+      result->emplace_back (current_end, end, std::move (data));
     }
-  VEC_safe_push(memory_read_result_s, (*result), &r);
 }
 
-void
-free_memory_read_result_vector (void *x)
-{
-  VEC(memory_read_result_s) **v = (VEC(memory_read_result_s) **) x;
-  memory_read_result_s *current;
-  int ix;
-
-  for (ix = 0; VEC_iterate (memory_read_result_s, *v, ix, current); ++ix)
-    {
-      xfree (current->data);
-    }
-  VEC_free (memory_read_result_s, *v);
-}
-
-VEC(memory_read_result_s) *
+std::vector<memory_read_result>
 read_memory_robust (struct target_ops *ops,
                    const ULONGEST offset, const LONGEST len)
 {
-  VEC(memory_read_result_s) *result = 0;
+  std::vector<memory_read_result> result;
   int unit_size = gdbarch_addressable_memory_unit_size (target_gdbarch ());
-  struct cleanup *cleanup = make_cleanup (free_memory_read_result_vector,
-                                         &result);
 
   LONGEST xfered_total = 0;
   while (xfered_total < len)
@@ -1860,19 +1848,17 @@ read_memory_robust (struct target_ops *ops,
       else
        {
          LONGEST to_read = std::min (len - xfered_total, region_len);
-         gdb_byte *buffer = (gdb_byte *) xmalloc (to_read * unit_size);
-         struct cleanup *inner_cleanup = make_cleanup (xfree, buffer);
+         gdb::unique_xmalloc_ptr<gdb_byte> buffer
+           ((gdb_byte *) xmalloc (to_read * unit_size));
 
          LONGEST xfered_partial =
-             target_read (ops, TARGET_OBJECT_MEMORY, NULL,
-                          (gdb_byte *) buffer,
+             target_read (ops, TARGET_OBJECT_MEMORY, NULL, buffer.get (),
                           offset + xfered_total, to_read);
          /* Call an observer, notifying them of the xfer progress?  */
          if (xfered_partial <= 0)
            {
              /* Got an error reading full chunk.  See if maybe we can read
                 some subrange.  */
-             do_cleanups (inner_cleanup);
              read_whatever_is_readable (ops, offset + xfered_total,
                                         offset + xfered_total + to_read,
                                         unit_size, &result);
@@ -1880,20 +1866,15 @@ read_memory_robust (struct target_ops *ops,
            }
          else
            {
-             struct memory_read_result r;
-
-             discard_cleanups (inner_cleanup);
-             r.data = buffer;
-             r.begin = offset + xfered_total;
-             r.end = r.begin + xfered_partial;
-             VEC_safe_push (memory_read_result_s, result, &r);
+             result.emplace_back (offset + xfered_total,
+                                  offset + xfered_total + xfered_partial,
+                                  std::move (buffer));
              xfered_total += xfered_partial;
            }
          QUIT;
        }
     }
 
-  discard_cleanups (cleanup);
   return result;
 }
 
@@ -2030,13 +2011,9 @@ target_read_alloc (struct target_ops *ops, enum target_object object,
   return target_read_alloc_1 (ops, object, annex, buf_p, 0);
 }
 
-/* Read OBJECT/ANNEX using OPS.  The result is NUL-terminated and
-   returned as a string, allocated using xmalloc.  If an error occurs
-   or the transfer is unsupported, NULL is returned.  Empty objects
-   are returned as allocated but empty strings.  A warning is issued
-   if the result contains any embedded NUL bytes.  */
+/* See target.h.  */
 
-char *
+gdb::unique_xmalloc_ptr<char>
 target_read_stralloc (struct target_ops *ops, enum target_object object,
                      const char *annex)
 {
@@ -2051,7 +2028,7 @@ target_read_stralloc (struct target_ops *ops, enum target_object object,
     return NULL;
 
   if (transferred == 0)
-    return xstrdup ("");
+    return gdb::unique_xmalloc_ptr<char> (xstrdup (""));
 
   bufstr[transferred] = 0;
 
@@ -2065,7 +2042,7 @@ target_read_stralloc (struct target_ops *ops, enum target_object object,
        break;
       }
 
-  return bufstr;
+  return gdb::unique_xmalloc_ptr<char> (bufstr);
 }
 
 /* Memory transfer methods.  */
@@ -2132,7 +2109,7 @@ target_remove_breakpoint (struct gdbarch *gdbarch,
 }
 
 static void
-target_info (char *args, int from_tty)
+info_target_command (const char *args, int from_tty)
 {
   struct target_ops *t;
   int has_all_mem = 0;
@@ -2221,7 +2198,7 @@ dispose_inferior (struct inferior *inf, void *args)
       if (target_has_execution)
        target_kill ();
       else
-       target_detach (NULL, 0);
+       target_detach (inf, 0);
     }
 
   return 0;
@@ -2254,11 +2231,18 @@ target_preopen (int from_tty)
   target_pre_inferior (from_tty);
 }
 
-/* Detach a target after doing deferred register stores.  */
+/* See target.h.  */
 
 void
-target_detach (const char *args, int from_tty)
+target_detach (inferior *inf, int from_tty)
 {
+  /* As long as some to_detach implementations rely on the current_inferior
+     (either directly, or indirectly, like through target_gdbarch or by
+     reading memory), INF needs to be the current inferior.  When that
+     requirement will become no longer true, then we can remove this
+     assertion.  */
+  gdb_assert (inf == current_inferior ());
+
   if (gdbarch_has_global_breakpoints (target_gdbarch ()))
     /* Don't remove global breakpoints here.  They're removed on
        disconnection from the target.  */
@@ -2270,7 +2254,7 @@ target_detach (const char *args, int from_tty)
 
   prepare_for_detach ();
 
-  current_target.to_detach (&current_target, args, from_tty);
+  current_target.to_detach (&current_target, inf, from_tty);
 }
 
 void
@@ -2303,7 +2287,7 @@ default_target_wait (struct target_ops *ops,
   return minus_one_ptid;
 }
 
-char *
+const char *
 target_pid_to_str (ptid_t ptid)
 {
   return (*current_target.to_pid_to_str) (&current_target, ptid);
@@ -2315,6 +2299,15 @@ target_thread_name (struct thread_info *info)
   return current_target.to_thread_name (&current_target, info);
 }
 
+struct thread_info *
+target_thread_handle_to_thread_info (const gdb_byte *thread_handle,
+                                    int handle_len,
+                                    struct inferior *inf)
+{
+  return current_target.to_thread_handle_to_thread_info
+           (&current_target, thread_handle, handle_len, inf);
+}
+
 void
 target_resume (ptid_t ptid, int step, enum gdb_signal signal)
 {
@@ -2337,8 +2330,6 @@ static int defer_target_commit_resume;
 void
 target_commit_resume (void)
 {
-  struct target_ops *t;
-
   if (defer_target_commit_resume)
     return;
 
@@ -2347,14 +2338,10 @@ target_commit_resume (void)
 
 /* See target.h.  */
 
-struct cleanup *
-make_cleanup_defer_target_commit_resume (void)
+scoped_restore_tmpl<int>
+make_scoped_defer_target_commit_resume ()
 {
-  struct cleanup *old_chain;
-
-  old_chain = make_cleanup_restore_integer (&defer_target_commit_resume);
-  defer_target_commit_resume = 1;
-  return old_chain;
+  return make_scoped_restore (&defer_target_commit_resume, 1);
 }
 
 void
@@ -2439,9 +2426,7 @@ simple_search_memory (struct target_ops *ops,
 #define SEARCH_CHUNK_SIZE 16000
   const unsigned chunk_size = SEARCH_CHUNK_SIZE;
   /* Buffer to hold memory contents for searching.  */
-  gdb_byte *search_buf;
   unsigned search_buf_size;
-  struct cleanup *old_cleanups;
 
   search_buf_size = chunk_size + pattern_len - 1;
 
@@ -2449,20 +2434,17 @@ simple_search_memory (struct target_ops *ops,
   if (search_space_len < search_buf_size)
     search_buf_size = search_space_len;
 
-  search_buf = (gdb_byte *) malloc (search_buf_size);
-  if (search_buf == NULL)
-    error (_("Unable to allocate memory to perform the search."));
-  old_cleanups = make_cleanup (free_current_contents, &search_buf);
+  gdb::byte_vector search_buf (search_buf_size);
 
   /* Prime the search buffer.  */
 
   if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
-                  search_buf, start_addr, search_buf_size) != search_buf_size)
+                  search_buf.data (), start_addr, search_buf_size)
+      != search_buf_size)
     {
       warning (_("Unable to access %s bytes of target "
                 "memory at %s, halting search."),
               pulongest (search_buf_size), hex_string (start_addr));
-      do_cleanups (old_cleanups);
       return -1;
     }
 
@@ -2478,15 +2460,14 @@ simple_search_memory (struct target_ops *ops,
       unsigned nr_search_bytes
        = std::min (search_space_len, (ULONGEST) search_buf_size);
 
-      found_ptr = (gdb_byte *) memmem (search_buf, nr_search_bytes,
+      found_ptr = (gdb_byte *) memmem (search_buf.data (), nr_search_bytes,
                                       pattern, pattern_len);
 
       if (found_ptr != NULL)
        {
-         CORE_ADDR found_addr = start_addr + (found_ptr - search_buf);
+         CORE_ADDR found_addr = start_addr + (found_ptr - search_buf.data ());
 
          *found_addrp = found_addr;
-         do_cleanups (old_cleanups);
          return 1;
        }
 
@@ -2507,20 +2488,19 @@ simple_search_memory (struct target_ops *ops,
          /* Copy the trailing part of the previous iteration to the front
             of the buffer for the next iteration.  */
          gdb_assert (keep_len == pattern_len - 1);
-         memcpy (search_buf, search_buf + chunk_size, keep_len);
+         memcpy (&search_buf[0], &search_buf[chunk_size], keep_len);
 
          nr_to_read = std::min (search_space_len - keep_len,
                                 (ULONGEST) chunk_size);
 
          if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
-                          search_buf + keep_len, read_addr,
+                          &search_buf[keep_len], read_addr,
                           nr_to_read) != nr_to_read)
            {
              warning (_("Unable to access %s bytes of target "
                         "memory at %s, halting search."),
                       plongest (nr_to_read),
                       hex_string (read_addr));
-             do_cleanups (old_cleanups);
              return -1;
            }
 
@@ -2530,7 +2510,6 @@ simple_search_memory (struct target_ops *ops,
 
   /* Not found.  */
 
-  do_cleanups (old_cleanups);
   return 0;
 }
 
@@ -2624,7 +2603,7 @@ show_auto_connect_native_target (struct ui_file *file, int from_tty,
    called for errors); else, return NULL on error.  */
 
 static struct target_ops *
-find_default_run_target (char *do_mesg)
+find_default_run_target (const char *do_mesg)
 {
   struct target_ops *runable = NULL;
 
@@ -2763,7 +2742,9 @@ target_supports_multi_process (void)
   return (*current_target.to_supports_multi_process) (&current_target);
 }
 
-char *
+/* See target.h.  */
+
+gdb::unique_xmalloc_ptr<char>
 target_get_osdata (const char *type)
 {
   struct target_ops *t;
@@ -3079,7 +3060,7 @@ target_fileio_unlink (struct inferior *inf, const char *filename,
 
 /* See target.h.  */
 
-char *
+gdb::optional<std::string>
 target_fileio_readlink (struct inferior *inf, const char *filename,
                        int *target_errno)
 {
@@ -3089,32 +3070,54 @@ target_fileio_readlink (struct inferior *inf, const char *filename,
     {
       if (t->to_fileio_readlink != NULL)
        {
-         char *ret = t->to_fileio_readlink (t, inf, filename,
-                                            target_errno);
+         gdb::optional<std::string> ret
+           = t->to_fileio_readlink (t, inf, filename, target_errno);
 
          if (targetdebug)
            fprintf_unfiltered (gdb_stdlog,
                                "target_fileio_readlink (%d,%s)"
                                " = %s (%d)\n",
                                inf == NULL ? 0 : inf->num,
-                               filename, ret? ret : "(nil)",
-                               ret? 0 : *target_errno);
+                               filename, ret ? ret->c_str () : "(nil)",
+                               ret ? 0 : *target_errno);
          return ret;
        }
     }
 
   *target_errno = FILEIO_ENOSYS;
-  return NULL;
+  return {};
 }
 
-static void
-target_fileio_close_cleanup (void *opaque)
+/* Like scoped_fd, but specific to target fileio.  */
+
+class scoped_target_fd
 {
-  int fd = *(int *) opaque;
-  int target_errno;
+public:
+  explicit scoped_target_fd (int fd) noexcept
+    : m_fd (fd)
+  {
+  }
 
-  target_fileio_close (fd, &target_errno);
-}
+  ~scoped_target_fd ()
+  {
+    if (m_fd >= 0)
+      {
+       int target_errno;
+
+       target_fileio_close (m_fd, &target_errno);
+      }
+  }
+
+  DISABLE_COPY_AND_ASSIGN (scoped_target_fd);
+
+  int get () const noexcept
+  {
+    return m_fd;
+  }
+
+private:
+  int m_fd;
+};
 
 /* Read target file FILENAME, in the filesystem as seen by INF.  If
    INF is NULL, use the filesystem seen by the debugger (GDB or, for
@@ -3128,20 +3131,16 @@ static LONGEST
 target_fileio_read_alloc_1 (struct inferior *inf, const char *filename,
                            gdb_byte **buf_p, int padding)
 {
-  struct cleanup *close_cleanup;
   size_t buf_alloc, buf_pos;
   gdb_byte *buf;
   LONGEST n;
-  int fd;
   int target_errno;
 
-  fd = target_fileio_open (inf, filename, FILEIO_O_RDONLY, 0700,
-                          &target_errno);
-  if (fd == -1)
+  scoped_target_fd fd (target_fileio_open (inf, filename, FILEIO_O_RDONLY,
+                                          0700, &target_errno));
+  if (fd.get () == -1)
     return -1;
 
-  close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
-
   /* Start by reading up to 4K at a time.  The target will throttle
      this number down if necessary.  */
   buf_alloc = 4096;
@@ -3149,20 +3148,18 @@ target_fileio_read_alloc_1 (struct inferior *inf, const char *filename,
   buf_pos = 0;
   while (1)
     {
-      n = target_fileio_pread (fd, &buf[buf_pos],
+      n = target_fileio_pread (fd.get (), &buf[buf_pos],
                               buf_alloc - buf_pos - padding, buf_pos,
                               &target_errno);
       if (n < 0)
        {
          /* An error occurred.  */
-         do_cleanups (close_cleanup);
          xfree (buf);
          return -1;
        }
       else if (n == 0)
        {
          /* Read all there was.  */
-         do_cleanups (close_cleanup);
          if (buf_pos == 0)
            xfree (buf);
          else
@@ -3194,7 +3191,7 @@ target_fileio_read_alloc (struct inferior *inf, const char *filename,
 
 /* See target.h.  */
 
-char *
+gdb::unique_xmalloc_ptr<char> 
 target_fileio_read_stralloc (struct inferior *inf, const char *filename)
 {
   gdb_byte *buffer;
@@ -3205,10 +3202,10 @@ target_fileio_read_stralloc (struct inferior *inf, const char *filename)
   bufstr = (char *) buffer;
 
   if (transferred < 0)
-    return NULL;
+    return gdb::unique_xmalloc_ptr<char> (nullptr);
 
   if (transferred == 0)
-    return xstrdup ("");
+    return gdb::unique_xmalloc_ptr<char> (xstrdup (""));
 
   bufstr[transferred] = 0;
 
@@ -3222,7 +3219,7 @@ target_fileio_read_stralloc (struct inferior *inf, const char *filename)
        break;
       }
 
-  return bufstr;
+  return gdb::unique_xmalloc_ptr<char> (bufstr);
 }
 
 
@@ -3244,7 +3241,9 @@ default_watchpoint_addr_within_range (struct target_ops *target,
 static struct gdbarch *
 default_thread_architecture (struct target_ops *ops, ptid_t ptid)
 {
-  return target_gdbarch ();
+  inferior *inf = find_inferior_ptid (ptid);
+  gdb_assert (inf != NULL);
+  return inf->gdbarch;
 }
 
 static int
@@ -3291,7 +3290,7 @@ void
 target_announce_detach (int from_tty)
 {
   pid_t pid;
-  char *exec_file;
+  const char *exec_file;
 
   if (!from_tty)
     return;
@@ -3344,7 +3343,7 @@ generic_mourn_inferior (void)
 /* Convert a normal process ID to a string.  Returns the string in a
    static buffer.  */
 
-char *
+const char *
 normal_pid_to_str (ptid_t ptid)
 {
   static char buf[32];
@@ -3353,7 +3352,7 @@ normal_pid_to_str (ptid_t ptid)
   return buf;
 }
 
-static char *
+static const char *
 default_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
   return normal_pid_to_str (ptid);
@@ -3439,7 +3438,7 @@ target_stop (ptid_t ptid)
 }
 
 void
-target_interrupt (ptid_t ptid)
+target_interrupt ()
 {
   if (!may_stop)
     {
@@ -3447,7 +3446,7 @@ target_interrupt (ptid_t ptid)
       return;
     }
 
-  (*current_target.to_interrupt) (&current_target, ptid);
+  (*current_target.to_interrupt) (&current_target);
 }
 
 /* See target.h.  */
@@ -3463,7 +3462,7 @@ target_pass_ctrlc (void)
 void
 default_target_pass_ctrlc (struct target_ops *ops)
 {
-  target_interrupt (inferior_ptid);
+  target_interrupt ();
 }
 
 /* See target/target.h.  */
@@ -3518,7 +3517,7 @@ str_comma_list_concat_elem (char *list, const char *elem)
 
 static char *
 do_option (int *target_options, char *ret,
-          int opt, char *opt_str)
+          int opt, const char *opt_str)
 {
   if ((*target_options & opt) != 0)
     {
@@ -3547,51 +3546,12 @@ target_options_to_string (int target_options)
   return ret;
 }
 
-static void
-debug_print_register (const char * func,
-                     struct regcache *regcache, int regno)
-{
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
-  fprintf_unfiltered (gdb_stdlog, "%s ", func);
-  if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)
-      && gdbarch_register_name (gdbarch, regno) != NULL
-      && gdbarch_register_name (gdbarch, regno)[0] != '\0')
-    fprintf_unfiltered (gdb_stdlog, "(%s)",
-                       gdbarch_register_name (gdbarch, regno));
-  else
-    fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
-  if (regno >= 0 && regno < gdbarch_num_regs (gdbarch))
-    {
-      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-      int i, size = register_size (gdbarch, regno);
-      gdb_byte buf[MAX_REGISTER_SIZE];
-
-      regcache_raw_collect (regcache, regno, buf);
-      fprintf_unfiltered (gdb_stdlog, " = ");
-      for (i = 0; i < size; i++)
-       {
-         fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
-       }
-      if (size <= sizeof (LONGEST))
-       {
-         ULONGEST val = extract_unsigned_integer (buf, size, byte_order);
-
-         fprintf_unfiltered (gdb_stdlog, " %s %s",
-                             core_addr_to_string_nz (val), plongest (val));
-       }
-    }
-  fprintf_unfiltered (gdb_stdlog, "\n");
-}
-
 void
 target_fetch_registers (struct regcache *regcache, int regno)
 {
-  gdb_assert (ptid_equal (regcache_get_ptid (regcache), inferior_ptid));
-
   current_target.to_fetch_registers (&current_target, regcache, regno);
   if (targetdebug)
-    debug_print_register ("target_fetch_registers", regcache, regno);
+    regcache->debug_print_register ("target_fetch_registers", regno);
 }
 
 void
@@ -3600,12 +3560,10 @@ target_store_registers (struct regcache *regcache, int regno)
   if (!may_write_registers)
     error (_("Writing to registers is not allowed (regno %d)"), regno);
 
-  gdb_assert (ptid_equal (regcache_get_ptid (regcache), inferior_ptid));
-
   current_target.to_store_registers (&current_target, regcache, regno);
   if (targetdebug)
     {
-      debug_print_register ("target_store_registers", regcache, regno);
+      regcache->debug_print_register ("target_store_registers", regno);
     }
 }
 
@@ -3704,14 +3662,6 @@ target_ranged_break_num_registers (void)
 
 /* See target.h.  */
 
-int
-target_supports_btrace (enum btrace_format format)
-{
-  return current_target.to_supports_btrace (&current_target, format);
-}
-
-/* See target.h.  */
-
 struct btrace_target_info *
 target_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 {
@@ -3850,7 +3800,7 @@ target_goto_record (ULONGEST insn)
 /* See target.h.  */
 
 void
-target_insn_history (int size, int flags)
+target_insn_history (int size, gdb_disassembly_flags flags)
 {
   current_target.to_insn_history (&current_target, size, flags);
 }
@@ -3858,7 +3808,8 @@ target_insn_history (int size, int flags)
 /* See target.h.  */
 
 void
-target_insn_history_from (ULONGEST from, int size, int flags)
+target_insn_history_from (ULONGEST from, int size,
+                         gdb_disassembly_flags flags)
 {
   current_target.to_insn_history_from (&current_target, from, size, flags);
 }
@@ -3866,7 +3817,8 @@ target_insn_history_from (ULONGEST from, int size, int flags)
 /* See target.h.  */
 
 void
-target_insn_history_range (ULONGEST begin, ULONGEST end, int flags)
+target_insn_history_range (ULONGEST begin, ULONGEST end,
+                          gdb_disassembly_flags flags)
 {
   current_target.to_insn_history_range (&current_target, begin, end, flags);
 }
@@ -3874,7 +3826,7 @@ target_insn_history_range (ULONGEST begin, ULONGEST end, int flags)
 /* See target.h.  */
 
 void
-target_call_history (int size, int flags)
+target_call_history (int size, record_print_flags flags)
 {
   current_target.to_call_history (&current_target, size, flags);
 }
@@ -3882,7 +3834,7 @@ target_call_history (int size, int flags)
 /* See target.h.  */
 
 void
-target_call_history_from (ULONGEST begin, int size, int flags)
+target_call_history_from (ULONGEST begin, int size, record_print_flags flags)
 {
   current_target.to_call_history_from (&current_target, begin, size, flags);
 }
@@ -3890,7 +3842,7 @@ target_call_history_from (ULONGEST begin, int size, int flags)
 /* See target.h.  */
 
 void
-target_call_history_range (ULONGEST begin, ULONGEST end, int flags)
+target_call_history_range (ULONGEST begin, ULONGEST end, record_print_flags flags)
 {
   current_target.to_call_history_range (&current_target, begin, end, flags);
 }
@@ -3949,8 +3901,7 @@ default_rcmd (struct target_ops *self, const char *command,
 }
 
 static void
-do_monitor_command (char *cmd,
-                int from_tty)
+do_monitor_command (const char *cmd, int from_tty)
 {
   target_rcmd (cmd, gdb_stdtarg);
 }
@@ -3959,38 +3910,30 @@ do_monitor_command (char *cmd,
    ignored.  */
 
 void
-flash_erase_command (char *cmd, int from_tty)
+flash_erase_command (const char *cmd, int from_tty)
 {
   /* Used to communicate termination of flash operations to the target.  */
   bool found_flash_region = false;
-  struct mem_region *m;
   struct gdbarch *gdbarch = target_gdbarch ();
 
-  VEC(mem_region_s) *mem_regions = target_memory_map ();
+  std::vector<mem_region> mem_regions = target_memory_map ();
 
   /* Iterate over all memory regions.  */
-  for (int i = 0; VEC_iterate (mem_region_s, mem_regions, i, m); i++)
+  for (const mem_region &m : mem_regions)
     {
-      /* Fetch the memory attribute.  */
-      struct mem_attrib *attrib = &m->attrib;
-
       /* Is this a flash memory region?  */
-      if (attrib->mode == MEM_FLASH)
+      if (m.attrib.mode == MEM_FLASH)
         {
           found_flash_region = true;
-          target_flash_erase (m->lo, m->hi - m->lo);
+          target_flash_erase (m.lo, m.hi - m.lo);
 
-         struct cleanup *cleanup_tuple
-             = make_cleanup_ui_out_tuple_begin_end (current_uiout,
-                                                    "erased-regions");
+         ui_out_emit_tuple tuple_emitter (current_uiout, "erased-regions");
 
           current_uiout->message (_("Erasing flash memory region at address "));
-          current_uiout->field_fmt ("address", "%s", paddress (gdbarch,
-                                                                m->lo));
+          current_uiout->field_fmt ("address", "%s", paddress (gdbarch, m.lo));
           current_uiout->message (", size = ");
-          current_uiout->field_fmt ("size", "%s", hex_string (m->hi - m->lo));
+          current_uiout->field_fmt ("size", "%s", hex_string (m.hi - m.lo));
           current_uiout->message ("\n");
-          do_cleanups (cleanup_tuple);
         }
     }
 
@@ -4004,7 +3947,7 @@ flash_erase_command (char *cmd, int from_tty)
 /* Print the name of each layers of our target stack.  */
 
 static void
-maintenance_print_target_stack (char *cmd, int from_tty)
+maintenance_print_target_stack (const char *cmd, int from_tty)
 {
   struct target_ops *t;
 
@@ -4042,7 +3985,7 @@ int target_async_permitted = 1;
 static int target_async_permitted_1 = 1;
 
 static void
-maint_set_target_async_command (char *args, int from_tty,
+maint_set_target_async_command (const char *args, int from_tty,
                                struct cmd_list_element *c)
 {
   if (have_live_inferiors ())
@@ -4095,7 +4038,7 @@ static enum auto_boolean target_non_stop_enabled_1 = AUTO_BOOLEAN_AUTO;
 /* Implementation of "maint set target-non-stop".  */
 
 static void
-maint_set_target_non_stop_command (char *args, int from_tty,
+maint_set_target_non_stop_command (const char *args, int from_tty,
                                   struct cmd_list_element *c)
 {
   if (have_live_inferiors ())
@@ -4151,7 +4094,7 @@ update_target_permissions (void)
    way.  */
 
 static void
-set_target_permissions (char *args, int from_tty,
+set_target_permissions (const char *args, int from_tty,
                        struct cmd_list_element *c)
 {
   if (target_has_execution)
@@ -4172,7 +4115,7 @@ set_target_permissions (char *args, int from_tty,
 /* Set memory write permission independently of observer mode.  */
 
 static void
-set_write_memory_permission (char *args, int from_tty,
+set_write_memory_permission (const char *args, int from_tty,
                        struct cmd_list_element *c)
 {
   /* Make the real values match the user-changed values.  */
@@ -4180,6 +4123,53 @@ set_write_memory_permission (char *args, int from_tty,
   update_observer_mode ();
 }
 
+#if GDB_SELF_TEST
+namespace selftests {
+
+static int
+test_target_has_registers (target_ops *self)
+{
+  return 1;
+}
+
+static int
+test_target_has_stack (target_ops *self)
+{
+  return 1;
+}
+
+static int
+test_target_has_memory (target_ops *self)
+{
+  return 1;
+}
+
+static void
+test_target_prepare_to_store (target_ops *self, regcache *regs)
+{
+}
+
+static void
+test_target_store_registers (target_ops *self, regcache *regs, int regno)
+{
+}
+
+test_target_ops::test_target_ops ()
+  : target_ops {}
+{
+  to_magic = OPS_MAGIC;
+  to_stratum = process_stratum;
+  to_has_memory = test_target_has_memory;
+  to_has_stack = test_target_has_stack;
+  to_has_registers = test_target_has_registers;
+  to_prepare_to_store = test_target_prepare_to_store;
+  to_store_registers = test_target_store_registers;
+
+  complete_target_initialization (this);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
 
 void
 initialize_targets (void)
@@ -4187,8 +4177,8 @@ initialize_targets (void)
   init_dummy_target ();
   push_target (&dummy_target);
 
-  add_info ("target", target_info, targ_desc);
-  add_info ("files", target_info, targ_desc);
+  add_info ("target", info_target_command, targ_desc);
+  add_info ("files", info_target_command, targ_desc);
 
   add_setshow_zuinteger_cmd ("target", class_maintenance, &targetdebug, _("\
 Set target debugging."), _("\
This page took 0.044746 seconds and 4 git commands to generate.