/* PPC GNU/Linux native support.
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2018 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include <string.h>
-#include "observer.h"
+#include "observable.h"
#include "frame.h"
#include "inferior.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "regcache.h"
-#include "gdb_assert.h"
#include "target.h"
#include "linux-nat.h"
-
-#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/user.h>
#include "gdb_wait.h"
#include <fcntl.h>
#include <sys/procfs.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
+#include "inf-ptrace.h"
/* Prototypes for supply_gregset etc. */
#include "gregset.h"
#include "elf/common.h"
#include "auxv.h"
-/* This sometimes isn't defined. */
-#ifndef PT_ORIG_R3
-#define PT_ORIG_R3 34
-#endif
-#ifndef PT_TRAP
-#define PT_TRAP 40
-#endif
-
-/* The PPC_FEATURE_* defines should be provided by <asm/cputable.h>.
- If they aren't, we can provide them ourselves (their values are fixed
- because they are part of the kernel ABI). They are used in the AT_HWCAP
- entry of the AUXV. */
-#ifndef PPC_FEATURE_CELL
-#define PPC_FEATURE_CELL 0x00010000
-#endif
-#ifndef PPC_FEATURE_BOOKE
-#define PPC_FEATURE_BOOKE 0x00008000
-#endif
-#ifndef PPC_FEATURE_HAS_DFP
-#define PPC_FEATURE_HAS_DFP 0x00000400 /* Decimal Floating Point. */
-#endif
-
-/* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a
- configure time check. Some older glibc's (for instance 2.2.1)
- don't have a specific powerpc version of ptrace.h, and fall back on
- a generic one. In such cases, sys/ptrace.h defines
- PTRACE_GETFPXREGS and PTRACE_SETFPXREGS to the same numbers that
- ppc kernel's asm/ptrace.h defines PTRACE_GETVRREGS and
- PTRACE_SETVRREGS to be. This also makes a configury check pretty
- much useless. */
-
-/* These definitions should really come from the glibc header files,
- but Glibc doesn't know about the vrregs yet. */
-#ifndef PTRACE_GETVRREGS
-#define PTRACE_GETVRREGS 18
-#define PTRACE_SETVRREGS 19
-#endif
-
-/* PTRACE requests for POWER7 VSX registers. */
-#ifndef PTRACE_GETVSXREGS
-#define PTRACE_GETVSXREGS 27
-#define PTRACE_SETVSXREGS 28
-#endif
-
-/* Similarly for the ptrace requests for getting / setting the SPE
- registers (ev0 -- ev31, acc, and spefscr). See the description of
- gdb_evrregset_t for details. */
-#ifndef PTRACE_GETEVRREGS
-#define PTRACE_GETEVRREGS 20
-#define PTRACE_SETEVRREGS 21
-#endif
+#include "nat/ppc-linux.h"
/* Similarly for the hardware watchpoint support. These requests are used
when the PowerPC HWDEBUG ptrace interface is not available. */
them and gotten an error. */
int have_ptrace_getsetfpregs = 1;
+struct ppc_linux_nat_target final : public linux_nat_target
+{
+ /* Add our register access methods. */
+ void fetch_registers (struct regcache *, int) override;
+ void store_registers (struct regcache *, int) override;
+
+ /* Add our breakpoint/watchpoint methods. */
+ int can_use_hw_breakpoint (enum bptype, int, int) override;
+
+ int insert_hw_breakpoint (struct gdbarch *, struct bp_target_info *)
+ override;
+
+ int remove_hw_breakpoint (struct gdbarch *, struct bp_target_info *)
+ override;
+
+ int region_ok_for_hw_watchpoint (CORE_ADDR, int) override;
+
+ int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
+ struct expression *) override;
+
+ int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
+ struct expression *) override;
+
+ int insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, enum target_hw_bp_type)
+ override;
+
+ int remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, enum target_hw_bp_type)
+ override;
+
+ bool stopped_by_watchpoint () override;
+
+ bool stopped_data_address (CORE_ADDR *) override;
+
+ bool watchpoint_addr_within_range (CORE_ADDR, CORE_ADDR, int) override;
+
+ bool can_accel_watchpoint_condition (CORE_ADDR, int, int, struct expression *)
+ override;
+
+ int masked_watch_num_registers (CORE_ADDR, CORE_ADDR) override;
+
+ int ranged_break_num_registers () override;
+
+ const struct target_desc *read_description () override;
+
+ int auxv_parse (gdb_byte **readptr,
+ gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+ override;
+
+ /* Override linux_nat_target low methods. */
+ void low_new_thread (struct lwp_info *lp) override;
+};
+
+static ppc_linux_nat_target the_ppc_linux_nat_target;
+
/* *INDENT-OFF* */
/* registers layout, as presented by the ptrace interface:
PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
{
int ret;
gdb_vsxregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
int ret;
int offset = 0;
gdb_vrregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
static void
fetch_spe_register (struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
struct gdb_evrregset_t evrregs;
static void
fetch_register (struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* This isn't really an address. But ptrace thinks of it as one. */
CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
int bytes_transferred;
unsigned int offset; /* Offset of registers within the u area. */
- gdb_byte buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[PPC_MAX_REGISTER_SIZE];
if (altivec_register_p (gdbarch, regno))
{
supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
static int
fetch_all_gp_regs (struct regcache *regcache, int tid)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_gregset_t gregset;
static void
fetch_gp_regs (struct regcache *regcache, int tid)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int i;
static void
fetch_fp_regs (struct regcache *regcache, int tid)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int i;
fetch_ppc_registers (struct regcache *regcache, int tid)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fetch_gp_regs (regcache, tid);
/* Fetch registers from the child process. Fetch all registers if
regno == -1, otherwise fetch all general registers or all floating
point registers depending upon the value of regno. */
-static void
-ppc_linux_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
+void
+ppc_linux_nat_target::fetch_registers (struct regcache *regcache, int regno)
{
- /* Overload thread id onto process id. */
- int tid = ptid_get_lwp (inferior_ptid);
-
- /* No thread id, just use process id. */
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ pid_t tid = get_ptrace_pid (regcache_get_ptid (regcache));
if (regno == -1)
fetch_ppc_registers (regcache, tid);
{
int ret;
gdb_vsxregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
int ret;
int offset = 0;
gdb_vrregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
static void
store_spe_register (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
struct gdb_evrregset_t evrregs;
static void
store_register (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* This isn't really an address. But ptrace thinks of it as one. */
CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
int i;
size_t bytes_to_transfer;
- gdb_byte buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[PPC_MAX_REGISTER_SIZE];
if (altivec_register_p (gdbarch, regno))
{
fill_vsxregset (const struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
fill_vrregset (const struct regcache *regcache, gdb_vrregset_t *vrregsetp)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
static int
store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_gregset_t gregset;
static void
store_gp_regs (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int i;
static void
store_fp_regs (const struct regcache *regcache, int tid, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int i;
store_ppc_registers (const struct regcache *regcache, int tid)
{
int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
store_gp_regs (regcache, tid, -1);
{
CORE_ADDR field;
- if (target_auxv_search (¤t_target, AT_HWCAP, &field))
+ if (target_auxv_search (target_stack, AT_HWCAP, &field))
return (unsigned long) field;
return 0;
return have_ptrace_hwdebug_interface;
}
-static int
-ppc_linux_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int ot)
+int
+ppc_linux_nat_target::can_use_hw_breakpoint (enum bptype type, int cnt, int ot)
{
int total_hw_wp, total_hw_bp;
}
else if (type == bp_hardware_breakpoint)
{
+ if (total_hw_bp == 0)
+ {
+ /* No hardware breakpoint support. */
+ return 0;
+ }
if (cnt > total_hw_bp)
return -1;
}
return 1;
}
-static int
-ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+int
+ppc_linux_nat_target::region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
/* Handle sub-8-byte quantities. */
if (len <= 0)
if the wanted one does not exist? */
if (alloc_new)
{
- t = xmalloc (sizeof (struct thread_points));
- t->hw_breaks
- = xzalloc (max_slots_number * sizeof (struct hw_break_tuple));
+ t = XNEW (struct thread_points);
+ t->hw_breaks = XCNEWVEC (struct hw_break_tuple, max_slots_number);
t->tid = tid;
VEC_safe_push (thread_points_p, ppc_threads, t);
}
{
int i;
long slot;
- struct ppc_hw_breakpoint *p = xmalloc (sizeof (struct ppc_hw_breakpoint));
+ gdb::unique_xmalloc_ptr<ppc_hw_breakpoint> p (XDUP (ppc_hw_breakpoint, b));
struct hw_break_tuple *hw_breaks;
- struct cleanup *c = make_cleanup (xfree, p);
struct thread_points *t;
struct hw_break_tuple *tuple;
- memcpy (p, b, sizeof (struct ppc_hw_breakpoint));
-
errno = 0;
- slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p);
+ slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p.get ());
if (slot < 0)
perror_with_name (_("Unexpected error setting breakpoint or watchpoint"));
if (hw_breaks[i].hw_break == NULL)
{
hw_breaks[i].slot = slot;
- hw_breaks[i].hw_break = p;
+ hw_breaks[i].hw_break = p.release ();
break;
}
gdb_assert (i != max_slots_number);
-
- discard_cleanups (c);
}
/* This function is a generic wrapper that is responsible for removing a
/* Return the number of registers needed for a ranged breakpoint. */
-static int
-ppc_linux_ranged_break_num_registers (struct target_ops *target)
+int
+ppc_linux_nat_target::ranged_break_num_registers ()
{
return ((have_ptrace_hwdebug_interface ()
&& hwdebug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
/* Insert the hardware breakpoint described by BP_TGT. Returns 0 for
success, 1 if hardware breakpoints are not supported or -1 for failure. */
-static int
-ppc_linux_insert_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+int
+ppc_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = (uint64_t) bp_tgt->placed_address;
+ p.addr = (uint64_t) (bp_tgt->placed_address = bp_tgt->reqstd_address);
p.condition_value = 0;
if (bp_tgt->length)
return 0;
}
-static int
-ppc_linux_remove_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+int
+ppc_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
}
static int
-get_trigger_type (int rw)
+get_trigger_type (enum target_hw_bp_type type)
{
int t;
- if (rw == hw_read)
+ if (type == hw_read)
t = PPC_BREAKPOINT_TRIGGER_READ;
- else if (rw == hw_write)
+ else if (type == hw_write)
t = PPC_BREAKPOINT_TRIGGER_WRITE;
else
t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
or hw_access for an access watchpoint. Returns 0 on success and throws
an error on failure. */
-static int
-ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
+int
+ppc_linux_nat_target::insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask,
+ target_hw_bp_type rw)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
or hw_access for an access watchpoint. Returns 0 on success and throws
an error on failure. */
-static int
-ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
+int
+ppc_linux_nat_target::remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask,
+ target_hw_bp_type rw)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
other kinds of values which are not acceptable in a condition
expression (e.g., lval_computed or lval_internalvar). */
static int
-num_memory_accesses (struct value *v)
+num_memory_accesses (const std::vector<value_ref_ptr> &chain)
{
int found_memory_cnt = 0;
- struct value *head = v;
/* The idea here is that evaluating an expression generates a series
of values, one holding the value of every subexpression. (The
notice that an expression contains an inferior function call.
FIXME. */
- for (; v; v = value_next (v))
+ for (const value_ref_ptr &iter : chain)
{
+ struct value *v = iter.get ();
+
/* Constants and values from the history are fine. */
if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
continue;
CORE_ADDR *data_value, int *len)
{
int pc = 1, num_accesses_left, num_accesses_right;
- struct value *left_val, *right_val, *left_chain, *right_chain;
+ struct value *left_val, *right_val;
+ std::vector<value_ref_ptr> left_chain, right_chain;
if (cond->elts[0].opcode != BINOP_EQUAL)
return 0;
num_accesses_left = num_memory_accesses (left_chain);
if (left_val == NULL || num_accesses_left < 0)
- {
- free_value_chain (left_chain);
-
- return 0;
- }
+ return 0;
fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
num_accesses_right = num_memory_accesses (right_chain);
if (right_val == NULL || num_accesses_right < 0)
- {
- free_value_chain (left_chain);
- free_value_chain (right_chain);
-
- return 0;
- }
+ return 0;
if (num_accesses_left == 1 && num_accesses_right == 0
&& VALUE_LVAL (left_val) == lval_memory
*len = TYPE_LENGTH (check_typedef (value_type (right_val)));
}
else
- {
- free_value_chain (left_chain);
- free_value_chain (right_chain);
-
- return 0;
- }
-
- free_value_chain (left_chain);
- free_value_chain (right_chain);
+ return 0;
return 1;
}
/* Return non-zero if the target is capable of using hardware to evaluate
the condition expression, thus only triggering the watchpoint when it is
true. */
-static int
-ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
- struct expression *cond)
+bool
+ppc_linux_nat_target::can_accel_watchpoint_condition (CORE_ADDR addr, int len,
+ int rw,
+ struct expression *cond)
{
CORE_ADDR data_value;
static void
create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
- int len, int rw, struct expression *cond,
- int insert)
+ int len, enum target_hw_bp_type type,
+ struct expression *cond, int insert)
{
if (len == 1
|| !(hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
}
p->version = PPC_DEBUG_CURRENT_VERSION;
- p->trigger_type = get_trigger_type (rw);
+ p->trigger_type = get_trigger_type (type);
p->addr = (uint64_t) addr;
}
-static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
- struct expression *cond)
+int
+ppc_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
+ struct expression *cond)
{
struct lwp_info *lp;
int ret = -1;
{
struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 1);
+ create_watchpoint_request (&p, addr, len, type, cond, 1);
ALL_LWPS (lp)
hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
}
dabr_value = addr & ~(read_mode | write_mode);
- switch (rw)
+ switch (type)
{
case hw_read:
/* Set read and translate bits. */
return ret;
}
-static int
-ppc_linux_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
+int
+ppc_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
+ struct expression *cond)
{
struct lwp_info *lp;
int ret = -1;
{
struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 0);
+ create_watchpoint_request (&p, addr, len, type, cond, 0);
ALL_LWPS (lp)
hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
return ret;
}
-static void
-ppc_linux_new_thread (struct lwp_info *lp)
+void
+ppc_linux_nat_target::low_new_thread (struct lwp_info *lp)
{
int tid = ptid_get_lwp (lp->ptid);
xfree (t);
}
-static int
-ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+bool
+ppc_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
{
siginfo_t siginfo;
if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return 0;
+ return false;
if (siginfo.si_signo != SIGTRAP
|| (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
- return 0;
+ return false;
if (have_ptrace_hwdebug_interface ())
{
if (hw_breaks[i].hw_break && hw_breaks[i].slot == slot
&& hw_breaks[i].hw_break->trigger_type
== PPC_BREAKPOINT_TRIGGER_EXECUTE)
- return 0;
+ return false;
}
}
*addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
- return 1;
+ return true;
}
-static int
-ppc_linux_stopped_by_watchpoint (struct target_ops *ops)
+bool
+ppc_linux_nat_target::stopped_by_watchpoint ()
{
CORE_ADDR addr;
- return ppc_linux_stopped_data_address (ops, &addr);
+ return stopped_data_address (&addr);
}
-static int
-ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
- CORE_ADDR addr,
- CORE_ADDR start, int length)
+bool
+ppc_linux_nat_target::watchpoint_addr_within_range (CORE_ADDR addr,
+ CORE_ADDR start,
+ int length)
{
int mask;
/* Return the number of registers needed for a masked hardware watchpoint. */
-static int
-ppc_linux_masked_watch_num_registers (struct target_ops *target,
- CORE_ADDR addr, CORE_ADDR mask)
+int
+ppc_linux_nat_target::masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
{
if (!have_ptrace_hwdebug_interface ()
|| (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
return 2;
}
-static void
-ppc_linux_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
+void
+ppc_linux_nat_target::store_registers (struct regcache *regcache, int regno)
{
- /* Overload thread id onto process id. */
- int tid = ptid_get_lwp (inferior_ptid);
-
- /* No thread id, just use process id. */
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ pid_t tid = get_ptrace_pid (regcache_get_ptid (regcache));
if (regno >= 0)
store_register (regcache, tid, regno);
errno = 0;
msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
- if (errno == 0 && msr < 0)
+ if (errno == 0 && ppc64_64bit_inferior_p (msr))
wordsize = 8;
#endif
return wordsize;
}
-static int
-ppc_linux_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
- gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
+int
+ppc_linux_nat_target::auxv_parse (gdb_byte **readptr,
+ gdb_byte *endptr, CORE_ADDR *typep,
+ CORE_ADDR *valp)
{
int sizeof_auxv_field = ppc_linux_target_wordsize ();
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
return 1;
}
-static const struct target_desc *
-ppc_linux_read_description (struct target_ops *ops)
+const struct target_desc *
+ppc_linux_nat_target::read_description ()
{
int altivec = 0;
int vsx = 0;
perror_with_name (_("Unable to fetch SPE registers"));
}
- if (have_ptrace_getsetvsxregs)
+ if (have_ptrace_getsetvsxregs
+ && (ppc_linux_get_hwcap () & PPC_FEATURE_HAS_VSX))
{
gdb_vsxregset_t vsxregset;
perror_with_name (_("Unable to fetch VSX registers"));
}
- if (have_ptrace_getvrregs)
+ if (have_ptrace_getvrregs
+ && (ppc_linux_get_hwcap () & PPC_FEATURE_HAS_ALTIVEC))
{
gdb_vrregset_t vrregset;
return isa205? tdesc_powerpc_isa205_32l : tdesc_powerpc_32l;
}
-void _initialize_ppc_linux_nat (void);
-
void
_initialize_ppc_linux_nat (void)
{
- struct target_ops *t;
-
- /* Fill in the generic GNU/Linux methods. */
- t = linux_target ();
+ linux_target = &the_ppc_linux_nat_target;
- /* Add our register access methods. */
- t->to_fetch_registers = ppc_linux_fetch_inferior_registers;
- t->to_store_registers = ppc_linux_store_inferior_registers;
-
- /* Add our breakpoint/watchpoint methods. */
- t->to_can_use_hw_breakpoint = ppc_linux_can_use_hw_breakpoint;
- t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
- t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
- t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
- t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
- t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
- t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
- t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
- t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = ppc_linux_stopped_data_address;
- t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
- t->to_can_accel_watchpoint_condition
- = ppc_linux_can_accel_watchpoint_condition;
- t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
- t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
-
- t->to_read_description = ppc_linux_read_description;
- t->to_auxv_parse = ppc_linux_auxv_parse;
-
- observer_attach_thread_exit (ppc_linux_thread_exit);
+ gdb::observers::thread_exit.attach (ppc_linux_thread_exit);
/* Register the target. */
- linux_nat_add_target (t);
- linux_nat_set_new_thread (t, ppc_linux_new_thread);
+ add_inf_child_target (linux_target);
}