This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 1/1] Threaded Watchpoints


Second part of the patch.

Best regards,
-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center
LoP Toolchain/Debuggers' team
Phone: +55 19-2132-2218
T/L: 839-2218
e-mail: luisgpm@vnet.linux.ibm.com
2007-08-13  Jeff Johnston  <jjohnstn@redhat.com>

	* config/i386/nm-linux.h: Change dr register routines to
	accept a ptid_t first argument.  Change all calling macros
	to default the inferior_ptid for the first argument.
	(i386_linux_insert_watchpoint): New prototype.
	(i386_linux_remove_watchpoint, i386_linux_insert_hw_breakpoint): Ditto.
	(i386_linux_remove_hw_breakpoint): Ditto.
	(target_insert_watchpoint, target_remove_watchpoint): Undef and
	override.
	(target_insert_hw_breakpoint, target_remove_hw_breakpoint): Ditto.
	* config/i386/nm-linux64.h: Ditto except add amd64 versions of
	the watchpoint/hw-breakpoint insert/remove routines.
	* i386-nat.c: Include "inferior.h" to define inferior_ptid.
	* i386-linux-nat.c: Change all dr get/set routines to accept
	ptid_t as first argument and to use this argument to determine
	the tid for PTRACE.
	(i386_linux_set_debug_regs_for_thread): New function.
	(i386_linux_sync_debug_registers_callback): Ditto.
	(i386_linux_sync_debug_registers_across_threads): Ditto.
	(i386_linux_insert_watchpoint, i386_linux_remove_watchpoint): Ditto.
	(i386_linux_hw_breakpoint, i386_linux_remove_hw_breakpoint): Ditto.
	(i386_linux_new_thread): Ditto.
	(_initialize_i386_linux_nat): Ditto.
	* amd64-linux-nat.c: Change all dr get/set routines to accept
	ptid_t as first argument and to use this argument to determine
	the tid for PTRACE.
	(amd64_linux_set_debug_regs_for_thread): New function.
	(amd64_linux_sync_debug_registers_callback): Ditto.
	(amd64_linux_sync_debug_registers_across_threads): Ditto.
	(amd64_linux_insert_watchpoint, amd64_linux_remove_watchpoint): Ditto.
	(amd64_linux_hw_breakpoint, amd64_linux_remove_hw_breakpoint): Ditto.
	(amd64_linux_new_thread): Ditto.
	(_initialize_amd64_linux_nat): Register linux new thread observer.

Index: gdb/config/i386/nm-linux64.h
===================================================================
--- gdb.orig/config/i386/nm-linux64.h	2007-08-13 06:22:00.000000000 -0700
+++ gdb/config/i386/nm-linux64.h	2007-08-13 06:22:05.000000000 -0700
@@ -37,18 +37,57 @@
 
 extern void amd64_linux_dr_set_control (unsigned long control);
 #define I386_DR_LOW_SET_CONTROL(control) \
-  amd64_linux_dr_set_control (control)
+  amd64_linux_dr_set_control (inferior_ptid, control)
 
 extern void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr);
 #define I386_DR_LOW_SET_ADDR(regnum, addr) \
-  amd64_linux_dr_set_addr (regnum, addr)
+  amd64_linux_dr_set_addr (inferior_ptid, regnum, addr)
 
 extern void amd64_linux_dr_reset_addr (int regnum);
 #define I386_DR_LOW_RESET_ADDR(regnum) \
-  amd64_linux_dr_reset_addr (regnum)
+  amd64_linux_dr_reset_addr (inferior_ptid, regnum)
 
 extern unsigned long amd64_linux_dr_get_status (void);
 #define I386_DR_LOW_GET_STATUS() \
-  amd64_linux_dr_get_status ()
+  amd64_linux_dr_get_status (inferior_ptid, )
+
+/* Watchpoints and hardware breakpoints.  */
+
+/* Insert a watchpoint to watch a memory region which starts at
+ *  *    address ADDR and whose length is LEN bytes.  Watch memory accesses
+ *   *       of the type TYPE.  Return 0 on success, -1 on failure.  */
+extern int amd64_linux_insert_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* 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.  */
+extern int amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
+ *  *    unused.  Return 0 on success, EBUSY on failure.  */
+extern int amd64_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
+ *  *    unused. Return 0 on success, -1 on failure.  */
+extern int  amd64_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+/* Override basic amd64 macros for watchpoint and hardware breakpoint 
+ *    insertion/removal to support threads.  */
+#undef target_insert_watchpoint
+#define target_insert_watchpoint(addr, len, type) \
+  amd64_linux_insert_watchpoint (addr, len, type)
+
+#undef target_remove_watchpoint
+#define target_remove_watchpoint(addr, len, type) \
+  amd64_linux_remove_watchpoint (addr, len, type)
+
+#undef target_insert_hw_breakpoint
+#define target_insert_hw_breakpoint(bp_tgt) \
+  amd64_linux_insert_hw_breakpoint (bp_tgt)
+
+#undef target_remove_hw_breakpoint
+#define target_remove_hw_breakpoint(bp_tgt) \
+  amd64_linux_remove_hw_breakpoint (bp_tgt)
+
 
 #endif /* nm-linux64.h */
Index: gdb/config/i386/nm-linux.h
===================================================================
--- gdb.orig/config/i386/nm-linux.h	2007-08-13 06:22:00.000000000 -0700
+++ gdb/config/i386/nm-linux.h	2007-08-13 06:22:05.000000000 -0700
@@ -31,23 +31,62 @@
 
 /* Provide access to the i386 hardware debugging registers.  */
 
-extern void i386_linux_dr_set_control (unsigned long control);
+extern void i386_linux_dr_set_control (ptid_t ptid, unsigned long control);
 #define I386_DR_LOW_SET_CONTROL(control) \
-  i386_linux_dr_set_control (control)
+  i386_linux_dr_set_control (inferior_ptid, control)
 
-extern void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+extern void i386_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr);
 #define I386_DR_LOW_SET_ADDR(regnum, addr) \
-  i386_linux_dr_set_addr (regnum, addr)
+  i386_linux_dr_set_addr (inferior_ptid, regnum, addr)
 
-extern void i386_linux_dr_reset_addr (int regnum);
+extern void i386_linux_dr_reset_addr (ptid_t ptid, int regnum);
 #define I386_DR_LOW_RESET_ADDR(regnum) \
-  i386_linux_dr_reset_addr (regnum)
+  i386_linux_dr_reset_addr (inferior_ptid, regnum)
 
-extern unsigned long i386_linux_dr_get_status (void);
+extern unsigned long i386_linux_dr_get_status (ptid_t ptid, );
 #define I386_DR_LOW_GET_STATUS() \
-  i386_linux_dr_get_status ()
+  i386_linux_dr_get_status (inferior_ptid, )
 
 
+/* Watchpoints and hardware breakpoints.  */
+
+/* Insert a watchpoint to watch a memory region which starts at
+ *    address ADDR and whose length is LEN bytes.  Watch memory accesses
+ *       of the type TYPE.  Return 0 on success, -1 on failure.  */
+extern int i386_linux_insert_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* 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.  */
+extern int i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
+ *    unused.  Return 0 on success, EBUSY on failure.  */
+extern int i386_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
+ *    unused. Return 0 on success, -1 on failure.  */
+extern int  i386_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+/* Override basic i386 macros for watchpoint and hardware breakpoint 
+   insertion/removal to support threads.  */
+#undef target_insert_watchpoint
+#define target_insert_watchpoint(addr, len, type) \
+  i386_linux_insert_watchpoint (addr, len, type)
+
+#undef target_remove_watchpoint
+#define target_remove_watchpoint(addr, len, type) \
+  i386_linux_remove_watchpoint (addr, len, type)
+
+#undef target_insert_hw_breakpoint
+#define target_insert_hw_breakpoint(bp_tgt) \
+  i386_linux_insert_hw_breakpoint (bp_tgt)
+
+#undef target_remove_hw_breakpoint
+#define target_remove_hw_breakpoint(bp_tgt) \
+  i386_linux_remove_hw_breakpoint (bp_tgt)
+
+
 #ifdef HAVE_PTRACE_GETFPXREGS
 /* Include register set support for the SSE registers.  */
 #define FILL_FPXREGSET
Index: gdb/i386-nat.c
===================================================================
--- gdb.orig/i386-nat.c	2007-08-13 06:22:00.000000000 -0700
+++ gdb/i386-nat.c	2007-08-13 06:22:05.000000000 -0700
@@ -21,6 +21,7 @@
 
 #include "defs.h"
 #include "breakpoint.h"
+#include "inferior.h"
 #include "command.h"
 #include "gdbcmd.h"
 
Index: gdb/i386-linux-nat.c
===================================================================
--- gdb.orig/i386-linux-nat.c	2007-08-13 06:22:00.000000000 -0700
+++ gdb/i386-linux-nat.c	2007-08-13 06:22:05.000000000 -0700
@@ -24,6 +24,7 @@
 #include "inferior.h"
 #include "gdbcore.h"
 #include "regcache.h"
+#include "observer.h"
 #include "target.h"
 #include "linux-nat.h"
 
@@ -582,14 +583,14 @@
 /* Support for debug registers.  */
 
 static unsigned long
-i386_linux_dr_get (int regnum)
+i386_linux_dr_get (ptid_t ptid, int regnum)
 {
   int tid;
   unsigned long value;
 
-  tid = TIDGET (inferior_ptid);
+  tid = TIDGET (ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = PIDGET (ptid);
 
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
      ptrace call fails breaks debugging remote targets.  The correct
@@ -610,13 +611,13 @@
 }
 
 static void
-i386_linux_dr_set (int regnum, unsigned long value)
+i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
 {
   int tid;
 
-  tid = TIDGET (inferior_ptid);
+  tid = TIDGET (ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = PIDGET (ptid);
 
   errno = 0;
   ptrace (PTRACE_POKEUSER, tid,
@@ -626,34 +627,158 @@
 }
 
 void
-i386_linux_dr_set_control (unsigned long control)
+i386_linux_dr_set_control (ptid_t ptid, unsigned long control)
 {
-  i386_linux_dr_set (DR_CONTROL, control);
+  i386_linux_dr_set (ptid, DR_CONTROL, control);
 }
 
 void
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+i386_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr)
 {
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
 
-  i386_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+  i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
 }
 
 void
-i386_linux_dr_reset_addr (int regnum)
+i386_linux_dr_reset_addr (ptid_t ptid, int regnum)
 {
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
 
-  i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+  i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, 0L);
 }
 
 unsigned long
-i386_linux_dr_get_status (void)
+i386_linux_dr_get_status (ptid_t ptid)
 {
-  return i386_linux_dr_get (DR_STATUS);
+  return i386_linux_dr_get (ptid, DR_STATUS);
 }
 
 
+/* Structure used to sync debug registers for all threads.  */
+struct i386_debug_register_state
+{
+  int tid;
+  CORE_ADDR addr[DR_LASTADDR - DR_FIRSTADDR + 1];
+  unsigned long control;
+};
+
+static void
+i386_linux_set_debug_regs_for_thread (ptid_t ptid,
+				      struct i386_debug_register_state *dbs)
+{
+  int i;
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    i386_linux_dr_set_addr (ptid, i, dbs->addr[i]);
+  i386_linux_dr_set_control (ptid, dbs->control);
+}
+
+/* Iterator function to support syncing debug registers across all threads.  */
+static int
+i386_linux_sync_debug_registers_callback (struct lwp_info *lwp, void *data)
+{
+  struct i386_debug_register_state *args = data;
+  int i, tid;
+
+  tid = TIDGET (lwp->ptid);
+  if (tid == 0)
+    tid = PIDGET (lwp->ptid);
+
+  if (tid != args->tid)
+    i386_linux_set_debug_regs_for_thread (lwp->ptid, args);
+  return 0;
+}
+
+/* Sync the debug registers for all known threads to the current
+   thread that has just performed an operation.  This is required
+   because the debug registers are thread-specific.  We want
+   watchpoints and hardware breakpoints to be treated globally
+   across all threads.  */
+static int
+i386_linux_sync_debug_registers_across_threads (void)
+{
+  int i, tid;
+  struct i386_debug_register_state args;
+
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
+
+  args.tid = tid;
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    args.addr[i] = i386_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
+  args.control = i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+
+  iterate_over_lwps (&i386_linux_sync_debug_registers_callback, &args);
+
+  return 0;
+}
+
+/* Insert a watchpoint to watch a memory region which starts at
+   address ADDR and whose length is LEN bytes.  Watch memory accesses
+   of the type TYPE.  Return 0 on success, -1 on failure.  */
+int
+i386_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  int rc;
+  rc = i386_insert_watchpoint (addr, len, type);
+  if (!rc)
+    i386_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* 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.  */
+int
+i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  int rc;
+  rc = i386_remove_watchpoint (addr, len, type);
+  if (!rc)
+    i386_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
+   unused.  Return 0 on success, EBUSY on failure.  */
+int
+i386_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
+{
+  int rc;
+  rc = i386_insert_hw_breakpoint (bp_tgt);
+  if (!rc)
+    i386_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
+   unused.  Return 0 on success, -1 on failure.  */
+int
+i386_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
+{
+  int rc;
+  rc = i386_remove_hw_breakpoint (bp_tgt);
+  if (!rc)
+    i386_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Observer function for a new thread attach.  We need to insert
+   existing watchpoints and hardware breakpoints on the new thread.  */
+static void
+i386_linux_new_thread (ptid_t ptid)
+{
+  int i;
+  struct i386_debug_register_state dbs;
+
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    dbs.addr[i] = i386_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
+  dbs.control = i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+
+  i386_linux_set_debug_regs_for_thread (ptid, &dbs);
+}
+
 /* Called by libthread_db.  Returns a pointer to the thread local
    storage (or its descriptor).  */
 
@@ -818,4 +943,6 @@
 
   /* Register the target.  */
   linux_nat_add_target (t);
+
+  observer_attach_linux_new_thread (i386_linux_new_thread);
 }
Index: gdb/amd64-linux-nat.c
===================================================================
--- gdb.orig/amd64-linux-nat.c	2007-08-13 06:22:00.000000000 -0700
+++ gdb/amd64-linux-nat.c	2007-08-13 06:22:05.000000000 -0700
@@ -25,6 +25,7 @@
 #include "inferior.h"
 #include "gdbcore.h"
 #include "regcache.h"
+#include "observer.h"
 #include "linux-nat.h"
 #include "amd64-linux-tdep.h"
 
@@ -237,14 +238,14 @@
 
 
 static unsigned long
-amd64_linux_dr_get (int regnum)
+amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
   int tid;
   unsigned long value;
 
-  tid = TIDGET (inferior_ptid);
+  tid = TIDGET (ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = PIDGET (ptid);
 
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
      ptrace call fails breaks debugging remote targets.  The correct
@@ -265,13 +266,13 @@
 }
 
 static void
-amd64_linux_dr_set (int regnum, unsigned long value)
+amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
 {
   int tid;
 
-  tid = TIDGET (inferior_ptid);
+  tid = TIDGET (ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid);
+    tid = PIDGET (ptid);
 
   errno = 0;
   ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
@@ -280,34 +281,158 @@
 }
 
 void
-amd64_linux_dr_set_control (unsigned long control)
+amd64_linux_dr_set_control (ptid_t ptid, unsigned long control)
 {
-  amd64_linux_dr_set (DR_CONTROL, control);
+  amd64_linux_dr_set (ptid, DR_CONTROL, control);
 }
 
 void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+amd64_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr)
 {
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
 
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+  amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
 }
 
 void
-amd64_linux_dr_reset_addr (int regnum)
+amd64_linux_dr_reset_addr (ptid_t ptid, int regnum)
 {
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
 
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+  amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, 0L);
 }
 
 unsigned long
-amd64_linux_dr_get_status (void)
+amd64_linux_dr_get_status (ptid_t ptid)
 {
-  return amd64_linux_dr_get (DR_STATUS);
+  return amd64_linux_dr_get (ptid, DR_STATUS);
 }
 
 
+/* Structure used to sync debug registers for all threads.  */
+struct amd64_debug_register_state
+{
+  int tid;
+  CORE_ADDR addr[DR_LASTADDR - DR_FIRSTADDR + 1];
+  unsigned long control;
+};
+
+static void
+amd64_linux_set_debug_regs_for_thread (ptid_t ptid,
+				       struct amd64_debug_register_state *dbs)
+{
+  int i;
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    amd64_linux_dr_set_addr (ptid, i, dbs->addr[i]);
+  amd64_linux_dr_set_control (ptid, dbs->control);
+}
+
+/* Iterator function to support syncing debug registers across all threads.  */
+static int
+amd64_linux_sync_debug_registers_callback (struct lwp_info *lwp, void *data)
+{
+  struct amd64_debug_register_state *args = data;
+  int i, tid;
+
+  tid = TIDGET (lwp->ptid);
+  if (tid == 0)
+    tid = PIDGET (lwp->ptid);
+
+  if (tid != args->tid)
+    amd64_linux_set_debug_regs_for_thread (lwp->ptid, args);
+  return 0;
+}
+
+/* Sync the debug registers for all known threads to the current
+   thread that has just performed an operation.  This is required
+   because the debug registers are thread-specific.  We want
+   watchpoints and hardware breakpoints to be treated globally
+   across all threads.  */
+static int
+amd64_linux_sync_debug_registers_across_threads (void)
+{
+  int i, tid;
+  struct amd64_debug_register_state args;
+
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
+
+  args.tid = tid;
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    args.addr[i] = amd64_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
+  args.control = amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+
+  iterate_over_lwps (&amd64_linux_sync_debug_registers_callback, &args);
+
+  return 0;
+}
+
+/* Insert a watchpoint to watch a memory region which starts at
+   address ADDR and whose length is LEN bytes.  Watch memory accesses
+   of the type TYPE.  Return 0 on success, -1 on failure.  */
+int
+amd64_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  int rc;
+  rc = i386_insert_watchpoint (addr, len, type);
+  if (!rc)
+    amd64_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* 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.  */
+int
+amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+  int rc;
+  rc = i386_remove_watchpoint (addr, len, type);
+  if (!rc)
+    amd64_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
+   unused.  Return 0 on success, EBUSY on failure.  */
+int
+amd64_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
+{
+  int rc;
+  rc = i386_insert_hw_breakpoint (bp_tgt);
+  if (!rc)
+    amd64_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
+   unused.  Return 0 on success, -1 on failure.  */
+int
+amd64_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
+{
+  int rc;
+  rc = i386_remove_hw_breakpoint (bp_tgt);
+  if (!rc)
+    amd64_linux_sync_debug_registers_across_threads ();
+  return rc;
+}
+
+/* Observer function for a new thread attach.  We need to insert
+   existing watchpoints and hardware breakpoints on the new thread.  */
+static void
+amd64_linux_new_thread (ptid_t ptid)
+{
+  int i;
+  struct amd64_debug_register_state dbs;
+
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
+    dbs.addr[i] = amd64_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
+  dbs.control = amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+
+  amd64_linux_set_debug_regs_for_thread (ptid, &dbs);
+}
+
 /* This function is called by libthread_db as part of its handling of
    a request for a thread's local storage address.  */
 
@@ -408,4 +533,6 @@
 
   /* Register the target.  */
   linux_nat_add_target (t);
+
+  observer_attach_linux_new_thread (amd64_linux_new_thread);
 }
Index: gdb/testsuite/gdb.threads/watchthreads.c
===================================================================
--- gdb.orig/testsuite/gdb.threads/watchthreads.c	2007-08-13 06:22:00.000000000 -0700
+++ gdb/testsuite/gdb.threads/watchthreads.c	2007-08-13 06:22:05.000000000 -0700
@@ -58,7 +58,7 @@
     /* Don't run forever.  Run just short of it :)  */
     while (*myp > 0)
       {
-	(*myp) ++;  /* Loop increment.  */
+	(*myp) ++; usleep (1); /* Loop increment.  */
       }
 
     pthread_exit(NULL);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]