[31/40] target_ops/C++: Base FreeBSD target

Message ID 20180414190953.24481-32-palves@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves April 14, 2018, 7:09 p.m. UTC
  The

  $architecture x NetBSD/OpenBSD/FreeBSD

support matrix complicates things a bit.  There's common BSD target
code, and there's common architecture-specific code shared between the
different BSDs.  Current, all that is stiched together to form a final
target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
functions etc.

Introduces a fbsd_nat_target base/prototype target.  To be used in
following patches.
---
 gdb/fbsd-nat.c | 208 ++++++++++++++++++---------------------------------------
 gdb/fbsd-nat.h |  70 ++++++++++++++++++-
 2 files changed, 132 insertions(+), 146 deletions(-)
  

Comments

John Baldwin April 17, 2018, 4:05 p.m. UTC | #1
On Saturday, April 14, 2018 08:09:44 PM Pedro Alves wrote:
> The
> 
>   $architecture x NetBSD/OpenBSD/FreeBSD
> 
> support matrix complicates things a bit.  There's common BSD target
> code, and there's common architecture-specific code shared between the
> different BSDs.  Current, all that is stiched together to form a final
> target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
> functions etc.
> 
> Introduces a fbsd_nat_target base/prototype target.  To be used in
> following patches.

I will do some tests of FreeBSD/amd64 first and let you know what I find.
One small thing I noticed:

> diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
> index 8326b96db7..a4418bb8f8 100644
> --- a/gdb/fbsd-nat.h
> +++ b/gdb/fbsd-nat.h
> +
> +#ifdef PL_FLAG_EXEC
> +  int insert_exec_catchpoint (int) override;
> +  int remove_exec_catchpoint (int) override;
> +#endif
> +
> +#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
> +  int set_syscall_catchpoint (int, bool, int, gdb::array_view<const int>)
> +    override;
> +#endif /* HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE */
> +
> +#endif /* PT_LWPINFO */
> +};

Do we want to be consistent about whether or not to have comments for
#endif's?  Most in this change don't but these two do.

(Also, my initial impression is that the #ifdef's are more readable in this
version than the current code)
  
Pedro Alves April 17, 2018, 5:07 p.m. UTC | #2
On 04/17/2018 05:05 PM, John Baldwin wrote:
> On Saturday, April 14, 2018 08:09:44 PM Pedro Alves wrote:
>> The
>>
>>   $architecture x NetBSD/OpenBSD/FreeBSD
>>
>> support matrix complicates things a bit.  There's common BSD target
>> code, and there's common architecture-specific code shared between the
>> different BSDs.  Current, all that is stiched together to form a final
>> target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
>> functions etc.
>>
>> Introduces a fbsd_nat_target base/prototype target.  To be used in
>> following patches.
> 
> I will do some tests of FreeBSD/amd64 first and let you know what I find.

Thank you!

> One small thing I noticed:
> 
>> diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
>> index 8326b96db7..a4418bb8f8 100644
>> --- a/gdb/fbsd-nat.h
>> +++ b/gdb/fbsd-nat.h
>> +
>> +#ifdef PL_FLAG_EXEC
>> +  int insert_exec_catchpoint (int) override;
>> +  int remove_exec_catchpoint (int) override;
>> +#endif
>> +
>> +#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
>> +  int set_syscall_catchpoint (int, bool, int, gdb::array_view<const int>)
>> +    override;
>> +#endif /* HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE */
>> +
>> +#endif /* PT_LWPINFO */
>> +};
> 
> Do we want to be consistent about whether or not to have comments for
> #endif's?  Most in this change don't but these two do.

I think I have added the one for PT_LWPINFO thinking that the
corresponding #ifdef is so far away, and then added the one just
above too, while missing the others.

I don't have a strong opinion on whether all should have the
comment, I'm fine either way since the #ifdef blocks are small,
i.e., removing the comment for HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
is totally fine with me and may even reduce noise.  I do think
the comment for "#endif PT_LWPINFO" is beneficial, however.

> 
> (Also, my initial impression is that the #ifdef's are more readable in this
> version than the current code)
> 

Yeah, the #endif for PT_LWPINFO is the one that I think I
recall gave me pause in the current code.

Thanks,
Pedro Alves
  
Kamil Rytarowski April 17, 2018, 5:30 p.m. UTC | #3
On 17.04.2018 19:07, Pedro Alves wrote:
> On 04/17/2018 05:05 PM, John Baldwin wrote:
>> On Saturday, April 14, 2018 08:09:44 PM Pedro Alves wrote:
>>> The
>>>
>>>   $architecture x NetBSD/OpenBSD/FreeBSD
>>>
>>> support matrix complicates things a bit.  There's common BSD target
>>> code, and there's common architecture-specific code shared between the
>>> different BSDs.  Current, all that is stiched together to form a final
>>> target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
>>> functions etc.
>>>
>>> Introduces a fbsd_nat_target base/prototype target.  To be used in
>>> following patches.
>>
>> I will do some tests of FreeBSD/amd64 first and let you know what I find.
> 
> Thank you!
> 

Common BSD target should be changed in future to common BSD/Linux target
like in LLDB. There is a shared Remote Process Plugin used by Linux and
NetBSD.

Enforcing a layer of common BSD code is counterproductive nowadays.
  
Pedro Alves April 17, 2018, 6:13 p.m. UTC | #4
Hi Kamil!

Will you be able to smoke test the branch on your favorite
port?  That'd be super.  :-)

On 04/17/2018 06:30 PM, Kamil Rytarowski wrote:

> Common BSD target should be changed in future to common BSD/Linux target
> like in LLDB. There is a shared Remote Process Plugin used by Linux and
> NetBSD.

I think that is confusing or oversimplifying things.  Also, it's
a bit orthogonal to the present effort.  :-)  The "shared" Remote
Process Plugin is just the equivalent of "target remote" in gdb.

See:

 https://sourceware.org/gdb/wiki/Common
 https://sourceware.org/gdb/wiki/LocalRemoteFeatureParity

What we're missing is that gdbserver was never ported over to the
BSDs.  At least, upstream.  Just like in lldb not all ports
have been converted to use the remote process plugin.

Clearly there needs to be a shared interface the different target
backends such as BSD and Linux implement to interact with the
core of the debugger or the server.  In gdb and gdbserver that is
their corresponding target_ops definitions (they're similar, but
not the same).  So even when "going always remote", the target
backend implementations can well share code.

If you're considering porting gdbserver to some platform that
gdb already supports debugging natively, I strongly suggest
making gdbserver reuse the native target code in gdb instead of
duplicating the code.  A few years back someone was working
on doing that for a Hurd gdbserver port, but unfortunately
the work was never completed.  I was positively surprised how
little change the gdb code was requiring for gdbserver
adaptation though.

If done right (by making gdb and gdbserver use the same native
backend target_ops-like interface), there's nothing preventing using
the same backend code in-process in both gdb and gdbserver if we'd like,
instead of always forcing use of gdbserver behind the scenes.  There
are advantages to supporting native-without-forcing-gdbserver
debugging too.  It's all open in the air at this point.

> Enforcing a layer of common BSD code is counterproductive nowadays.

Note that nothing is being "enforced" and that there's no actual
"common BSD layer" in the sense that everything sits on top of some
common BSD layer.  There are simply a few pieces of shared functionality.
If some BSD port doesn't want to use the shared bits, it's very easy
not to use them.

Thanks,
Pedro Alves
  
Kamil Rytarowski April 17, 2018, 6:51 p.m. UTC | #5
On 17.04.2018 20:13, Pedro Alves wrote:
> Hi Kamil!
> 
> Will you be able to smoke test the branch on your favorite
> port?  That'd be super.  :-)
> 

I can try to test it on NetBSD/amd64.

> On 04/17/2018 06:30 PM, Kamil Rytarowski wrote:
> 
>> Common BSD target should be changed in future to common BSD/Linux target
>> like in LLDB. There is a shared Remote Process Plugin used by Linux and
>> NetBSD.
> 
> I think that is confusing or oversimplifying things.  Also, it's
> a bit orthogonal to the present effort.  :-)  The "shared" Remote
> Process Plugin is just the equivalent of "target remote" in gdb.
> 

My comment was rather orthogonal to the process plugin model. I wanted
to state that FreeBSD and NetBSD diverged, while NetBSD was trying to
follow FreeBSD / Linux API with a clean room design.

Cloning 1:1: other BSD would require breakage in existing software as
the APIs were already incompatible. For example PT_LWPINFO has a
different meaning on FreeBSD (get thread info with trap details) and
NetBSD (iterate over threads in tracee).

This means that we are today a distinct target. It's an open question
about OpenBSD, they could follow NetBSD with marginal differences...
once we could convince them to sync up with proper support in debuggers.

> See:
> 
>  https://sourceware.org/gdb/wiki/Common
>  https://sourceware.org/gdb/wiki/LocalRemoteFeatureParity
> 
> What we're missing is that gdbserver was never ported over to the
> BSDs.  At least, upstream.  Just like in lldb not all ports
> have been converted to use the remote process plugin.
> 
> Clearly there needs to be a shared interface the different target
> backends such as BSD and Linux implement to interact with the
> core of the debugger or the server.  In gdb and gdbserver that is
> their corresponding target_ops definitions (they're similar, but
> not the same).  So even when "going always remote", the target
> backend implementations can well share code.
> 
> If you're considering porting gdbserver to some platform that
> gdb already supports debugging natively, I strongly suggest
> making gdbserver reuse the native target code in gdb instead of
> duplicating the code.  A few years back someone was working
> on doing that for a Hurd gdbserver port, but unfortunately
> the work was never completed.  I was positively surprised how
> little change the gdb code was requiring for gdbserver
> adaptation though.
> 
> If done right (by making gdb and gdbserver use the same native
> backend target_ops-like interface), there's nothing preventing using
> the same backend code in-process in both gdb and gdbserver if we'd like,
> instead of always forcing use of gdbserver behind the scenes.  There
> are advantages to supporting native-without-forcing-gdbserver
> debugging too.  It's all open in the air at this point.
> 

There was a port of gdbserver to NetBSD, perhaps so old that it's no
longer relevant today (code from 2010).

http://gnats.netbsd.org/43332 gdbserver for powerpc

Right now, I'm busy with kernel work improving correctness of
forking-like code in the context of debuggers, it will be followed by
signals and threads. It's mostly a one-man show as of today... so it's a
process taking time. I'm reporting the monthly progress on blog.netbsd.org.

>> Enforcing a layer of common BSD code is counterproductive nowadays.
> 
> Note that nothing is being "enforced" and that there's no actual
> "common BSD layer" in the sense that everything sits on top of some
> common BSD layer.  There are simply a few pieces of shared functionality.
> If some BSD port doesn't want to use the shared bits, it's very easy
> not to use them.
> 

It will be revisited in future.

> Thanks,
> Pedro Alves
>
  
John Baldwin April 18, 2018, 12:37 a.m. UTC | #6
On Tuesday, April 17, 2018 06:07:37 PM Pedro Alves wrote:
> On 04/17/2018 05:05 PM, John Baldwin wrote:
> > On Saturday, April 14, 2018 08:09:44 PM Pedro Alves wrote:
> >> The
> >>
> >>   $architecture x NetBSD/OpenBSD/FreeBSD
> >>
> >> support matrix complicates things a bit.  There's common BSD target
> >> code, and there's common architecture-specific code shared between the
> >> different BSDs.  Current, all that is stiched together to form a final
> >> target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
> >> functions etc.
> >>
> >> Introduces a fbsd_nat_target base/prototype target.  To be used in
> >> following patches.
> > 
> > I will do some tests of FreeBSD/amd64 first and let you know what I find.
> 
> Thank you!

I've pushed a target_ops-cxx branch to github.com/bsdjhb/gdb.git that has
some small fixups (compile fixes).  I've built the amd64, i386, arm, and
aarch64 FreeBSD native targets so far.  Simple testing of the the amd64
and i386 binaries seems to work, but I encountered a new test failure
in the testsuite for FreeBSD/amd64 that is a bit odd.  In particular,
I get a core dump running 'info set' when it tries to display the
current setting of whether ASLR is disabled.  Looking at the core of gdb:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000d3a7d4 in target_ops::supports_disable_randomization (
    this=0x28d4c68 <the_amd64_fbsd_nat_target>)
    at ../../gdb/target-delegates.c:2732
2732      return this->beneath->supports_disable_randomization ();

(top-gdb) where
#0  0x0000000000d3a7d4 in target_ops::supports_disable_randomization (
    this=0x28d4c68 <the_amd64_fbsd_nat_target>)
    at ../../gdb/target-delegates.c:2732
#1  0x0000000000d3a857 in find_default_supports_disable_randomization (
#2  0x0000000000d3a805 in dummy_target::supports_disable_randomization (
    this=0x8040d6060) at ../../gdb/target-delegates.c:2738
#3  0x0000000000d2edd8 in target_supports_disable_randomization ()
    at ../../gdb/target.c:2560
#4  0x0000000000b9adbc in show_disable_randomization (file=0x8047b1200, 
    from_tty=1, c=0x80476db80, value=0x7fffffffd859 "on")
    at ../../gdb/infrun.c:181
#5  0x00000000007b1178 in do_show_command (arg=0x0, from_tty=1, c=0x80476db80)
    at ../../gdb/cli/cli-setshow.c:646
#6  0x00000000007b1434 in cmd_show_list (list=0x80476db80, from_tty=1, 
    prefix=0x22a7ead "") at ../../gdb/cli/cli-setshow.c:685
...

The native target isn't currently in the target_stack so its 'beneath' is
NULL:

(top-gdb) p beneath
During symbol reading, missing name for subprogram DIE at 14709647.
$1 = (target_ops *) 0x0
(top-gdb) p target_stack
$2 = (target_ops *) 0x8040d6060
(top-gdb) p *target_stack
$3 = {_vptr$target_ops = 0x183aaf0 <vtable for dummy_target+16>, 
  beneath = 0x0, to_stratum = dummy_stratum}

From the stack trace we can see that it already bounced down to the dummy
target which calls find_default_supports_disable_randomization.  That
finds the native "run" target and invokes its method without pushing
it onto the stack.  I think before if a native target didn't support ASLR
at all it just didn't set the function pointer and no harm was done.
Now the function pointer is effectively always set but to something that
assumes 'beneath' is valid.  I'm not quite sure how you want to fix this.
The simple solution is to change the default method to return false if
beneath is NULL, but I'm not quite sure that fits in with the design this
branch is aiming for.
  
Kamil Rytarowski April 18, 2018, 1:52 a.m. UTC | #7
On 18.04.2018 02:37, John Baldwin wrote:
> On Tuesday, April 17, 2018 06:07:37 PM Pedro Alves wrote:
>> On 04/17/2018 05:05 PM, John Baldwin wrote:
>>> On Saturday, April 14, 2018 08:09:44 PM Pedro Alves wrote:
>>>> The
>>>>
>>>>   $architecture x NetBSD/OpenBSD/FreeBSD
>>>>
>>>> support matrix complicates things a bit.  There's common BSD target
>>>> code, and there's common architecture-specific code shared between the
>>>> different BSDs.  Current, all that is stiched together to form a final
>>>> target, via the i386bsd_target, x86bsd_target, fbsd_nat_add_target
>>>> functions etc.
>>>>
>>>> Introduces a fbsd_nat_target base/prototype target.  To be used in
>>>> following patches.
>>>
>>> I will do some tests of FreeBSD/amd64 first and let you know what I find.
>>
>> Thank you!
> 
> I've pushed a target_ops-cxx branch to github.com/bsdjhb/gdb.git that has
> some small fixups (compile fixes).  I've built the amd64, i386, arm, and
> aarch64 FreeBSD native targets so far.  Simple testing of the the amd64
> and i386 binaries seems to work, but I encountered a new test failure
> in the testsuite for FreeBSD/amd64 that is a bit odd.  In particular,
> I get a core dump running 'info set' when it tries to display the
> current setting of whether ASLR is disabled.  Looking at the core of gdb:
> 

I've checked this branch on NetBSD/amd64 8.99.7 (target_ops-cxx
github.com/bsdjhb/gdb.git). It builds and it's not fully functional..
perhaps not much different to previous versions, for I'm not going to
open new threads and focus on kernel fixes.
  
Pedro Alves April 18, 2018, 11:23 a.m. UTC | #8
On 04/18/2018 02:52 AM, Kamil Rytarowski wrote:

> I've checked this branch on NetBSD/amd64 8.99.7 (target_ops-cxx
> github.com/bsdjhb/gdb.git). It builds and it's not fully functional..
> perhaps not much different to previous versions, for I'm not going to
> open new threads and focus on kernel fixes.

Thanks for testing!

Pedro Alves
  

Patch

diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index bea7f42c7e..5324f8b07e 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -57,8 +57,8 @@ 
 /* Return the name of a file that can be opened to get the symbols for
    the child process identified by PID.  */
 
-static char *
-fbsd_pid_to_exec_file (struct target_ops *self, int pid)
+char *
+fbsd_nat_target::pid_to_exec_file (int pid)
 {
   ssize_t len;
   static char buf[PATH_MAX];
@@ -96,9 +96,9 @@  fbsd_pid_to_exec_file (struct target_ops *self, int pid)
    calling FUNC for each memory region.  OBFD is passed as the last
    argument to FUNC.  */
 
-static int
-fbsd_find_memory_regions (struct target_ops *self,
-			  find_memory_region_ftype func, void *obfd)
+int
+fbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
+				      void *obfd)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   struct kinfo_vmentry *kve;
@@ -170,9 +170,9 @@  fbsd_read_mapping (FILE *mapfile, unsigned long *start, unsigned long *end,
    calling FUNC for each memory region.  OBFD is passed as the last
    argument to FUNC.  */
 
-static int
-fbsd_find_memory_regions (struct target_ops *self,
-			  find_memory_region_ftype func, void *obfd)
+int
+fbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
+				      void *obfd)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   unsigned long start, end, size;
@@ -259,11 +259,10 @@  fbsd_fetch_kinfo_proc (pid_t pid, struct kinfo_proc *kp)
   return (sysctl (mib, 4, kp, &len, NULL, 0) == 0);
 }
 
-/* Implement the "to_info_proc target_ops" method.  */
+/* Implement the "info_proc" target_ops method.  */
 
-static void
-fbsd_info_proc (struct target_ops *ops, const char *args,
-		enum info_proc_what what)
+void
+fbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
 {
 #ifdef HAVE_KINFO_GETFILE
   gdb::unique_xmalloc_ptr<struct kinfo_file> fdtbl;
@@ -542,14 +541,6 @@  fbsd_info_proc (struct target_ops *ops, const char *args,
 }
 
 #ifdef KERN_PROC_AUXV
-static enum target_xfer_status (*super_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);
 
 #ifdef PT_LWPINFO
 /* Return the size of siginfo for the current inferior.  */
@@ -680,13 +671,14 @@  fbsd_convert_siginfo (siginfo_t *si)
 }
 #endif
 
-/* Implement the "to_xfer_partial target_ops" method.  */
+/* Implement the "xfer_partial" target_ops method.  */
 
-static enum target_xfer_status
-fbsd_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
+fbsd_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)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
 
@@ -766,8 +758,9 @@  fbsd_xfer_partial (struct target_ops *ops, enum target_object object,
 	return TARGET_XFER_E_IO;
       }
     default:
-      return super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
-				 len, xfered_len);
+      return inf_ptrace_target::xfer_partial (object, annex,
+					      readbuf, writebuf, offset,
+					      len, xfered_len);
     }
 }
 #endif
@@ -776,15 +769,6 @@  fbsd_xfer_partial (struct target_ops *ops, enum target_object object,
 static int debug_fbsd_lwp;
 static int debug_fbsd_nat;
 
-static void (*super_resume) (struct target_ops *,
-			     ptid_t,
-			     int,
-			     enum gdb_signal);
-static ptid_t (*super_wait) (struct target_ops *,
-			     ptid_t,
-			     struct target_waitstatus *,
-			     int);
-
 static void
 show_fbsd_lwp_debug (struct ui_file *file, int from_tty,
 		     struct cmd_list_element *c, const char *value)
@@ -829,8 +813,8 @@  show_fbsd_nat_debug (struct ui_file *file, int from_tty,
 
 /* Return true if PTID is still active in the inferior.  */
 
-static int
-fbsd_thread_alive (struct target_ops *ops, ptid_t ptid)
+int
+fbsd_nat_target::thread_alive (ptid_t ptid)
 {
   if (ptid_lwp_p (ptid))
     {
@@ -851,8 +835,8 @@  fbsd_thread_alive (struct target_ops *ops, ptid_t ptid)
 /* Convert PTID to a string.  Returns the string in a static
    buffer.  */
 
-static const char *
-fbsd_pid_to_str (struct target_ops *ops, ptid_t ptid)
+const char *
+fbsd_nat_target::pid_to_str (ptid_t ptid)
 {
   lwpid_t lwp;
 
@@ -873,8 +857,8 @@  fbsd_pid_to_str (struct target_ops *ops, ptid_t ptid)
 /* Return the name assigned to a thread by an application.  Returns
    the string in a static buffer.  */
 
-static const char *
-fbsd_thread_name (struct target_ops *self, struct thread_info *thr)
+const char *
+fbsd_nat_target::thread_name (struct thread_info *thr)
 {
   struct ptrace_lwpinfo pl;
   struct kinfo_proc kp;
@@ -984,10 +968,10 @@  fbsd_add_threads (pid_t pid)
     }
 }
 
-/* Implement the "to_update_thread_list" target_ops method.  */
+/* Implement the "update_thread_list" target_ops method.  */
 
-static void
-fbsd_update_thread_list (struct target_ops *ops)
+void
+fbsd_nat_target::update_thread_list ()
 {
 #ifdef PT_LWP_EVENTS
   /* With support for thread events, threads are added/deleted from the
@@ -1102,11 +1086,10 @@  fbsd_next_vfork_done (void)
 #endif
 #endif
 
-/* Implement the "to_resume" target_ops method.  */
+/* Implement the "resume" target_ops method.  */
 
-static void
-fbsd_resume (struct target_ops *ops,
-	     ptid_t ptid, int step, enum gdb_signal signo)
+void
+fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signo)
 {
 #if defined(TDP_RFPPWAIT) && !defined(PTRACE_VFORK)
   pid_t pid;
@@ -1193,7 +1176,7 @@  fbsd_resume (struct target_ops *ops,
     }
   ptid = ptid_t (ptid.pid ());
 #endif
-  super_resume (ops, ptid, step, signo);
+  inf_ptrace_target::resume (ptid, step, signo);
 }
 
 #ifdef USE_SIGTRAP_SIGINFO
@@ -1202,8 +1185,7 @@  fbsd_resume (struct target_ops *ops,
    core, return true.  */
 
 static bool
-fbsd_handle_debug_trap (struct target_ops *ops, ptid_t ptid,
-			const struct ptrace_lwpinfo &pl)
+fbsd_handle_debug_trap (ptid_t ptid, const struct ptrace_lwpinfo &pl)
 {
 
   /* Ignore traps without valid siginfo or for signals other than
@@ -1250,10 +1232,9 @@  fbsd_handle_debug_trap (struct target_ops *ops, ptid_t ptid,
    process ID of the child, or MINUS_ONE_PTID in case of error; store
    the status in *OURSTATUS.  */
 
-static ptid_t
-fbsd_wait (struct target_ops *ops,
-	   ptid_t ptid, struct target_waitstatus *ourstatus,
-	   int target_options)
+ptid_t
+fbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+		       int target_options)
 {
   ptid_t wptid;
 
@@ -1267,7 +1248,7 @@  fbsd_wait (struct target_ops *ops,
 	  return wptid;
 	}
 #endif
-      wptid = super_wait (ops, ptid, ourstatus, target_options);
+      wptid = inf_ptrace_target::wait (ptid, ourstatus, target_options);
       if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
 	{
 	  struct ptrace_lwpinfo pl;
@@ -1432,7 +1413,7 @@  fbsd_wait (struct target_ops *ops,
 #endif
 
 #ifdef USE_SIGTRAP_SIGINFO
-	  if (fbsd_handle_debug_trap (ops, wptid, pl))
+	  if (fbsd_handle_debug_trap (wptid, pl))
 	    return wptid;
 #endif
 
@@ -1475,10 +1456,10 @@  fbsd_wait (struct target_ops *ops,
 }
 
 #ifdef USE_SIGTRAP_SIGINFO
-/* Implement the "to_stopped_by_sw_breakpoint" target_ops method.  */
+/* Implement the "stopped_by_sw_breakpoint" target_ops method.  */
 
-static int
-fbsd_stopped_by_sw_breakpoint (struct target_ops *ops)
+int
+fbsd_nat_target::stopped_by_sw_breakpoint ()
 {
   struct ptrace_lwpinfo pl;
 
@@ -1491,32 +1472,22 @@  fbsd_stopped_by_sw_breakpoint (struct target_ops *ops)
 	  && pl.pl_siginfo.si_code == TRAP_BRKPT);
 }
 
-/* Implement the "to_supports_stopped_by_sw_breakpoint" target_ops
+/* Implement the "supports_stopped_by_sw_breakpoint" target_ops
    method.  */
 
-static int
-fbsd_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+int
+fbsd_nat_target::supports_stopped_by_sw_breakpoint ()
 {
   return 1;
 }
-
-/* Implement the "to_supports_stopped_by_hw_breakpoint" target_ops
-   method.  */
-
-static int
-fbsd_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
-{
-  return ops->to_stopped_by_hw_breakpoint != NULL;
-}
 #endif
 
 #ifdef TDP_RFPPWAIT
 /* Target hook for follow_fork.  On entry and at return inferior_ptid is
    the ptid of the followed inferior.  */
 
-static int
-fbsd_follow_fork (struct target_ops *ops, int follow_child,
-			int detach_fork)
+int
+fbsd_nat_target::follow_fork (int follow_child, int detach_fork)
 {
   if (!follow_child && detach_fork)
     {
@@ -1562,35 +1533,35 @@  fbsd_follow_fork (struct target_ops *ops, int follow_child,
   return 0;
 }
 
-static int
-fbsd_insert_fork_catchpoint (struct target_ops *self, int pid)
+int
+fbsd_nat_target::insert_fork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-fbsd_remove_fork_catchpoint (struct target_ops *self, int pid)
+int
+fbsd_nat_target::remove_fork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-fbsd_insert_vfork_catchpoint (struct target_ops *self, int pid)
+int
+fbsd_nat_target::insert_vfork_catchpoint (int pid)
 {
   return 0;
 }
 
-static int
-fbsd_remove_vfork_catchpoint (struct target_ops *self, int pid)
+int
+fbsd_nat_target::remove_vfork_catchpoint (int pid)
 {
   return 0;
 }
 #endif
 
-/* Implement the "to_post_startup_inferior" target_ops method.  */
+/* Implement the "post_startup_inferior" target_ops method.  */
 
 static void
-fbsd_post_startup_inferior (struct target_ops *self, ptid_t pid)
+fbsd_nat_target::post_startup_inferior (ptid_t pid)
 {
   fbsd_enable_proc_events (ptid_get_pid (pid));
 }
@@ -1608,24 +1579,24 @@  fbsd_post_attach (struct target_ops *self, int pid)
 /* If the FreeBSD kernel supports PL_FLAG_EXEC, then traced processes
    will always stop after exec.  */
 
-static int
-fbsd_insert_exec_catchpoint (struct target_ops *self, int pid)
+int
+fbsd_nat_target::insert_exec_catchpoint (int pid)
 {
   return 0;
 }
 
 static int
-fbsd_remove_exec_catchpoint (struct target_ops *self, int pid)
+fbsd_nat_target::remove_exec_catchpoint (int pid)
 {
   return 0;
 }
 #endif
 
 #ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
-static int
-fbsd_set_syscall_catchpoint (struct target_ops *self, int pid, bool needed,
-			     int any_count,
-			     gdb::array_view<const int> syscall_counts)
+int
+fbsd_nat_target::set_syscall_catchpoint (int pid, bool needed,
+					 int any_count,
+					 gdb::array_view<const int> syscall_counts)
 {
 
   /* Ignore the arguments.  inf-ptrace.c will use PT_SYSCALL which
@@ -1636,55 +1607,6 @@  fbsd_set_syscall_catchpoint (struct target_ops *self, int pid, bool needed,
 #endif
 #endif
 
-void
-fbsd_nat_add_target (struct target_ops *t)
-{
-  t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
-  t->to_find_memory_regions = fbsd_find_memory_regions;
-  t->to_info_proc = fbsd_info_proc;
-#ifdef KERN_PROC_AUXV
-  super_xfer_partial = t->to_xfer_partial;
-  t->to_xfer_partial = fbsd_xfer_partial;
-#endif
-#ifdef PT_LWPINFO
-  t->to_thread_alive = fbsd_thread_alive;
-  t->to_pid_to_str = fbsd_pid_to_str;
-#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_TDNAME
-  t->to_thread_name = fbsd_thread_name;
-#endif
-  t->to_update_thread_list = fbsd_update_thread_list;
-  t->to_has_thread_control = tc_schedlock;
-  super_resume = t->to_resume;
-  t->to_resume = fbsd_resume;
-  super_wait = t->to_wait;
-  t->to_wait = fbsd_wait;
-  t->to_post_startup_inferior = fbsd_post_startup_inferior;
-  t->to_post_attach = fbsd_post_attach;
-#ifdef USE_SIGTRAP_SIGINFO
-  t->to_stopped_by_sw_breakpoint = fbsd_stopped_by_sw_breakpoint;
-  t->to_supports_stopped_by_sw_breakpoint
-    = fbsd_supports_stopped_by_sw_breakpoint;
-  t->to_supports_stopped_by_hw_breakpoint
-    = fbsd_supports_stopped_by_hw_breakpoint;
-#endif
-#ifdef TDP_RFPPWAIT
-  t->to_follow_fork = fbsd_follow_fork;
-  t->to_insert_fork_catchpoint = fbsd_insert_fork_catchpoint;
-  t->to_remove_fork_catchpoint = fbsd_remove_fork_catchpoint;
-  t->to_insert_vfork_catchpoint = fbsd_insert_vfork_catchpoint;
-  t->to_remove_vfork_catchpoint = fbsd_remove_vfork_catchpoint;
-#endif
-#ifdef PL_FLAG_EXEC
-  t->to_insert_exec_catchpoint = fbsd_insert_exec_catchpoint;
-  t->to_remove_exec_catchpoint = fbsd_remove_exec_catchpoint;
-#endif
-#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
-  t->to_set_syscall_catchpoint = fbsd_set_syscall_catchpoint;
-#endif
-#endif
-  add_target (t);
-}
-
 void
 _initialize_fbsd_nat (void)
 {
diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
index 8326b96db7..a4418bb8f8 100644
--- a/gdb/fbsd-nat.h
+++ b/gdb/fbsd-nat.h
@@ -20,8 +20,72 @@ 
 #ifndef FBSD_NAT_H
 #define FBSD_NAT_H
 
-/* Register the customized FreeBSD target.  This should be used
-   instead of calling add_target directly.  */
-extern void fbsd_nat_add_target (struct target_ops *);
+/* A prototype FreeBSD target.  */
+
+class fbsd_nat_target : public inf_ptrace_target
+{
+public:
+  char *pid_to_exec_file (int pid) override;
+
+  int find_memory_regions (find_memory_region_ftype func, void *data);
+
+  bool info_proc (const char *, enum info_proc_what);
+
+#ifdef KERN_PROC_AUXV
+  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;
+#endif
+
+#ifdef PT_LWPINFO
+  int thread_alive (ptid_t ptid) override;
+  const char *pid_to_str (ptid_t) override;
+
+#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_TDNAME
+  const char *thread_name (struct thread_info *) override;
+#endif
+
+  void update_thread_list () override;
+
+  thread_control_capabilities get_thread_control_capabilities () override
+  { return tc_schedlock; }
+
+  void resume (ptid_t, int, enum gdb_signal) override;
+
+  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+
+  void post_startup_inferior (ptid_t) override;
+  void post_attach (int) override;
+
+#ifdef USE_SIGTRAP_SIGINFO
+  int supports_stopped_by_sw_breakpoint () override;
+  int stopped_by_sw_breakpoint () override;
+#endif
+
+#ifdef TDP_RFPPWAIT
+  int follow_fork (int, int) 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;
+#endif
+
+#ifdef PL_FLAG_EXEC
+  int insert_exec_catchpoint (int) override;
+  int remove_exec_catchpoint (int) override;
+#endif
+
+#ifdef HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE
+  int set_syscall_catchpoint (int, bool, int, gdb::array_view<const int>)
+    override;
+#endif /* HAVE_STRUCT_PTRACE_LWPINFO_PL_SYSCALL_CODE */
+
+#endif /* PT_LWPINFO */
+};
 
 #endif /* fbsd-nat.h */