8a516c7
2005-02-28  Jeff Johnston  <jjohnstn@redhat.com>
8a516c7
8a516c7
	* config/i386/nm-linux.h: Change dr register routines to
8a516c7
	accept a ptid_t first argument.  Change all calling macros
8a516c7
	to default the inferior_ptid for the first argument.
8a516c7
	(i386_linux_insert_watchpoint): New prototype.
8a516c7
	(i386_linux_remove_watchpoint, i386_linux_insert_hw_breakpoint): Ditto.
8a516c7
	(i386_linux_remove_hw_breakpoint): Ditto.
8a516c7
	(target_insert_watchpoint, target_remove_watchpoint): Undef and
8a516c7
	override.
8a516c7
	(target_insert_hw_breakpoint, target_remove_hw_breakpoint): Ditto.
8a516c7
	* config/i386/nm-linux64.h: Ditto except add amd64 versions of
8a516c7
	the watchpoint/hw-breakpoint insert/remove routines.
8a516c7
	* i386-nat.c: Include "inferior.h" to define inferior_ptid.
8a516c7
	* i386-linux-nat.c: Change all dr get/set routines to accept
8a516c7
	ptid_t as first argument and to use this argument to determine
8a516c7
	the tid for PTRACE.
8a516c7
	(i386_linux_set_debug_regs_for_thread): New function.
8a516c7
	(i386_linux_sync_debug_registers_callback): Ditto.
8a516c7
	(i386_linux_sync_debug_registers_across_threads): Ditto.
8a516c7
	(i386_linux_insert_watchpoint, i386_linux_remove_watchpoint): Ditto.
8a516c7
	(i386_linux_hw_breakpoint, i386_linux_remove_hw_breakpoint): Ditto.
8a516c7
	(i386_linux_new_thread): Ditto.
8a516c7
	(_initialize_i386_linux_nat): Ditto.
8a516c7
	* amd64-linux-nat.c: Change all dr get/set routines to accept
8a516c7
	ptid_t as first argument and to use this argument to determine
8a516c7
	the tid for PTRACE.
8a516c7
	(amd64_linux_set_debug_regs_for_thread): New function.
8a516c7
	(amd64_linux_sync_debug_registers_callback): Ditto.
8a516c7
	(amd64_linux_sync_debug_registers_across_threads): Ditto.
8a516c7
	(amd64_linux_insert_watchpoint, amd64_linux_remove_watchpoint): Ditto.
8a516c7
	(amd64_linux_hw_breakpoint, amd64_linux_remove_hw_breakpoint): Ditto.
8a516c7
	(amd64_linux_new_thread): Ditto.
8a516c7
	(_initialize_amd64_linux_nat): Register linux new thread observer.
8a516c7
	* testsuite/gdb.threads/watchthreads2.c: New test case.
8a516c7
	* testsuite/gdb.threads/watchthreads2.exp: Ditto.
8a516c7
9231e41
Index: gdb-6.5/gdb/config/i386/nm-linux64.h
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/config/i386/nm-linux64.h	2006-07-12 01:54:10.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/config/i386/nm-linux64.h	2006-07-12 01:54:29.000000000 -0300
8a516c7
@@ -35,22 +35,59 @@
8a516c7
 
8a516c7
 /* Provide access to the i386 hardware debugging registers.  */
8a516c7
 
8a516c7
-extern void amd64_linux_dr_set_control (unsigned long control);
8a516c7
+extern void amd64_linux_dr_set_control (ptid_t ptid, unsigned long control);
8a516c7
 #define I386_DR_LOW_SET_CONTROL(control) \
8a516c7
-  amd64_linux_dr_set_control (control)
8a516c7
+  amd64_linux_dr_set_control (inferior_ptid, control)
8a516c7
 
8a516c7
-extern void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr);
8a516c7
+extern void amd64_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr);
8a516c7
 #define I386_DR_LOW_SET_ADDR(regnum, addr) \
8a516c7
-  amd64_linux_dr_set_addr (regnum, addr)
8a516c7
+  amd64_linux_dr_set_addr (inferior_ptid, regnum, addr)
8a516c7
 
8a516c7
-extern void amd64_linux_dr_reset_addr (int regnum);
8a516c7
+extern void amd64_linux_dr_reset_addr (ptid_t ptid, int regnum);
8a516c7
 #define I386_DR_LOW_RESET_ADDR(regnum) \
8a516c7
-  amd64_linux_dr_reset_addr (regnum)
8a516c7
+  amd64_linux_dr_reset_addr (inferior_ptid, regnum)
8a516c7
 
8a516c7
-extern unsigned long amd64_linux_dr_get_status (void);
8a516c7
+extern unsigned long amd64_linux_dr_get_status (ptid_t ptid);
8a516c7
 #define I386_DR_LOW_GET_STATUS() \
8a516c7
-  amd64_linux_dr_get_status ()
8a516c7
+  amd64_linux_dr_get_status (inferior_ptid)
8a516c7
 
8a516c7
+/* Watchpoints and hardware breakpoints.  */
8a516c7
+
8a516c7
+/* Insert a watchpoint to watch a memory region which starts at
8a516c7
+ *  *    address ADDR and whose length is LEN bytes.  Watch memory accesses
8a516c7
+ *   *       of the type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+extern int amd64_linux_insert_watchpoint (CORE_ADDR addr, int len, int type);
8a516c7
+
8a516c7
+/* Remove a watchpoint that watched the memory region which starts at
8a516c7
+ *  *    address ADDR, whose length is LEN bytes, and for accesses of the
8a516c7
+ *   *       type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+extern int amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
8a516c7
+
8a516c7
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+ *  *    unused.  Return 0 on success, EBUSY on failure.  */
9231e41
+extern int amd64_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt);
8a516c7
+
8a516c7
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+ *  *    unused. Return 0 on success, -1 on failure.  */
9231e41
+extern int  amd64_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt);
8a516c7
+
8a516c7
+/* Override basic amd64 macros for watchpoint and hardware breakpoint 
8a516c7
+ *    insertion/removal to support threads.  */
8a516c7
+#undef target_insert_watchpoint
8a516c7
+#define target_insert_watchpoint(addr, len, type) \
8a516c7
+  amd64_linux_insert_watchpoint (addr, len, type)
8a516c7
+
8a516c7
+#undef target_remove_watchpoint
8a516c7
+#define target_remove_watchpoint(addr, len, type) \
8a516c7
+  amd64_linux_remove_watchpoint (addr, len, type)
8a516c7
+
8a516c7
+#undef target_insert_hw_breakpoint
9231e41
+#define target_insert_hw_breakpoint(bp_tgt) \
9231e41
+  amd64_linux_insert_hw_breakpoint (bp_tgt)
8a516c7
+
8a516c7
+#undef target_remove_hw_breakpoint
9231e41
+#define target_remove_hw_breakpoint(bp_tgt) \
9231e41
+  amd64_linux_remove_hw_breakpoint (bp_tgt)
8a516c7
 
8a516c7
 /* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
8a516c7
 #define FETCH_INFERIOR_REGISTERS
9231e41
Index: gdb-6.5/gdb/config/i386/nm-linux.h
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/config/i386/nm-linux.h	2006-07-12 01:54:10.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/config/i386/nm-linux.h	2006-07-12 01:54:29.000000000 -0300
9231e41
@@ -46,23 +46,61 @@ extern CORE_ADDR register_u_addr (CORE_A
8a516c7
 
8a516c7
 /* Provide access to the i386 hardware debugging registers.  */
8a516c7
 
8a516c7
-extern void i386_linux_dr_set_control (unsigned long control);
8a516c7
+extern void i386_linux_dr_set_control (ptid_t ptid, unsigned long control);
8a516c7
 #define I386_DR_LOW_SET_CONTROL(control) \
8a516c7
-  i386_linux_dr_set_control (control)
8a516c7
+  i386_linux_dr_set_control (inferior_ptid, control)
8a516c7
 
8a516c7
-extern void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr);
8a516c7
+extern void i386_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr);
8a516c7
 #define I386_DR_LOW_SET_ADDR(regnum, addr) \
8a516c7
-  i386_linux_dr_set_addr (regnum, addr)
8a516c7
+  i386_linux_dr_set_addr (inferior_ptid, regnum, addr)
8a516c7
 
8a516c7
-extern void i386_linux_dr_reset_addr (int regnum);
8a516c7
+extern void i386_linux_dr_reset_addr (ptid_t ptid, int regnum);
8a516c7
 #define I386_DR_LOW_RESET_ADDR(regnum) \
8a516c7
-  i386_linux_dr_reset_addr (regnum)
8a516c7
+  i386_linux_dr_reset_addr (inferior_ptid, regnum)
8a516c7
 
8a516c7
-extern unsigned long i386_linux_dr_get_status (void);
8a516c7
+extern unsigned long i386_linux_dr_get_status (ptid_t ptid);
8a516c7
 #define I386_DR_LOW_GET_STATUS() \
8a516c7
-  i386_linux_dr_get_status ()
8a516c7
+  i386_linux_dr_get_status (inferior_ptid)
8a516c7
 
8a516c7
 
8a516c7
+/* Watchpoints and hardware breakpoints.  */
8a516c7
+
8a516c7
+/* Insert a watchpoint to watch a memory region which starts at
8a516c7
+ *    address ADDR and whose length is LEN bytes.  Watch memory accesses
8a516c7
+ *       of the type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+extern int i386_linux_insert_watchpoint (CORE_ADDR addr, int len, int type);
8a516c7
+
8a516c7
+/* Remove a watchpoint that watched the memory region which starts at
8a516c7
+ *    address ADDR, whose length is LEN bytes, and for accesses of the
8a516c7
+ *       type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+extern int i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
8a516c7
+
8a516c7
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+ *    unused.  Return 0 on success, EBUSY on failure.  */
9231e41
+extern int i386_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt);
8a516c7
+
8a516c7
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+ *    unused. Return 0 on success, -1 on failure.  */
9231e41
+extern int  i386_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt);
8a516c7
+
8a516c7
+/* Override basic i386 macros for watchpoint and hardware breakpoint 
8a516c7
+   insertion/removal to support threads.  */
8a516c7
+#undef target_insert_watchpoint
8a516c7
+#define target_insert_watchpoint(addr, len, type) \
8a516c7
+  i386_linux_insert_watchpoint (addr, len, type)
8a516c7
+
8a516c7
+#undef target_remove_watchpoint
8a516c7
+#define target_remove_watchpoint(addr, len, type) \
8a516c7
+  i386_linux_remove_watchpoint (addr, len, type)
8a516c7
+
8a516c7
+#undef target_insert_hw_breakpoint
9231e41
+#define target_insert_hw_breakpoint(bp_tgt) \
9231e41
+  i386_linux_insert_hw_breakpoint (bp_tgt)
8a516c7
+
8a516c7
+#undef target_remove_hw_breakpoint
9231e41
+#define target_remove_hw_breakpoint(bp_tgt) \
9231e41
+  i386_linux_remove_hw_breakpoint (bp_tgt)
8a516c7
+
8a516c7
 /* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
8a516c7
 #define FETCH_INFERIOR_REGISTERS
8a516c7
 
9231e41
Index: gdb-6.5/gdb/i386-nat.c
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/i386-nat.c	2006-07-12 01:54:10.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/i386-nat.c	2006-07-12 01:54:29.000000000 -0300
8a516c7
@@ -21,6 +21,7 @@
8a516c7
 
8a516c7
 #include "defs.h"
8a516c7
 #include "breakpoint.h"
8a516c7
+#include "inferior.h"
8a516c7
 #include "command.h"
8a516c7
 #include "gdbcmd.h"
8a516c7
 
9231e41
Index: gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.c
9231e41
===================================================================
9231e41
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
fef19e0
+++ gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.c	2006-07-12 01:54:29.000000000 -0300
8a516c7
@@ -0,0 +1,66 @@
8a516c7
+/* This testcase is part of GDB, the GNU debugger.
8a516c7
+
8a516c7
+   Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
8a516c7
+
8a516c7
+   This program is free software; you can redistribute it and/or modify
8a516c7
+   it under the terms of the GNU General Public License as published by
8a516c7
+   the Free Software Foundation; either version 2 of the License, or
8a516c7
+   (at your option) any later version.
8a516c7
+
8a516c7
+   This program is distributed in the hope that it will be useful,
8a516c7
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
8a516c7
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8a516c7
+   GNU General Public License for more details.
8a516c7
+
8a516c7
+   You should have received a copy of the GNU General Public License
8a516c7
+   along with this program; if not, write to the Free Software
8a516c7
+   Foundation, Inc., 59 Temple Place - Suite 330,
8a516c7
+   Boston, MA 02111-1307, USA.  
8a516c7
+ 
8a516c7
+   This file is copied from schedlock.c.  */
8a516c7
+
8a516c7
+#include <stdio.h>
8a516c7
+#include <unistd.h>
8a516c7
+#include <stdlib.h>
8a516c7
+#include <pthread.h>
8a516c7
+
8a516c7
+void *thread_function(void *arg); /* Pointer to function executed by each thread */
8a516c7
+
8a516c7
+#define NUM 5
8a516c7
+
8a516c7
+unsigned int args[NUM+1];
8a516c7
+
8a516c7
+int main() {
8a516c7
+    int res;
8a516c7
+    pthread_t threads[NUM];
8a516c7
+    void *thread_result;
8a516c7
+    long i;
8a516c7
+
8a516c7
+    for (i = 0; i < NUM; i++)
8a516c7
+      {
8a516c7
+	args[i] = 1; /* Init value.  */
8a516c7
+	res = pthread_create(&threads[i],
8a516c7
+		             NULL,
8a516c7
+			     thread_function,
8a516c7
+			     (void *) i);
8a516c7
+      }
8a516c7
+
8a516c7
+    args[i] = 1;
8a516c7
+    thread_function ((void *) i);
8a516c7
+
8a516c7
+    exit(EXIT_SUCCESS);
8a516c7
+}
8a516c7
+
8a516c7
+void *thread_function(void *arg) {
8a516c7
+    int my_number =  (long) arg;
8a516c7
+    int *myp = (int *) &args[my_number];
8a516c7
+
8a516c7
+    /* Don't run forever.  Run just short of it :)  */
8a516c7
+    while (*myp > 0)
8a516c7
+      {
fef19e0
+	(*myp) ++; usleep (1); /* Loop increment.  */
8a516c7
+      }
8a516c7
+
8a516c7
+    pthread_exit(NULL);
8a516c7
+}
8a516c7
+
9231e41
Index: gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.exp
9231e41
===================================================================
9231e41
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
fef19e0
+++ gdb-6.5/gdb/testsuite/gdb.threads/watchthreads2.exp	2006-07-12 01:54:29.000000000 -0300
8a516c7
@@ -0,0 +1,133 @@
8a516c7
+# This testcase is part of GDB, the GNU debugger.
8a516c7
+
8a516c7
+# Copyright 2005 Free Software Foundation, Inc.
8a516c7
+
8a516c7
+# This program is free software; you can redistribute it and/or modify
8a516c7
+# it under the terms of the GNU General Public License as published by
8a516c7
+# the Free Software Foundation; either version 2 of the License, or
8a516c7
+# (at your option) any later version.
8a516c7
+#
8a516c7
+# This program is distributed in the hope that it will be useful,
8a516c7
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
8a516c7
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8a516c7
+# GNU General Public License for more details.
8a516c7
+#
8a516c7
+# You should have received a copy of the GNU General Public License
8a516c7
+# along with this program; if not, write to the Free Software
8a516c7
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
8a516c7
+
8a516c7
+# Check that GDB can support multiple watchpoints across threads.
8a516c7
+
8a516c7
+if $tracelevel {
8a516c7
+    strace $tracelevel
8a516c7
+}
8a516c7
+
8a516c7
+set prms_id 0
8a516c7
+set bug_id 0
8a516c7
+
8a516c7
+# This test verifies that a watchpoint is detected in the proper thread
8a516c7
+# so the test is only meaningful on a system with hardware watchpoints.
8a516c7
+if [target_info exists gdb,no_hardware_watchpoints] {
8a516c7
+    return 0;
8a516c7
+}
8a516c7
+
8a516c7
+set testfile "watchthreads2"
8a516c7
+set srcfile ${testfile}.c
8a516c7
+set binfile ${objdir}/${subdir}/${testfile}
8a516c7
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
8a516c7
+    return -1
8a516c7
+}
8a516c7
+
8a516c7
+gdb_exit
8a516c7
+gdb_start
8a516c7
+gdb_reinitialize_dir $srcdir/$subdir
8a516c7
+gdb_load ${binfile}
8a516c7
+
8a516c7
+gdb_test "set can-use-hw-watchpoints 1" "" ""
8a516c7
+
8a516c7
+#
8a516c7
+# Run to `main' where we begin our tests.
8a516c7
+#
8a516c7
+
8a516c7
+if ![runto_main] then {
8a516c7
+    gdb_suppress_tests
8a516c7
+}
8a516c7
+
8a516c7
+set args_2 0
8a516c7
+set args_3 0
8a516c7
+
8a516c7
+gdb_breakpoint "thread_function"
8a516c7
+gdb_continue_to_breakpoint "thread_function"
8a516c7
+gdb_test "disable 2" ""
8a516c7
+
8a516c7
+gdb_test_multiple "p args\[2\]" "get initial args2" {
8a516c7
+  -re "\\\$\[0-9\]* = (.*)$gdb_prompt $" {
8a516c7
+    set init_args_2 $expect_out(1,string)
8a516c7
+    pass "get initial args2"
8a516c7
+  }
8a516c7
+}
8a516c7
+
8a516c7
+gdb_test_multiple "p args\[3\]" "get initial args3" {
8a516c7
+  -re "\\\$\[0-9\]* = (.*)$gdb_prompt $" {
8a516c7
+    set init_args_3 $expect_out(1,string)
8a516c7
+    pass "get initial args3"
8a516c7
+  }
8a516c7
+}
8a516c7
+
8a516c7
+set args_2 $init_args_2
8a516c7
+set args_3 $init_args_3
8a516c7
+
8a516c7
+# Watch values that will be modified by distinct threads.
8a516c7
+gdb_test "watch args\[2\]" "Hardware watchpoint 3: args\\\[2\\\]"
8a516c7
+gdb_test "watch args\[3\]" "Hardware watchpoint 4: args\\\[3\\\]"
8a516c7
+
8a516c7
+set init_line [expr [gdb_get_line_number "Init value"]+1]
8a516c7
+set inc_line [gdb_get_line_number "Loop increment"]
8a516c7
+
8a516c7
+# Loop and continue to allow both watchpoints to be triggered.
8a516c7
+for {set i 0} {$i < 30} {incr i} {
8a516c7
+  set test_flag 0
8a516c7
+  gdb_test_multiple "continue" "threaded watch loop" {
8a516c7
+    -re "Hardware watchpoint 3: args\\\[2\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads2.c:$init_line.*$gdb_prompt $"
8a516c7
+       { set args_2 1; set test_flag 1 }
8a516c7
+    -re "Hardware watchpoint 4: args\\\[3\\\].*Old value = 0.*New value = 1.*main \\\(\\\) at .*watchthreads2.c:$init_line.*$gdb_prompt $"
8a516c7
+       { set args_3 1; set test_flag 1 }
8a516c7
+    -re "Hardware watchpoint 3: args\\\[2\\\].*Old value = $args_2.*New value = [expr $args_2+1].*in thread_function \\\(arg=0x2\\\) at .*watchthreads2.c:$inc_line.*$gdb_prompt $"
8a516c7
+       { set args_2 [expr $args_2+1]; set test_flag 1 }
8a516c7
+    -re "Hardware watchpoint 4: args\\\[3\\\].*Old value = $args_3.*New value = [expr $args_3+1].*in thread_function \\\(arg=0x3\\\) at .*watchthreads2.c:$inc_line.*$gdb_prompt $"
8a516c7
+       { set args_3 [expr $args_3+1]; set test_flag 1 }
8a516c7
+  }
8a516c7
+  # If we fail above, don't bother continuing loop
8a516c7
+  if { $test_flag == 0 } {
8a516c7
+    set i 30;
8a516c7
+  }
8a516c7
+}
8a516c7
+
8a516c7
+# Print success message if loop succeeded.
8a516c7
+if { $test_flag == 1 } {
8a516c7
+  pass "threaded watch loop"
8a516c7
+}
8a516c7
+
8a516c7
+# Verify that we hit first watchpoint in child thread.
8a516c7
+set message "watchpoint on args\[2\] hit in thread"
8a516c7
+if { $args_2 > 1 } {
8a516c7
+  pass $message 
8a516c7
+} else {
8a516c7
+  fail $message
8a516c7
+}
8a516c7
+
8a516c7
+# Verify that we hit second watchpoint in child thread.
8a516c7
+set message "watchpoint on args\[3\] hit in thread"
8a516c7
+if { $args_3 > 1 } {
8a516c7
+  pass $message 
8a516c7
+} else {
8a516c7
+  fail $message 
8a516c7
+}
8a516c7
+
8a516c7
+# Verify that all watchpoint hits are accounted for.
8a516c7
+set message "combination of threaded watchpoints = 30 + initial values"
8a516c7
+if { [expr $args_2+$args_3] == [expr [expr 30+$init_args_2]+$init_args_3] } {
8a516c7
+  pass $message 
8a516c7
+} else {
8a516c7
+  fail $message 
8a516c7
+}
9231e41
Index: gdb-6.5/gdb/i386-linux-nat.c
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/i386-linux-nat.c	2006-07-12 01:54:28.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/i386-linux-nat.c	2006-07-12 01:57:19.000000000 -0300
9231e41
@@ -24,6 +24,7 @@
8a516c7
 #include "inferior.h"
8a516c7
 #include "gdbcore.h"
8a516c7
 #include "regcache.h"
8a516c7
+#include "observer.h"
9231e41
 #include "target.h"
8a516c7
 #include "linux-nat.h"
8a516c7
 
9231e41
@@ -614,14 +615,14 @@ i386_linux_store_inferior_registers (int
8a516c7
 /* Support for debug registers.  */
8a516c7
 
8a516c7
 static unsigned long
8a516c7
-i386_linux_dr_get (int regnum)
8a516c7
+i386_linux_dr_get (ptid_t ptid, int regnum)
8a516c7
 {
8a516c7
   int tid;
8a516c7
   unsigned long value;
8a516c7
 
8a516c7
-  tid = TIDGET (inferior_ptid);
8a516c7
+  tid = TIDGET (ptid);
8a516c7
   if (tid == 0)
8a516c7
-    tid = PIDGET (inferior_ptid);
8a516c7
+    tid = PIDGET (ptid);
8a516c7
 
8a516c7
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
8a516c7
      ptrace call fails breaks debugging remote targets.  The correct
9231e41
@@ -642,13 +643,13 @@ i386_linux_dr_get (int regnum)
8a516c7
 }
8a516c7
 
8a516c7
 static void
8a516c7
-i386_linux_dr_set (int regnum, unsigned long value)
8a516c7
+i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
8a516c7
 {
8a516c7
   int tid;
8a516c7
 
8a516c7
-  tid = TIDGET (inferior_ptid);
8a516c7
+  tid = TIDGET (ptid);
8a516c7
   if (tid == 0)
8a516c7
-    tid = PIDGET (inferior_ptid);
8a516c7
+    tid = PIDGET (ptid);
8a516c7
 
8a516c7
   errno = 0;
8a516c7
   ptrace (PTRACE_POKEUSER, tid,
9231e41
@@ -658,34 +659,158 @@ i386_linux_dr_set (int regnum, unsigned 
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-i386_linux_dr_set_control (unsigned long control)
8a516c7
+i386_linux_dr_set_control (ptid_t ptid, unsigned long control)
8a516c7
 {
8a516c7
-  i386_linux_dr_set (DR_CONTROL, control);
8a516c7
+  i386_linux_dr_set (ptid, DR_CONTROL, control);
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
8a516c7
+i386_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr)
8a516c7
 {
8a516c7
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
8a516c7
 
8a516c7
-  i386_linux_dr_set (DR_FIRSTADDR + regnum, addr);
8a516c7
+  i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-i386_linux_dr_reset_addr (int regnum)
8a516c7
+i386_linux_dr_reset_addr (ptid_t ptid, int regnum)
8a516c7
 {
8a516c7
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
8a516c7
 
8a516c7
-  i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
8a516c7
+  i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, 0L);
8a516c7
 }
8a516c7
 
8a516c7
 unsigned long
8a516c7
-i386_linux_dr_get_status (void)
8a516c7
+i386_linux_dr_get_status (ptid_t ptid)
8a516c7
 {
8a516c7
-  return i386_linux_dr_get (DR_STATUS);
8a516c7
+  return i386_linux_dr_get (ptid, DR_STATUS);
8a516c7
 }
8a516c7
 
8a516c7
 
8a516c7
+/* Structure used to sync debug registers for all threads.  */
8a516c7
+struct i386_debug_register_state
8a516c7
+{
8a516c7
+  int tid;
8a516c7
+  CORE_ADDR addr[DR_LASTADDR - DR_FIRSTADDR + 1];
8a516c7
+  unsigned long control;
8a516c7
+};
8a516c7
+
8a516c7
+static void
8a516c7
+i386_linux_set_debug_regs_for_thread (ptid_t ptid,
8a516c7
+				      struct i386_debug_register_state *dbs)
8a516c7
+{
8a516c7
+  int i;
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    i386_linux_dr_set_addr (ptid, i, dbs->addr[i]);
8a516c7
+  i386_linux_dr_set_control (ptid, dbs->control);
8a516c7
+}
8a516c7
+
8a516c7
+/* Iterator function to support syncing debug registers across all threads.  */
8a516c7
+static int
8a516c7
+i386_linux_sync_debug_registers_callback (struct lwp_info *lwp, void *data)
8a516c7
+{
8a516c7
+  struct i386_debug_register_state *args = data;
8a516c7
+  int i, tid;
8a516c7
+
8a516c7
+  tid = TIDGET (lwp->ptid);
8a516c7
+  if (tid == 0)
8a516c7
+    tid = PIDGET (lwp->ptid);
8a516c7
+
8a516c7
+  if (tid != args->tid)
8a516c7
+    i386_linux_set_debug_regs_for_thread (lwp->ptid, args);
8a516c7
+  return 0;
8a516c7
+}
8a516c7
+
8a516c7
+/* Sync the debug registers for all known threads to the current
8a516c7
+   thread that has just performed an operation.  This is required
8a516c7
+   because the debug registers are thread-specific.  We want
8a516c7
+   watchpoints and hardware breakpoints to be treated globally
8a516c7
+   across all threads.  */
8a516c7
+static int
8a516c7
+i386_linux_sync_debug_registers_across_threads (void)
8a516c7
+{
8a516c7
+  int i, tid;
8a516c7
+  struct i386_debug_register_state args;
8a516c7
+
8a516c7
+  tid = TIDGET (inferior_ptid);
8a516c7
+  if (tid == 0)
8a516c7
+    tid = PIDGET (inferior_ptid);
8a516c7
+
8a516c7
+  args.tid = tid;
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    args.addr[i] = i386_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
8a516c7
+  args.control = i386_linux_dr_get (inferior_ptid, DR_CONTROL);
8a516c7
+
8a516c7
+  iterate_over_lwps (&i386_linux_sync_debug_registers_callback, &args);
8a516c7
+
8a516c7
+  return 0;
8a516c7
+}
8a516c7
+
8a516c7
+/* Insert a watchpoint to watch a memory region which starts at
8a516c7
+   address ADDR and whose length is LEN bytes.  Watch memory accesses
8a516c7
+   of the type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+int
8a516c7
+i386_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
8a516c7
+{
8a516c7
+  int rc;
8a516c7
+  rc = i386_insert_watchpoint (addr, len, type);
8a516c7
+  if (!rc)
8a516c7
+    i386_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Remove a watchpoint that watched the memory region which starts at
8a516c7
+   address ADDR, whose length is LEN bytes, and for accesses of the
8a516c7
+   type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+int
8a516c7
+i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
8a516c7
+{
8a516c7
+  int rc;
8a516c7
+  rc = i386_remove_watchpoint (addr, len, type);
8a516c7
+  if (!rc)
8a516c7
+    i386_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+   unused.  Return 0 on success, EBUSY on failure.  */
8a516c7
+int
9231e41
+i386_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
8a516c7
+{
8a516c7
+  int rc;
1e7b928
+  rc = i386_insert_hw_breakpoint (bp_tgt);
8a516c7
+  if (!rc)
8a516c7
+    i386_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+   unused.  Return 0 on success, -1 on failure.  */
8a516c7
+int
9231e41
+i386_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
8a516c7
+{
8a516c7
+  int rc;
9231e41
+  rc = i386_remove_hw_breakpoint (bp_tgt);
8a516c7
+  if (!rc)
8a516c7
+    i386_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Observer function for a new thread attach.  We need to insert
8a516c7
+   existing watchpoints and hardware breakpoints on the new thread.  */
8a516c7
+static void
8a516c7
+i386_linux_new_thread (ptid_t ptid)
8a516c7
+{
8a516c7
+  int i;
8a516c7
+  struct i386_debug_register_state dbs;
8a516c7
+
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    dbs.addr[i] = i386_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
8a516c7
+  dbs.control = i386_linux_dr_get (inferior_ptid, DR_CONTROL);
8a516c7
+
8a516c7
+  i386_linux_set_debug_regs_for_thread (ptid, &dbs;;
8a516c7
+}
8a516c7
+
8a516c7
 /* Called by libthread_db.  Returns a pointer to the thread local
8a516c7
    storage (or its descriptor).  */
8a516c7
 
1e7b928
@@ -843,4 +968,6 @@ _initialize_i386_linux_nat (void)
1e7b928
 
9231e41
   /* Register the target.  */
9231e41
   linux_nat_add_target (t);
8a516c7
+
8a516c7
+  observer_attach_linux_new_thread (i386_linux_new_thread);
1e7b928
 }
9231e41
Index: gdb-6.5/gdb/amd64-linux-nat.c
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/amd64-linux-nat.c	2006-07-12 01:54:28.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/amd64-linux-nat.c	2006-07-12 01:54:29.000000000 -0300
9231e41
@@ -25,6 +25,7 @@
8a516c7
 #include "inferior.h"
8a516c7
 #include "gdbcore.h"
8a516c7
 #include "regcache.h"
8a516c7
+#include "observer.h"
8a516c7
 #include "linux-nat.h"
8a516c7
 
8a516c7
 #include "gdb_assert.h"
9231e41
@@ -229,14 +230,14 @@ amd64_linux_store_inferior_registers (in
8a516c7
 
8a516c7
 
8a516c7
 static unsigned long
8a516c7
-amd64_linux_dr_get (int regnum)
8a516c7
+amd64_linux_dr_get (ptid_t ptid, int regnum)
8a516c7
 {
8a516c7
   int tid;
8a516c7
   unsigned long value;
8a516c7
 
8a516c7
-  tid = TIDGET (inferior_ptid);
8a516c7
+  tid = TIDGET (ptid);
8a516c7
   if (tid == 0)
8a516c7
-    tid = PIDGET (inferior_ptid);
8a516c7
+    tid = PIDGET (ptid);
8a516c7
 
8a516c7
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
8a516c7
      ptrace call fails breaks debugging remote targets.  The correct
9231e41
@@ -257,13 +258,13 @@ amd64_linux_dr_get (int regnum)
8a516c7
 }
8a516c7
 
8a516c7
 static void
8a516c7
-amd64_linux_dr_set (int regnum, unsigned long value)
8a516c7
+amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
8a516c7
 {
8a516c7
   int tid;
8a516c7
 
8a516c7
-  tid = TIDGET (inferior_ptid);
8a516c7
+  tid = TIDGET (ptid);
8a516c7
   if (tid == 0)
8a516c7
-    tid = PIDGET (inferior_ptid);
8a516c7
+    tid = PIDGET (ptid);
8a516c7
 
8a516c7
   errno = 0;
8a516c7
   ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
9231e41
@@ -272,34 +273,158 @@ amd64_linux_dr_set (int regnum, unsigned
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-amd64_linux_dr_set_control (unsigned long control)
8a516c7
+amd64_linux_dr_set_control (ptid_t ptid, unsigned long control)
8a516c7
 {
8a516c7
-  amd64_linux_dr_set (DR_CONTROL, control);
8a516c7
+  amd64_linux_dr_set (ptid, DR_CONTROL, control);
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
8a516c7
+amd64_linux_dr_set_addr (ptid_t ptid, int regnum, CORE_ADDR addr)
8a516c7
 {
8a516c7
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
8a516c7
 
8a516c7
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
8a516c7
+  amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
8a516c7
 }
8a516c7
 
8a516c7
 void
8a516c7
-amd64_linux_dr_reset_addr (int regnum)
8a516c7
+amd64_linux_dr_reset_addr (ptid_t ptid, int regnum)
8a516c7
 {
8a516c7
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
8a516c7
 
8a516c7
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
8a516c7
+  amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, 0L);
8a516c7
 }
8a516c7
 
8a516c7
 unsigned long
8a516c7
-amd64_linux_dr_get_status (void)
8a516c7
+amd64_linux_dr_get_status (ptid_t ptid)
8a516c7
 {
8a516c7
-  return amd64_linux_dr_get (DR_STATUS);
8a516c7
+  return amd64_linux_dr_get (ptid, DR_STATUS);
8a516c7
 }
8a516c7
 
8a516c7
 
8a516c7
+/* Structure used to sync debug registers for all threads.  */
8a516c7
+struct amd64_debug_register_state
8a516c7
+{
8a516c7
+  int tid;
8a516c7
+  CORE_ADDR addr[DR_LASTADDR - DR_FIRSTADDR + 1];
8a516c7
+  unsigned long control;
8a516c7
+};
8a516c7
+
8a516c7
+static void
8a516c7
+amd64_linux_set_debug_regs_for_thread (ptid_t ptid,
8a516c7
+				       struct amd64_debug_register_state *dbs)
8a516c7
+{
8a516c7
+  int i;
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    amd64_linux_dr_set_addr (ptid, i, dbs->addr[i]);
8a516c7
+  amd64_linux_dr_set_control (ptid, dbs->control);
8a516c7
+}
8a516c7
+
8a516c7
+/* Iterator function to support syncing debug registers across all threads.  */
8a516c7
+static int
8a516c7
+amd64_linux_sync_debug_registers_callback (struct lwp_info *lwp, void *data)
8a516c7
+{
8a516c7
+  struct amd64_debug_register_state *args = data;
8a516c7
+  int i, tid;
8a516c7
+
8a516c7
+  tid = TIDGET (lwp->ptid);
8a516c7
+  if (tid == 0)
8a516c7
+    tid = PIDGET (lwp->ptid);
8a516c7
+
8a516c7
+  if (tid != args->tid)
8a516c7
+    amd64_linux_set_debug_regs_for_thread (lwp->ptid, args);
8a516c7
+  return 0;
8a516c7
+}
8a516c7
+
8a516c7
+/* Sync the debug registers for all known threads to the current
8a516c7
+   thread that has just performed an operation.  This is required
8a516c7
+   because the debug registers are thread-specific.  We want
8a516c7
+   watchpoints and hardware breakpoints to be treated globally
8a516c7
+   across all threads.  */
8a516c7
+static int
8a516c7
+amd64_linux_sync_debug_registers_across_threads (void)
8a516c7
+{
8a516c7
+  int i, tid;
8a516c7
+  struct amd64_debug_register_state args;
8a516c7
+
8a516c7
+  tid = TIDGET (inferior_ptid);
8a516c7
+  if (tid == 0)
8a516c7
+    tid = PIDGET (inferior_ptid);
8a516c7
+
8a516c7
+  args.tid = tid;
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    args.addr[i] = amd64_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
8a516c7
+  args.control = amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
8a516c7
+
8a516c7
+  iterate_over_lwps (&amd64_linux_sync_debug_registers_callback, &args);
8a516c7
+
8a516c7
+  return 0;
8a516c7
+}
8a516c7
+
8a516c7
+/* Insert a watchpoint to watch a memory region which starts at
8a516c7
+   address ADDR and whose length is LEN bytes.  Watch memory accesses
8a516c7
+   of the type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+int
8a516c7
+amd64_linux_insert_watchpoint (CORE_ADDR addr, int len, int type)
8a516c7
+{
8a516c7
+  int rc;
8a516c7
+  rc = i386_insert_watchpoint (addr, len, type);
8a516c7
+  if (!rc)
8a516c7
+    amd64_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Remove a watchpoint that watched the memory region which starts at
8a516c7
+   address ADDR, whose length is LEN bytes, and for accesses of the
8a516c7
+   type TYPE.  Return 0 on success, -1 on failure.  */
8a516c7
+int
8a516c7
+amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
8a516c7
+{
8a516c7
+  int rc;
8a516c7
+  rc = i386_remove_watchpoint (addr, len, type);
8a516c7
+  if (!rc)
8a516c7
+    amd64_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Insert a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+   unused.  Return 0 on success, EBUSY on failure.  */
8a516c7
+int
9231e41
+amd64_linux_insert_hw_breakpoint (struct bp_target_info *bp_tgt)
8a516c7
+{
8a516c7
+  int rc;
9231e41
+  rc = i386_insert_hw_breakpoint (bp_tgt);
8a516c7
+  if (!rc)
8a516c7
+    amd64_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Remove a hardware-assisted breakpoint at address ADDR.  SHADOW is
8a516c7
+   unused.  Return 0 on success, -1 on failure.  */
8a516c7
+int
9231e41
+amd64_linux_remove_hw_breakpoint (struct bp_target_info *bp_tgt)
8a516c7
+{
8a516c7
+  int rc;
9231e41
+  rc = i386_remove_hw_breakpoint (bp_tgt);
8a516c7
+  if (!rc)
8a516c7
+    amd64_linux_sync_debug_registers_across_threads ();
8a516c7
+  return rc;
8a516c7
+}
8a516c7
+
8a516c7
+/* Observer function for a new thread attach.  We need to insert
8a516c7
+   existing watchpoints and hardware breakpoints on the new thread.  */
8a516c7
+static void
8a516c7
+amd64_linux_new_thread (ptid_t ptid)
8a516c7
+{
8a516c7
+  int i;
8a516c7
+  struct amd64_debug_register_state dbs;
8a516c7
+
8a516c7
+  for (i = 0; i < (DR_LASTADDR - DR_FIRSTADDR) + 1; ++i)
8a516c7
+    dbs.addr[i] = amd64_linux_dr_get (inferior_ptid, DR_FIRSTADDR + i);
8a516c7
+  dbs.control = amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
8a516c7
+
8a516c7
+  amd64_linux_set_debug_regs_for_thread (ptid, &dbs;;
8a516c7
+}
8a516c7
+
8a516c7
 /* This function is called by libthread_db as part of its handling of
8a516c7
    a request for a thread's local storage address.  */
8a516c7
 
9231e41
@@ -399,4 +524,6 @@ _initialize_amd64_linux_nat (void)
9231e41
 
9231e41
   /* Register the target.  */
9231e41
   linux_nat_add_target (t);
8a516c7
+
8a516c7
+  observer_attach_linux_new_thread (amd64_linux_new_thread);
8a516c7
 }
fef19e0
Index: gdb-6.5/gdb/testsuite/gdb.threads/watchthreads.c
fef19e0
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/testsuite/gdb.threads/watchthreads.c	2006-07-12 01:55:19.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/testsuite/gdb.threads/watchthreads.c	2006-07-12 01:56:51.000000000 -0300
fef19e0
@@ -58,7 +58,7 @@ void *thread_function(void *arg) {
fef19e0
     /* Don't run forever.  Run just short of it :)  */
fef19e0
     while (*myp > 0)
fef19e0
       {
fef19e0
-	(*myp) ++;  /* Loop increment.  */
fef19e0
+	(*myp) ++; usleep (1); /* Loop increment.  */
fef19e0
       }
fef19e0
 
fef19e0
     pthread_exit(NULL);