Patchwork [13/40] target_ops/C++: GNU/Linux + x86/AMD64

login
register
mail settings
Submitter Pedro Alves
Date April 14, 2018, 7:09 p.m.
Message ID <20180414190953.24481-14-palves@redhat.com>
Download mbox | patch
Permalink /patch/26746/
State New
Headers show

Comments

Pedro Alves - April 14, 2018, 7:09 p.m.
This converts the x86/AMD64 GNU/Linux ports to C++ified target_ops.

- inf-child/"native" is converted to an actual base class
  (inf_child_target), that is inherited by the linux-nat target.
  inf_child_target will be inherited by all other native targets too,
  of course, in the following patches.

- The old weird double-target linux_ops mechanism in linux-nat.c, is
  gone, replaced by adding a few virtual methods to linux-nat.h's
  target_ops, called low_XXX, that the concrete linux-nat
  implementations override.  Sort of like gdbserver's
  linux_target_ops, but simpler, for requiring only one
  target_ops-like hierarchy, which spares implementing the same method
  twice when we need to forward the method to a low implementation.
  The low target simply reimplements the target_ops method directly in
  that case.

  There are a few remaining linux-nat.c hooks that would be better
  converted to low_ methods like above too.  E.g.:

   linux_nat_set_new_thread (t, x86_linux_new_thread);
   linux_nat_set_new_fork (t, x86_linux_new_fork);
   linux_nat_set_forget_process

  That'll be done in a follow up patch.

- We can no longer use functions like x86_use_watchpoints to install
  custom methods on an arbitrary base target.  The patch replaces that
  with a template mixin.  See x86_nat_target in x86-nat.h.  That will
  be used by other non-Linux x86 targets in following patches.

- linux-thread-db is converted here too.
---
 gdb/amd64-linux-nat.c |  33 ++--
 gdb/i386-linux-nat.c  |  42 ++---
 gdb/inf-child.c       | 295 +++++++++++++++----------------
 gdb/inf-child.h       | 112 ++++++++++--
 gdb/inf-ptrace.c      | 142 ++++++---------
 gdb/inf-ptrace.h      |  67 +++++--
 gdb/linux-nat.c       | 480 +++++++++++++++++++-------------------------------
 gdb/linux-nat.h       | 141 +++++++++++++--
 gdb/linux-thread-db.c | 155 ++++++++--------
 gdb/x86-linux-nat.c   |  80 +++------
 gdb/x86-linux-nat.h   |  44 ++++-
 gdb/x86-nat.c         |  64 ++-----
 gdb/x86-nat.h         |  79 ++++++++-
 13 files changed, 926 insertions(+), 808 deletions(-)

Patch

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index ad942435b8..cee364476c 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -30,7 +30,6 @@ 
 #include "gdb_proc_service.h"
 
 #include "amd64-nat.h"
-#include "linux-nat.h"
 #include "amd64-tdep.h"
 #include "amd64-linux-tdep.h"
 #include "i386-linux-tdep.h"
@@ -46,6 +45,15 @@ 
 #define PTRACE_ARCH_PRCTL      30
 #endif
 
+struct amd64_linux_nat_target final : public x86_linux_nat_target
+{
+  /* Add our register access methods.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+};
+
+static amd64_linux_nat_target the_amd64_linux_nat_target;
+
 /* Mapping between the general-purpose registers in GNU/Linux x86-64
    `struct user' format and GDB's register cache layout for GNU/Linux
    i386.
@@ -130,9 +138,8 @@  fill_fpregset (const struct regcache *regcache,
    this for all registers (including the floating point and SSE
    registers).  */
 
-static void
-amd64_linux_fetch_inferior_registers (struct target_ops *ops,
-				      struct regcache *regcache, int regnum)
+void
+amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   int tid;
@@ -209,9 +216,8 @@  amd64_linux_fetch_inferior_registers (struct target_ops *ops,
    -1, do this for all registers (including the floating-point and SSE
    registers).  */
 
-static void
-amd64_linux_store_inferior_registers (struct target_ops *ops,
-				      struct regcache *regcache, int regnum)
+void
+amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   int tid;
@@ -399,8 +405,6 @@  amd64_linux_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction)
 void
 _initialize_amd64_linux_nat (void)
 {
-  struct target_ops *t;
-
   amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
   amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
   amd64_native_gregset64_reg_offset = amd64_linux_gregset_reg_offset;
@@ -409,16 +413,11 @@  _initialize_amd64_linux_nat (void)
   gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
 	      == amd64_native_gregset32_num_regs);
 
-  /* Create a generic x86 GNU/Linux target.  */
-  t = x86_linux_create_target ();
-
-  /* Add our register access methods.  */
-  t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
-  t->to_store_registers = amd64_linux_store_inferior_registers;
+  linux_target = &the_amd64_linux_nat_target;
 
   /* Add the target.  */
-  x86_linux_add_target (t);
+  x86_linux_add_target (linux_target);
 
   /* Add our siginfo layout converter.  */
-  linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
+  linux_nat_set_siginfo_fixup (linux_target, amd64_linux_siginfo_fixup);
 }
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index d1d32e1b20..b923e65712 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -33,11 +33,22 @@ 
 #include "i386-linux-tdep.h"
 #include "x86-xstate.h"
 
-#include "linux-nat.h"
 #include "x86-linux-nat.h"
 #include "nat/linux-ptrace.h"
 #include "inf-ptrace.h"
 
+struct i386_linux_nat_target final : public x86_linux_nat_target
+{
+  /* Add our register access methods.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+  /* Override the default ptrace resume method.  */
+  void low_resume (ptid_t ptid, int step, enum gdb_signal sig) override;
+};
+
+static i386_linux_nat_target the_i386_linux_nat_target;
+
 /* The register sets used in GNU/Linux ELF core-dumps are identical to
    the register sets in `struct user' that is used for a.out
    core-dumps, and is also used by `ptrace'.  The corresponding types
@@ -446,9 +457,8 @@  store_fpxregs (const struct regcache *regcache, int tid, int regno)
    this for all registers (including the floating point and SSE
    registers).  */
 
-static void
-i386_linux_fetch_inferior_registers (struct target_ops *ops,
-				     struct regcache *regcache, int regno)
+void
+i386_linux_nat_target::fetch_registers (struct regcache *regcache, int regno)
 {
   pid_t tid;
 
@@ -478,7 +488,7 @@  i386_linux_fetch_inferior_registers (struct target_ops *ops,
       /* The call above might reset `have_ptrace_getregs'.  */
       if (!have_ptrace_getregs)
 	{
-	  i386_linux_fetch_inferior_registers (ops, regcache, regno);
+	  fetch_registers (regcache, regno);
 	  return;
 	}
 
@@ -524,9 +534,8 @@  i386_linux_fetch_inferior_registers (struct target_ops *ops,
 /* Store register REGNO back into the child process.  If REGNO is -1,
    do this for all registers (including the floating point and SSE
    registers).  */
-static void
-i386_linux_store_inferior_registers (struct target_ops *ops,
-				     struct regcache *regcache, int regno)
+void
+i386_linux_nat_target::store_registers (struct regcache *regcache, int regno)
 {
   pid_t tid;
 
@@ -635,9 +644,8 @@  static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
    If STEP is nonzero, single-step it.
    If SIGNAL is nonzero, give it that signal.  */
 
-static void
-i386_linux_resume (struct target_ops *ops,
-		   ptid_t ptid, int step, enum gdb_signal signal)
+void
+i386_linux_nat_target::low_resume (ptid_t ptid, int step, enum gdb_signal signal)
 {
   int pid = ptid_get_lwp (ptid);
   int request;
@@ -706,16 +714,8 @@  i386_linux_resume (struct target_ops *ops,
 void
 _initialize_i386_linux_nat (void)
 {
-  /* Create a generic x86 GNU/Linux target.  */
-  struct target_ops *t = x86_linux_create_target ();
-
-  /* Override the default ptrace resume method.  */
-  t->to_resume = i386_linux_resume;
-
-  /* Add our register access methods.  */
-  t->to_fetch_registers = i386_linux_fetch_inferior_registers;
-  t->to_store_registers = i386_linux_store_inferior_registers;
+  linux_target = &the_i386_linux_nat_target;
 
   /* Add the target.  */
-  x86_linux_add_target (t);
+  x86_linux_add_target (linux_target);
 }
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index c7c45530b6..7b2f2a25a2 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -39,11 +39,6 @@ 
 #include <fcntl.h>
 #include <unistd.h>
 
-/* A pointer to what is returned by inf_child_target.  Used by
-   inf_child_open to push the most-derived target in reaction to
-   "target native".  */
-static struct target_ops *inf_child_ops = NULL;
-
 /* Helper function for child_wait and the derivatives of child_wait.
    HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
    translation of that in OURSTATUS.  */
@@ -67,35 +62,11 @@  store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
     }
 }
 
-/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
-   for all registers.  */
-
-static void
-inf_child_fetch_inferior_registers (struct target_ops *ops,
-				    struct regcache *regcache, int regnum)
-{
-  if (regnum == -1)
-    {
-      for (regnum = 0;
-	   regnum < gdbarch_num_regs (regcache->arch ());
-	   regnum++)
-	regcache_raw_supply (regcache, regnum, NULL);
-    }
-  else
-    regcache_raw_supply (regcache, regnum, NULL);
-}
-
-/* Store register REGNUM back into the inferior.  If REGNUM is -1, do
-   this for all registers (including the floating point registers).  */
-
-static void
-inf_child_store_inferior_registers (struct target_ops *ops,
-				    struct regcache *regcache, int regnum)
-{
-}
+inf_child_target::~inf_child_target ()
+{}
 
-static void
-inf_child_post_attach (struct target_ops *self, int pid)
+void
+inf_child_target::post_attach (int pid)
 {
   /* This target doesn't require a meaningful "post attach" operation
      by a debugger.  */
@@ -107,12 +78,59 @@  inf_child_post_attach (struct target_ops *self, int pid)
    makes sure that registers contains all the registers from the
    program being debugged.  */
 
-static void
-inf_child_prepare_to_store (struct target_ops *self,
-			    struct regcache *regcache)
+void
+inf_child_target::prepare_to_store (struct regcache *regcache)
 {
 }
 
+bool
+inf_child_target::supports_terminal_ours ()
+{
+  return true;
+}
+
+void
+inf_child_target::terminal_init ()
+{
+  child_terminal_init (this);
+}
+
+void
+inf_child_target::terminal_inferior ()
+{
+  child_terminal_inferior (this);
+}
+
+void
+inf_child_target::terminal_ours_for_output ()
+{
+  child_terminal_ours_for_output (this);
+}
+
+void
+inf_child_target::terminal_ours ()
+{
+  child_terminal_ours (this);
+}
+
+void
+inf_child_target::interrupt ()
+{
+  child_interrupt (this);
+}
+
+void
+inf_child_target::pass_ctrlc ()
+{
+  child_pass_ctrlc (this);
+}
+
+void
+inf_child_target::terminal_info (const char *args, int from_tty)
+{
+  child_terminal_info (this, args, from_tty);
+}
+
 /* True if the user did "target native".  In that case, we won't
    unpush the child target automatically when the last inferior is
    gone.  */
@@ -131,16 +149,16 @@  inf_child_open_target (struct target_ops *target, const char *arg,
     printf_filtered ("Done.  Use the \"run\" command to start a process.\n");
 }
 
-static void
-inf_child_open (const char *arg, int from_tty)
+void
+inf_child_target::open (const char *arg, int from_tty)
 {
-  inf_child_open_target (inf_child_ops, arg, from_tty);
+  inf_child_open_target (this, arg, from_tty);
 }
 
 /* Implement the to_disconnect target_ops method.  */
 
-static void
-inf_child_disconnect (struct target_ops *target, const char *args, int from_tty)
+void
+inf_child_target::disconnect (const char *args, int from_tty)
 {
   if (args != NULL)
     error (_("Argument given to \"disconnect\"."));
@@ -152,65 +170,98 @@  inf_child_disconnect (struct target_ops *target, const char *args, int from_tty)
 
 /* Implement the to_close target_ops method.  */
 
-static void
-inf_child_close (struct target_ops *target)
+void
+inf_child_target::close ()
 {
   /* In case we were forcibly closed.  */
   inf_child_explicitly_opened = 0;
 }
 
 void
-inf_child_mourn_inferior (struct target_ops *ops)
+inf_child_target::mourn_inferior ()
 {
   generic_mourn_inferior ();
-  inf_child_maybe_unpush_target (ops);
+  maybe_unpush_target ();
 }
 
 /* See inf-child.h.  */
 
 void
-inf_child_maybe_unpush_target (struct target_ops *ops)
+inf_child_target::maybe_unpush_target ()
 {
   if (!inf_child_explicitly_opened && !have_inferiors ())
-    unpush_target (ops);
+    unpush_target (this);
 }
 
-static void
-inf_child_post_startup_inferior (struct target_ops *self, ptid_t ptid)
+void
+inf_child_target::post_startup_inferior (ptid_t ptid)
 {
   /* This target doesn't require a meaningful "post startup inferior"
      operation by a debugger.  */
 }
 
-static int
-inf_child_follow_fork (struct target_ops *ops, int follow_child,
-		       int detach_fork)
+int
+inf_child_target::can_run ()
 {
-  /* This target doesn't support following fork or vfork events.  */
-  return 0;
+  return 1;
 }
 
-static int
-inf_child_can_run (struct target_ops *self)
+bool
+inf_child_target::can_create_inferior ()
 {
-  return 1;
+  return true;
+}
+
+bool
+inf_child_target::can_attach ()
+{
+  return true;
 }
 
-static char *
-inf_child_pid_to_exec_file (struct target_ops *self, int pid)
+char *
+inf_child_target::pid_to_exec_file (int pid)
 {
   /* This target doesn't support translation of a process ID to the
      filename of the executable file.  */
   return NULL;
 }
 
+int
+inf_child_target::has_all_memory ()
+{
+  return default_child_has_all_memory ();
+}
+
+int
+inf_child_target::has_memory ()
+{
+  return default_child_has_memory ();
+}
+
+int
+inf_child_target::has_stack ()
+{
+  return default_child_has_stack ();
+}
+
+int
+inf_child_target::has_registers ()
+{
+  return default_child_has_registers ();
+}
+
+int
+inf_child_target::has_execution (ptid_t ptid)
+{
+  return default_child_has_execution (ptid);
+}
+
 /* Implementation of to_fileio_open.  */
 
-static int
-inf_child_fileio_open (struct target_ops *self,
-		       struct inferior *inf, const char *filename,
-		       int flags, int mode, int warn_if_slow,
-		       int *target_errno)
+int
+inf_child_target::fileio_open (struct inferior *inf, const char *filename,
+			       int flags, int mode, int warn_if_slow,
+			       int *target_errno)
 {
   int nat_flags;
   mode_t nat_mode;
@@ -232,10 +283,9 @@  inf_child_fileio_open (struct target_ops *self,
 
 /* Implementation of to_fileio_pwrite.  */
 
-static int
-inf_child_fileio_pwrite (struct target_ops *self,
-			 int fd, const gdb_byte *write_buf, int len,
-			 ULONGEST offset, int *target_errno)
+int
+inf_child_target::fileio_pwrite (int fd, const gdb_byte *write_buf, int len,
+				 ULONGEST offset, int *target_errno)
 {
   int ret;
 
@@ -260,10 +310,9 @@  inf_child_fileio_pwrite (struct target_ops *self,
 
 /* Implementation of to_fileio_pread.  */
 
-static int
-inf_child_fileio_pread (struct target_ops *self,
-			int fd, gdb_byte *read_buf, int len,
-			ULONGEST offset, int *target_errno)
+int
+inf_child_target::fileio_pread (int fd, gdb_byte *read_buf, int len,
+				ULONGEST offset, int *target_errno)
 {
   int ret;
 
@@ -288,9 +337,8 @@  inf_child_fileio_pread (struct target_ops *self,
 
 /* Implementation of to_fileio_fstat.  */
 
-static int
-inf_child_fileio_fstat (struct target_ops *self, int fd,
-			struct stat *sb, int *target_errno)
+int
+inf_child_target::fileio_fstat (int fd, struct stat *sb, int *target_errno)
 {
   int ret;
 
@@ -303,12 +351,12 @@  inf_child_fileio_fstat (struct target_ops *self, int fd,
 
 /* Implementation of to_fileio_close.  */
 
-static int
-inf_child_fileio_close (struct target_ops *self, int fd, int *target_errno)
+int
+inf_child_target::fileio_close (int fd, int *target_errno)
 {
   int ret;
 
-  ret = close (fd);
+  ret = ::close (fd);
   if (ret == -1)
     *target_errno = host_to_fileio_error (errno);
 
@@ -317,10 +365,9 @@  inf_child_fileio_close (struct target_ops *self, int fd, int *target_errno)
 
 /* Implementation of to_fileio_unlink.  */
 
-static int
-inf_child_fileio_unlink (struct target_ops *self,
-			 struct inferior *inf, const char *filename,
-			 int *target_errno)
+int
+inf_child_target::fileio_unlink (struct inferior *inf, const char *filename,
+				 int *target_errno)
 {
   int ret;
 
@@ -333,10 +380,9 @@  inf_child_fileio_unlink (struct target_ops *self,
 
 /* Implementation of to_fileio_readlink.  */
 
-static gdb::optional<std::string>
-inf_child_fileio_readlink (struct target_ops *self,
-			   struct inferior *inf, const char *filename,
-			   int *target_errno)
+gdb::optional<std::string>
+inf_child_target::fileio_readlink (struct inferior *inf, const char *filename,
+				   int *target_errno)
 {
   /* We support readlink only on systems that also provide a compile-time
      maximum path length (PATH_MAX), at least for now.  */
@@ -358,86 +404,25 @@  inf_child_fileio_readlink (struct target_ops *self,
 #endif
 }
 
-static int
-inf_child_use_agent (struct target_ops *self, int use)
+int
+inf_child_target::use_agent (int use)
 {
   if (agent_loaded_p ())
     {
-      use_agent = use;
+      ::use_agent = use;
       return 1;
     }
   else
     return 0;
 }
 
-static int
-inf_child_can_use_agent (struct target_ops *self)
+int
+inf_child_target::can_use_agent ()
 {
   return agent_loaded_p ();
 }
 
-/* Default implementation of the to_can_async_p and
-   to_supports_non_stop methods.  */
-
-static int
-return_zero (struct target_ops *ignore)
-{
-  return 0;
-}
-
-struct target_ops *
-inf_child_target (void)
-{
-  struct target_ops *t = XCNEW (struct target_ops);
-
-  t->to_shortname = "native";
-  t->to_longname = "Native process";
-  t->to_doc = "Native process (started by the \"run\" command).";
-  t->to_open = inf_child_open;
-  t->to_close = inf_child_close;
-  t->to_disconnect = inf_child_disconnect;
-  t->to_post_attach = inf_child_post_attach;
-  t->to_fetch_registers = inf_child_fetch_inferior_registers;
-  t->to_store_registers = inf_child_store_inferior_registers;
-  t->to_prepare_to_store = inf_child_prepare_to_store;
-  t->to_insert_breakpoint = memory_insert_breakpoint;
-  t->to_remove_breakpoint = memory_remove_breakpoint;
-  t->to_terminal_init = child_terminal_init;
-  t->to_terminal_inferior = child_terminal_inferior;
-  t->to_terminal_save_inferior = child_terminal_save_inferior;
-  t->to_terminal_ours_for_output = child_terminal_ours_for_output;
-  t->to_terminal_ours = child_terminal_ours;
-  t->to_terminal_info = child_terminal_info;
-  t->to_pass_ctrlc = child_pass_ctrlc;
-  t->to_interrupt = child_interrupt;
-  t->to_post_startup_inferior = inf_child_post_startup_inferior;
-  t->to_follow_fork = inf_child_follow_fork;
-  t->to_can_run = inf_child_can_run;
-  /* We must default these because they must be implemented by any
-     target that can run.  */
-  t->to_can_async_p = return_zero;
-  t->to_supports_non_stop = return_zero;
-  t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
-  t->to_stratum = process_stratum;
-  t->to_has_all_memory = default_child_has_all_memory;
-  t->to_has_memory = default_child_has_memory;
-  t->to_has_stack = default_child_has_stack;
-  t->to_has_registers = default_child_has_registers;
-  t->to_has_execution = default_child_has_execution;
-  t->to_fileio_open = inf_child_fileio_open;
-  t->to_fileio_pwrite = inf_child_fileio_pwrite;
-  t->to_fileio_pread = inf_child_fileio_pread;
-  t->to_fileio_fstat = inf_child_fileio_fstat;
-  t->to_fileio_close = inf_child_fileio_close;
-  t->to_fileio_unlink = inf_child_fileio_unlink;
-  t->to_fileio_readlink = inf_child_fileio_readlink;
-  t->to_magic = OPS_MAGIC;
-  t->to_use_agent = inf_child_use_agent;
-  t->to_can_use_agent = inf_child_can_use_agent;
-
-  /* Store a pointer so we can push the most-derived target from
-     inf_child_open.  */
-  inf_child_ops = t;
-
-  return t;
+inf_child_target::inf_child_target ()
+{
+  this->to_stratum = process_stratum;
 }
diff --git a/gdb/inf-child.h b/gdb/inf-child.h
index 5fb966d506..1b9c8c53ae 100644
--- a/gdb/inf-child.h
+++ b/gdb/inf-child.h
@@ -20,33 +20,107 @@ 
 #ifndef INF_CHILD_H
 #define INF_CHILD_H
 
-/* Create a prototype child target.  The client can override it with
-   local methods.  */
+#include "target.h"
 
-extern struct target_ops *inf_child_target (void);
+/* A prototype child target.  The client can override it with local
+   methods.  */
 
-/* Functions for helping to write a native target.  */
+class inf_child_target
+  : public memory_breakpoint_target<target_ops>
+{
+public:
+  inf_child_target ();
+  ~inf_child_target () override = 0;
 
-/* This is for native targets which use a unix/POSIX-style waitstatus.  */
-extern void store_waitstatus (struct target_waitstatus *, int);
+  const char *shortname () override
+  { return "native"; }
+
+  const char *longname () override
+  { return _("Native process"); }
+
+  const char *doc () override
+  { return _("Native process (started by the \"run\" command)."); }
+
+  void open (const char *arg, int from_tty) override;
+  void close () override;
+
+  void disconnect (const char *, int) override;
+
+  void fetch_registers (struct regcache *, int) override = 0;
+  void store_registers (struct regcache *, int) override = 0;
+
+  void prepare_to_store (struct regcache *) override;
+
+  bool supports_terminal_ours () override;
+  void terminal_init () override;
+  void terminal_inferior () override;
+  void terminal_ours_for_output () override;
+  void terminal_ours () override;
+  void terminal_info (const char *, int) override;
+
+  void interrupt () override;
+  void pass_ctrlc () override;
 
-/* This is to be called by the native target's open routine to push
-   the target, in case it need to override to_open.  */
+  void post_startup_inferior (ptid_t) override;
 
-extern void inf_child_open_target (struct target_ops *target,
-				   const char *arg, int from_tty);
+  void mourn_inferior () override;
 
-/* To be called by the native target's to_mourn_inferior routine.  */
+  int can_run () override;
 
-extern void inf_child_mourn_inferior (struct target_ops *ops);
+  bool can_create_inferior () override;
+  void create_inferior (const char *, const std::string &,
+			char **, int) = 0;
 
-/* Unpush the target if it wasn't explicitly open with "target native"
-   and there are no live inferiors left.  Note: if calling this as a
-   result of a mourn or detach, the current inferior shall already
-   have its PID cleared, so it isn't counted as live.  That's usually
-   done by calling either generic_mourn_inferior or
-   detach_inferior.  */
+  bool can_attach () override;
+  void attach (const char *, int) override = 0;
 
-extern void inf_child_maybe_unpush_target (struct target_ops *ops);
+  void post_attach (int);
+
+  /* We must default these because they must be implemented by any
+     target that can run.  */
+  int can_async_p ()  override { return 0; }
+  int supports_non_stop ()  override { return 0; }
+
+  char *pid_to_exec_file (int pid) override;
+
+  int has_all_memory () override;
+  int has_memory () override;
+  int has_stack () override;
+  int has_registers () override;
+  int has_execution (ptid_t) override;
+
+  int fileio_open (struct inferior *inf, const char *filename,
+		   int flags, int mode, int warn_if_slow,
+		   int *target_errno) override;
+  int fileio_pwrite (int fd, const gdb_byte *write_buf, int len,
+		     ULONGEST offset, int *target_errno) override;
+  int fileio_pread (int fd, gdb_byte *read_buf, int len,
+		    ULONGEST offset, int *target_errno) override;
+  int fileio_fstat (int fd, struct stat *sb, int *target_errno) override;
+  int fileio_close (int fd, int *target_errno) override;
+  int fileio_unlink (struct inferior *inf,
+		     const char *filename,
+		     int *target_errno) override;
+  gdb::optional<std::string> fileio_readlink (struct inferior *inf,
+					      const char *filename,
+					      int *target_errno) override;
+  int use_agent (int use) override;
+
+  int can_use_agent () override;
+
+protected:
+  /* Unpush the target if it wasn't explicitly open with "target native"
+     and there are no live inferiors left.  Note: if calling this as a
+     result of a mourn or detach, the current inferior shall already
+     have its PID cleared, so it isn't counted as live.  That's usually
+     done by calling either generic_mourn_inferior or
+     detach_inferior.  */
+  void maybe_unpush_target ();
+};
+
+/* Functions for helping to write a native target.  */
+
+/* This is for native targets which use a unix/POSIX-style waitstatus.  */
+extern void store_waitstatus (struct target_waitstatus *, int);
 
 #endif
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 7c4d597be9..8f5a378353 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -52,14 +52,16 @@  typedef std::unique_ptr<struct target_ops, target_unpusher> target_unpush_up;
 
 
 
+inf_ptrace_target::~inf_ptrace_target ()
+{}
+
 #ifdef PT_GET_PROCESS_STATE
 
 /* Target hook for follow_fork.  On entry and at return inferior_ptid is
    the ptid of the followed inferior.  */
 
-static int
-inf_ptrace_follow_fork (struct target_ops *ops, int follow_child,
-			int detach_fork)
+int
+inf_ptrace_target::follow_fork (int follow_child, int detach_fork)
 {
   if (!follow_child)
     {
@@ -76,14 +78,14 @@  inf_ptrace_follow_fork (struct target_ops *ops, int follow_child,
   return 0;
 }
 
-static int
-inf_ptrace_insert_fork_catchpoint (struct target_ops *self, int pid)
+int
+inf_ptrace_target::insert_fork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-inf_ptrace_remove_fork_catchpoint (struct target_ops *self, int pid)
+int
+inf_ptrace_target::remove_fork_catchpoint (int pid)
 {
   return 0;
 }
@@ -106,24 +108,24 @@  inf_ptrace_me (void)
    ENV is the environment vector to pass.  If FROM_TTY is non-zero, be
    chatty about it.  */
 
-static void
-inf_ptrace_create_inferior (struct target_ops *ops,
-			    const char *exec_file, const std::string &allargs,
-			    char **env, int from_tty)
+void
+inf_ptrace_target::create_inferior (const char *exec_file,
+				    const std::string &allargs,
+				    char **env, int from_tty)
 {
   pid_t pid;
   ptid_t ptid;
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
-  int ops_already_pushed = target_is_pushed (ops);
+  int ops_already_pushed = target_is_pushed (this);
 
   target_unpush_up unpusher;
   if (! ops_already_pushed)
     {
       /* Clear possible core file with its process_stratum.  */
-      push_target (ops);
-      unpusher.reset (ops);
+      push_target (this);
+      unpusher.reset (this);
     }
 
   pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
@@ -146,8 +148,8 @@  inf_ptrace_create_inferior (struct target_ops *ops,
 
 #ifdef PT_GET_PROCESS_STATE
 
-static void
-inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid)
+void
+inf_ptrace_target::post_startup_inferior (ptid_t pid)
 {
   ptrace_event_t pe;
 
@@ -163,8 +165,8 @@  inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid)
 
 /* Clean up a rotting corpse of an inferior after it died.  */
 
-static void
-inf_ptrace_mourn_inferior (struct target_ops *ops)
+void
+inf_ptrace_target::mourn_inferior ()
 {
   int status;
 
@@ -174,14 +176,14 @@  inf_ptrace_mourn_inferior (struct target_ops *ops)
      only report its exit status to its original parent.  */
   waitpid (ptid_get_pid (inferior_ptid), &status, 0);
 
-  inf_child_mourn_inferior (ops);
+  inf_child_target::mourn_inferior ();
 }
 
 /* Attach to the process specified by ARGS.  If FROM_TTY is non-zero,
    be chatty about it.  */
 
-static void
-inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
+void
+inf_ptrace_target::attach (const char *args, int from_tty)
 {
   char *exec_file;
   pid_t pid;
@@ -189,7 +191,7 @@  inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
 
   /* Do not change either targets above or the same target if already present.
      The reason is the target stack is shared across multiple inferiors.  */
-  int ops_already_pushed = target_is_pushed (ops);
+  int ops_already_pushed = target_is_pushed (this);
 
   pid = parse_pid_to_attach (args);
 
@@ -201,8 +203,8 @@  inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
     {
       /* target_pid_to_str already uses the target.  Also clear possible core
 	 file with its process_stratum.  */
-      push_target (ops);
-      unpusher.reset (ops);
+      push_target (this);
+      unpusher.reset (this);
     }
 
   if (from_tty)
@@ -242,8 +244,8 @@  inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty)
 
 #ifdef PT_GET_PROCESS_STATE
 
-static void
-inf_ptrace_post_attach (struct target_ops *self, int pid)
+void
+inf_ptrace_target::post_attach (int pid)
 {
   ptrace_event_t pe;
 
@@ -259,8 +261,8 @@  inf_ptrace_post_attach (struct target_ops *self, int pid)
 
 /* Detach from the inferior.  If FROM_TTY is non-zero, be chatty about it.  */
 
-static void
-inf_ptrace_detach (struct target_ops *ops, inferior *inf, int from_tty)
+void
+inf_ptrace_target::detach (inferior *inf, int from_tty)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
 
@@ -279,24 +281,24 @@  inf_ptrace_detach (struct target_ops *ops, inferior *inf, int from_tty)
   error (_("This system does not support detaching from a process"));
 #endif
 
-  inf_ptrace_detach_success (ops, inf);
+  detach_success (inf);
 }
 
 /* See inf-ptrace.h.  */
 
 void
-inf_ptrace_detach_success (struct target_ops *ops, inferior *inf)
+inf_ptrace_target::detach_success (inferior *inf)
 {
   inferior_ptid = null_ptid;
   detach_inferior (inf);
 
-  inf_child_maybe_unpush_target (ops);
+  maybe_unpush_target ();
 }
 
 /* Kill the inferior.  */
 
-static void
-inf_ptrace_kill (struct target_ops *ops)
+void
+inf_ptrace_target::kill ()
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   int status;
@@ -330,9 +332,8 @@  get_ptrace_pid (ptid_t ptid)
    STEP is nonzero, single-step it.  If SIGNAL is nonzero, give it
    that signal.  */
 
-static void
-inf_ptrace_resume (struct target_ops *ops,
-		   ptid_t ptid, int step, enum gdb_signal signal)
+void
+inf_ptrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
 {
   pid_t pid;
   int request;
@@ -372,9 +373,9 @@  inf_ptrace_resume (struct target_ops *ops,
    process ID of the child, or MINUS_ONE_PTID in case of error; store
    the status in *OURSTATUS.  */
 
-static ptid_t
-inf_ptrace_wait (struct target_ops *ops,
-		 ptid_t ptid, struct target_waitstatus *ourstatus, int options)
+ptid_t
+inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+			 int options)
 {
   pid_t pid;
   int status, save_errno;
@@ -520,11 +521,11 @@  inf_ptrace_peek_poke (pid_t pid, gdb_byte *readbuf,
 
 /* Implement the to_xfer_partial target_ops method.  */
 
-static enum target_xfer_status
-inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
-			 const char *annex, gdb_byte *readbuf,
-			 const gdb_byte *writebuf,
-			 ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
+enum target_xfer_status
+inf_ptrace_target::xfer_partial (enum target_object object,
+				 const char *annex, gdb_byte *readbuf,
+				 const gdb_byte *writebuf,
+				 ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
 {
   pid_t pid = get_ptrace_pid (inferior_ptid);
 
@@ -606,17 +607,17 @@  inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
 
 /* Return non-zero if the thread specified by PTID is alive.  */
 
-static int
-inf_ptrace_thread_alive (struct target_ops *ops, ptid_t ptid)
+int
+inf_ptrace_target::thread_alive (ptid_t ptid)
 {
   /* ??? Is kill the right way to do this?  */
-  return (kill (ptid_get_pid (ptid), 0) != -1);
+  return (::kill (ptid_get_pid (ptid), 0) != -1);
 }
 
 /* Print status information about what we're accessing.  */
 
-static void
-inf_ptrace_files_info (struct target_ops *ignore)
+void
+inf_ptrace_target::files_info ()
 {
   struct inferior *inf = current_inferior ();
 
@@ -625,8 +626,8 @@  inf_ptrace_files_info (struct target_ops *ignore)
 		   target_pid_to_str (inferior_ptid));
 }
 
-static const char *
-inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
+const char *
+inf_ptrace_target::pid_to_str (ptid_t ptid)
 {
   return normal_pid_to_str (ptid);
 }
@@ -638,9 +639,9 @@  inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
    Return -1 if there is insufficient buffer for a whole entry.
    Return 1 if an entry was read into *TYPEP and *VALP.  */
 
-static int
-inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
-		       gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+int
+inf_ptrace_target::auxv_parse (gdb_byte **readptr, gdb_byte *endptr,
+			       CORE_ADDR *typep, CORE_ADDR *valp)
 {
   struct type *int_type = builtin_type (target_gdbarch ())->builtin_int;
   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
@@ -665,37 +666,4 @@  inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
 }
 
 #endif
-
-/* Create a prototype ptrace target.  The client can override it with
-   local methods.  */
-
-struct target_ops *
-inf_ptrace_target (void)
-{
-  struct target_ops *t = inf_child_target ();
-
-  t->to_attach = inf_ptrace_attach;
-  t->to_detach = inf_ptrace_detach;
-  t->to_resume = inf_ptrace_resume;
-  t->to_wait = inf_ptrace_wait;
-  t->to_files_info = inf_ptrace_files_info;
-  t->to_kill = inf_ptrace_kill;
-  t->to_create_inferior = inf_ptrace_create_inferior;
-#ifdef PT_GET_PROCESS_STATE
-  t->to_follow_fork = inf_ptrace_follow_fork;
-  t->to_insert_fork_catchpoint = inf_ptrace_insert_fork_catchpoint;
-  t->to_remove_fork_catchpoint = inf_ptrace_remove_fork_catchpoint;
-  t->to_post_startup_inferior = inf_ptrace_post_startup_inferior;
-  t->to_post_attach = inf_ptrace_post_attach;
-#endif
-  t->to_mourn_inferior = inf_ptrace_mourn_inferior;
-  t->to_thread_alive = inf_ptrace_thread_alive;
-  t->to_pid_to_str = inf_ptrace_pid_to_str;
-  t->to_xfer_partial = inf_ptrace_xfer_partial;
-#if defined (PT_IO) && defined (PIOD_READ_AUXV)
-  t->to_auxv_parse = inf_ptrace_auxv_parse;
-#endif
-
-  return t;
-}
 
diff --git a/gdb/inf-ptrace.h b/gdb/inf-ptrace.h
index d10f64ae56..bd9b609ab4 100644
--- a/gdb/inf-ptrace.h
+++ b/gdb/inf-ptrace.h
@@ -20,26 +20,67 @@ 
 #ifndef INF_PTRACE_H
 #define INF_PTRACE_H
 
-/* Create a prototype ptrace target.  The client can override it with
-   local methods.  */
+#include "inf-child.h"
 
-extern struct target_ops *inf_ptrace_target (void);
+/* An abstract prototype ptrace target.  The client can override it
+   with local methods.  */
 
-/* Create a "traditional" ptrace target.  REGISTER_U_OFFSET should be
-   a function returning the offset within the user area where a
-   particular register is stored.  */
+struct inf_ptrace_target : public inf_child_target
+{
+  ~inf_ptrace_target () override = 0;
 
-extern struct target_ops *
-  inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
-					(struct gdbarch *, int, int));
+  void attach (const char *, int) override;
+
+  void detach (inferior *inf, int) override;
+
+  void resume (ptid_t, int, enum gdb_signal) override;
+
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+
+  void files_info () override;
+
+  void kill () override;
+
+  void create_inferior (const char *, const std::string &,
+			char **, int) override;
+#ifdef PT_GET_PROCESS_STATE
+  int follow_fork (int, int) override;
+
+  int insert_fork_catchpoint (int) override;
+
+  int remove_fork_catchpoint (int) override;
+
+  void post_startup_inferior (ptid_t) override;
+
+  void post_attach (int) override;
+#endif
+
+  void mourn_inferior () override;
+
+  int thread_alive (ptid_t ptid) override;
+
+  const char *pid_to_str (ptid_t) override;
+
+  enum target_xfer_status xfer_partial (enum target_object object,
+					const char *annex,
+					gdb_byte *readbuf,
+					const gdb_byte *writebuf,
+					ULONGEST offset, ULONGEST len,
+					ULONGEST *xfered_len) override;
+
+#if defined (PT_IO) && defined (PIOD_READ_AUXV)
+  int auxv_parse (gdb_byte **readptr,
+		  gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) override;
+#endif
+
+protected:
+  /* Cleanup the inferior after a successful ptrace detach.  */
+  void detach_success (inferior *inf);
+};
 
 /* Return which PID to pass to ptrace in order to observe/control the
    tracee identified by PTID.  */
 
 extern pid_t get_ptrace_pid (ptid_t);
 
-
-/* Cleanup the inferior after a successful ptrace detach.  */
-extern void inf_ptrace_detach_success (struct target_ops *ops, inferior *inf);
-
 #endif
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index c23f83e057..bfc2e46ed6 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -186,14 +186,11 @@  leader.  */
 #define O_LARGEFILE 0
 #endif
 
+struct linux_nat_target *linux_target;
+
 /* Does the current host support PTRACE_GETREGSET?  */
 enum tribool have_ptrace_getregset = TRIBOOL_UNKNOWN;
 
-/* The single-threaded native GNU/Linux target_ops.  We save a pointer for
-   the use of the multi-threaded target.  */
-static struct target_ops *linux_ops;
-static struct target_ops linux_ops_saved;
-
 /* The method to call, if any, when a new thread is attached.  */
 static void (*linux_nat_new_thread) (struct lwp_info *);
 
@@ -217,10 +214,6 @@  static int (*linux_nat_siginfo_fixup) (siginfo_t *,
 				       gdb_byte *,
 				       int);
 
-/* The saved to_xfer_partial method, inherited from inf-ptrace.c.
-   Called by our to_xfer_partial.  */
-static target_xfer_partial_ftype *super_xfer_partial;
-
 /* The saved to_close method, inherited from inf-ptrace.c.
    Called by our to_close.  */
 static void (*super_close) (struct target_ops *);
@@ -431,14 +424,17 @@  linux_init_ptrace (pid_t pid, int attached)
   linux_ptrace_init_warnings ();
 }
 
-static void
-linux_child_post_attach (struct target_ops *self, int pid)
+linux_nat_target::~linux_nat_target ()
+{}
+
+void
+linux_nat_target::post_attach (int pid)
 {
   linux_init_ptrace (pid, 1);
 }
 
-static void
-linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid)
+void
+linux_nat_target::post_startup_inferior (ptid_t ptid)
 {
   linux_init_ptrace (ptid_get_pid (ptid), 0);
 }
@@ -472,9 +468,8 @@  delete_lwp_cleanup (void *lp_voidp)
    ptid of the followed inferior.  At return, inferior_ptid will be
    unchanged.  */
 
-static int
-linux_child_follow_fork (struct target_ops *ops, int follow_child,
-			 int detach_fork)
+int
+linux_nat_target::follow_fork (int follow_child, int detach_fork)
 {
   if (!follow_child)
     {
@@ -638,46 +633,45 @@  linux_child_follow_fork (struct target_ops *ops, int follow_child,
 }
 
 
-static int
-linux_child_insert_fork_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::insert_fork_catchpoint (int pid)
 {
   return !linux_supports_tracefork ();
 }
 
-static int
-linux_child_remove_fork_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::remove_fork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-linux_child_insert_vfork_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::insert_vfork_catchpoint (int pid)
 {
   return !linux_supports_tracefork ();
 }
 
-static int
-linux_child_remove_vfork_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::remove_vfork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-linux_child_insert_exec_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::insert_exec_catchpoint (int pid)
 {
   return !linux_supports_tracefork ();
 }
 
-static int
-linux_child_remove_exec_catchpoint (struct target_ops *self, int pid)
+int
+linux_nat_target::remove_exec_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-linux_child_set_syscall_catchpoint (struct target_ops *self,
-				    int pid, bool needed, int any_count,
-				    gdb::array_view<const int> syscall_counts)
+int
+linux_nat_target::set_syscall_catchpoint (int pid, bool needed, int any_count,
+					  gdb::array_view<const int> syscall_counts)
 {
   if (!linux_supports_tracesysgood ())
     return 1;
@@ -811,9 +805,8 @@  restore_child_signals_mask (sigset_t *prev_mask)
 static sigset_t pass_mask;
 
 /* Update signals to pass to the inferior.  */
-static void
-linux_nat_pass_signals (struct target_ops *self,
-			int numsigs, unsigned char *pass_signals)
+void
+linux_nat_target::pass_signals (int numsigs, unsigned char *pass_signals)
 {
   int signo;
 
@@ -831,7 +824,6 @@  linux_nat_pass_signals (struct target_ops *self,
 
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
-static char *linux_child_pid_to_exec_file (struct target_ops *self, int pid);
 static int resume_stopped_resumed_lwps (struct lwp_info *lp, void *data);
 static int check_ptrace_stopped_lwp_gone (struct lwp_info *lp);
 
@@ -1113,10 +1105,10 @@  linux_nat_post_attach_wait (ptid_t ptid, int *signalled)
   return status;
 }
 
-static void
-linux_nat_create_inferior (struct target_ops *ops, 
-			   const char *exec_file, const std::string &allargs,
-			   char **env, int from_tty)
+void
+linux_nat_target::create_inferior (const char *exec_file,
+				   const std::string &allargs,
+				   char **env, int from_tty)
 {
   maybe_disable_address_space_randomization restore_personality
     (disable_randomization);
@@ -1125,9 +1117,9 @@  linux_nat_create_inferior (struct target_ops *ops,
      we have to mask the async mode.  */
 
   /* Make sure we report all signals during startup.  */
-  linux_nat_pass_signals (ops, 0, NULL);
+  pass_signals (0, NULL);
 
-  linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
+  inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty);
 }
 
 /* Callback for linux_proc_attach_tgid_threads.  Attach to PTID if not
@@ -1207,19 +1199,19 @@  attach_proc_task_lwp_callback (ptid_t ptid)
   return 0;
 }
 
-static void
-linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
+void
+linux_nat_target::attach (const char *args, int from_tty)
 {
   struct lwp_info *lp;
   int status;
   ptid_t ptid;
 
   /* Make sure we report all signals during attach.  */
-  linux_nat_pass_signals (ops, 0, NULL);
+  pass_signals (0, NULL);
 
   TRY
     {
-      linux_ops->to_attach (ops, args, from_tty);
+      inf_ptrace_target::attach (args, from_tty);
     }
   CATCH (ex, RETURN_MASK_ERROR)
     {
@@ -1496,8 +1488,8 @@  detach_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
-static void
-linux_nat_detach (struct target_ops *ops, inferior *inf, int from_tty)
+void
+linux_nat_target::detach (inferior *inf, int from_tty)
 {
   struct lwp_info *main_lwp;
   int pid = inf->pid;
@@ -1536,7 +1528,7 @@  linux_nat_detach (struct target_ops *ops, inferior *inf, int from_tty)
 
       detach_one_lwp (main_lwp, &signo);
 
-      inf_ptrace_detach_success (ops, inf);
+      detach_success (inf);
     }
 }
 
@@ -1563,7 +1555,7 @@  linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
 
   if (linux_nat_prepare_to_resume != NULL)
     linux_nat_prepare_to_resume (lp);
-  linux_ops->to_resume (linux_ops, lp->ptid, step, signo);
+  linux_target->low_resume (lp->ptid, step, signo);
 
   /* Successfully resumed.  Clear state that no longer makes sense,
      and mark the LWP as running.  Must not do this before resuming
@@ -1716,9 +1708,8 @@  resume_set_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
-static void
-linux_nat_resume (struct target_ops *ops,
-		  ptid_t ptid, int step, enum gdb_signal signo)
+void
+linux_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
 {
   struct lwp_info *lp;
   int resume_many;
@@ -2117,7 +2108,7 @@  linux_handle_extended_wait (struct lwp_info *lp, int status)
 
       ourstatus->kind = TARGET_WAITKIND_EXECD;
       ourstatus->value.execd_pathname
-	= xstrdup (linux_child_pid_to_exec_file (NULL, pid));
+	= xstrdup (linux_proc_pid_to_exec_file (pid));
 
       /* The thread that execed must have been resumed, but, when a
 	 thread execs, it changes its tid to the tgid, and the old
@@ -2468,22 +2459,14 @@  maybe_clear_ignore_sigint (struct lwp_info *lp)
 static int
 check_stopped_by_watchpoint (struct lwp_info *lp)
 {
-  if (linux_ops->to_stopped_by_watchpoint == NULL)
-    return 0;
-
   scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
   inferior_ptid = lp->ptid;
 
-  if (linux_ops->to_stopped_by_watchpoint (linux_ops))
+  if (linux_target->low_stopped_by_watchpoint ())
     {
       lp->stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
-
-      if (linux_ops->to_stopped_data_address != NULL)
-	lp->stopped_data_address_p =
-	  linux_ops->to_stopped_data_address (&current_target,
-					      &lp->stopped_data_address);
-      else
-	lp->stopped_data_address_p = 0;
+      lp->stopped_data_address_p
+	= linux_target->low_stopped_data_address (&lp->stopped_data_address);
     }
 
   return lp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
@@ -2491,8 +2474,8 @@  check_stopped_by_watchpoint (struct lwp_info *lp)
 
 /* Returns true if the LWP had stopped for a watchpoint.  */
 
-static int
-linux_nat_stopped_by_watchpoint (struct target_ops *ops)
+int
+linux_nat_target::stopped_by_watchpoint ()
 {
   struct lwp_info *lp = find_lwp_pid (inferior_ptid);
 
@@ -2501,8 +2484,8 @@  linux_nat_stopped_by_watchpoint (struct target_ops *ops)
   return lp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
 }
 
-static int
-linux_nat_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+int
+linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
 {
   struct lwp_info *lp = find_lwp_pid (inferior_ptid);
 
@@ -2852,8 +2835,8 @@  save_stop_reason (struct lwp_info *lp)
 
 /* Returns true if the LWP had stopped for a software breakpoint.  */
 
-static int
-linux_nat_stopped_by_sw_breakpoint (struct target_ops *ops)
+int
+linux_nat_target::stopped_by_sw_breakpoint ()
 {
   struct lwp_info *lp = find_lwp_pid (inferior_ptid);
 
@@ -2864,8 +2847,8 @@  linux_nat_stopped_by_sw_breakpoint (struct target_ops *ops)
 
 /* Implement the supports_stopped_by_sw_breakpoint method.  */
 
-static int
-linux_nat_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+int
+linux_nat_target::supports_stopped_by_sw_breakpoint ()
 {
   return USE_SIGTRAP_SIGINFO;
 }
@@ -2873,8 +2856,8 @@  linux_nat_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
 /* Returns true if the LWP had stopped for a hardware
    breakpoint/watchpoint.  */
 
-static int
-linux_nat_stopped_by_hw_breakpoint (struct target_ops *ops)
+int
+linux_nat_target::stopped_by_hw_breakpoint ()
 {
   struct lwp_info *lp = find_lwp_pid (inferior_ptid);
 
@@ -2885,8 +2868,8 @@  linux_nat_stopped_by_hw_breakpoint (struct target_ops *ops)
 
 /* Implement the supports_stopped_by_hw_breakpoint method.  */
 
-static int
-linux_nat_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
+int
+linux_nat_target::supports_stopped_by_hw_breakpoint ()
 {
   return USE_SIGTRAP_SIGINFO;
 }
@@ -3297,8 +3280,7 @@  filter_exit_event (struct lwp_info *event_child,
 }
 
 static ptid_t
-linux_nat_wait_1 (struct target_ops *ops,
-		  ptid_t ptid, struct target_waitstatus *ourstatus,
+linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
 		  int target_options)
 {
   sigset_t prev_mask;
@@ -3600,10 +3582,9 @@  resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
   return 0;
 }
 
-static ptid_t
-linux_nat_wait (struct target_ops *ops,
-		ptid_t ptid, struct target_waitstatus *ourstatus,
-		int target_options)
+ptid_t
+linux_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+			int target_options)
 {
   ptid_t event_ptid;
 
@@ -3633,7 +3614,7 @@  linux_nat_wait (struct target_ops *ops,
   if (target_is_non_stop_p ())
     iterate_over_lwps (minus_one_ptid, resume_stopped_resumed_lwps, &ptid);
 
-  event_ptid = linux_nat_wait_1 (ops, ptid, ourstatus, target_options);
+  event_ptid = linux_nat_wait_1 (ptid, ourstatus, target_options);
 
   /* If we requested any event, and something came out, assume there
      may be more.  If we requested a specific lwp or process, also
@@ -3759,8 +3740,8 @@  kill_unfollowed_fork_children (struct inferior *inf)
       }
 }
 
-static void
-linux_nat_kill (struct target_ops *ops)
+void
+linux_nat_target::kill ()
 {
   /* If we're stopped while forking and we haven't followed yet,
      kill the other task.  We need to do this first because the
@@ -3790,8 +3771,8 @@  linux_nat_kill (struct target_ops *ops)
   target_mourn_inferior (inferior_ptid);
 }
 
-static void
-linux_nat_mourn_inferior (struct target_ops *ops)
+void
+linux_nat_target::mourn_inferior ()
 {
   int pid = ptid_get_pid (inferior_ptid);
 
@@ -3799,7 +3780,7 @@  linux_nat_mourn_inferior (struct target_ops *ops)
 
   if (! forks_exist_p ())
     /* Normal case, no other forks available.  */
-    linux_ops->to_mourn_inferior (ops);
+    inf_ptrace_target::mourn_inferior ();
   else
     /* Multi-fork case.  The current inferior_ptid has exited, but
        there are other viable forks to debug.  Delete the exiting
@@ -3833,7 +3814,7 @@  siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
 }
 
 static enum target_xfer_status
-linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
+linux_xfer_siginfo (enum target_object object,
                     const char *annex, gdb_byte *readbuf,
 		    const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
 		    ULONGEST *xfered_len)
@@ -3888,15 +3869,33 @@  linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
 }
 
 static enum target_xfer_status
-linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
-			const char *annex, gdb_byte *readbuf,
-			const gdb_byte *writebuf,
-			ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
+linux_nat_xfer_osdata (enum target_object object,
+		       const char *annex, gdb_byte *readbuf,
+		       const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
+		       ULONGEST *xfered_len);
+
+static enum target_xfer_status
+linux_proc_xfer_spu (enum target_object object,
+		     const char *annex, gdb_byte *readbuf,
+		     const gdb_byte *writebuf,
+		     ULONGEST offset, ULONGEST len, ULONGEST *xfered_len);
+
+static enum target_xfer_status
+linux_proc_xfer_partial (enum target_object object,
+			 const char *annex, gdb_byte *readbuf,
+			 const gdb_byte *writebuf,
+			 ULONGEST offset, LONGEST len, ULONGEST *xfered_len);
+
+enum target_xfer_status
+linux_nat_target::xfer_partial (enum target_object object,
+				const char *annex, gdb_byte *readbuf,
+				const gdb_byte *writebuf,
+				ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
 {
   enum target_xfer_status xfer;
 
   if (object == TARGET_OBJECT_SIGNAL_INFO)
-    return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf,
+    return linux_xfer_siginfo (object, annex, readbuf, writebuf,
 			       offset, len, xfered_len);
 
   /* The target is connected but no live inferior is selected.  Pass
@@ -3905,14 +3904,44 @@  linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
   if (object == TARGET_OBJECT_MEMORY && ptid_equal (inferior_ptid, null_ptid))
     return TARGET_XFER_EOF;
 
-  xfer = linux_ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
-				     offset, len, xfered_len);
+  if (object == TARGET_OBJECT_AUXV)
+    return memory_xfer_auxv (this, object, annex, readbuf, writebuf,
+			     offset, len, xfered_len);
+
+  if (object == TARGET_OBJECT_OSDATA)
+    return linux_nat_xfer_osdata (object, annex, readbuf, writebuf,
+				  offset, len, xfered_len);
 
-  return xfer;
+  if (object == TARGET_OBJECT_SPU)
+    return linux_proc_xfer_spu (object, annex, readbuf, writebuf,
+				offset, len, xfered_len);
+
+  /* GDB calculates all addresses in the largest possible address
+     width.
+     The address width must be masked before its final use - either by
+     linux_proc_xfer_partial or inf_ptrace_target::xfer_partial.
+
+     Compare ADDR_BIT first to avoid a compiler warning on shift overflow.  */
+
+  if (object == TARGET_OBJECT_MEMORY)
+    {
+      int addr_bit = gdbarch_addr_bit (target_gdbarch ());
+
+      if (addr_bit < (sizeof (ULONGEST) * HOST_CHAR_BIT))
+	offset &= ((ULONGEST) 1 << addr_bit) - 1;
+    }
+
+  xfer = linux_proc_xfer_partial (object, annex, readbuf, writebuf,
+				  offset, len, xfered_len);
+  if (xfer != TARGET_XFER_EOF)
+    return xfer;
+
+  return inf_ptrace_target::xfer_partial (object, annex, readbuf, writebuf,
+					  offset, len, xfered_len);
 }
 
-static int
-linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid)
+int
+linux_nat_target::thread_alive (ptid_t ptid)
 {
   /* As long as a PTID is in lwp list, consider it alive.  */
   return find_lwp_pid (ptid) != NULL;
@@ -3921,8 +3950,8 @@  linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid)
 /* Implement the to_update_thread_list target method for this
    target.  */
 
-static void
-linux_nat_update_thread_list (struct target_ops *ops)
+void
+linux_nat_target::update_thread_list ()
 {
   struct lwp_info *lwp;
 
@@ -3943,8 +3972,8 @@  linux_nat_update_thread_list (struct target_ops *ops)
     }
 }
 
-static const char *
-linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
+const char *
+linux_nat_target::pid_to_str (ptid_t ptid)
 {
   static char buf[64];
 
@@ -3959,8 +3988,8 @@  linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
-static const char *
-linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
+const char *
+linux_nat_target::thread_name (struct thread_info *thr)
 {
   return linux_proc_tid_get_name (thr->ptid);
 }
@@ -3968,8 +3997,8 @@  linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
-static char *
-linux_child_pid_to_exec_file (struct target_ops *self, int pid)
+char *
+linux_nat_target::pid_to_exec_file (int pid)
 {
   return linux_proc_pid_to_exec_file (pid);
 }
@@ -3979,7 +4008,7 @@  linux_child_pid_to_exec_file (struct target_ops *self, int pid)
    efficient than banging away at PTRACE_PEEKTEXT.  */
 
 static enum target_xfer_status
-linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
+linux_proc_xfer_partial (enum target_object object,
 			 const char *annex, gdb_byte *readbuf,
 			 const gdb_byte *writebuf,
 			 ULONGEST offset, LONGEST len, ULONGEST *xfered_len)
@@ -4083,7 +4112,7 @@  spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, ULONGEST len)
    object type, using the /proc file system.  */
 
 static enum target_xfer_status
-linux_proc_xfer_spu (struct target_ops *ops, enum target_object object,
+linux_proc_xfer_spu (enum target_object object,
 		     const char *annex, gdb_byte *readbuf,
 		     const gdb_byte *writebuf,
 		     ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
@@ -4223,7 +4252,7 @@  linux_proc_pending_signals (int pid, sigset_t *pending,
 }
 
 static enum target_xfer_status
-linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
+linux_nat_xfer_osdata (enum target_object object,
 		       const char *annex, gdb_byte *readbuf,
 		       const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
 		       ULONGEST *xfered_len)
@@ -4237,49 +4266,6 @@  linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
     return TARGET_XFER_OK;
 }
 
-static enum target_xfer_status
-linux_xfer_partial (struct target_ops *ops, enum target_object object,
-                    const char *annex, gdb_byte *readbuf,
-		    const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
-		    ULONGEST *xfered_len)
-{
-  enum target_xfer_status xfer;
-
-  if (object == TARGET_OBJECT_AUXV)
-    return memory_xfer_auxv (ops, object, annex, readbuf, writebuf,
-			     offset, len, xfered_len);
-
-  if (object == TARGET_OBJECT_OSDATA)
-    return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
-				  offset, len, xfered_len);
-
-  if (object == TARGET_OBJECT_SPU)
-    return linux_proc_xfer_spu (ops, object, annex, readbuf, writebuf,
-				offset, len, xfered_len);
-
-  /* GDB calculates all the addresses in possibly larget width of the address.
-     Address width needs to be masked before its final use - either by
-     linux_proc_xfer_partial or inf_ptrace_xfer_partial.
-
-     Compare ADDR_BIT first to avoid a compiler warning on shift overflow.  */
-
-  if (object == TARGET_OBJECT_MEMORY)
-    {
-      int addr_bit = gdbarch_addr_bit (target_gdbarch ());
-
-      if (addr_bit < (sizeof (ULONGEST) * HOST_CHAR_BIT))
-	offset &= ((ULONGEST) 1 << addr_bit) - 1;
-    }
-
-  xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
-				  offset, len, xfered_len);
-  if (xfer != TARGET_XFER_EOF)
-    return xfer;
-
-  return super_xfer_partial (ops, object, annex, readbuf, writebuf,
-			     offset, len, xfered_len);
-}
-
 static void
 cleanup_target_stop (void *arg)
 {
@@ -4291,9 +4277,8 @@  cleanup_target_stop (void *arg)
   target_continue_no_signal (*ptid);
 }
 
-static std::vector<static_tracepoint_marker>
-linux_child_static_tracepoint_markers_by_strid (struct target_ops *self,
-						const char *strid)
+std::vector<static_tracepoint_marker>
+linux_nat_target::static_tracepoint_markers_by_strid (const char *strid)
 {
   char s[IPA_CMD_BUF_SIZE];
   struct cleanup *old_chain;
@@ -4335,70 +4320,34 @@  linux_child_static_tracepoint_markers_by_strid (struct target_ops *self,
   return markers;
 }
 
-/* Create a prototype generic GNU/Linux target.  The client can override
-   it with local methods.  */
-
-void
-linux_target_install_ops (struct target_ops *t)
-{
-  t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
-  t->to_remove_fork_catchpoint = linux_child_remove_fork_catchpoint;
-  t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
-  t->to_remove_vfork_catchpoint = linux_child_remove_vfork_catchpoint;
-  t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
-  t->to_remove_exec_catchpoint = linux_child_remove_exec_catchpoint;
-  t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint;
-  t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
-  t->to_post_startup_inferior = linux_child_post_startup_inferior;
-  t->to_post_attach = linux_child_post_attach;
-  t->to_follow_fork = linux_child_follow_fork;
-
-  super_xfer_partial = t->to_xfer_partial;
-  t->to_xfer_partial = linux_xfer_partial;
-
-  t->to_static_tracepoint_markers_by_strid
-    = linux_child_static_tracepoint_markers_by_strid;
-}
-
-struct target_ops *
-linux_target (void)
-{
-  struct target_ops *t;
-
-  t = inf_ptrace_target ();
-  linux_target_install_ops (t);
-
-  return t;
-}
-
 /* target_is_async_p implementation.  */
 
-static int
-linux_nat_is_async_p (struct target_ops *ops)
+int
+linux_nat_target::is_async_p ()
 {
   return linux_is_async_p ();
 }
 
 /* target_can_async_p implementation.  */
 
-static int
-linux_nat_can_async_p (struct target_ops *ops)
+int
+linux_nat_target::can_async_p ()
 {
   /* We're always async, unless the user explicitly prevented it with the
      "maint set target-async" command.  */
   return target_async_permitted;
 }
 
-static int
-linux_nat_supports_non_stop (struct target_ops *self)
+int
+linux_nat_target::supports_non_stop ()
 {
   return 1;
 }
 
 /* to_always_non_stop_p implementation.  */
 
-static int
-linux_nat_always_non_stop_p (struct target_ops *self)
+int
+linux_nat_target::always_non_stop_p ()
 {
   return 1;
 }
@@ -4408,14 +4357,14 @@  linux_nat_always_non_stop_p (struct target_ops *self)
 
 int linux_multi_process = 1;
 
-static int
-linux_nat_supports_multi_process (struct target_ops *self)
+int
+linux_nat_target::supports_multi_process ()
 {
   return linux_multi_process;
 }
 
-static int
-linux_nat_supports_disable_randomization (struct target_ops *self)
+int
+linux_nat_target::supports_disable_randomization ()
 {
 #ifdef HAVE_PERSONALITY
   return 1;
@@ -4494,8 +4443,8 @@  linux_async_pipe (int enable)
 
 /* target_async implementation.  */
 
-static void
-linux_nat_async (struct target_ops *ops, int enable)
+void
+linux_nat_target::async (int enable)
 {
   if (enable)
     {
@@ -4563,23 +4512,20 @@  linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
   return 0;
 }
 
-static void
-linux_nat_stop (struct target_ops *self, ptid_t ptid)
+void
+linux_nat_target::stop (ptid_t ptid)
 {
   iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
 }
 
-static void
-linux_nat_close (struct target_ops *self)
+void
+linux_nat_target::close ()
 {
   /* Unregister from the event loop.  */
-  if (linux_nat_is_async_p (self))
-    linux_nat_async (self, 0);
+  if (is_async_p ())
+    async (0);
 
-  if (linux_ops->to_close)
-    linux_ops->to_close (linux_ops);
-
-  super_close (self);
+  inf_ptrace_target::close ();
 }
 
 /* When requests are passed down from the linux-nat layer to the
@@ -4589,8 +4535,8 @@  linux_nat_close (struct target_ops *self)
    lwpid is a "main" process id or not (it assumes so).  We reverse
    look up the "main" process id from the lwp here.  */
 
-static struct address_space *
-linux_nat_thread_address_space (struct target_ops *t, ptid_t ptid)
+struct address_space *
+linux_nat_target::thread_address_space (ptid_t ptid)
 {
   struct lwp_info *lwp;
   struct inferior *inf;
@@ -4616,8 +4562,8 @@  linux_nat_thread_address_space (struct target_ops *t, ptid_t ptid)
 
 /* Return the cached value of the processor core for thread PTID.  */
 
-static int
-linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
+int
+linux_nat_target::core_of_thread (ptid_t ptid)
 {
   struct lwp_info *info = find_lwp_pid (ptid);
 
@@ -4628,8 +4574,8 @@  linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
 
 /* Implementation of to_filesystem_is_local.  */
 
-static int
-linux_nat_filesystem_is_local (struct target_ops *ops)
+int
+linux_nat_target::filesystem_is_local ()
 {
   struct inferior *inf = current_inferior ();
 
@@ -4658,11 +4604,10 @@  linux_nat_fileio_pid_of (struct inferior *inf)
 
 /* Implementation of to_fileio_open.  */
 
-static int
-linux_nat_fileio_open (struct target_ops *self,
-		       struct inferior *inf, const char *filename,
-		       int flags, int mode, int warn_if_slow,
-		       int *target_errno)
+int
+linux_nat_target::fileio_open (struct inferior *inf, const char *filename,
+			       int flags, int mode, int warn_if_slow,
+			       int *target_errno)
 {
   int nat_flags;
   mode_t nat_mode;
@@ -4685,10 +4630,9 @@  linux_nat_fileio_open (struct target_ops *self,
 
 /* Implementation of to_fileio_readlink.  */
 
-static gdb::optional<std::string>
-linux_nat_fileio_readlink (struct target_ops *self,
-			   struct inferior *inf, const char *filename,
-			   int *target_errno)
+gdb::optional<std::string>
+linux_nat_target::fileio_readlink (struct inferior *inf, const char *filename,
+				   int *target_errno)
 {
   char buf[PATH_MAX];
   int len;
@@ -4706,10 +4650,9 @@  linux_nat_fileio_readlink (struct target_ops *self,
 
 /* Implementation of to_fileio_unlink.  */
 
-static int
-linux_nat_fileio_unlink (struct target_ops *self,
-			 struct inferior *inf, const char *filename,
-			 int *target_errno)
+int
+linux_nat_target::fileio_unlink (struct inferior *inf, const char *filename,
+				 int *target_errno)
 {
   int ret;
 
@@ -4723,76 +4666,19 @@  linux_nat_fileio_unlink (struct target_ops *self,
 
 /* Implementation of the to_thread_events method.  */
 
-static void
-linux_nat_thread_events (struct target_ops *ops, int enable)
+void
+linux_nat_target::thread_events (int enable)
 {
   report_thread_events = enable;
 }
 
-void
-linux_nat_add_target (struct target_ops *t)
-{
-  /* Save the provided single-threaded target.  We save this in a separate
-     variable because another target we've inherited from (e.g. inf-ptrace)
-     may have saved a pointer to T; we want to use it for the final
-     process stratum target.  */
-  linux_ops_saved = *t;
-  linux_ops = &linux_ops_saved;
-
-  /* Override some methods for multithreading.  */
-  t->to_create_inferior = linux_nat_create_inferior;
-  t->to_attach = linux_nat_attach;
-  t->to_detach = linux_nat_detach;
-  t->to_resume = linux_nat_resume;
-  t->to_wait = linux_nat_wait;
-  t->to_pass_signals = linux_nat_pass_signals;
-  t->to_xfer_partial = linux_nat_xfer_partial;
-  t->to_kill = linux_nat_kill;
-  t->to_mourn_inferior = linux_nat_mourn_inferior;
-  t->to_thread_alive = linux_nat_thread_alive;
-  t->to_update_thread_list = linux_nat_update_thread_list;
-  t->to_pid_to_str = linux_nat_pid_to_str;
-  t->to_thread_name = linux_nat_thread_name;
-  t->to_has_thread_control = tc_schedlock;
-  t->to_thread_address_space = linux_nat_thread_address_space;
-  t->to_stopped_by_watchpoint = linux_nat_stopped_by_watchpoint;
-  t->to_stopped_data_address = linux_nat_stopped_data_address;
-  t->to_stopped_by_sw_breakpoint = linux_nat_stopped_by_sw_breakpoint;
-  t->to_supports_stopped_by_sw_breakpoint = linux_nat_supports_stopped_by_sw_breakpoint;
-  t->to_stopped_by_hw_breakpoint = linux_nat_stopped_by_hw_breakpoint;
-  t->to_supports_stopped_by_hw_breakpoint = linux_nat_supports_stopped_by_hw_breakpoint;
-  t->to_thread_events = linux_nat_thread_events;
-
-  t->to_can_async_p = linux_nat_can_async_p;
-  t->to_is_async_p = linux_nat_is_async_p;
-  t->to_supports_non_stop = linux_nat_supports_non_stop;
-  t->to_always_non_stop_p = linux_nat_always_non_stop_p;
-  t->to_async = linux_nat_async;
-
-  super_close = t->to_close;
-  t->to_close = linux_nat_close;
-
-  t->to_stop = linux_nat_stop;
-
-  t->to_supports_multi_process = linux_nat_supports_multi_process;
-
-  t->to_supports_disable_randomization
-    = linux_nat_supports_disable_randomization;
-
-  t->to_core_of_thread = linux_nat_core_of_thread;
-
-  t->to_filesystem_is_local = linux_nat_filesystem_is_local;
-  t->to_fileio_open = linux_nat_fileio_open;
-  t->to_fileio_readlink = linux_nat_fileio_readlink;
-  t->to_fileio_unlink = linux_nat_fileio_unlink;
-
+linux_nat_target::linux_nat_target ()
+{
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable
      target, but we want to be on the stack below thread_db, and we
      also want to be used for single-threaded processes.  */
-
-  add_target (t);
 }
 
 /* Register a method to call whenever a new thread is attached.  */
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 03c2021911..da5357a21e 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -18,9 +18,138 @@ 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "nat/linux-nat.h"
+#include "inf-ptrace.h"
 #include "target.h"
 #include <signal.h>
 
+/* A prototype generic GNU/Linux target.  A concrete instance should
+   override it with local methods.  */
+
+class linux_nat_target : public inf_ptrace_target
+{
+public:
+  linux_nat_target ();
+  ~linux_nat_target () override = 0;
+
+  thread_control_capabilities get_thread_control_capabilities () override
+  { return tc_schedlock; }
+
+  void create_inferior (const char *, const std::string &,
+			char **, int) override;
+
+  void attach (const char *, int) override;
+
+  void detach (inferior *, int) override;
+
+  void resume (ptid_t, int, enum gdb_signal) override;
+
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+
+  void pass_signals (int, unsigned char *) override;
+
+  enum target_xfer_status xfer_partial (enum target_object object,
+					const char *annex,
+					gdb_byte *readbuf,
+					const gdb_byte *writebuf,
+					ULONGEST offset, ULONGEST len,
+					ULONGEST *xfered_len) override;
+
+  void kill () override;
+
+  void mourn_inferior () override;
+  int thread_alive (ptid_t ptid) override;
+
+  void update_thread_list () override;
+
+  const char *pid_to_str (ptid_t) override;
+
+  const char *thread_name (struct thread_info *) override;
+
+  struct address_space *thread_address_space (ptid_t) override;
+
+  int stopped_by_watchpoint () override;
+
+  int stopped_data_address (CORE_ADDR *) override;
+
+  int stopped_by_sw_breakpoint () override;
+  int supports_stopped_by_sw_breakpoint () override;
+
+  int stopped_by_hw_breakpoint () override;
+  int supports_stopped_by_hw_breakpoint () override;
+
+  void thread_events (int) override;
+
+  int can_async_p () override;
+  int is_async_p () override;
+
+  int supports_non_stop () override;
+  int always_non_stop_p () override;
+
+  void async (int) override;
+
+  void close () override;
+
+  void stop (ptid_t) override;
+
+  int supports_multi_process () override;
+
+  int supports_disable_randomization () override;
+
+  int core_of_thread (ptid_t ptid) override;
+
+  int filesystem_is_local () override;
+
+  int fileio_open (struct inferior *inf, const char *filename,
+		   int flags, int mode, int warn_if_slow,
+		   int *target_errno) override;
+
+  gdb::optional<std::string>
+    fileio_readlink (struct inferior *inf,
+		     const char *filename,
+		     int *target_errno) override;
+
+  int fileio_unlink (struct inferior *inf,
+		     const char *filename,
+		     int *target_errno) override;
+
+  int insert_fork_catchpoint (int) override;
+  int remove_fork_catchpoint (int) override;
+  int insert_vfork_catchpoint (int) override;
+  int remove_vfork_catchpoint (int) override;
+
+  int insert_exec_catchpoint (int) override;
+  int remove_exec_catchpoint (int) override;
+
+  int set_syscall_catchpoint (int pid, bool needed, int any_count,
+			      gdb::array_view<const int> syscall_counts) override;
+
+  char *pid_to_exec_file (int pid) override;
+
+  void post_startup_inferior (ptid_t) override;
+
+  void post_attach (int) override;
+
+  int follow_fork (int, int) override;
+
+  std::vector<static_tracepoint_marker>
+    static_tracepoint_markers_by_strid (const char *id) override;
+
+  /* Methods that are meant to overridden by the concrete
+     arch-specific target instance.  */
+
+  virtual void low_resume (ptid_t ptid, int step, enum gdb_signal sig)
+  { inf_ptrace_target::resume (ptid, step, sig); }
+
+  virtual int low_stopped_by_watchpoint ()
+  { return 0; }
+
+  virtual int low_stopped_data_address (CORE_ADDR *addr_p)
+  { return 0; }
+};
+
+/* The final/concrete instance.  */
+extern linux_nat_target *linux_target;
+
 struct arch_lwp_info;
 
 /* Structure describing an LWP.  This is public only for the purposes
@@ -149,18 +278,6 @@  extern void linux_stop_and_wait_all_lwps (void);
    left stopped.)  */
 extern void linux_unstop_all_lwps (void);
 
-/* Create a prototype generic GNU/Linux target.  The client can
-   override it with local methods.  */
-struct target_ops * linux_target (void);
-
-/* Make a prototype generic GNU/Linux target.  The client can override
-   it with local methods.  */
-void linux_target_install_ops (struct target_ops *t);
-
-/* Register the customized GNU/Linux target.  This should be used
-   instead of calling add_target directly.  */
-void linux_nat_add_target (struct target_ops *);
-
 /* Register a method to call whenever a new thread is attached.  */
 void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *));
 
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 08e3cfbc8b..a7b0772d45 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -75,6 +75,40 @@ 
    of the ptid_t prevents thread IDs changing when libpthread is
    loaded or unloaded.  */
 
+class thread_db_target : public target_ops
+{
+public:
+  thread_db_target ();
+
+  const char *shortname () override
+  { return "multi-thread"; }
+  const char *longname () override
+  { return _("multi-threaded child process."); }
+  const char *doc () override
+  { return _("Threads and pthreads support."); }
+
+  void detach (inferior *, int) override;
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+  void resume (ptid_t, int, enum gdb_signal) override;
+  void mourn_inferior () override;
+  void update_thread_list () override;
+  const char *pid_to_str (ptid_t) override;
+  CORE_ADDR get_thread_local_address (ptid_t ptid,
+				      CORE_ADDR load_module_addr,
+				      CORE_ADDR offset) override;
+  const char *extra_thread_info (struct thread_info *) override;
+  ptid_t get_ada_task_ptid (long lwp, long thread) override;
+
+  thread_info *thread_handle_to_thread_info (const gdb_byte *thread_handle,
+					     int handle_len,
+					     inferior *inf) override;
+};
+
+thread_db_target::thread_db_target()
+{
+  this->to_stratum = thread_stratum;
+}
+
 static char *libthread_db_search_path;
 
 /* Set to non-zero if thread_db auto-loading is enabled
@@ -118,7 +152,7 @@  show_libthread_db_debug (struct ui_file *file, int from_tty,
    threads.  */
 
 /* This module's target vector.  */
-static struct target_ops thread_db_ops;
+static thread_db_target the_thread_db_target;
 
 /* Non-zero if we have determined the signals used by the threads
    library.  */
@@ -635,7 +669,7 @@  try_thread_db_load_1 (struct thread_db_info *info)
   /* The thread library was detected.  Activate the thread_db target
      if this is the first process using it.  */
   if (thread_db_list->next == NULL)
-    push_target (&thread_db_ops);
+    push_target (&the_thread_db_target);
 
   return 1;
 }
@@ -889,7 +923,7 @@  thread_db_load (void)
     return 0;
 
   /* Don't attempt to use thread_db for remote targets.  */
-  if (!(target_can_run (&current_target) || core_bfd))
+  if (!(target_can_run () || core_bfd))
     return 0;
 
   if (thread_db_load_search ())
@@ -980,7 +1014,7 @@  static void
 check_pid_namespace_match (void)
 {
   /* Check is only relevant for local targets targets.  */
-  if (target_can_run (&current_target))
+  if (target_can_run ())
     {
       /* If the child is in a different PID namespace, its idea of its
 	 PID will differ from our idea of its PID.  When we scan the
@@ -1055,32 +1089,31 @@  record_thread (struct thread_db_info *info,
   return tp;
 }
 
-static void
-thread_db_detach (struct target_ops *ops, inferior *inf, int from_tty)
+void
+thread_db_target::detach (inferior *inf, int from_tty)
 {
-  struct target_ops *target_beneath = find_target_beneath (ops);
+  struct target_ops *target_beneath = find_target_beneath (this);
 
   delete_thread_db_info (inf->pid);
 
-  target_beneath->to_detach (target_beneath, inf, from_tty);
+  target_beneath->detach (inf, from_tty);
 
   /* NOTE: From this point on, inferior_ptid is null_ptid.  */
 
   /* If there are no more processes using libpthread, detach the
      thread_db target ops.  */
   if (!thread_db_list)
-    unpush_target (&thread_db_ops);
+    unpush_target (this);
 }
 
-static ptid_t
-thread_db_wait (struct target_ops *ops,
-		ptid_t ptid, struct target_waitstatus *ourstatus,
-		int options)
+ptid_t
+thread_db_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+			int options)
 {
   struct thread_db_info *info;
-  struct target_ops *beneath = find_target_beneath (ops);
+  struct target_ops *beneath = find_target_beneath (this);
 
-  ptid = beneath->to_wait (beneath, ptid, ourstatus, options);
+  ptid = beneath->wait (ptid, ourstatus, options);
 
   switch (ourstatus->kind)
     {
@@ -1103,7 +1136,7 @@  thread_db_wait (struct target_ops *ops,
 	 not unless we find otherwise.  */
       delete_thread_db_info (ptid_get_pid (ptid));
       if (!thread_db_list)
- 	unpush_target (&thread_db_ops);
+	unpush_target (&the_thread_db_target);
 
       return ptid;
     }
@@ -1114,18 +1147,18 @@  thread_db_wait (struct target_ops *ops,
   return ptid;
 }
 
-static void
-thread_db_mourn_inferior (struct target_ops *ops)
+void
+thread_db_target::mourn_inferior ()
 {
-  struct target_ops *target_beneath = find_target_beneath (ops);
+  struct target_ops *target_beneath = find_target_beneath (this);
 
   delete_thread_db_info (ptid_get_pid (inferior_ptid));
 
-  target_beneath->to_mourn_inferior (target_beneath);
+  target_beneath->mourn_inferior ();
 
   /* Detach thread_db target ops.  */
   if (!thread_db_list)
-    unpush_target (ops);
+    unpush_target (&the_thread_db_target);
 }
 
 struct callback_data
@@ -1293,8 +1326,8 @@  thread_db_find_new_threads_1 (ptid_t ptid)
 /* Implement the to_update_thread_list target method for this
    target.  */
 
-static void
-thread_db_update_thread_list (struct target_ops *ops)
+void
+thread_db_target::update_thread_list ()
 {
   struct thread_db_info *info;
   struct inferior *inf;
@@ -1334,11 +1367,11 @@  thread_db_update_thread_list (struct target_ops *ops)
     }
 
   /* Give the beneath target a chance to do extra processing.  */
-  ops->beneath->to_update_thread_list (ops->beneath);
+  this->beneath->update_thread_list ();
 }
 
-static const char *
-thread_db_pid_to_str (struct target_ops *ops, ptid_t ptid)
+const char *
+thread_db_target::pid_to_str (ptid_t ptid)
 {
   struct thread_info *thread_info = find_thread_ptid (ptid);
   struct target_ops *beneath;
@@ -1354,16 +1387,15 @@  thread_db_pid_to_str (struct target_ops *ops, ptid_t ptid)
       return buf;
     }
 
-  beneath = find_target_beneath (ops);
-  return beneath->to_pid_to_str (beneath, ptid);
+  beneath = find_target_beneath (this);
+  return beneath->pid_to_str (ptid);
 }
 
 /* Return a string describing the state of the thread specified by
    INFO.  */
 
-static const char *
-thread_db_extra_thread_info (struct target_ops *self,
-			     struct thread_info *info)
+const char *
+thread_db_target::extra_thread_info (thread_info *info)
 {
   if (info->priv == NULL)
     return NULL;
@@ -1379,11 +1411,10 @@  thread_db_extra_thread_info (struct target_ops *self,
 /* Return pointer to the thread_info struct which corresponds to
    THREAD_HANDLE (having length HANDLE_LEN).  */
 
-static struct thread_info *
-thread_db_thread_handle_to_thread_info (struct target_ops *ops,
-					const gdb_byte *thread_handle,
-					int handle_len,
-					struct inferior *inf)
+thread_info *
+thread_db_target::thread_handle_to_thread_info (const gdb_byte *thread_handle,
+						int handle_len,
+						inferior *inf)
 {
   struct thread_info *tp;
   thread_t handle_tid;
@@ -1412,11 +1443,10 @@  thread_db_thread_handle_to_thread_info (struct target_ops *ops,
 /* Get the address of the thread local variable in load module LM which
    is stored at OFFSET within the thread local storage for thread PTID.  */
 
-static CORE_ADDR
-thread_db_get_thread_local_address (struct target_ops *ops,
-				    ptid_t ptid,
-				    CORE_ADDR lm,
-				    CORE_ADDR offset)
+CORE_ADDR
+thread_db_target::get_thread_local_address (ptid_t ptid,
+					    CORE_ADDR lm,
+					    CORE_ADDR offset)
 {
   struct thread_info *thread_info;
   struct target_ops *beneath;
@@ -1491,24 +1521,23 @@  thread_db_get_thread_local_address (struct target_ops *ops,
 	      : (CORE_ADDR) (uintptr_t) address);
     }
 
-  beneath = find_target_beneath (ops);
-  return beneath->to_get_thread_local_address (beneath, ptid, lm, offset);
+  beneath = find_target_beneath (this);
+  return beneath->get_thread_local_address (ptid, lm, offset);
 }
 
 /* Implement the to_get_ada_task_ptid target method for this target.  */
 
-static ptid_t
-thread_db_get_ada_task_ptid (struct target_ops *self, long lwp, long thread)
+ptid_t
+thread_db_target::get_ada_task_ptid (long lwp, long thread)
 {
   /* NPTL uses a 1:1 model, so the LWP id suffices.  */
   return ptid_build (ptid_get_pid (inferior_ptid), lwp, 0);
 }
 
-static void
-thread_db_resume (struct target_ops *ops,
-		  ptid_t ptid, int step, enum gdb_signal signo)
+void
+thread_db_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
 {
-  struct target_ops *beneath = find_target_beneath (ops);
+  struct target_ops *beneath = find_target_beneath (this);
   struct thread_db_info *info;
 
   if (ptid_equal (ptid, minus_one_ptid))
@@ -1522,7 +1551,7 @@  thread_db_resume (struct target_ops *ops,
   if (info)
     info->need_stale_parent_threads_check = 0;
 
-  beneath->to_resume (beneath, ptid, step, signo);
+  beneath->resume (ptid, step, signo);
 }
 
 /* std::sort helper function for info_auto_load_libthread_db, sort the
@@ -1637,35 +1666,9 @@  info_auto_load_libthread_db (const char *args, int from_tty)
     uiout->message (_("No auto-loaded libthread-db.\n"));
 }
 
-static void
-init_thread_db_ops (void)
-{
-  thread_db_ops.to_shortname = "multi-thread";
-  thread_db_ops.to_longname = "multi-threaded child process.";
-  thread_db_ops.to_doc = "Threads and pthreads support.";
-  thread_db_ops.to_detach = thread_db_detach;
-  thread_db_ops.to_wait = thread_db_wait;
-  thread_db_ops.to_resume = thread_db_resume;
-  thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
-  thread_db_ops.to_update_thread_list = thread_db_update_thread_list;
-  thread_db_ops.to_pid_to_str = thread_db_pid_to_str;
-  thread_db_ops.to_stratum = thread_stratum;
-  thread_db_ops.to_has_thread_control = tc_schedlock;
-  thread_db_ops.to_get_thread_local_address
-    = thread_db_get_thread_local_address;
-  thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info;
-  thread_db_ops.to_get_ada_task_ptid = thread_db_get_ada_task_ptid;
-  thread_db_ops.to_thread_handle_to_thread_info = thread_db_thread_handle_to_thread_info;
-  thread_db_ops.to_magic = OPS_MAGIC;
-
-  complete_target_initialization (&thread_db_ops);
-}
-
 void
 _initialize_thread_db (void)
 {
-  init_thread_db_ops ();
-
   /* Defer loading of libthread_db.so until inferior is running.
      This allows gdb to load correct libthread_db for a given
      executable -- there could be multiple versions of glibc,
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index a3bdafffa2..0910d0047e 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -27,7 +27,6 @@ 
 #include <sys/uio.h>
 
 #include "x86-nat.h"
-#include "linux-nat.h"
 #ifndef __x86_64__
 #include "i386-linux-nat.h"
 #endif
@@ -78,14 +77,15 @@  x86_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
 }
 
 
-static void (*super_post_startup_inferior) (struct target_ops *self,
-					    ptid_t ptid);
+x86_linux_nat_target::~x86_linux_nat_target ()
+{
+}
 
-static void
-x86_linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid)
+void
+x86_linux_nat_target::post_startup_inferior (ptid_t ptid)
 {
   x86_cleanup_dregs ();
-  super_post_startup_inferior (self, ptid);
+  linux_nat_target::post_startup_inferior (ptid);
 }
 
 #ifdef __x86_64__
@@ -102,8 +102,8 @@  x86_linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid)
 
 /* Get Linux/x86 target description from running target.  */
 
-static const struct target_desc *
-x86_linux_read_description (struct target_ops *ops)
+const struct target_desc *
+x86_linux_nat_target::read_description ()
 {
   int tid;
   int is_64bit = 0;
@@ -212,9 +212,9 @@  x86_linux_read_description (struct target_ops *ops)
 
 /* Enable branch tracing.  */
 
-static struct btrace_target_info *
-x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid,
-			 const struct btrace_config *conf)
+struct btrace_target_info *
+x86_linux_nat_target::enable_btrace (ptid_t ptid,
+				     const struct btrace_config *conf)
 {
   struct btrace_target_info *tinfo = nullptr;
   TRY
@@ -233,9 +233,8 @@  x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid,
 
 /* Disable branch tracing.  */
 
-static void
-x86_linux_disable_btrace (struct target_ops *self,
-			  struct btrace_target_info *tinfo)
+void
+x86_linux_nat_target::disable_btrace (struct btrace_target_info *tinfo)
 {
   enum btrace_error errcode = linux_disable_btrace (tinfo);
 
@@ -245,28 +244,25 @@  x86_linux_disable_btrace (struct target_ops *self,
 
 /* Teardown branch tracing.  */
 
-static void
-x86_linux_teardown_btrace (struct target_ops *self,
-			   struct btrace_target_info *tinfo)
+void
+x86_linux_nat_target::teardown_btrace (struct btrace_target_info *tinfo)
 {
   /* Ignore errors.  */
   linux_disable_btrace (tinfo);
 }
 
-static enum btrace_error
-x86_linux_read_btrace (struct target_ops *self,
-		       struct btrace_data *data,
-		       struct btrace_target_info *btinfo,
-		       enum btrace_read_type type)
+enum btrace_error
+x86_linux_nat_target::read_btrace (struct btrace_data *data,
+				   struct btrace_target_info *btinfo,
+				   enum btrace_read_type type)
 {
   return linux_read_btrace (data, btinfo, type);
 }
 
 /* See to_btrace_conf in target.h.  */
 
-static const struct btrace_config *
-x86_linux_btrace_conf (struct target_ops *self,
-		       const struct btrace_target_info *btinfo)
+const struct btrace_config *
+x86_linux_nat_target::btrace_conf (const struct btrace_target_info *btinfo)
 {
   return linux_btrace_conf (btinfo);
 }
@@ -315,16 +311,12 @@  x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr)
 }
 
 
-/* Create an x86 GNU/Linux target.  */
+/* Add an x86 GNU/Linux target.  */
 
-struct target_ops *
-x86_linux_create_target (void)
+void
+x86_linux_add_target (linux_nat_target *t)
 {
-  /* Fill in the generic GNU/Linux methods.  */
-  struct target_ops *t = linux_target ();
-
   /* Initialize the debug register function vectors.  */
-  x86_use_watchpoints (t);
   x86_dr_low.set_control = x86_linux_dr_set_control;
   x86_dr_low.set_addr = x86_linux_dr_set_addr;
   x86_dr_low.get_addr = x86_linux_dr_get_addr;
@@ -332,29 +324,7 @@  x86_linux_create_target (void)
   x86_dr_low.get_control = x86_linux_dr_get_control;
   x86_set_debug_register_length (sizeof (void *));
 
-  /* Override the GNU/Linux inferior startup hook.  */
-  super_post_startup_inferior = t->to_post_startup_inferior;
-  t->to_post_startup_inferior = x86_linux_child_post_startup_inferior;
-
-  /* Add the description reader.  */
-  t->to_read_description = x86_linux_read_description;
-
-  /* Add btrace methods.  */
-  t->to_enable_btrace = x86_linux_enable_btrace;
-  t->to_disable_btrace = x86_linux_disable_btrace;
-  t->to_teardown_btrace = x86_linux_teardown_btrace;
-  t->to_read_btrace = x86_linux_read_btrace;
-  t->to_btrace_conf = x86_linux_btrace_conf;
-
-  return t;
-}
-
-/* Add an x86 GNU/Linux target.  */
-
-void
-x86_linux_add_target (struct target_ops *t)
-{
-  linux_nat_add_target (t);
+  add_target (t);
   linux_nat_set_new_thread (t, x86_linux_new_thread);
   linux_nat_set_delete_thread (t, x86_linux_delete_thread);
   linux_nat_set_new_fork (t, x86_linux_new_fork);
diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h
index 383bfd5314..0bafaaa71f 100644
--- a/gdb/x86-linux-nat.h
+++ b/gdb/x86-linux-nat.h
@@ -21,6 +21,44 @@ 
 #define X86_LINUX_NAT_H 1
 
 #include "gdb_proc_service.h"  /* For ps_err_e.  */
+#include "linux-nat.h"
+#include "x86-nat.h"
+
+struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
+{
+  virtual ~x86_linux_nat_target () override = 0;
+
+  /* Override the GNU/Linux inferior startup hook.  */
+  void post_startup_inferior (ptid_t) override;
+
+  /* Add the description reader.  */
+  const struct target_desc *read_description () override;
+
+  struct btrace_target_info *enable_btrace (ptid_t ptid,
+					    const struct btrace_config *conf) override;
+  void disable_btrace (struct btrace_target_info *tinfo) override;
+  void teardown_btrace (struct btrace_target_info *tinfo) override;
+  enum btrace_error read_btrace (struct btrace_data *data,
+				 struct btrace_target_info *btinfo,
+				 enum btrace_read_type type) override;
+  const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;
+
+  /* These two are rewired to low_ versions.  linux-nat.c queries
+     stopped-by-watchpoint info as soon as an lwp stops (via the low_
+     methods) and caches the result, to be returned via the normal
+     non-low methods.  */
+  int stopped_by_watchpoint () override
+  { return linux_nat_target::stopped_by_watchpoint (); }
+
+  int stopped_data_address (CORE_ADDR *addr_p) override
+  { return linux_nat_target::stopped_data_address (addr_p); }
+
+  int low_stopped_by_watchpoint () override
+  { return x86_nat_target::stopped_by_watchpoint (); }
+
+  int low_stopped_data_address (CORE_ADDR *addr_p) override
+  { return x86_nat_target::stopped_data_address (addr_p); }
+};
 
 
 
@@ -32,12 +70,8 @@  extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr,
 					   unsigned int *base_addr);
 
 
-/* Create an x86 GNU/Linux target.  */
-
-extern struct target_ops *x86_linux_create_target (void);
-
 /* Add an x86 GNU/Linux target.  */
 
-extern void x86_linux_add_target (struct target_ops *t);
+extern void x86_linux_add_target (linux_nat_target *t);
 
 #endif
diff --git a/gdb/x86-nat.c b/gdb/x86-nat.c
index bec51373a6..cfd293c17f 100644
--- a/gdb/x86-nat.c
+++ b/gdb/x86-nat.c
@@ -146,8 +146,8 @@  x86_cleanup_dregs (void)
    address ADDR and whose length is LEN bytes.  Watch memory accesses
    of the type TYPE.  Return 0 on success, -1 on failure.  */
 
-static int
-x86_insert_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
+int
+x86_insert_watchpoint (CORE_ADDR addr, int len,
 		       enum target_hw_bp_type type, struct expression *cond)
 {
   struct x86_debug_reg_state *state
@@ -159,8 +159,8 @@  x86_insert_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
 /* Remove a watchpoint that watched the memory region which starts at
    address ADDR, whose length is LEN bytes, and for accesses of the
    type TYPE.  Return 0 on success, -1 on failure.  */
-static int
-x86_remove_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
+int
+x86_remove_watchpoint (CORE_ADDR addr, int len,
 		       enum target_hw_bp_type type, struct expression *cond)
 {
   struct x86_debug_reg_state *state
@@ -172,9 +172,8 @@  x86_remove_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
 /* Return non-zero if we can watch a memory region that starts at
    address ADDR and whose length is LEN bytes.  */
 
-static int
-x86_region_ok_for_watchpoint (struct target_ops *self,
-			      CORE_ADDR addr, int len)
+int
+x86_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
   struct x86_debug_reg_state *state
     = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
@@ -186,8 +185,8 @@  x86_region_ok_for_watchpoint (struct target_ops *self,
    address associated with that break/watchpoint and return non-zero.
    Otherwise, return zero.  */
 
-static int
-x86_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+int
+x86_stopped_data_address (CORE_ADDR *addr_p)
 {
   struct x86_debug_reg_state *state
     = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
@@ -198,8 +197,8 @@  x86_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
 /* Return non-zero if the inferior has some watchpoint that triggered.
    Otherwise return zero.  */
 
-static int
-x86_stopped_by_watchpoint (struct target_ops *ops)
+int
+x86_stopped_by_watchpoint ()
 {
   struct x86_debug_reg_state *state
     = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
@@ -210,9 +209,8 @@  x86_stopped_by_watchpoint (struct target_ops *ops)
 /* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address.
    Return 0 on success, EBUSY on failure.  */
 
-static int
-x86_insert_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch,
-			  struct bp_target_info *bp_tgt)
+int
+x86_insert_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt)
 {
   struct x86_debug_reg_state *state
     = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
@@ -225,8 +223,8 @@  x86_insert_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch,
 /* Remove a hardware-assisted breakpoint at BP_TGT->placed_address.
    Return 0 on success, -1 on failure.  */
 
-static int
-x86_remove_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch,
+int
+x86_remove_hw_breakpoint (struct gdbarch *gdbarch,
 			  struct bp_target_info *bp_tgt)
 {
   struct x86_debug_reg_state *state
@@ -253,9 +251,8 @@  x86_remove_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch,
    virtually unlimited number of watchpoints, due to debug register
    sharing implemented via reference counts in x86-nat.c.  */
 
-static int
-x86_can_use_hw_breakpoint (struct target_ops *self,
-			   enum bptype type, int cnt, int othertype)
+int
+x86_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype)
 {
   return 1;
 }
@@ -263,8 +260,8 @@  x86_can_use_hw_breakpoint (struct target_ops *self,
 /* Return non-zero if the inferior has some breakpoint that triggered.
    Otherwise return zero.  */
 
-static int
-x86_stopped_by_hw_breakpoint (struct target_ops *ops)
+int
+x86_stopped_by_hw_breakpoint ()
 {
   struct x86_debug_reg_state *state
     = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
@@ -291,30 +288,7 @@  triggers a breakpoint or watchpoint."),
 			   &maintenance_show_cmdlist);
 }
 
-/* There are only two global functions left.  */
-
-void
-x86_use_watchpoints (struct target_ops *t)
-{
-  /* After a watchpoint trap, the PC points to the instruction after the
-     one that caused the trap.  Therefore we don't need to step over it.
-     But we do need to reset the status register to avoid another trap.  */
-  t->to_have_continuable_watchpoint = 1;
-
-  t->to_can_use_hw_breakpoint = x86_can_use_hw_breakpoint;
-  t->to_region_ok_for_hw_watchpoint = x86_region_ok_for_watchpoint;
-  t->to_stopped_by_watchpoint = x86_stopped_by_watchpoint;
-  t->to_stopped_data_address = x86_stopped_data_address;
-  t->to_insert_watchpoint = x86_insert_watchpoint;
-  t->to_remove_watchpoint = x86_remove_watchpoint;
-  t->to_insert_hw_breakpoint = x86_insert_hw_breakpoint;
-  t->to_remove_hw_breakpoint = x86_remove_hw_breakpoint;
-
-  /* A target must provide an implementation of the
-     "to_supports_stopped_by_hw_breakpoint" target method before this
-     callback will be used.  */
-  t->to_stopped_by_hw_breakpoint = x86_stopped_by_hw_breakpoint;
-}
+/* See x86-nat.h.  */
 
 void
 x86_set_debug_register_length (int len)
diff --git a/gdb/x86-nat.h b/gdb/x86-nat.h
index 80c7fdfa80..8ad1821360 100644
--- a/gdb/x86-nat.h
+++ b/gdb/x86-nat.h
@@ -23,16 +23,12 @@ 
 #ifndef X86_NAT_H
 #define X86_NAT_H 1
 
+#include "breakpoint.h"
 #include "nat/x86-dregs.h"
+#include "target.h"
 
 /* Hardware-assisted breakpoints and watchpoints.  */
 
-/* Add watchpoint methods to the provided target_ops.  
-   Targets using x86 family debug registers for watchpoints should call
-   this.  */
-struct target_ops;
-extern void x86_use_watchpoints (struct target_ops *);
-
 /* Use this function to set x86_dr_low debug_register_length field
    rather than setting it directly to check that the length is only
    set once.  It also enables the 'maint set/show show-debug-regs' 
@@ -49,4 +45,75 @@  extern void x86_cleanup_dregs (void);
 
 extern void x86_forget_process (pid_t pid);
 
+/* Helper functions used by x86_nat_target below.  See their
+   definitions.  */
+
+extern int x86_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype);
+extern int x86_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len);
+extern int x86_stopped_by_watchpoint ();
+extern int x86_stopped_data_address (CORE_ADDR *addr_p);
+extern int x86_insert_watchpoint (CORE_ADDR addr, int len,
+			   enum target_hw_bp_type type,
+			   struct expression *cond);
+extern int x86_remove_watchpoint (CORE_ADDR addr, int len,
+			   enum target_hw_bp_type type,
+			   struct expression *cond);
+extern int x86_insert_hw_breakpoint (struct gdbarch *gdbarch,
+			      struct bp_target_info *bp_tgt);
+extern int x86_remove_hw_breakpoint (struct gdbarch *gdbarch,
+				     struct bp_target_info *bp_tgt);
+extern int x86_stopped_by_hw_breakpoint ();
+
+/* Convenience template mixin used to add x86 watchpoints support to a
+   target.  */
+
+template <typename BaseTarget>
+struct x86_nat_target : public BaseTarget
+{
+  /* Hook in the x86 hardware watchpoints/breakpoints support.  */
+
+  /* After a watchpoint trap, the PC points to the instruction after
+     the one that caused the trap.  Therefore we don't need to step
+     over it.  But we do need to reset the status register to avoid
+     another trap.  */
+  bool have_continuable_watchpoint () override
+  { return true; }
+
+  int can_use_hw_breakpoint (enum bptype type, int cnt, int othertype) override
+  { return x86_can_use_hw_breakpoint (type, cnt, othertype); }
+
+  int region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) override
+  { return x86_region_ok_for_hw_watchpoint (addr, len); }
+
+  int insert_watchpoint (CORE_ADDR addr, int len,
+			 enum target_hw_bp_type type,
+			 struct expression *cond) override
+  { return x86_insert_watchpoint (addr, len, type, cond); }
+
+  int remove_watchpoint (CORE_ADDR addr, int len,
+			 enum target_hw_bp_type type,
+			 struct expression *cond) override
+  { return x86_remove_watchpoint (addr, len, type, cond); }
+
+  int insert_hw_breakpoint (struct gdbarch *gdbarch,
+			    struct bp_target_info *bp_tgt) override
+  { return x86_insert_hw_breakpoint (gdbarch, bp_tgt); }
+
+  int remove_hw_breakpoint (struct gdbarch *gdbarch,
+			    struct bp_target_info *bp_tgt) override
+  { return x86_remove_hw_breakpoint (gdbarch, bp_tgt); }
+
+  int stopped_by_watchpoint () override
+  { return x86_stopped_by_watchpoint (); }
+
+  int stopped_data_address (CORE_ADDR *addr_p) override
+  { return x86_stopped_data_address (addr_p); }
+
+  /* A target must provide an implementation of the
+     "supports_stopped_by_hw_breakpoint" target method before this
+     callback will be used.  */
+  int stopped_by_hw_breakpoint () override
+  { return x86_stopped_by_hw_breakpoint (); }
+};
+
 #endif /* X86_NAT_H */