/* GNU/Linux on ARM native support.
- Copyright (C) 1999-2018 Free Software Foundation, Inc.
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include <sys/procfs.h>
#include "nat/linux-ptrace.h"
+#include "linux-tdep.h"
/* Prototypes for supply_gregset etc. */
#include "gregset.h"
int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
struct expression *) override;
- int stopped_by_watchpoint () override;
+ bool stopped_by_watchpoint () override;
- int stopped_data_address (CORE_ADDR *) override;
+ bool stopped_data_address (CORE_ADDR *) override;
- int watchpoint_addr_within_range (CORE_ADDR, CORE_ADDR, int) override;
+ bool watchpoint_addr_within_range (CORE_ADDR, CORE_ADDR, int) override;
const struct target_desc *read_description () override;
+
+ /* Override linux_nat_target low methods. */
+
+ /* Handle thread creation and exit. */
+ void low_new_thread (struct lwp_info *lp) override;
+ void low_delete_thread (struct arch_lwp_info *lp) override;
+ void low_prepare_to_resume (struct lwp_info *lp) override;
+
+ /* Handle process creation and exit. */
+ void low_new_fork (struct lwp_info *parent, pid_t child_pid) override;
+ void low_forget_process (pid_t pid) override;
};
static arm_linux_nat_target the_arm_linux_nat_target;
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
/* Read the floating point state. */
if (have_ptrace_getregset == TRIBOOL_TRUE)
perror_with_name (_("Unable to fetch the floating point registers."));
/* Fetch fpsr. */
- regcache_raw_supply (regcache, ARM_FPS_REGNUM,
- fp + NWFPE_FPSR_OFFSET);
+ regcache->raw_supply (ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
/* Fetch the floating point registers. */
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
/* Read the floating point state. */
if (have_ptrace_getregset == TRIBOOL_TRUE)
perror_with_name (_("Unable to fetch the floating point registers."));
/* Store fpsr. */
- if (REG_VALID == regcache_register_status (regcache, ARM_FPS_REGNUM))
- regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
+ if (REG_VALID == regcache->get_register_status (ARM_FPS_REGNUM))
+ regcache->raw_collect (ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
/* Store the floating point registers. */
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
- if (REG_VALID == regcache_register_status (regcache, regno))
+ if (REG_VALID == regcache->get_register_status (regno))
collect_nwfpe_register (regcache, regno, fp);
if (have_ptrace_getregset == TRIBOOL_TRUE)
static void
fetch_regs (struct regcache *regcache)
{
- int ret, regno, tid;
+ int ret, tid;
elf_gregset_t regs;
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
static void
store_regs (const struct regcache *regcache)
{
- int ret, regno, tid;
+ int ret, tid;
elf_gregset_t regs;
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
/* Fetch the general registers. */
if (have_ptrace_getregset == TRIBOOL_TRUE)
int ret, regno, tid;
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
if (ret < 0)
perror_with_name (_("Unable to fetch WMMX registers."));
for (regno = 0; regno < 16; regno++)
- regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
- ®buf[regno * 8]);
+ regcache->raw_supply (regno + ARM_WR0_REGNUM, ®buf[regno * 8]);
for (regno = 0; regno < 2; regno++)
- regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
- ®buf[16 * 8 + regno * 4]);
+ regcache->raw_supply (regno + ARM_WCSSF_REGNUM,
+ ®buf[16 * 8 + regno * 4]);
for (regno = 0; regno < 4; regno++)
- regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
- ®buf[16 * 8 + 2 * 4 + regno * 4]);
+ regcache->raw_supply (regno + ARM_WCGR0_REGNUM,
+ ®buf[16 * 8 + 2 * 4 + regno * 4]);
}
static void
int ret, regno, tid;
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
if (ret < 0)
perror_with_name (_("Unable to fetch WMMX registers."));
for (regno = 0; regno < 16; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WR0_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
- ®buf[regno * 8]);
+ if (REG_VALID == regcache->get_register_status (regno + ARM_WR0_REGNUM))
+ regcache->raw_collect (regno + ARM_WR0_REGNUM, ®buf[regno * 8]);
for (regno = 0; regno < 2; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WCSSF_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
- ®buf[16 * 8 + regno * 4]);
+ if (REG_VALID == regcache->get_register_status (regno + ARM_WCSSF_REGNUM))
+ regcache->raw_collect (regno + ARM_WCSSF_REGNUM,
+ ®buf[16 * 8 + regno * 4]);
for (regno = 0; regno < 4; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WCGR0_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
- ®buf[16 * 8 + 2 * 4 + regno * 4]);
+ if (REG_VALID == regcache->get_register_status (regno + ARM_WCGR0_REGNUM))
+ regcache->raw_collect (regno + ARM_WCGR0_REGNUM,
+ ®buf[16 * 8 + 2 * 4 + regno * 4]);
ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
fetch_vfp_regs (struct regcache *regcache)
{
gdb_byte regbuf[VFP_REGS_SIZE];
- int ret, regno, tid;
+ int ret, tid;
struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
store_vfp_regs (const struct regcache *regcache)
{
gdb_byte regbuf[VFP_REGS_SIZE];
- int ret, regno, tid;
+ int ret, tid;
struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Get the thread id for the ptrace call. */
- tid = ptid_get_lwp (regcache_get_ptid (regcache));
+ tid = regcache->ptid ().lwp ();
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
const struct target_desc *
arm_linux_nat_target::read_description ()
{
- CORE_ADDR arm_hwcap = 0;
+ CORE_ADDR arm_hwcap = linux_get_hwcap (this);
if (have_ptrace_getregset == TRIBOOL_UNKNOWN)
{
elf_gregset_t gpregs;
struct iovec iov;
- int tid = ptid_get_lwp (inferior_ptid);
+ int tid = inferior_ptid.lwp ();
iov.iov_base = &gpregs;
iov.iov_len = sizeof (gpregs);
have_ptrace_getregset = TRIBOOL_TRUE;
}
- if (target_auxv_search (this, AT_HWCAP, &arm_hwcap) != 1)
- {
- return this->beneath->read_description ();
- }
-
if (arm_hwcap & HWCAP_IWMMXT)
return tdesc_arm_with_iwmmxt;
/* Now make sure that the kernel supports reading these
registers. Support was added in 2.6.30. */
- pid = ptid_get_lwp (inferior_ptid);
+ pid = inferior_ptid.lwp ();
errno = 0;
buf = (char *) alloca (VFP_REGS_SIZE);
if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
return result;
}
- return this->beneath->read_description ();
+ return this->beneath ()->read_description ();
}
/* Information describing the hardware breakpoint capabilities. */
int tid;
unsigned int val;
- tid = ptid_get_lwp (inferior_ptid);
+ tid = inferior_ptid.lwp ();
if (ptrace (PTRACE_GETHBPREGS, tid, 0, &val) < 0)
available = 0;
else
return -1;
}
else
- gdb_assert (FALSE);
+ gdb_assert_not_reached ("unknown breakpoint type");
return 1;
}
/* Called whenever GDB is no longer debugging process PID. It deletes
data structures that keep track of debug register state. */
-static void
-arm_linux_forget_process (pid_t pid)
+void
+arm_linux_nat_target::low_forget_process (pid_t pid)
{
struct arm_linux_process_info *proc, **proc_link;
/* Callback to mark a watch-/breakpoint to be updated in all threads of
the current process. */
-struct update_registers_data
-{
- int watch;
- int index;
-};
-
static int
-update_registers_callback (struct lwp_info *lwp, void *arg)
+update_registers_callback (struct lwp_info *lwp, int watch, int index)
{
- struct update_registers_data *data = (struct update_registers_data *) arg;
-
if (lwp->arch_private == NULL)
lwp->arch_private = XCNEW (struct arch_lwp_info);
/* The actual update is done later just before resuming the lwp,
we just mark that the registers need updating. */
- if (data->watch)
- lwp->arch_private->wpts_changed[data->index] = 1;
+ if (watch)
+ lwp->arch_private->wpts_changed[index] = 1;
else
- lwp->arch_private->bpts_changed[data->index] = 1;
+ lwp->arch_private->bpts_changed[index] = 1;
/* If the lwp isn't stopped, force it to momentarily pause, so
we can update its breakpoint registers. */
ptid_t pid_ptid;
gdb_byte count, i;
struct arm_linux_hw_breakpoint* bpts;
- struct update_registers_data data;
- pid = ptid_get_pid (inferior_ptid);
- pid_ptid = pid_to_ptid (pid);
+ pid = inferior_ptid.pid ();
+ pid_ptid = ptid_t (pid);
if (watchpoint)
{
for (i = 0; i < count; ++i)
if (!arm_hwbp_control_is_enabled (bpts[i].control))
{
- data.watch = watchpoint;
- data.index = i;
bpts[i] = *bpt;
- iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+ iterate_over_lwps (pid_ptid,
+ [=] (struct lwp_info *info)
+ {
+ return update_registers_callback (info, watchpoint,
+ i);
+ });
break;
}
gdb_byte count, i;
ptid_t pid_ptid;
struct arm_linux_hw_breakpoint* bpts;
- struct update_registers_data data;
- pid = ptid_get_pid (inferior_ptid);
- pid_ptid = pid_to_ptid (pid);
+ pid = inferior_ptid.pid ();
+ pid_ptid = ptid_t (pid);
if (watchpoint)
{
for (i = 0; i < count; ++i)
if (arm_linux_hw_breakpoint_equal (bpt, bpts + i))
{
- data.watch = watchpoint;
- data.index = i;
bpts[i].control = arm_hwbp_control_disable (bpts[i].control);
- iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+ iterate_over_lwps (pid_ptid,
+ [=] (struct lwp_info *info)
+ {
+ return update_registers_callback (info, watchpoint,
+ i);
+ });
break;
}
arm_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
if (arm_linux_get_hw_breakpoint_count () == 0)
arm_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
if (arm_linux_get_hw_breakpoint_count () == 0)
enum target_hw_bp_type rw,
struct expression *cond)
{
- struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
if (arm_linux_get_hw_watchpoint_count () == 0)
int len, enum target_hw_bp_type rw,
struct expression *cond)
{
- struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
if (arm_linux_get_hw_watchpoint_count () == 0)
}
/* What was the data address the target was stopped on accessing. */
-int
+bool
arm_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
{
siginfo_t siginfo;
int slot;
if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return 0;
+ return false;
/* This must be a hardware breakpoint. */
if (siginfo.si_signo != SIGTRAP
|| (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
- return 0;
+ return false;
/* We must be able to set hardware watchpoints. */
if (arm_linux_get_hw_watchpoint_count () == 0)
/* If we are in a positive slot then we're looking at a breakpoint and not
a watchpoint. */
if (slot >= 0)
- return 0;
+ return false;
*addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
- return 1;
+ return true;
}
/* Has the target been stopped by hitting a watchpoint? */
-int
+bool
arm_linux_nat_target::stopped_by_watchpoint ()
{
CORE_ADDR addr;
return stopped_data_address (&addr);
}
-int
+bool
arm_linux_nat_target::watchpoint_addr_within_range (CORE_ADDR addr,
CORE_ADDR start,
int length)
/* Handle thread creation. We need to copy the breakpoints and watchpoints
in the parent thread to the child thread. */
-static void
-arm_linux_new_thread (struct lwp_info *lp)
+void
+arm_linux_nat_target::low_new_thread (struct lwp_info *lp)
{
int i;
struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
/* Function to call when a thread is being deleted. */
-static void
-arm_linux_delete_thread (struct arch_lwp_info *arch_lwp)
+void
+arm_linux_nat_target::low_delete_thread (struct arch_lwp_info *arch_lwp)
{
xfree (arch_lwp);
}
/* Called when resuming a thread.
The hardware debug registers are updated when there is any change. */
-static void
-arm_linux_prepare_to_resume (struct lwp_info *lwp)
+void
+arm_linux_nat_target::low_prepare_to_resume (struct lwp_info *lwp)
{
int pid, i;
struct arm_linux_hw_breakpoint *bpts, *wpts;
struct arch_lwp_info *arm_lwp_info = lwp->arch_private;
- pid = ptid_get_lwp (lwp->ptid);
- bpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->bpts;
- wpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->wpts;
+ pid = lwp->ptid.lwp ();
+ bpts = arm_linux_get_debug_reg_state (lwp->ptid.pid ())->bpts;
+ wpts = arm_linux_get_debug_reg_state (lwp->ptid.pid ())->wpts;
/* NULL means this is the main thread still going through the shell,
or, no watchpoint has been set yet. In that case, there's
/* linux_nat_new_fork hook. */
-static void
-arm_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
+void
+arm_linux_nat_target::low_new_fork (struct lwp_info *parent, pid_t child_pid)
{
pid_t parent_pid;
struct arm_linux_debug_reg_state *parent_state;
new process so that all breakpoints and watchpoints can be
removed together. */
- parent_pid = ptid_get_pid (parent->ptid);
+ parent_pid = parent->ptid.pid ();
parent_state = arm_linux_get_debug_reg_state (parent_pid);
child_state = arm_linux_get_debug_reg_state (child_pid);
*child_state = *parent_state;
void
_initialize_arm_linux_nat (void)
{
- target_ops *t = &the_arm_linux_nat_target;
-
/* Register the target. */
linux_target = &the_arm_linux_nat_target;
- add_target (t);
-
- /* Handle thread creation and exit. */
- linux_nat_set_new_thread (t, arm_linux_new_thread);
- linux_nat_set_delete_thread (t, arm_linux_delete_thread);
- linux_nat_set_prepare_to_resume (t, arm_linux_prepare_to_resume);
-
- /* Handle process creation and exit. */
- linux_nat_set_new_fork (t, arm_linux_new_fork);
- linux_nat_set_forget_process (t, arm_linux_forget_process);
+ add_inf_child_target (&the_arm_linux_nat_target);
}