Hello,

I couldn't stand not having it any more. Here are patches to finish
hardware breakpoint support to gnumach (including kdb) and gdb.  I have
uploaded pre-built gdb packages on
http://people.debian.org/~sthibault/hurd-i386/gdb/

Could people have a look at the interface and comment?  It's in straight
line with the existing thread state interface: get or set the whole 8
registers, so it should be just fine.

Mach makes sure that the addresses lie in the user space, and on task
switch, loads them into the cpu. The kernel can also makes use of the
hardware register. In that case, the userland-provided values are not
loaded any more until the kernel stops using them.

Thomas S., when we agree on the interface, could you review and commit
the gdb part?

Samuel
diff --git a/i386/i386/db_interface.c b/i386/i386/db_interface.c
index d149adc..660da72 100644
--- a/i386/i386/db_interface.c
+++ b/i386/i386/db_interface.c
@@ -27,8 +27,6 @@
  * Interface to new debugger.
  */
 
-#if MACH_KDB
-
 #include <sys/reboot.h>
 #include <vm/pmap.h>
 
@@ -57,12 +55,149 @@
 #include <machine/db_interface.h>
 #include <machine/machspl.h>
 
+#if MACH_KDB
+/* Whether the kernel uses any debugging register.  */
+static int kernel_dr;
+#endif
+
+void db_load_context(pcb_t pcb)
+{
+#if MACH_KDB
+       int s = splhigh();
+
+       if (kernel_dr) {
+               splx(s);
+               return;
+       }
+#endif
+
+       /* Else set user debug registers */
+       set_dr0(pcb->ims.ids.dr[0]);
+       set_dr1(pcb->ims.ids.dr[1]);
+       set_dr2(pcb->ims.ids.dr[2]);
+       set_dr3(pcb->ims.ids.dr[3]);
+       set_dr7(pcb->ims.ids.dr[7]);
+#if MACH_KDB
+       splx(s);
+#endif
+}
+
+void db_get_debug_state(
+       pcb_t pcb,
+       struct i386_debug_state *state)
+{
+       *state = pcb->ims.ids;
+}
+
+kern_return_t db_set_debug_state(
+       pcb_t pcb,
+       const struct i386_debug_state *state)
+{
+       int i;
+
+       for (i = 0; i <= 3; i++)
+               if (state->dr[i] < VM_MIN_ADDRESS
+                || state->dr[i] >= VM_MAX_ADDRESS)
+                       return KERN_INVALID_ARGUMENT;
+
+       pcb->ims.ids = *state;
+
+       if (pcb == current_thread()->pcb)
+               db_load_context(pcb);
+
+       return KERN_SUCCESS;
+}
+
+#if MACH_KDB
+
 struct  i386_saved_state *i386_last_saved_statep;
 struct  i386_saved_state i386_nested_saved_state;
 unsigned i386_last_kdb_sp;
 
 extern thread_t db_default_thread;
 
+static struct i386_debug_state ids;
+
+void db_dr (
+       int             num,
+       vm_offset_t     linear_addr,
+       int             type,
+       int             len,
+       int             persistence)
+{
+       int s = splhigh();
+       unsigned long dr7;
+
+       if (!kernel_dr) {
+           if (!linear_addr) {
+               splx(s);
+               return;
+           }
+           kernel_dr = 1;
+           /* Clear user debugging registers */
+           set_dr7(0);
+           set_dr0(0);
+           set_dr1(0);
+           set_dr2(0);
+           set_dr3(0);
+       }
+
+       ids.dr[num] = linear_addr;
+       switch (num) {
+           case 0: set_dr0(linear_addr); break;
+           case 1: set_dr1(linear_addr); break;
+           case 2: set_dr2(linear_addr); break;
+           case 3: set_dr3(linear_addr); break;
+       }
+
+       /* Replace type/len/persistence for DRnum in dr7 */
+       dr7 = get_dr7 ();
+       dr7 &= ~(0xfUL << (4*num+16)) & ~(0x3UL << (2*num));
+       dr7 |= (((len << 2) | type) << (4*num+16)) | (persistence << (2*num));
+       set_dr7 (dr7);
+
+       if (kernel_dr) {
+           if (!ids.dr[0] && !ids.dr[1] && !ids.dr[2] && !ids.dr[3]) {
+               /* Not used any more, switch back to user debugging registers */
+               kernel_dr = 0;
+               db_load_context(current_thread()->pcb);
+           }
+       }
+       splx(s);
+}
+
+void db_set_hw_watchpoint(
+       int             num,
+       task_t          task,
+       db_addr_t       addr,
+       vm_size_t       size)
+{
+       unsigned int kern_addr;
+
+       if (size != 1 && size != 2 && size != 4)
+           return;
+
+       if (addr & (size-1))
+           /* Unaligned */
+           return;
+
+       if (!addr) {
+           db_dr (num, 0, 0, 0, 0);
+           db_printf("Hardware watchpoint %d deleted\n", num);
+       }
+
+       if (task) {
+           if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
+               return;
+           addr = kern_addr;
+       }
+       addr = kvtolin(addr);
+
+       db_dr (num, addr, I386_DB_TYPE_W, size-1, I386_DB_LOCAL|I386_DB_GLOBAL);
+
+       db_printf("Hardware watchpoint %d set for %x\n", num, addr);
+}
+
 /*
  * Print trap reason.
  */
@@ -95,15 +230,14 @@ kdb_trap(
        switch (type) {
            case T_DEBUG:       /* single_step */
            {
-               extern int dr_addr[];
                int addr;
-               int status = dr6();
+               int status = get_dr6();
 
                if (status & 0xf) {     /* hmm hdw break */
-                       addr =  status & 0x8 ? dr_addr[3] :
-                               status & 0x4 ? dr_addr[2] :
-                               status & 0x2 ? dr_addr[1] :
-                                              dr_addr[0];
+                       addr =  status & 0x8 ? get_dr3() :
+                               status & 0x4 ? get_dr2() :
+                               status & 0x2 ? get_dr1() :
+                                              get_dr0();
                        regs->efl |= EFL_RF;
                        db_single_step_cmd(addr, 0, 1, "p");
                }
diff --git a/i386/i386/db_interface.h b/i386/i386/db_interface.h
index 10a02e2..a8dfdce 100644
--- a/i386/i386/db_interface.h
+++ b/i386/i386/db_interface.h
@@ -53,6 +53,12 @@ extern boolean_t db_phys_eq (
        task_t          task2,
        vm_offset_t     addr2);
 
+extern int db_user_to_kernel_address(
+       task_t          task,
+       vm_offset_t     addr,
+       unsigned int    *kaddr,
+       int             flag);
+
 extern void db_task_name (task_t task);
 
 #define I386_DB_TYPE_X 0
@@ -67,9 +73,26 @@ extern void db_task_name (task_t task);
 #define I386_DB_LOCAL 1
 #define I386_DB_GLOBAL 2
 
-extern unsigned long dr0 (vm_offset_t linear_addr, int type, int len, int 
persistence);
-extern unsigned long dr1 (vm_offset_t linear_addr, int type, int len, int 
persistence);
-extern unsigned long dr2 (vm_offset_t linear_addr, int type, int len, int 
persistence);
-extern unsigned long dr3 (vm_offset_t linear_addr, int type, int len, int 
persistence);
+extern void db_set_hw_watchpoint(
+       int             num,
+       task_t          task,
+       vm_offset_t     addr,
+       vm_size_t       size);
+
+extern void db_dr (
+       int             num,
+       vm_offset_t     linear_addr,
+       int             type,
+       int             len,
+       int             persistence);
+
+extern void db_get_debug_state(
+       pcb_t pcb,
+       struct i386_debug_state *state);
+extern kern_return_t db_set_debug_state(
+       pcb_t pcb,
+       const struct i386_debug_state *state);
+
+extern void db_load_context(pcb_t pcb);
 
 #endif /* _I386_DB_INTERFACE_H_ */
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
index 379b219..21bec0a 100644
--- a/i386/i386/locore.S
+++ b/i386/i386/locore.S
@@ -1424,128 +1424,6 @@ _inst_fetch_fault:
 
 
 
-ENTRY(dr6)
-#ifdef MACH_XEN
-       pushl   %ebx
-       movl    $6, %ebx
-       call    __hyp_get_debugreg
-       popl    %ebx
-#else /* MACH_XEN */
-       movl    %db6, %eax
-#endif /* MACH_XEN */
-       ret
-
-/*     dr<i>(address, type, len, persistence)
- */
-ENTRY(dr0)
-       movl    S_ARG0, %eax
-       movl    %eax,EXT(dr_addr)
-#ifdef MACH_XEN
-       pushl   %ebx
-       movl    $0,%ebx
-       movl    %eax,%ecx
-       call    __hyp_set_debugreg
-#else /* MACH_XEN */
-       movl    %eax, %db0
-#endif /* MACH_XEN */
-       movl    $0, %ecx
-       jmp     0f
-ENTRY(dr1)
-       movl    S_ARG0, %eax
-       movl    %eax,EXT(dr_addr)+1*4
-#ifdef MACH_XEN
-       pushl   %ebx
-       movl    $1,%ebx
-       movl    %eax,%ecx
-       call    __hyp_set_debugreg
-#else /* MACH_XEN */
-       movl    %eax, %db1
-#endif /* MACH_XEN */
-       movl    $2, %ecx
-       jmp     0f
-ENTRY(dr2)
-       movl    S_ARG0, %eax
-       movl    %eax,EXT(dr_addr)+2*4
-#ifdef MACH_XEN
-       pushl   %ebx
-       movl    $2,%ebx
-       movl    %eax,%ecx
-       call    __hyp_set_debugreg
-#else /* MACH_XEN */
-       movl    %eax, %db2
-#endif /* MACH_XEN */
-       movl    $4, %ecx
-       jmp     0f
-
-ENTRY(dr3)
-       movl    S_ARG0, %eax
-       movl    %eax,EXT(dr_addr)+3*4
-#ifdef MACH_XEN
-       pushl   %ebx
-       movl    $3,%ebx
-       movl    %eax,%ecx
-       call    __hyp_set_debugreg
-#else /* MACH_XEN */
-       movl    %eax, %db3
-#endif /* MACH_XEN */
-       movl    $6, %ecx
-
-0:
-       pushl   %ebp
-       movl    %esp, %ebp
-
-#ifdef MACH_XEN
-       movl    $7,%ebx
-       call    __hyp_get_debugreg
-       movl    %eax, %edx
-#else /* MACH_XEN */
-       movl    %db7, %edx
-#endif /* MACH_XEN */
-       movl    %edx,EXT(dr_addr)+4*4
-       andl    dr_msk(,%ecx,2),%edx    /* clear out new entry */
-       movl    %edx,EXT(dr_addr)+5*4
-       movzbl  B_ARG3, %eax
-       andb    $3, %al
-       shll    %cl, %eax
-       orl     %eax, %edx
-
-       movzbl  B_ARG1, %eax
-       andb    $3, %al
-       addb    %cl, %cl
-       addb    $0x10, %cl
-       shll    %cl, %eax
-       orl     %eax, %edx
-
-       movzbl  B_ARG2, %eax
-       andb    $3, %al
-       addb    $0x2, %cl
-       shll    %cl, %eax
-       orl     %eax, %edx
-
-#ifdef MACH_XEN
-       movl    $7,%ebx
-       movl    %edx, %ecx
-       call    __hyp_set_debugreg
-       popl    %ebx
-#else /* MACH_XEN */
-       movl    %edx, %db7
-#endif /* MACH_XEN */
-       movl    %edx,EXT(dr_addr)+7*4
-       movl    %edx, %eax
-       leave
-       ret
-
-       .data
-dr_msk:
-       .long   ~0x000f0003
-       .long   ~0x00f0000c
-       .long   ~0x0f000030
-       .long   ~0xf00000c0
-ENTRY(dr_addr)
-       .long   0,0,0,0
-       .long   0,0,0,0
-       .text
-
 /*
  * cpu_shutdown()
  * Force reboot
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index f687db1..2b41577 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -46,6 +46,7 @@
 #include <i386/proc_reg.h>
 #include <i386/seg.h>
 #include <i386/user_ldt.h>
+#include <i386/db_interface.h>
 #include <i386/fpu.h>
 #include "eflags.h"
 #include "gdt.h"
@@ -213,6 +214,8 @@ void switch_ktss(pcb)
         pcb->ims.user_gdt, sizeof pcb->ims.user_gdt);
 #endif /* MACH_XEN */
 
+       db_load_context(pcb);
+
        /*
         * Load the floating-point context, if necessary.
         */
@@ -621,6 +624,21 @@ kern_return_t thread_setstatus(thread, flavor, tstate, 
count)
                break;
            }
 
+           case i386_DEBUG_STATE:
+           {
+               register struct i386_debug_state *state;
+               kern_return_t ret;
+
+               if (count < i386_DEBUG_STATE_COUNT)
+                   return KERN_INVALID_ARGUMENT;
+
+               state = (struct i386_debug_state *) tstate;
+               ret = db_set_debug_state(thread->pcb, state);
+               if (ret)
+                       return ret;
+               break;
+           }
+
            default:
                return(KERN_INVALID_ARGUMENT);
        }
@@ -760,6 +778,20 @@ kern_return_t thread_getstatus(thread, flavor, tstate, 
count)
                break;
            }
 
+           case i386_DEBUG_STATE:
+           {
+               register struct i386_debug_state *state;
+
+               if (*count < i386_DEBUG_STATE_COUNT)
+                   return KERN_INVALID_ARGUMENT;
+
+               state = (struct i386_debug_state *) tstate;
+               db_get_debug_state(thread->pcb, state);
+
+               *count = i386_DEBUG_STATE_COUNT;
+               break;
+           }
+
            default:
                return(KERN_INVALID_ARGUMENT);
        }
diff --git a/i386/i386/proc_reg.h b/i386/i386/proc_reg.h
index 64d8c43..3e81d70 100644
--- a/i386/i386/proc_reg.h
+++ b/i386/i386/proc_reg.h
@@ -234,6 +234,132 @@ extern unsigned long cr3;
        asm("jmp 0f\n" \
             "0:\n")
 
+#ifdef MACH_HYP
+#define get_dr0() hyp_get_debugreg(0)
+#else
+#define        get_dr0() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr0, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr0(value) hyp_set_debugreg(0, value)
+#else
+#define        set_dr0(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr0" : : "r" (_temp__)); \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define get_dr1() hyp_get_debugreg(1)
+#else
+#define        get_dr1() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr1, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr1(value) hyp_set_debugreg(1, value)
+#else
+#define        set_dr1(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr1" : : "r" (_temp__)); \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define get_dr2() hyp_get_debugreg(2)
+#else
+#define        get_dr2() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr2, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr2(value) hyp_set_debugreg(2, value)
+#else
+#define        set_dr2(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr2" : : "r" (_temp__)); \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define get_dr3() hyp_get_debugreg(3)
+#else
+#define        get_dr3() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr3, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr3(value) hyp_set_debugreg(3, value)
+#else
+#define        set_dr3(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr3" : : "r" (_temp__)); \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define get_dr6() hyp_get_debugreg(6)
+#else
+#define        get_dr6() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr6, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr6(value) hyp_set_debugreg(6, value)
+#else
+#define        set_dr6(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr6" : : "r" (_temp__)); \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define get_dr7() hyp_get_debugreg(7)
+#else
+#define        get_dr7() \
+    ({ \
+       register unsigned long _temp__; \
+       asm volatile("movl %%dr7, %0" : "=r" (_temp__)); \
+       _temp__; \
+    })
+#endif
+
+#ifdef MACH_HYP
+#define set_dr7(value) hyp_set_debugreg(7, value)
+#else
+#define        set_dr7(value) \
+    ({ \
+       register unsigned long _temp__ = (value); \
+       asm volatile("movl %0,%%dr7" : : "r" (_temp__)); \
+    })
+#endif
+
 #endif /* __GNUC__ */
 #endif /* __ASSEMBLER__ */
 
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index f2ae8bf..658793e 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -36,6 +36,7 @@
 #include <mach/boolean.h>
 #include <mach/machine/vm_types.h>
 #include <mach/machine/fp_reg.h>
+#include <mach/machine/thread_status.h>
 
 #include <kern/lock.h>
 
@@ -168,6 +169,7 @@ struct i386_machine_state {
        struct i386_fpsave_state *ifps;
        struct v86_assist_state v86s;
        struct real_descriptor user_gdt[USER_GDT_SLOTS];
+       struct i386_debug_state ids;
 };
 
 typedef struct pcb {
diff --git a/i386/include/mach/i386/thread_status.h 
b/i386/include/mach/i386/thread_status.h
index 5f20355..ba1e3de 100644
--- a/i386/include/mach/i386/thread_status.h
+++ b/i386/include/mach/i386/thread_status.h
@@ -56,6 +56,7 @@
 #define i386_ISA_PORT_MAP_STATE        3
 #define        i386_V86_ASSIST_STATE   4
 #define        i386_REGS_SEGS_STATE    5
+#define        i386_DEBUG_STATE        6
 
 /*
  * This structure is used for both
@@ -144,4 +145,10 @@ struct v86_interrupt_table {
 #define        i386_V86_ASSIST_STATE_COUNT \
            (sizeof(struct i386_v86_assist_state)/sizeof(unsigned int))
 
+struct i386_debug_state {
+       unsigned int    dr[8];
+};
+#define        i386_DEBUG_STATE_COUNT \
+           (sizeof(struct i386_debug_state)/sizeof(unsigned int))
+
 #endif /* _MACH_I386_THREAD_STATUS_H_ */
diff -ur gdb-7.3.50~cvs20110627-orig/gdb/gnu-nat.c 
gdb-7.3.50~cvs20110627/gdb/gnu-nat.c
--- gdb-7.3.50~cvs20110627-orig/gdb/gnu-nat.c   2011-06-27 23:37:36.000000000 
+0000
+++ gdb-7.3.50~cvs20110627/gdb/gnu-nat.c        2011-08-21 23:00:39.000000000 
+0000
@@ -989,6 +989,16 @@
   return 0;
 }
 
+/* Interate F over threads.  */
+void
+inf_threads (struct inf *inf, void (*f)(struct proc *thread))
+{
+  struct proc *thread;
+
+  for (thread = inf->threads; thread; thread = thread->next)
+    f(thread);
+}
+
 
 /* Make INF's list of threads be consistent with reality of TASK.  */
 void
diff -ur gdb-7.3.50~cvs20110627-orig/gdb/gnu-nat.h 
gdb-7.3.50~cvs20110627/gdb/gnu-nat.h
--- gdb-7.3.50~cvs20110627-orig/gdb/gnu-nat.h   2011-08-21 23:08:19.000000000 
+0000
+++ gdb-7.3.50~cvs20110627/gdb/gnu-nat.h        2011-08-21 23:08:24.000000000 
+0000
@@ -30,6 +30,9 @@
 /* Converts a GDB pid to a struct proc.  */
 struct proc *inf_tid_to_thread (struct inf *inf, int tid);
 
+/* Iterate F over threads */
+void inf_threads (struct inf *inf, void (*f)(struct proc *thread));
+
 /* Makes sure that INF's thread list is synced with the actual process.  */
 int inf_update_procs (struct inf *inf);
 
diff -ur gdb-7.3.50~cvs20110627-orig/gdb/i386gnu-nat.c 
gdb-7.3.50~cvs20110627/gdb/i386gnu-nat.c
--- gdb-7.3.50~cvs20110627-orig/gdb/i386gnu-nat.c       2011-06-27 
23:37:36.000000000 +0000
+++ gdb-7.3.50~cvs20110627/gdb/i386gnu-nat.c    2011-08-21 23:33:38.000000000 
+0000
@@ -19,6 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "i386-nat.h"
 #include "inferior.h"
 #include "floatformat.h"
 #include "regcache.h"
@@ -36,6 +37,7 @@
 #include "i386-tdep.h"
 
 #include "gnu-nat.h"
+#include "inf-child.h"
 #include "i387-tdep.h"
 
 #ifdef HAVE_SYS_PROCFS_H
@@ -297,6 +299,142 @@
     }
 }
 
+
+/* Support for debug registers.  */
+
+#ifdef i386_DEBUG_STATE
+
+#ifndef DR_FIRSTADDR
+#define DR_FIRSTADDR 0
+#endif
+
+#ifndef DR_LASTADDR
+#define DR_LASTADDR 3
+#endif
+
+#ifndef DR_STATUS
+#define DR_STATUS 6
+#endif
+
+#ifndef DR_CONTROL
+#define DR_CONTROL 7
+#endif
+
+/* Get debug registers for thread THREAD.  */
+
+static void
+i386_gnu_dr_get(struct i386_debug_state *regs, struct proc *thread)
+{
+  mach_msg_type_number_t count = i386_DEBUG_STATE_COUNT;
+  error_t err;
+
+  err = thread_get_state (thread->port, i386_DEBUG_STATE,
+                         (thread_state_t) regs, &count);
+  if (err || count != i386_DEBUG_STATE_COUNT)
+    {
+      warning (_("Couldn't fetch debug state from %s"),
+              proc_string (thread));
+      return;
+    }
+}
+
+/* Set debug registers for thread THREAD.  */
+
+static void
+i386_gnu_dr_set(const struct i386_debug_state *regs, struct proc *thread)
+{
+  error_t err;
+
+  err = thread_set_state (thread->port, i386_DEBUG_STATE,
+                         (thread_state_t) regs, i386_DEBUG_STATE_COUNT);
+  if (err)
+    {
+      warning (_("Couldn't store debug state into %s"),
+              proc_string (thread));
+      return;
+    }
+}
+
+/* Set DR_CONTROL to ADDR in all threads.  */
+
+static void
+i386_gnu_dr_set_control (unsigned long control)
+{
+  void f(struct proc *thread)
+  {
+    struct i386_debug_state regs;
+    i386_gnu_dr_get(&regs, thread);
+    regs.dr[DR_CONTROL] = control;
+    i386_gnu_dr_set(&regs, thread);
+  }
+
+  inf_update_procs (gnu_current_inf);
+  inf_threads(gnu_current_inf, f);
+}
+
+/* Set address REGNUM (zero based) to ADDR in all threads.  */
+
+static void
+i386_gnu_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+  void f(struct proc *thread)
+  {
+    struct i386_debug_state regs;
+    i386_gnu_dr_get(&regs, thread);
+    regs.dr[DR_FIRSTADDR + regnum] = addr;
+    i386_gnu_dr_set(&regs, thread);
+  }
+
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  inf_update_procs (gnu_current_inf);
+  inf_threads(gnu_current_inf, f);
+}
+
+/* Set address REGNUM (zero based) to zero in all threads.  */
+
+static void
+i386_gnu_dr_reset_addr (int regnum)
+{
+  i386_gnu_dr_set_addr (regnum, 0);
+}
+
+/* Get DR_STATUS from only the one thread of INFERIOR_PTID.  */
+
+static unsigned long
+i386_gnu_dr_get_status (void)
+{
+  struct proc *thread;
+  struct i386_debug_state regs;
+
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
+
+  thread = inf_tid_to_thread (gnu_current_inf,
+                             ptid_get_tid (inferior_ptid));
+  i386_gnu_dr_get(&regs, thread);
+
+  return regs.dr[DR_STATUS];
+}
+
+/* Unset MASK bits in DR_STATUS in all threads.  */
+
+static void
+i386_gnu_dr_unset_status (unsigned long mask)
+{
+  void f(struct proc *thread)
+  {
+    struct i386_debug_state regs;
+    i386_gnu_dr_get(&regs, thread);
+    regs.dr[DR_STATUS] &= ~mask;
+    i386_gnu_dr_set(&regs, thread);
+  }
+
+  inf_update_procs (gnu_current_inf);
+  inf_threads(gnu_current_inf, f);
+}
+#endif /* i386_DEBUG_STATE */
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_i386gnu_nat;
 
@@ -308,6 +446,17 @@
   /* Fill in the generic GNU/Hurd methods.  */
   t = gnu_target ();
 
+#ifdef i386_DEBUG_STATE
+  i386_use_watchpoints (t);
+
+  i386_dr_low.set_control = i386_gnu_dr_set_control;
+  i386_dr_low.set_addr = i386_gnu_dr_set_addr;
+  i386_dr_low.reset_addr = i386_gnu_dr_reset_addr;
+  i386_dr_low.get_status = i386_gnu_dr_get_status;
+  i386_dr_low.unset_status = i386_gnu_dr_unset_status;
+  i386_set_debug_register_length (4);
+#endif /* i386_DEBUG_STATE */
+
   t->to_fetch_registers = gnu_fetch_registers;
   t->to_store_registers = gnu_store_registers;
 
diff -ur gdb-7.3.50~cvs20110627-orig/gdb/config/i386/i386gnu.mh 
gdb-7.3.50~cvs20110627-mine/gdb/config/i386/i386gnu.mh
--- gdb-7.3.50~cvs20110627-orig/gdb/config/i386/i386gnu.mh      2011-06-27 
23:37:36.000000000 +0000
+++ gdb-7.3.50~cvs20110627-mine/gdb/config/i386/i386gnu.mh      2011-08-21 
22:31:02.000000000 +0000
@@ -1,5 +1,5 @@
 # Host: Intel 386 running the GNU Hurd
-NATDEPFILES= i386gnu-nat.o gnu-nat.o corelow.o core-regset.o fork-child.o \
+NATDEPFILES= i386gnu-nat.o gnu-nat.o i386-nat.o corelow.o core-regset.o 
fork-child.o \
             notify_S.o process_reply_S.o msg_reply_S.o \
             msg_U.o exc_request_U.o exc_request_S.o
 

Reply via email to