Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/2] xtensa: add hardware breakpoints support
@ 2016-03-09 21:48 Max Filippov
  2016-03-09 21:48 ` [PATCH 1/2] gdb: xtensa: make locally used functions static Max Filippov
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Max Filippov @ 2016-03-09 21:48 UTC (permalink / raw)
  To: gdb-patches
  Cc: Maxim Grigoriev, Woody LaRue, Marc Gauthier, linux-xtensa, Max Filippov

Hello,

this series cleans up gdb/xtensa-linux-nat.c so that it builds without
warnings and adds support for hardware breakpoints and watchpoints.
The implementation closely follows what ARM does.
Please review.

Max Filippov (2):
  gdb: xtensa: make locally used functions static
  gdb: xtensa: support hardware breakpoints/watchpoints

 gdb/xtensa-linux-nat.c | 607 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 604 insertions(+), 3 deletions(-)

-- 
2.1.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] gdb: xtensa: make locally used functions static
  2016-03-09 21:48 [PATCH 0/2] xtensa: add hardware breakpoints support Max Filippov
@ 2016-03-09 21:48 ` Max Filippov
  2016-03-09 21:49 ` [PATCH 2/2] gdb: xtensa: support hardware breakpoints/watchpoints Max Filippov
  2016-03-10 17:17 ` [PATCH 0/2] xtensa: add hardware breakpoints support Pedro Alves
  2 siblings, 0 replies; 5+ messages in thread
From: Max Filippov @ 2016-03-09 21:48 UTC (permalink / raw)
  To: gdb-patches
  Cc: Maxim Grigoriev, Woody LaRue, Marc Gauthier, linux-xtensa, Max Filippov

This fixes 'no previous prototype for function' warnings when building
gdb/xtensa-linux-nat.c

2016-03-10  Max Filippov  <jcmvbkbc@gmail.com>
gdb/
	* xtensa-linux-nat.c (supply_gregset_reg,
	xtensa_linux_fetch_inferior_registers,
	xtensa_linux_store_inferior_registers): Mark as static.
---
 gdb/xtensa-linux-nat.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gdb/xtensa-linux-nat.c b/gdb/xtensa-linux-nat.c
index fa62732..4247f70 100644
--- a/gdb/xtensa-linux-nat.c
+++ b/gdb/xtensa-linux-nat.c
@@ -103,7 +103,7 @@ fill_gregset (const struct regcache *regcache,
     }
 }
 
-void
+static void
 supply_gregset_reg (struct regcache *regcache,
 		    const gdb_gregset_t *gregsetp, int regnum)
 {
@@ -260,7 +260,7 @@ store_xtregs (struct regcache *regcache, int regnum)
     perror_with_name (_("Couldn't write extended registers"));
 }
 
-void
+static void
 xtensa_linux_fetch_inferior_registers (struct target_ops *ops,
 				       struct regcache *regcache, int regnum)
 {
@@ -275,7 +275,7 @@ xtensa_linux_fetch_inferior_registers (struct target_ops *ops,
     fetch_xtregs (regcache, regnum);
 }
 
-void
+static void
 xtensa_linux_store_inferior_registers (struct target_ops *ops,
 				       struct regcache *regcache, int regnum)
 {
-- 
2.1.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] gdb: xtensa: support hardware breakpoints/watchpoints
  2016-03-09 21:48 [PATCH 0/2] xtensa: add hardware breakpoints support Max Filippov
  2016-03-09 21:48 ` [PATCH 1/2] gdb: xtensa: make locally used functions static Max Filippov
@ 2016-03-09 21:49 ` Max Filippov
  2016-03-10 17:17 ` [PATCH 0/2] xtensa: add hardware breakpoints support Pedro Alves
  2 siblings, 0 replies; 5+ messages in thread
From: Max Filippov @ 2016-03-09 21:49 UTC (permalink / raw)
  To: gdb-patches
  Cc: Maxim Grigoriev, Woody LaRue, Marc Gauthier, linux-xtensa, Max Filippov

2016-03-10  Max Filippov  <jcmvbkbc@gmail.com>
gdb/
	* xtensa-linux-nat.c (PTRACE_GETHBPREGS, PTRACE_SETHBPREGS,
	XTENSA_MAX_WP_LENGTH, MAX_BPTS, MAX_WPTS, DBREAKC_LOAD_MASK,
	DBREAKC_STOR_MASK): New definitions.
	(xtensa_linux_hwbp_cap, xtensa_linux_hw_point,
	xtensa_linux_process_info, arch_lwp_info,
	update_registers_data): New structures.
	(xtensa_linux_process_list): New static variable.
	(xtensa_linux_find_process_pid, xtensa_linux_add_process,
	xtensa_linux_process_info_get, xtensa_linux_forget_process,
	xtensa_linux_get_hwbp_cap, xtensa_linux_get_hw_breakpoint_count,
	xtensa_linux_get_hw_watchpoint_count,
	xtensa_linux_can_use_hw_breakpoint,
	xtensa_linux_hw_breakpoint_initialize,
	xtensa_linux_hw_watchpoint_initialize,
	update_registers_callback,
	xtensa_linux_insert_process_hw_point,
	xtensa_linux_remove_process_hw_point,
	xtensa_linux_insert_hw_breakpoint,
	xtensa_linux_remove_hw_breakpoint,
	xtensa_linux_region_ok_for_hw_watchpoint,
	xtensa_linux_insert_watchpoint,	xtensa_linux_remove_watchpoint,
	xtensa_linux_stopped_data_address,
       	xtensa_linux_stopped_by_watchpoint,
	xtensa_linux_watchpoint_addr_within_range,
	xtensa_linux_new_thread, xtensa_linux_set_hw_point,
	xtensa_linux_prepare_to_resume, xtensa_linux_new_fork): New
	functions.
	(_initialize_xtensa_linux_nat): Register thr following target
	callbacks: to_can_use_hw_breakpoint, to_insert_hw_breakpoint,
	to_remove_hw_breakpoint, to_region_ok_for_hw_watchpoint,
	to_insert_watchpoint, to_remove_watchpoint,
	to_stopped_by_watchpoint, to_stopped_data_address,
	to_watchpoint_addr_within_range. Register handlers for thread
	and process creation and exit.
---
 gdb/xtensa-linux-nat.c | 601 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 601 insertions(+)

diff --git a/gdb/xtensa-linux-nat.c b/gdb/xtensa-linux-nat.c
index 4247f70..1e9a2ca 100644
--- a/gdb/xtensa-linux-nat.c
+++ b/gdb/xtensa-linux-nat.c
@@ -290,6 +290,586 @@ xtensa_linux_store_inferior_registers (struct target_ops *ops,
     store_xtregs (regcache, regnum);
 }
 
+#ifndef PTRACE_GETHBPREGS
+#define PTRACE_GETHBPREGS   20
+#endif
+#ifndef PTRACE_SETHBPREGS
+#define PTRACE_SETHBPREGS   21
+#endif
+
+#define XTENSA_MAX_WP_LENGTH 64
+#define MAX_BPTS 2
+#define MAX_WPTS 2
+
+#define DBREAKC_LOAD_MASK 0x40000000
+#define DBREAKC_STOR_MASK 0x80000000
+
+/* Information describing the hardware breakpoint capabilities.  */
+struct xtensa_linux_hwbp_cap
+{
+  gdb_byte wp_count;
+  gdb_byte bp_count;
+};
+
+struct xtensa_linux_hw_point
+{
+  uint32_t addr;
+  uint32_t type;
+};
+
+/* Per-process arch-specific data we want to keep.  */
+struct xtensa_linux_process_info
+{
+  /* Linked list.  */
+  struct xtensa_linux_process_info *next;
+  /* The process identifier.  */
+  pid_t pid;
+  /* Hardware breakpoints state information.  */
+  struct xtensa_linux_hw_point bpt[MAX_BPTS];
+  /* Hardware watchpoints state information.  */
+  struct xtensa_linux_hw_point wpt[MAX_WPTS];
+};
+
+/* Per-thread arch-specific data we want to keep.  */
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  char bpts_changed[MAX_BPTS];
+  char wpts_changed[MAX_WPTS];
+};
+
+static struct xtensa_linux_process_info *xtensa_linux_process_list = NULL;
+
+/* Find process data for process PID.  */
+
+static struct xtensa_linux_process_info *
+xtensa_linux_find_process_pid (pid_t pid)
+{
+  struct xtensa_linux_process_info *proc;
+
+  for (proc = xtensa_linux_process_list; proc; proc = proc->next)
+    if (proc->pid == pid)
+      return proc;
+
+  return NULL;
+}
+
+/* Add process data for process PID.  Returns newly allocated info
+   object.  */
+
+static struct xtensa_linux_process_info *
+xtensa_linux_add_process (pid_t pid)
+{
+  struct xtensa_linux_process_info *proc;
+
+  proc = xcalloc (1, sizeof (*proc));
+  proc->pid = pid;
+
+  proc->next = xtensa_linux_process_list;
+  xtensa_linux_process_list = proc;
+
+  return proc;
+}
+
+/* Get data specific info for process PID, creating it if necessary.
+   Never returns NULL.  */
+
+static struct xtensa_linux_process_info *
+xtensa_linux_process_info_get (pid_t pid)
+{
+  struct xtensa_linux_process_info *proc;
+
+  proc = xtensa_linux_find_process_pid (pid);
+  if (proc == NULL)
+    proc = xtensa_linux_add_process (pid);
+
+  return proc;
+}
+
+/* Called whenever GDB is no longer debugging process PID.  It deletes
+   data structures that keep track of debug register state.  */
+
+static void
+xtensa_linux_forget_process (pid_t pid)
+{
+  struct xtensa_linux_process_info *proc, **proc_link;
+
+  proc = xtensa_linux_process_list;
+  proc_link = &xtensa_linux_process_list;
+
+  while (proc != NULL)
+    {
+      if (proc->pid == pid)
+	{
+	  *proc_link = proc->next;
+
+	  xfree (proc);
+	  return;
+	}
+
+      proc_link = &proc->next;
+      proc = *proc_link;
+    }
+}
+
+/* Get hold of the Hardware Breakpoint information for the target we are
+   attached to.  Returns NULL if the kernel doesn't support Hardware
+   breakpoints at all, or a pointer to the information structure.  */
+static const struct xtensa_linux_hwbp_cap *
+xtensa_linux_get_hwbp_cap (void)
+{
+  /* The info structure we return.  */
+  static struct xtensa_linux_hwbp_cap info;
+
+  /* Is INFO in a good state?  0 means that no attempt has been made to
+     initialize INFO; 1 means INFO is in an initialized state.  */
+  static int available;
+
+  if (!available)
+    {
+      int i;
+      int tid;
+      uint32_t v[2];
+
+      tid = GET_THREAD_ID (inferior_ptid);
+      for (i = 0; i < MAX_WPTS; ++i)
+	{
+	  if (ptrace (PTRACE_GETHBPREGS, tid, i << 1 | 1, v) < 0)
+	    break;
+	}
+      info.wp_count = i;
+
+      for (i = 0; i < MAX_BPTS; ++i)
+	{
+	  if (ptrace (PTRACE_GETHBPREGS, tid, i << 1, v) < 0)
+	    break;
+	}
+      info.bp_count = i;
+
+      available = 1;
+    }
+
+  return &info;
+}
+
+static int
+xtensa_linux_get_hw_breakpoint_count (void)
+{
+  const struct xtensa_linux_hwbp_cap *cap = xtensa_linux_get_hwbp_cap ();
+  return cap != NULL ? cap->bp_count : 0;
+}
+
+static int
+xtensa_linux_get_hw_watchpoint_count (void)
+{
+  const struct xtensa_linux_hwbp_cap *cap = xtensa_linux_get_hwbp_cap ();
+  return cap != NULL ? cap->wp_count : 0;
+}
+
+/* Have we got a free break-/watch-point available for use?  Returns -1 if
+   there is not an appropriate resource available, otherwise returns 1.  */
+static int
+xtensa_linux_can_use_hw_breakpoint (struct target_ops *self, int type,
+				    int cnt, int ot)
+{
+  if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
+      || type == bp_access_watchpoint || type == bp_watchpoint)
+    {
+      int count = xtensa_linux_get_hw_watchpoint_count ();
+
+      if (count == 0)
+	return 0;
+      else if (cnt > count)
+	return -1;
+    }
+  else if (type == bp_hardware_breakpoint)
+    {
+      int count = xtensa_linux_get_hw_breakpoint_count ();
+
+      if (count == 0)
+	return 0;
+      else if (cnt > count)
+	return -1;
+    }
+  else
+    gdb_assert (FALSE);
+
+  return 1;
+}
+
+/* Initialise the hardware breakpoint structure P.  The breakpoint will be
+   enabled, and will point to the placed address of BP_TGT.  */
+static void
+xtensa_linux_hw_point_initialize (struct gdbarch *gdbarch,
+				  struct bp_target_info *bp_tgt,
+				  struct xtensa_linux_hw_point *p)
+{
+  CORE_ADDR address = bp_tgt->placed_address = bp_tgt->reqstd_address;
+
+  p->addr = (unsigned int) address;
+  p->type = 1;
+}
+
+/* Initialize the hardware breakpoint structure P for a watchpoint at ADDR
+   to LEN.  The type of watchpoint is given in RW.  */
+static void
+xtensa_linux_hw_watchpoint_initialize (CORE_ADDR addr, int len, int rw,
+				       struct xtensa_linux_hw_point *p)
+{
+  p->addr = (unsigned int) addr;
+  p->type = len;
+  if (rw == hw_read)
+    p->type |= DBREAKC_LOAD_MASK;
+  else if (rw == hw_write)
+    p->type |= DBREAKC_STOR_MASK;
+  else
+    p->type |= DBREAKC_LOAD_MASK | DBREAKC_STOR_MASK;
+}
+
+/* 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)
+{
+  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;
+  else
+    lwp->arch_private->bpts_changed[data->index] = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so
+     we can update its breakpoint registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
+}
+
+/* Insert the hardware breakpoint (WATCHPOINT = 0) or watchpoint (WATCHPOINT
+   =1) BPT for the process.  */
+static int
+xtensa_linux_insert_process_hw_point (const struct xtensa_linux_hw_point *bpt,
+				      int watchpoint)
+{
+  int pid;
+  ptid_t pid_ptid;
+  struct xtensa_linux_hw_point *pt;
+  int max_slot_count;
+  int slot;
+
+  pid = ptid_get_pid (inferior_ptid);
+  pid_ptid = pid_to_ptid (pid);
+
+  if (watchpoint)
+    {
+      max_slot_count = xtensa_linux_get_hw_watchpoint_count();
+      pt = xtensa_linux_process_info_get (pid)->wpt;
+    }
+  else
+    {
+      max_slot_count = xtensa_linux_get_hw_breakpoint_count();
+      pt = xtensa_linux_process_info_get (pid)->bpt;
+    }
+
+  for (slot = 0; slot < max_slot_count; ++slot)
+    if (pt[slot].type == 0)
+      {
+	struct update_registers_data data =
+	  {
+	    .watch = watchpoint,
+	    .index = slot,
+	  };
+	pt[slot] = *bpt;
+	iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+	return 0;
+      }
+  return -1;
+}
+
+/* Remove the hardware breakpoint (WATCHPOINT = 0) or watchpoint
+   (WATCHPOINT = 1) BPT for the process.  */
+static int
+xtensa_linux_remove_process_hw_point (const struct xtensa_linux_hw_point *bpt,
+				      int watchpoint)
+{
+  int pid;
+  ptid_t pid_ptid;
+  struct xtensa_linux_hw_point *pt;
+  int max_slot_count;
+  int slot;
+
+  pid = ptid_get_pid (inferior_ptid);
+  pid_ptid = pid_to_ptid (pid);
+
+  if (watchpoint)
+    {
+      max_slot_count = xtensa_linux_get_hw_watchpoint_count();
+      pt = xtensa_linux_process_info_get (pid)->wpt;
+    }
+  else
+    {
+      max_slot_count = xtensa_linux_get_hw_breakpoint_count();
+      pt = xtensa_linux_process_info_get (pid)->bpt;
+    }
+
+  for (slot = 0; slot < max_slot_count; ++slot)
+    if (pt[slot].addr == bpt->addr &&
+	pt[slot].type == bpt->type)
+      {
+	struct update_registers_data data =
+	  {
+	    .watch = watchpoint,
+	    .index = slot,
+	  };
+	pt[slot].type = 0;
+	iterate_over_lwps (pid_ptid, update_registers_callback, &data);
+	return 0;
+      }
+  return -1;
+}
+
+/* Insert a Hardware breakpoint.  */
+static int
+xtensa_linux_insert_hw_breakpoint (struct target_ops *self,
+				   struct gdbarch *gdbarch,
+				   struct bp_target_info *bp_tgt)
+{
+  struct xtensa_linux_hw_point p;
+
+  if (xtensa_linux_get_hw_breakpoint_count () == 0)
+    return -1;
+
+  xtensa_linux_hw_point_initialize (gdbarch, bp_tgt, &p);
+  return xtensa_linux_insert_process_hw_point (&p, 0);
+}
+
+/* Remove a hardware breakpoint.  */
+static int
+xtensa_linux_remove_hw_breakpoint (struct target_ops *self,
+				   struct gdbarch *gdbarch,
+				   struct bp_target_info *bp_tgt)
+{
+  struct xtensa_linux_hw_point p;
+
+  if (xtensa_linux_get_hw_breakpoint_count () == 0)
+    return -1;
+
+  xtensa_linux_hw_point_initialize (gdbarch, bp_tgt, &p);
+  return xtensa_linux_remove_process_hw_point (&p, 0);
+}
+
+/* Are we able to use a hardware watchpoint for the LEN bytes starting at
+   ADDR?  */
+static int
+xtensa_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
+					  CORE_ADDR addr, int len)
+{
+  CORE_ADDR aligned_addr;
+
+  /* Can not set watchpoints for zero or negative lengths.  */
+  if (len <= 0)
+    return 0;
+
+  /* Test that the range [ADDR, ADDR + LEN) fits into the largest address
+     range covered by a watchpoint.  */
+  aligned_addr = addr & ~(XTENSA_MAX_WP_LENGTH - 1);
+
+  if (aligned_addr + XTENSA_MAX_WP_LENGTH < addr + len)
+    return 0;
+
+  /* The current ptrace interface can only handle watchpoint lengths that
+     are a power of 2.  */
+  if ((len & (len - 1)) != 0)
+    return 0;
+
+  /* All tests passed so we must be able to set a watchpoint.  */
+  return 1;
+}
+
+/* Insert a Hardware watchpoint.  */
+static int
+xtensa_linux_insert_watchpoint (struct target_ops *self,
+				CORE_ADDR addr, int len, int rw,
+				struct expression *cond)
+{
+  struct xtensa_linux_hw_point p;
+  int slot;
+
+  if (xtensa_linux_get_hw_watchpoint_count () == 0)
+    return -1;
+
+  xtensa_linux_hw_watchpoint_initialize (addr, len, rw, &p);
+  return xtensa_linux_insert_process_hw_point (&p, 1);
+}
+
+/* Remove a hardware watchpoint.  */
+static int
+xtensa_linux_remove_watchpoint (struct target_ops *self,
+				CORE_ADDR addr, int len, int rw,
+				struct expression *cond)
+{
+  struct xtensa_linux_hw_point p;
+  int slot;
+
+  if (xtensa_linux_get_hw_watchpoint_count () == 0)
+    return -1;
+
+  xtensa_linux_hw_watchpoint_initialize (addr, len, rw, &p);
+  return xtensa_linux_remove_process_hw_point (&p, 1);
+}
+
+/* What was the data address the target was stopped on accessing.  */
+static int
+xtensa_linux_stopped_data_address (struct target_ops *target,
+				   CORE_ADDR *addr_p)
+{
+  siginfo_t siginfo;
+  int slot;
+
+  if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+    return 0;
+
+  /* This must be a hardware breakpoint.  */
+  if (siginfo.si_signo != SIGTRAP
+      || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+    return 0;
+
+  /* We must be able to set hardware watchpoints.  */
+  if (xtensa_linux_get_hw_watchpoint_count () == 0)
+    return 0;
+
+  slot = siginfo.si_errno;
+
+  /* If we are in an even slot then we're looking at a breakpoint and not
+     a watchpoint.  */
+  if ((slot & 0x1) == 0)
+    return 0;
+
+  *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
+  return 1;
+}
+
+/* Has the target been stopped by hitting a watchpoint?  */
+static int
+xtensa_linux_stopped_by_watchpoint (struct target_ops *ops)
+{
+  CORE_ADDR addr;
+  return xtensa_linux_stopped_data_address (ops, &addr);
+}
+
+static int
+xtensa_linux_watchpoint_addr_within_range (struct target_ops *target,
+					   CORE_ADDR addr,
+					   CORE_ADDR start, int length)
+{
+  return start <= addr && start + length - 1 >= addr;
+}
+
+/* Handle thread creation.  We need to copy the breakpoints and watchpoints
+   in the parent thread to the child thread.  */
+static void
+xtensa_linux_new_thread (struct lwp_info *lp)
+{
+  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
+
+  /* Mark that all the hardware breakpoints/watchpoints
+     for this thread need to be initialized.  */
+
+  for (i = 0; i < MAX_BPTS; i++)
+    info->bpts_changed[i] = 1;
+  for (i = 0; i < MAX_WPTS; i++)
+    info->wpts_changed[i] = 1;
+
+  lp->arch_private = info;
+}
+
+static long
+xtensa_linux_set_hw_point (const struct xtensa_linux_hw_point *bpt,
+			   int pid, int slot, int watchpoint)
+{
+  uint32_t bp[2] = { bpt->addr, bpt->type };
+
+  return ptrace (PTRACE_SETHBPREGS, pid, slot << 1 | watchpoint, bp);
+}
+
+/* Called when resuming a thread.
+   The hardware debug registers are updated when there is any change.  */
+static void
+xtensa_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  int pid, i;
+  struct xtensa_linux_hw_point *bpts, *wpts;
+  struct arch_lwp_info *lwp_info = lwp->arch_private;
+
+  pid = ptid_get_lwp (lwp->ptid);
+  bpts = xtensa_linux_process_info_get (ptid_get_pid (lwp->ptid))->bpt;
+  wpts = xtensa_linux_process_info_get (ptid_get_pid (lwp->ptid))->wpt;
+
+  if (lwp_info == NULL)
+    return;
+
+  for (i = 0; i < xtensa_linux_get_hw_breakpoint_count (); i++)
+    if (lwp_info->bpts_changed[i])
+      {
+	errno = 0;
+
+	if (xtensa_linux_set_hw_point (bpts + i, pid, i, 0) < 0)
+	  perror_with_name (_("Unexpected error setting breakpoint"));
+
+	lwp_info->bpts_changed[i] = 0;
+      }
+
+  for (i = 0; i < xtensa_linux_get_hw_watchpoint_count (); i++)
+    if (lwp_info->wpts_changed[i])
+      {
+	errno = 0;
+
+	if (xtensa_linux_set_hw_point (wpts + i, pid, i, 1) < 0)
+	  perror_with_name (_("Unexpected error setting watchpoint"));
+
+	lwp_info->wpts_changed[i] = 0;
+      }
+}
+
+static void
+xtensa_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
+{
+  pid_t parent_pid;
+  struct xtensa_linux_process_info *parent_state;
+  struct xtensa_linux_process_info *child_state;
+
+  /* NULL means no watchpoint has ever been set in the parent.  In
+     that case, there's nothing to do.  */
+  if (parent->arch_private == NULL)
+    return;
+
+  /* GDB core assumes the child inherits the watchpoints/hw
+     breakpoints of the parent, and will remove them all from the
+     forked off process.  Copy the debug registers mirrors into the
+     new process so that all breakpoints and watchpoints can be
+     removed together.  */
+
+  parent_pid = ptid_get_pid (parent->ptid);
+  parent_state = xtensa_linux_process_info_get (parent_pid);
+  child_state = xtensa_linux_process_info_get (child_pid);
+  memcpy (child_state->bpt, parent_state->bpt, sizeof (parent_state->bpt));
+  memcpy (child_state->wpt, parent_state->wpt, sizeof (parent_state->wpt));
+}
+
 void _initialize_xtensa_linux_nat (void);
 
 void
@@ -316,5 +896,26 @@ _initialize_xtensa_linux_nat (void)
   t->to_fetch_registers = xtensa_linux_fetch_inferior_registers;
   t->to_store_registers = xtensa_linux_store_inferior_registers;
 
+  /* Add our hardware breakpoint and watchpoint implementation.  */
+  t->to_can_use_hw_breakpoint = xtensa_linux_can_use_hw_breakpoint;
+  t->to_insert_hw_breakpoint = xtensa_linux_insert_hw_breakpoint;
+  t->to_remove_hw_breakpoint = xtensa_linux_remove_hw_breakpoint;
+
+  t->to_region_ok_for_hw_watchpoint = xtensa_linux_region_ok_for_hw_watchpoint;
+  t->to_insert_watchpoint = xtensa_linux_insert_watchpoint;
+  t->to_remove_watchpoint = xtensa_linux_remove_watchpoint;
+  t->to_stopped_by_watchpoint = xtensa_linux_stopped_by_watchpoint;
+  t->to_stopped_data_address = xtensa_linux_stopped_data_address;
+  t->to_watchpoint_addr_within_range =
+    xtensa_linux_watchpoint_addr_within_range;
+
   linux_nat_add_target (t);
+
+  /* Handle thread creation and exit.  */
+  linux_nat_set_new_thread (t, xtensa_linux_new_thread);
+  linux_nat_set_prepare_to_resume (t, xtensa_linux_prepare_to_resume);
+
+  /* Handle process creation and exit.  */
+  linux_nat_set_new_fork (t, xtensa_linux_new_fork);
+  linux_nat_set_forget_process (t, xtensa_linux_forget_process);
 }
-- 
2.1.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] xtensa: add hardware breakpoints support
  2016-03-09 21:48 [PATCH 0/2] xtensa: add hardware breakpoints support Max Filippov
  2016-03-09 21:48 ` [PATCH 1/2] gdb: xtensa: make locally used functions static Max Filippov
  2016-03-09 21:49 ` [PATCH 2/2] gdb: xtensa: support hardware breakpoints/watchpoints Max Filippov
@ 2016-03-10 17:17 ` Pedro Alves
  2016-03-10 20:18   ` Max Filippov
  2 siblings, 1 reply; 5+ messages in thread
From: Pedro Alves @ 2016-03-10 17:17 UTC (permalink / raw)
  To: Max Filippov, gdb-patches
  Cc: Maxim Grigoriev, Woody LaRue, Marc Gauthier, linux-xtensa

On 03/09/2016 09:48 PM, Max Filippov wrote:
> Hello,
>
> this series cleans up gdb/xtensa-linux-nat.c so that it builds without
> warnings and adds support for hardware breakpoints and watchpoints.
> The implementation closely follows what ARM does.
> Please review.

Unfortunately, you looked at one of the targets that still doesn't
share the debug registers code with gdbserver.  See how at least
x86, aarch64 and mips put debug registers code in gdb/nat/.

I think we should require all new GNU/Linux debug registers
support code follow such a scheme.

Patch #1 is obvious, please push it in.

>
> Max Filippov (2):
>    gdb: xtensa: make locally used functions static
>    gdb: xtensa: support hardware breakpoints/watchpoints
>
>   gdb/xtensa-linux-nat.c | 607 ++++++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 604 insertions(+), 3 deletions(-)

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] xtensa: add hardware breakpoints support
  2016-03-10 17:17 ` [PATCH 0/2] xtensa: add hardware breakpoints support Pedro Alves
@ 2016-03-10 20:18   ` Max Filippov
  0 siblings, 0 replies; 5+ messages in thread
From: Max Filippov @ 2016-03-10 20:18 UTC (permalink / raw)
  To: Pedro Alves
  Cc: gdb-patches, Maxim Grigoriev, Woody LaRue, Marc Gauthier, linux-xtensa

On Thu, Mar 10, 2016 at 8:17 PM, Pedro Alves <palves@redhat.com> wrote:
> On 03/09/2016 09:48 PM, Max Filippov wrote:
>>
>> Hello,
>>
>> this series cleans up gdb/xtensa-linux-nat.c so that it builds without
>> warnings and adds support for hardware breakpoints and watchpoints.
>> The implementation closely follows what ARM does.
>> Please review.
>
>
> Unfortunately, you looked at one of the targets that still doesn't
> share the debug registers code with gdbserver.  See how at least
> x86, aarch64 and mips put debug registers code in gdb/nat/.

Will do, thanks for the tip.

> I think we should require all new GNU/Linux debug registers
> support code follow such a scheme.
>
> Patch #1 is obvious, please push it in.

Hmm, this is already fixed on master, sorry for the noise.

-- 
Thanks.
-- Max


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-03-10 20:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-09 21:48 [PATCH 0/2] xtensa: add hardware breakpoints support Max Filippov
2016-03-09 21:48 ` [PATCH 1/2] gdb: xtensa: make locally used functions static Max Filippov
2016-03-09 21:49 ` [PATCH 2/2] gdb: xtensa: support hardware breakpoints/watchpoints Max Filippov
2016-03-10 17:17 ` [PATCH 0/2] xtensa: add hardware breakpoints support Pedro Alves
2016-03-10 20:18   ` Max Filippov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox