From patchwork Sat Apr 14 19:09:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 26746 Received: (qmail 81487 invoked by alias); 14 Apr 2018 19:29:40 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 81449 invoked by uid 89); 14 Apr 2018 19:29:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_NUMSUBJECT, KAM_SHORT autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx3-rdu2.redhat.com (HELO mx1.redhat.com) (66.187.233.73) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 14 Apr 2018 19:29:29 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3A160401DEA2 for ; Sat, 14 Apr 2018 19:10:04 +0000 (UTC) Received: from localhost.localdomain (ovpn04.gateway.prod.ext.ams2.redhat.com [10.39.146.4]) by smtp.corp.redhat.com (Postfix) with ESMTP id CE588215CDC8 for ; Sat, 14 Apr 2018 19:10:03 +0000 (UTC) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 13/40] target_ops/C++: GNU/Linux + x86/AMD64 Date: Sat, 14 Apr 2018 20:09:26 +0100 Message-Id: <20180414190953.24481-14-palves@redhat.com> In-Reply-To: <20180414190953.24481-1-palves@redhat.com> References: <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 #include -/* 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 -inf_child_fileio_readlink (struct target_ops *self, - struct inferior *inf, const char *filename, - int *target_errno) +gdb::optional +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 +{ +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 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 target_unpush_up; +inf_ptrace_target::~inf_ptrace_target () +{} + #ifdef PT_GET_PROCESS_STATE /* Target hook for follow_fork. On entry and at return inferior_ptid is the ptid of the followed inferior. */ -static int -inf_ptrace_follow_fork (struct target_ops *ops, int follow_child, - int detach_fork) +int +inf_ptrace_target::follow_fork (int follow_child, int detach_fork) { if (!follow_child) { @@ -76,14 +78,14 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child, return 0; } -static int -inf_ptrace_insert_fork_catchpoint (struct target_ops *self, int pid) +int +inf_ptrace_target::insert_fork_catchpoint (int pid) { return 0; } -static int -inf_ptrace_remove_fork_catchpoint (struct target_ops *self, int pid) +int +inf_ptrace_target::remove_fork_catchpoint (int pid) { return 0; } @@ -106,24 +108,24 @@ inf_ptrace_me (void) ENV is the environment vector to pass. If FROM_TTY is non-zero, be chatty about it. */ -static void -inf_ptrace_create_inferior (struct target_ops *ops, - const char *exec_file, const std::string &allargs, - char **env, int from_tty) +void +inf_ptrace_target::create_inferior (const char *exec_file, + const std::string &allargs, + char **env, int from_tty) { pid_t pid; ptid_t ptid; /* Do not change either targets above or the same target if already present. The reason is the target stack is shared across multiple inferiors. */ - int ops_already_pushed = target_is_pushed (ops); + int ops_already_pushed = target_is_pushed (this); target_unpush_up unpusher; if (! ops_already_pushed) { /* Clear possible core file with its process_stratum. */ - push_target (ops); - unpusher.reset (ops); + push_target (this); + unpusher.reset (this); } pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL, @@ -146,8 +148,8 @@ inf_ptrace_create_inferior (struct target_ops *ops, #ifdef PT_GET_PROCESS_STATE -static void -inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid) +void +inf_ptrace_target::post_startup_inferior (ptid_t pid) { ptrace_event_t pe; @@ -163,8 +165,8 @@ inf_ptrace_post_startup_inferior (struct target_ops *self, ptid_t pid) /* Clean up a rotting corpse of an inferior after it died. */ -static void -inf_ptrace_mourn_inferior (struct target_ops *ops) +void +inf_ptrace_target::mourn_inferior () { int status; @@ -174,14 +176,14 @@ inf_ptrace_mourn_inferior (struct target_ops *ops) only report its exit status to its original parent. */ waitpid (ptid_get_pid (inferior_ptid), &status, 0); - inf_child_mourn_inferior (ops); + inf_child_target::mourn_inferior (); } /* Attach to the process specified by ARGS. If FROM_TTY is non-zero, be chatty about it. */ -static void -inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty) +void +inf_ptrace_target::attach (const char *args, int from_tty) { char *exec_file; pid_t pid; @@ -189,7 +191,7 @@ inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty) /* Do not change either targets above or the same target if already present. The reason is the target stack is shared across multiple inferiors. */ - int ops_already_pushed = target_is_pushed (ops); + int ops_already_pushed = target_is_pushed (this); pid = parse_pid_to_attach (args); @@ -201,8 +203,8 @@ inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty) { /* target_pid_to_str already uses the target. Also clear possible core file with its process_stratum. */ - push_target (ops); - unpusher.reset (ops); + push_target (this); + unpusher.reset (this); } if (from_tty) @@ -242,8 +244,8 @@ inf_ptrace_attach (struct target_ops *ops, const char *args, int from_tty) #ifdef PT_GET_PROCESS_STATE -static void -inf_ptrace_post_attach (struct target_ops *self, int pid) +void +inf_ptrace_target::post_attach (int pid) { ptrace_event_t pe; @@ -259,8 +261,8 @@ inf_ptrace_post_attach (struct target_ops *self, int pid) /* Detach from the inferior. If FROM_TTY is non-zero, be chatty about it. */ -static void -inf_ptrace_detach (struct target_ops *ops, inferior *inf, int from_tty) +void +inf_ptrace_target::detach (inferior *inf, int from_tty) { pid_t pid = ptid_get_pid (inferior_ptid); @@ -279,24 +281,24 @@ inf_ptrace_detach (struct target_ops *ops, inferior *inf, int from_tty) error (_("This system does not support detaching from a process")); #endif - inf_ptrace_detach_success (ops, inf); + detach_success (inf); } /* See inf-ptrace.h. */ void -inf_ptrace_detach_success (struct target_ops *ops, inferior *inf) +inf_ptrace_target::detach_success (inferior *inf) { inferior_ptid = null_ptid; detach_inferior (inf); - inf_child_maybe_unpush_target (ops); + maybe_unpush_target (); } /* Kill the inferior. */ -static void -inf_ptrace_kill (struct target_ops *ops) +void +inf_ptrace_target::kill () { pid_t pid = ptid_get_pid (inferior_ptid); int status; @@ -330,9 +332,8 @@ get_ptrace_pid (ptid_t ptid) STEP is nonzero, single-step it. If SIGNAL is nonzero, give it that signal. */ -static void -inf_ptrace_resume (struct target_ops *ops, - ptid_t ptid, int step, enum gdb_signal signal) +void +inf_ptrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal) { pid_t pid; int request; @@ -372,9 +373,9 @@ inf_ptrace_resume (struct target_ops *ops, process ID of the child, or MINUS_ONE_PTID in case of error; store the status in *OURSTATUS. */ -static ptid_t -inf_ptrace_wait (struct target_ops *ops, - ptid_t ptid, struct target_waitstatus *ourstatus, int options) +ptid_t +inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, + int options) { pid_t pid; int status, save_errno; @@ -520,11 +521,11 @@ inf_ptrace_peek_poke (pid_t pid, gdb_byte *readbuf, /* Implement the to_xfer_partial target_ops method. */ -static enum target_xfer_status -inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) +enum target_xfer_status +inf_ptrace_target::xfer_partial (enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { pid_t pid = get_ptrace_pid (inferior_ptid); @@ -606,17 +607,17 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object, /* Return non-zero if the thread specified by PTID is alive. */ -static int -inf_ptrace_thread_alive (struct target_ops *ops, ptid_t ptid) +int +inf_ptrace_target::thread_alive (ptid_t ptid) { /* ??? Is kill the right way to do this? */ - return (kill (ptid_get_pid (ptid), 0) != -1); + return (::kill (ptid_get_pid (ptid), 0) != -1); } /* Print status information about what we're accessing. */ -static void -inf_ptrace_files_info (struct target_ops *ignore) +void +inf_ptrace_target::files_info () { struct inferior *inf = current_inferior (); @@ -625,8 +626,8 @@ inf_ptrace_files_info (struct target_ops *ignore) target_pid_to_str (inferior_ptid)); } -static const char * -inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid) +const char * +inf_ptrace_target::pid_to_str (ptid_t ptid) { return normal_pid_to_str (ptid); } @@ -638,9 +639,9 @@ inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid) Return -1 if there is insufficient buffer for a whole entry. Return 1 if an entry was read into *TYPEP and *VALP. */ -static int -inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr, - gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) +int +inf_ptrace_target::auxv_parse (gdb_byte **readptr, gdb_byte *endptr, + CORE_ADDR *typep, CORE_ADDR *valp) { struct type *int_type = builtin_type (target_gdbarch ())->builtin_int; struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; @@ -665,37 +666,4 @@ inf_ptrace_auxv_parse (struct target_ops *ops, gdb_byte **readptr, } #endif - -/* Create a prototype ptrace target. The client can override it with - local methods. */ - -struct target_ops * -inf_ptrace_target (void) -{ - struct target_ops *t = inf_child_target (); - - t->to_attach = inf_ptrace_attach; - t->to_detach = inf_ptrace_detach; - t->to_resume = inf_ptrace_resume; - t->to_wait = inf_ptrace_wait; - t->to_files_info = inf_ptrace_files_info; - t->to_kill = inf_ptrace_kill; - t->to_create_inferior = inf_ptrace_create_inferior; -#ifdef PT_GET_PROCESS_STATE - t->to_follow_fork = inf_ptrace_follow_fork; - t->to_insert_fork_catchpoint = inf_ptrace_insert_fork_catchpoint; - t->to_remove_fork_catchpoint = inf_ptrace_remove_fork_catchpoint; - t->to_post_startup_inferior = inf_ptrace_post_startup_inferior; - t->to_post_attach = inf_ptrace_post_attach; -#endif - t->to_mourn_inferior = inf_ptrace_mourn_inferior; - t->to_thread_alive = inf_ptrace_thread_alive; - t->to_pid_to_str = inf_ptrace_pid_to_str; - t->to_xfer_partial = inf_ptrace_xfer_partial; -#if defined (PT_IO) && defined (PIOD_READ_AUXV) - t->to_auxv_parse = inf_ptrace_auxv_parse; -#endif - - return t; -} diff --git a/gdb/inf-ptrace.h b/gdb/inf-ptrace.h index d10f64ae56..bd9b609ab4 100644 --- a/gdb/inf-ptrace.h +++ b/gdb/inf-ptrace.h @@ -20,26 +20,67 @@ #ifndef INF_PTRACE_H #define INF_PTRACE_H -/* Create a prototype ptrace target. The client can override it with - local methods. */ +#include "inf-child.h" -extern struct target_ops *inf_ptrace_target (void); +/* An abstract prototype ptrace target. The client can override it + with local methods. */ -/* Create a "traditional" ptrace target. REGISTER_U_OFFSET should be - a function returning the offset within the user area where a - particular register is stored. */ +struct inf_ptrace_target : public inf_child_target +{ + ~inf_ptrace_target () override = 0; -extern struct target_ops * - inf_ptrace_trad_target (CORE_ADDR (*register_u_offset) - (struct gdbarch *, int, int)); + void attach (const char *, int) override; + + void detach (inferior *inf, int) override; + + void resume (ptid_t, int, enum gdb_signal) override; + + ptid_t wait (ptid_t, struct target_waitstatus *, int) override; + + void files_info () override; + + void kill () override; + + void create_inferior (const char *, const std::string &, + char **, int) override; +#ifdef PT_GET_PROCESS_STATE + int follow_fork (int, int) override; + + int insert_fork_catchpoint (int) override; + + int remove_fork_catchpoint (int) override; + + void post_startup_inferior (ptid_t) override; + + void post_attach (int) override; +#endif + + void mourn_inferior () override; + + int thread_alive (ptid_t ptid) override; + + const char *pid_to_str (ptid_t) override; + + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + +#if defined (PT_IO) && defined (PIOD_READ_AUXV) + int auxv_parse (gdb_byte **readptr, + gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) override; +#endif + +protected: + /* Cleanup the inferior after a successful ptrace detach. */ + void detach_success (inferior *inf); +}; /* Return which PID to pass to ptrace in order to observe/control the tracee identified by PTID. */ extern pid_t get_ptrace_pid (ptid_t); - -/* Cleanup the inferior after a successful ptrace detach. */ -extern void inf_ptrace_detach_success (struct target_ops *ops, inferior *inf); - #endif diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index c23f83e057..bfc2e46ed6 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -186,14 +186,11 @@ leader. */ #define O_LARGEFILE 0 #endif +struct linux_nat_target *linux_target; + /* Does the current host support PTRACE_GETREGSET? */ enum tribool have_ptrace_getregset = TRIBOOL_UNKNOWN; -/* The single-threaded native GNU/Linux target_ops. We save a pointer for - the use of the multi-threaded target. */ -static struct target_ops *linux_ops; -static struct target_ops linux_ops_saved; - /* The method to call, if any, when a new thread is attached. */ static void (*linux_nat_new_thread) (struct lwp_info *); @@ -217,10 +214,6 @@ static int (*linux_nat_siginfo_fixup) (siginfo_t *, gdb_byte *, int); -/* The saved to_xfer_partial method, inherited from inf-ptrace.c. - Called by our to_xfer_partial. */ -static target_xfer_partial_ftype *super_xfer_partial; - /* The saved to_close method, inherited from inf-ptrace.c. Called by our to_close. */ static void (*super_close) (struct target_ops *); @@ -431,14 +424,17 @@ linux_init_ptrace (pid_t pid, int attached) linux_ptrace_init_warnings (); } -static void -linux_child_post_attach (struct target_ops *self, int pid) +linux_nat_target::~linux_nat_target () +{} + +void +linux_nat_target::post_attach (int pid) { linux_init_ptrace (pid, 1); } -static void -linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid) +void +linux_nat_target::post_startup_inferior (ptid_t ptid) { linux_init_ptrace (ptid_get_pid (ptid), 0); } @@ -472,9 +468,8 @@ delete_lwp_cleanup (void *lp_voidp) ptid of the followed inferior. At return, inferior_ptid will be unchanged. */ -static int -linux_child_follow_fork (struct target_ops *ops, int follow_child, - int detach_fork) +int +linux_nat_target::follow_fork (int follow_child, int detach_fork) { if (!follow_child) { @@ -638,46 +633,45 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child, } -static int -linux_child_insert_fork_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::insert_fork_catchpoint (int pid) { return !linux_supports_tracefork (); } -static int -linux_child_remove_fork_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::remove_fork_catchpoint (int pid) { return 0; } -static int -linux_child_insert_vfork_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::insert_vfork_catchpoint (int pid) { return !linux_supports_tracefork (); } -static int -linux_child_remove_vfork_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::remove_vfork_catchpoint (int pid) { return 0; } -static int -linux_child_insert_exec_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::insert_exec_catchpoint (int pid) { return !linux_supports_tracefork (); } -static int -linux_child_remove_exec_catchpoint (struct target_ops *self, int pid) +int +linux_nat_target::remove_exec_catchpoint (int pid) { return 0; } -static int -linux_child_set_syscall_catchpoint (struct target_ops *self, - int pid, bool needed, int any_count, - gdb::array_view syscall_counts) +int +linux_nat_target::set_syscall_catchpoint (int pid, bool needed, int any_count, + gdb::array_view 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 -linux_child_static_tracepoint_markers_by_strid (struct target_ops *self, - const char *strid) +std::vector +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 -linux_nat_fileio_readlink (struct target_ops *self, - struct inferior *inf, const char *filename, - int *target_errno) +gdb::optional +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 . */ #include "nat/linux-nat.h" +#include "inf-ptrace.h" #include "target.h" #include +/* 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 + 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 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_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 #include "x86-nat.h" -#include "linux-nat.h" #ifndef __x86_64__ #include "i386-linux-nat.h" #endif @@ -78,14 +77,15 @@ x86_linux_new_fork (struct lwp_info *parent, pid_t child_pid) } -static void (*super_post_startup_inferior) (struct target_ops *self, - ptid_t ptid); +x86_linux_nat_target::~x86_linux_nat_target () +{ +} -static void -x86_linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid) +void +x86_linux_nat_target::post_startup_inferior (ptid_t ptid) { x86_cleanup_dregs (); - super_post_startup_inferior (self, ptid); + linux_nat_target::post_startup_inferior (ptid); } #ifdef __x86_64__ @@ -102,8 +102,8 @@ x86_linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid) /* Get Linux/x86 target description from running target. */ -static const struct target_desc * -x86_linux_read_description (struct target_ops *ops) +const struct target_desc * +x86_linux_nat_target::read_description () { int tid; int is_64bit = 0; @@ -212,9 +212,9 @@ x86_linux_read_description (struct target_ops *ops) /* Enable branch tracing. */ -static struct btrace_target_info * -x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid, - const struct btrace_config *conf) +struct btrace_target_info * +x86_linux_nat_target::enable_btrace (ptid_t ptid, + const struct btrace_config *conf) { struct btrace_target_info *tinfo = nullptr; TRY @@ -233,9 +233,8 @@ x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid, /* Disable branch tracing. */ -static void -x86_linux_disable_btrace (struct target_ops *self, - struct btrace_target_info *tinfo) +void +x86_linux_nat_target::disable_btrace (struct btrace_target_info *tinfo) { enum btrace_error errcode = linux_disable_btrace (tinfo); @@ -245,28 +244,25 @@ x86_linux_disable_btrace (struct target_ops *self, /* Teardown branch tracing. */ -static void -x86_linux_teardown_btrace (struct target_ops *self, - struct btrace_target_info *tinfo) +void +x86_linux_nat_target::teardown_btrace (struct btrace_target_info *tinfo) { /* Ignore errors. */ linux_disable_btrace (tinfo); } -static enum btrace_error -x86_linux_read_btrace (struct target_ops *self, - struct btrace_data *data, - struct btrace_target_info *btinfo, - enum btrace_read_type type) +enum btrace_error +x86_linux_nat_target::read_btrace (struct btrace_data *data, + struct btrace_target_info *btinfo, + enum btrace_read_type type) { return linux_read_btrace (data, btinfo, type); } /* See to_btrace_conf in target.h. */ -static const struct btrace_config * -x86_linux_btrace_conf (struct target_ops *self, - const struct btrace_target_info *btinfo) +const struct btrace_config * +x86_linux_nat_target::btrace_conf (const struct btrace_target_info *btinfo) { return linux_btrace_conf (btinfo); } @@ -315,16 +311,12 @@ x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr) } -/* Create an x86 GNU/Linux target. */ +/* Add an x86 GNU/Linux target. */ -struct target_ops * -x86_linux_create_target (void) +void +x86_linux_add_target (linux_nat_target *t) { - /* Fill in the generic GNU/Linux methods. */ - struct target_ops *t = linux_target (); - /* Initialize the debug register function vectors. */ - x86_use_watchpoints (t); x86_dr_low.set_control = x86_linux_dr_set_control; x86_dr_low.set_addr = x86_linux_dr_set_addr; x86_dr_low.get_addr = x86_linux_dr_get_addr; @@ -332,29 +324,7 @@ x86_linux_create_target (void) x86_dr_low.get_control = x86_linux_dr_get_control; x86_set_debug_register_length (sizeof (void *)); - /* Override the GNU/Linux inferior startup hook. */ - super_post_startup_inferior = t->to_post_startup_inferior; - t->to_post_startup_inferior = x86_linux_child_post_startup_inferior; - - /* Add the description reader. */ - t->to_read_description = x86_linux_read_description; - - /* Add btrace methods. */ - t->to_enable_btrace = x86_linux_enable_btrace; - t->to_disable_btrace = x86_linux_disable_btrace; - t->to_teardown_btrace = x86_linux_teardown_btrace; - t->to_read_btrace = x86_linux_read_btrace; - t->to_btrace_conf = x86_linux_btrace_conf; - - return t; -} - -/* Add an x86 GNU/Linux target. */ - -void -x86_linux_add_target (struct target_ops *t) -{ - linux_nat_add_target (t); + add_target (t); linux_nat_set_new_thread (t, x86_linux_new_thread); linux_nat_set_delete_thread (t, x86_linux_delete_thread); linux_nat_set_new_fork (t, x86_linux_new_fork); diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h index 383bfd5314..0bafaaa71f 100644 --- a/gdb/x86-linux-nat.h +++ b/gdb/x86-linux-nat.h @@ -21,6 +21,44 @@ #define X86_LINUX_NAT_H 1 #include "gdb_proc_service.h" /* For ps_err_e. */ +#include "linux-nat.h" +#include "x86-nat.h" + +struct x86_linux_nat_target : public x86_nat_target +{ + virtual ~x86_linux_nat_target () override = 0; + + /* Override the GNU/Linux inferior startup hook. */ + void post_startup_inferior (ptid_t) override; + + /* Add the description reader. */ + const struct target_desc *read_description () override; + + struct btrace_target_info *enable_btrace (ptid_t ptid, + const struct btrace_config *conf) override; + void disable_btrace (struct btrace_target_info *tinfo) override; + void teardown_btrace (struct btrace_target_info *tinfo) override; + enum btrace_error read_btrace (struct btrace_data *data, + struct btrace_target_info *btinfo, + enum btrace_read_type type) override; + const struct btrace_config *btrace_conf (const struct btrace_target_info *) override; + + /* These two are rewired to low_ versions. linux-nat.c queries + stopped-by-watchpoint info as soon as an lwp stops (via the low_ + methods) and caches the result, to be returned via the normal + non-low methods. */ + int stopped_by_watchpoint () override + { return linux_nat_target::stopped_by_watchpoint (); } + + int stopped_data_address (CORE_ADDR *addr_p) override + { return linux_nat_target::stopped_data_address (addr_p); } + + int low_stopped_by_watchpoint () override + { return x86_nat_target::stopped_by_watchpoint (); } + + int low_stopped_data_address (CORE_ADDR *addr_p) override + { return x86_nat_target::stopped_data_address (addr_p); } +}; @@ -32,12 +70,8 @@ extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr); -/* Create an x86 GNU/Linux target. */ - -extern struct target_ops *x86_linux_create_target (void); - /* Add an x86 GNU/Linux target. */ -extern void x86_linux_add_target (struct target_ops *t); +extern void x86_linux_add_target (linux_nat_target *t); #endif diff --git a/gdb/x86-nat.c b/gdb/x86-nat.c index bec51373a6..cfd293c17f 100644 --- a/gdb/x86-nat.c +++ b/gdb/x86-nat.c @@ -146,8 +146,8 @@ x86_cleanup_dregs (void) address ADDR and whose length is LEN bytes. Watch memory accesses of the type TYPE. Return 0 on success, -1 on failure. */ -static int -x86_insert_watchpoint (struct target_ops *self, CORE_ADDR addr, int len, +int +x86_insert_watchpoint (CORE_ADDR addr, int len, enum target_hw_bp_type type, struct expression *cond) { struct x86_debug_reg_state *state @@ -159,8 +159,8 @@ x86_insert_watchpoint (struct target_ops *self, CORE_ADDR addr, int len, /* Remove a watchpoint that watched the memory region which starts at address ADDR, whose length is LEN bytes, and for accesses of the type TYPE. Return 0 on success, -1 on failure. */ -static int -x86_remove_watchpoint (struct target_ops *self, CORE_ADDR addr, int len, +int +x86_remove_watchpoint (CORE_ADDR addr, int len, enum target_hw_bp_type type, struct expression *cond) { struct x86_debug_reg_state *state @@ -172,9 +172,8 @@ x86_remove_watchpoint (struct target_ops *self, CORE_ADDR addr, int len, /* Return non-zero if we can watch a memory region that starts at address ADDR and whose length is LEN bytes. */ -static int -x86_region_ok_for_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len) +int +x86_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) { struct x86_debug_reg_state *state = x86_debug_reg_state (ptid_get_pid (inferior_ptid)); @@ -186,8 +185,8 @@ x86_region_ok_for_watchpoint (struct target_ops *self, address associated with that break/watchpoint and return non-zero. Otherwise, return zero. */ -static int -x86_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) +int +x86_stopped_data_address (CORE_ADDR *addr_p) { struct x86_debug_reg_state *state = x86_debug_reg_state (ptid_get_pid (inferior_ptid)); @@ -198,8 +197,8 @@ x86_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) /* Return non-zero if the inferior has some watchpoint that triggered. Otherwise return zero. */ -static int -x86_stopped_by_watchpoint (struct target_ops *ops) +int +x86_stopped_by_watchpoint () { struct x86_debug_reg_state *state = x86_debug_reg_state (ptid_get_pid (inferior_ptid)); @@ -210,9 +209,8 @@ x86_stopped_by_watchpoint (struct target_ops *ops) /* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address. Return 0 on success, EBUSY on failure. */ -static int -x86_insert_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) +int +x86_insert_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { struct x86_debug_reg_state *state = x86_debug_reg_state (ptid_get_pid (inferior_ptid)); @@ -225,8 +223,8 @@ x86_insert_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch, /* Remove a hardware-assisted breakpoint at BP_TGT->placed_address. Return 0 on success, -1 on failure. */ -static int -x86_remove_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch, +int +x86_remove_hw_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) { struct x86_debug_reg_state *state @@ -253,9 +251,8 @@ x86_remove_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch, virtually unlimited number of watchpoints, due to debug register sharing implemented via reference counts in x86-nat.c. */ -static int -x86_can_use_hw_breakpoint (struct target_ops *self, - enum bptype type, int cnt, int othertype) +int +x86_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype) { return 1; } @@ -263,8 +260,8 @@ x86_can_use_hw_breakpoint (struct target_ops *self, /* Return non-zero if the inferior has some breakpoint that triggered. Otherwise return zero. */ -static int -x86_stopped_by_hw_breakpoint (struct target_ops *ops) +int +x86_stopped_by_hw_breakpoint () { struct x86_debug_reg_state *state = x86_debug_reg_state (ptid_get_pid (inferior_ptid)); @@ -291,30 +288,7 @@ triggers a breakpoint or watchpoint."), &maintenance_show_cmdlist); } -/* There are only two global functions left. */ - -void -x86_use_watchpoints (struct target_ops *t) -{ - /* After a watchpoint trap, the PC points to the instruction after the - one that caused the trap. Therefore we don't need to step over it. - But we do need to reset the status register to avoid another trap. */ - t->to_have_continuable_watchpoint = 1; - - t->to_can_use_hw_breakpoint = x86_can_use_hw_breakpoint; - t->to_region_ok_for_hw_watchpoint = x86_region_ok_for_watchpoint; - t->to_stopped_by_watchpoint = x86_stopped_by_watchpoint; - t->to_stopped_data_address = x86_stopped_data_address; - t->to_insert_watchpoint = x86_insert_watchpoint; - t->to_remove_watchpoint = x86_remove_watchpoint; - t->to_insert_hw_breakpoint = x86_insert_hw_breakpoint; - t->to_remove_hw_breakpoint = x86_remove_hw_breakpoint; - - /* A target must provide an implementation of the - "to_supports_stopped_by_hw_breakpoint" target method before this - callback will be used. */ - t->to_stopped_by_hw_breakpoint = x86_stopped_by_hw_breakpoint; -} +/* See x86-nat.h. */ void x86_set_debug_register_length (int len) diff --git a/gdb/x86-nat.h b/gdb/x86-nat.h index 80c7fdfa80..8ad1821360 100644 --- a/gdb/x86-nat.h +++ b/gdb/x86-nat.h @@ -23,16 +23,12 @@ #ifndef X86_NAT_H #define X86_NAT_H 1 +#include "breakpoint.h" #include "nat/x86-dregs.h" +#include "target.h" /* Hardware-assisted breakpoints and watchpoints. */ -/* Add watchpoint methods to the provided target_ops. - Targets using x86 family debug registers for watchpoints should call - this. */ -struct target_ops; -extern void x86_use_watchpoints (struct target_ops *); - /* Use this function to set x86_dr_low debug_register_length field rather than setting it directly to check that the length is only set once. It also enables the 'maint set/show show-debug-regs' @@ -49,4 +45,75 @@ extern void x86_cleanup_dregs (void); extern void x86_forget_process (pid_t pid); +/* Helper functions used by x86_nat_target below. See their + definitions. */ + +extern int x86_can_use_hw_breakpoint (enum bptype type, int cnt, int othertype); +extern int x86_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len); +extern int x86_stopped_by_watchpoint (); +extern int x86_stopped_data_address (CORE_ADDR *addr_p); +extern int x86_insert_watchpoint (CORE_ADDR addr, int len, + enum target_hw_bp_type type, + struct expression *cond); +extern int x86_remove_watchpoint (CORE_ADDR addr, int len, + enum target_hw_bp_type type, + struct expression *cond); +extern int x86_insert_hw_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt); +extern int x86_remove_hw_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt); +extern int x86_stopped_by_hw_breakpoint (); + +/* Convenience template mixin used to add x86 watchpoints support to a + target. */ + +template +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 */