From: Pedro Alves <palves@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 13/40] target_ops/C++: GNU/Linux + x86/AMD64
Date: Sat, 14 Apr 2018 19:29:00 -0000 [thread overview]
Message-ID: <20180414190953.24481-14-palves@redhat.com> (raw)
In-Reply-To: <20180414190953.24481-1-palves@redhat.com>
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(-)
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;
\f
+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;
-}
\f
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,
}
\f
-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 (¤t_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 (¤t_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 (¤t_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)
}
\f
-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)
}
\f
-/* 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); }
+};
\f
@@ -32,12 +70,8 @@ extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr,
unsigned int *base_addr);
\f
-/* 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 */
--
2.14.3
next prev parent reply other threads:[~2018-04-14 19:29 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-14 19:09 [PATCH 00/40] C++ify target_ops, toward multi-target Pedro Alves
2018-04-14 19:10 ` [PATCH 20/40] target_ops/C++: ARM GNU/Linux Pedro Alves
2018-04-14 19:10 ` [PATCH 34/40] target_ops/C++: bsd_kvm_add_target, BSD libkvm target Pedro Alves
2018-04-14 19:10 ` [PATCH 23/40] target_ops/C++: IA-64 GNU/Linux Pedro Alves
2018-04-14 19:10 ` [PATCH 09/40] target_ops/C++: bfd-target Pedro Alves
2018-04-14 19:10 ` [PATCH 27/40] target_ops/C++: SPARC GNU/Linux Pedro Alves
2018-04-14 19:10 ` [PATCH 08/40] target_ops/C++: bsd-uthread Pedro Alves
2018-04-14 19:10 ` [PATCH 19/40] target_ops/C++: AIX target Pedro Alves
2018-04-14 19:10 ` [PATCH 40/40] target factories, target open and multiple instances of targets Pedro Alves
2018-04-14 19:10 ` [PATCH 37/40] target_ops/C++: The Hurd Pedro Alves
2018-04-14 19:10 ` [PATCH 39/40] linux_nat_target: More low methods Pedro Alves
2018-04-18 0:40 ` John Baldwin
2018-04-14 19:10 ` [PATCH 07/40] target_ops/C++: ravenscar-thread Pedro Alves
2018-04-14 19:10 ` [PATCH 38/40] target_ops: Use bool throughout Pedro Alves
2018-04-14 19:10 ` [PATCH 29/40] target_ops/C++: Tile-Gx GNU/Linux Pedro Alves
2018-04-14 19:10 ` [PATCH 32/40] target_ops/C++: Generic i386/AMD64 BSD targets Pedro Alves
2018-04-14 19:10 ` [PATCH 17/40] target_ops/C++: macOS/Darwin target Pedro Alves
2018-04-14 19:10 ` [PATCH 02/40] make-target-delegates: line break between return type and function name Pedro Alves
2018-04-14 19:10 ` [PATCH 03/40] target_ops/C++: exec target Pedro Alves
2018-04-14 19:15 ` [PATCH 12/40] target_ops/C++: target remote-sim Pedro Alves
2018-04-14 19:15 ` [PATCH 22/40] target_ops/C++: HP-PA GNU/Linux Pedro Alves
2018-04-14 19:15 ` [PATCH 14/40] target_ops/C++: PPC/PPC64 GNU/Linux Pedro Alves
2018-04-14 19:18 ` [PATCH 24/40] target_ops/C++: m32r GNU/Linux Pedro Alves
2018-04-14 19:18 ` [PATCH 25/40] target_ops/C++: m68k GNU/Linux Pedro Alves
2018-04-14 19:18 ` [PATCH 36/40] target_ops/C++: go32/DJGPP Pedro Alves
2018-04-14 19:18 ` [PATCH 04/40] target_ops/C++: core target Pedro Alves
2018-04-14 19:19 ` [PATCH 16/40] target_ops/C++: Windows targets Pedro Alves
2018-04-14 19:19 ` [PATCH 15/40] target_ops/C++: Solaris/procfs Pedro Alves
2018-04-14 19:19 ` [PATCH 30/40] target_ops/C++: Xtensa GNU/Linux Pedro Alves
2018-04-14 19:19 ` [PATCH 26/40] target_ops/C++: s390 GNU/Linux Pedro Alves
2018-04-14 19:19 ` [PATCH 35/40] target_ops/C++: NTO/QNX, nto-procfs.c Pedro Alves
2018-04-14 19:19 ` [PATCH 05/40] target_ops/C++: ctf/tfile targets Pedro Alves
2018-04-14 19:19 ` [PATCH 31/40] target_ops/C++: Base FreeBSD target Pedro Alves
2018-04-17 16:12 ` John Baldwin
2018-04-17 17:07 ` Pedro Alves
2018-04-17 17:28 ` Kamil Rytarowski
2018-04-17 18:13 ` Pedro Alves
2018-04-17 18:50 ` Kamil Rytarowski
2018-04-18 0:40 ` John Baldwin
2018-04-18 1:51 ` Kamil Rytarowski
2018-04-18 11:23 ` Pedro Alves
2018-04-18 11:21 ` Pedro Alves
2018-04-18 14:20 ` Pedro Alves
2018-04-18 20:55 ` John Baldwin
2018-04-14 19:20 ` [PATCH 06/40] target_ops/C++: spu-multiarch Pedro Alves
2018-04-14 19:20 ` [PATCH 33/40] target_ops/C++: The rest of the BSD targets Pedro Alves
2018-04-14 19:20 ` [PATCH 11/40] target_ops/C++: remote/extended-remote targets Pedro Alves
2018-04-14 19:20 ` [PATCH 10/40] target_ops/C++: record targets Pedro Alves
2018-04-14 19:28 ` [PATCH 21/40] target_ops/C++: Aarch64 GNU/Linux Pedro Alves
2018-04-14 19:28 ` [PATCH 28/40] target_ops/C++: SPU/Linux Pedro Alves
2018-05-04 17:09 ` Ulrich Weigand
2018-05-04 17:15 ` Pedro Alves
2018-05-04 17:22 ` Ulrich Weigand
2018-05-04 17:27 ` Pedro Alves
2018-04-14 19:29 ` Pedro Alves [this message]
2018-04-14 19:30 ` [PATCH 18/40] target_ops/C++: linux_trad_target, MIPS and Alpha GNU/Linux Pedro Alves
2018-04-16 15:15 ` [RESEND][PATCH 01/40] Convert struct target_ops to C++ Pedro Alves
2018-05-03 0:06 ` Pedro Alves
2018-10-27 21:58 ` 8.2 regression for invalid -data-directory [Re: [RESEND][PATCH 01/40] Convert struct target_ops to C++] Jan Kratochvil
2018-10-30 20:24 ` Tom Tromey
2019-02-14 15:30 ` [RESEND][PATCH 01/40] Convert struct target_ops to C++ Thomas Schwinge
2018-04-27 15:47 ` [PATCH 00/40] C++ify target_ops, toward multi-target Tom Tromey
2018-05-02 22:55 ` Pedro Alves
2018-04-29 15:22 ` Simon Marchi
2018-05-02 22:51 ` Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180414190953.24481-14-palves@redhat.com \
--to=palves@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).