WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] PDB: watchpoints for process context

# HG changeset patch
# User ach61@xxxxxxxxxxxxxxxxxxxxxx
# Node ID a3fa9406d92681630cdba422c3c94a966627db39
# Parent  84962f30285bff88744db2d1aedf9e67e25b6e9f
PDB: watchpoints for process context

diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/Domain.ml
--- a/tools/debugger/pdb/Domain.ml      Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/Domain.ml      Mon Aug 15 19:04:28 2005
@@ -36,6 +36,7 @@
       Printf.sprintf "{domain} domain: %d, vcpu: %d"
                       ctx.domain  ctx.vcpu
 
+external read_register : context_t -> int -> int32 = "dom_read_register"
 external read_registers : context_t -> registers = "dom_read_registers"
 external write_register : context_t -> register -> int32 -> unit =
   "dom_write_register"
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/Domain.mli
--- a/tools/debugger/pdb/Domain.mli     Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/Domain.mli     Mon Aug 15 19:04:28 2005
@@ -22,6 +22,7 @@
 
 val string_of_context : context_t -> string
 
+val read_register : context_t -> int -> int32
 val read_registers : context_t -> registers
 val write_register : context_t -> register -> int32 -> unit
 val read_memory : context_t -> int32 -> int -> int list
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/Makefile
--- a/tools/debugger/pdb/Makefile       Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/Makefile       Mon Aug 15 19:04:28 2005
@@ -33,7 +33,8 @@
 LIBS       += unix str
 
 # bc = byte-code, dc = debug byte-code
-all : patches dc
+# patches = patch linux domU source code
+all : dc
 
 SOURCES    += pdb_caml_xc.c 
 SOURCES    += pdb_caml_domain.c pdb_caml_process.c
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/PDB.ml
--- a/tools/debugger/pdb/PDB.ml Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/PDB.ml Mon Aug 15 19:04:28 2005
@@ -219,6 +219,17 @@
 
 (***************************************************************************)
 
+let read_register ctx register =    (* register is int32 because of sscanf *)
+  match ctx with
+  | Void -> 0l                                      (* default for startup *)
+  | Domain d  -> Domain.read_register d register
+  | Process p ->
+      begin
+       Process.read_register p register;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "read registers")
+
 let read_registers ctx =
   match ctx with
   | Void -> Intel.null_registers                    (* default for startup *)
@@ -278,14 +289,42 @@
 let insert_memory_breakpoint ctx addr len =
   match ctx with
   | Domain d  -> Domain.insert_memory_breakpoint d addr len
-  | Process p  -> Process.insert_memory_breakpoint p addr len
+  | Process p  ->
+      begin
+       Process.insert_memory_breakpoint p addr len;
+       raise No_reply
+      end
   | _ -> raise (Unimplemented "insert memory breakpoint")
 
 let remove_memory_breakpoint ctx addr len =
   match ctx with
   | Domain d  -> Domain.remove_memory_breakpoint d addr len
-  | Process p  -> Process.remove_memory_breakpoint p addr len
+  | Process p  ->
+      begin
+       Process.remove_memory_breakpoint p addr len;
+       raise No_reply
+      end
   | _ -> raise (Unimplemented "remove memory breakpoint")
+
+let insert_watchpoint ctx kind addr len =
+  match ctx with
+(*  | Domain d  -> Domain.insert_watchpoint d kind addr len  TODO *)
+  | Process p  ->
+      begin
+       Process.insert_watchpoint p kind addr len;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "insert watchpoint")
+
+let remove_watchpoint ctx kind addr len =
+  match ctx with
+(*  | Domain d  -> Domain.remove_watchpoint d kind addr len  TODO *)
+  | Process p  ->
+      begin
+       Process.remove_watchpoint p kind addr len;
+       raise No_reply
+      end
+  | _ -> raise (Unimplemented "remove watchpoint")
 
 
 let pause ctx =
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/Process.ml
--- a/tools/debugger/pdb/Process.ml     Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/Process.ml     Mon Aug 15 19:04:28 2005
@@ -54,6 +54,7 @@
   proc_ctx.ring   <- Xen_domain.get_ring   dom_ctx;
   _attach_debugger proc_ctx
 
+external read_register : context_t -> int -> unit = "proc_read_register"
 external read_registers : context_t -> unit = "proc_read_registers"
 external write_register : context_t -> register -> int32 -> unit =
   "proc_write_register"
@@ -69,6 +70,10 @@
   "proc_insert_memory_breakpoint"
 external remove_memory_breakpoint : context_t -> int32 -> int -> unit = 
   "proc_remove_memory_breakpoint"
+external insert_watchpoint : context_t -> int -> int32 -> int -> unit =
+  "proc_insert_watchpoint"
+external remove_watchpoint : context_t -> int -> int32 -> int -> unit =
+  "proc_remove_watchpoint"
 
 let pause ctx =
   pause_target ctx
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/Process.mli
--- a/tools/debugger/pdb/Process.mli    Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/Process.mli    Mon Aug 15 19:04:28 2005
@@ -26,7 +26,7 @@
 val detach_debugger : context_t -> unit
 val pause : context_t -> unit
 
-
+val read_register : context_t -> int -> unit
 val read_registers : context_t -> unit
 val write_register : context_t -> register -> int32 -> unit
 val read_memory : context_t -> int32 -> int -> unit
@@ -37,3 +37,5 @@
 
 val insert_memory_breakpoint : context_t -> int32 -> int -> unit
 val remove_memory_breakpoint : context_t -> int32 -> int -> unit
+val insert_watchpoint : context_t -> int -> int32 -> int -> unit
+val remove_watchpoint : context_t -> int -> int32 -> int -> unit
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/debugger.ml
--- a/tools/debugger/pdb/debugger.ml    Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/debugger.ml    Mon Aug 15 19:04:28 2005
@@ -53,10 +53,20 @@
   PDB.step ctx;
   raise No_reply
 
+(**
+   Read Register Command.
+   return register as a 4-byte value.
+ *)
+let gdb_read_register ctx command =
+  let read_reg register =
+    (Printf.sprintf "%08lx" (Util.flip_int32 (PDB.read_register ctx register)))
+  in
+  Scanf.sscanf command "p%x" read_reg
+    
 
 (**
    Read Registers Command.
-   returns 16 4-byte registers in a particular defined by gdb.
+   returns 16 4-byte registers in a particular format defined by gdb.
  *)
 let gdb_read_registers ctx =
   let regs = PDB.read_registers ctx in
@@ -100,7 +110,7 @@
     with
       Failure s -> "E02"
   in
-  Scanf.sscanf command "m%lx,%d" read_mem
+  Scanf.sscanf command "m%lx,%x" read_mem
 
 
 
@@ -218,16 +228,24 @@
 (**
    Insert Breakpoint or Watchpoint Packet
  *)
+
+let bwc_watch_write  = 102                              (* from pdb_module.h *)
+let bwc_watch_read   = 103
+let bwc_watch_access = 104
+
 let gdb_insert_bwcpoint ctx command =
   let insert cmd addr length =
     try
       match cmd with
       | 0 -> PDB.insert_memory_breakpoint ctx addr length; "OK"
+      | 2 -> PDB.insert_watchpoint ctx bwc_watch_write  addr length; "OK"
+      | 3 -> PDB.insert_watchpoint ctx bwc_watch_read   addr length; "OK"
+      | 4 -> PDB.insert_watchpoint ctx bwc_watch_access addr length; "OK"
       | _ -> ""
     with
       Failure s -> "E03"
   in
-  Scanf.sscanf command "Z%d,%lx,%d" insert
+  Scanf.sscanf command "Z%d,%lx,%x" insert
 
 (**
    Remove Breakpoint or Watchpoint Packet
@@ -237,6 +255,9 @@
     try
       match cmd with
       | 0 -> PDB.remove_memory_breakpoint ctx addr length; "OK"
+      | 2 -> PDB.remove_watchpoint ctx bwc_watch_write  addr length; "OK"
+      | 3 -> PDB.remove_watchpoint ctx bwc_watch_read   addr length; "OK"
+      | 4 -> PDB.remove_watchpoint ctx bwc_watch_access addr length; "OK"
       | _ -> ""
     with
       Failure s -> "E04"
@@ -260,6 +281,7 @@
     | 'k' -> gdb_kill ()
     | 'm' -> gdb_read_memory ctx command
     | 'M' -> gdb_write_memory ctx command
+    | 'p' -> gdb_read_register ctx command
     | 'P' -> gdb_write_register ctx command
     | 'q' -> gdb_query command
     | 's' -> gdb_step ctx
@@ -270,7 +292,7 @@
     | 'Z' -> gdb_insert_bwcpoint ctx command
     | _ -> 
        print_endline (Printf.sprintf "unknown gdb command [%s]" command);
-       "E02"
+       ""
   with
     Unimplemented s ->
       print_endline (Printf.sprintf "loser. unimplemented command [%s][%s]" 
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/linux-2.6-module/debug.c
--- a/tools/debugger/pdb/linux-2.6-module/debug.c       Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/linux-2.6-module/debug.c       Mon Aug 15 19:04:28 2005
@@ -9,33 +9,143 @@
 #include <asm-i386/kdebug.h>
 #include <asm-xen/asm-i386/processor.h>
 #include <asm-xen/asm-i386/ptrace.h>
+#include <asm-xen/asm-i386/tlbflush.h>
 #include <asm-xen/xen-public/xen.h>
 #include "pdb_module.h"
 #include "pdb_debug.h"
 
-#define BWC_DEBUG 1
-#define BWC_INT3  3
+
+static int pdb_debug_fn (struct pt_regs *regs, long error_code,
+                         unsigned int condition);
+static int pdb_int3_fn (struct pt_regs *regs, long error_code);
+static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
+                              unsigned int condition);
+
+/***********************************************************************/
+
 typedef struct bwcpoint                           /* break/watch/catch point */
 {
     struct list_head list;
     memory_t address;
-    u32 domain;
+    int length;
+
+    u8  type;                                                     /* BWC_??? */
+    u8  mode;                   /* for BWC_PAGE, the current protection mode */
     u32 process;
-    u8  old_value;                            /* old value for software bkpt */
-    u8  type;                                                     /* BWC_??? */
+    u8  error;                /* error occured when enabling: don't disable. */
+
+    /* original values */
+    u8    orig_bkpt;                               /* single byte breakpoint */
+    pte_t orig_pte;
+
+    struct list_head watchpt_read_list;     /* read watchpoints on this page */
+    struct list_head watchpt_write_list;                            /* write */
+    struct list_head watchpt_access_list;                          /* access */
+    struct list_head watchpt_disabled_list;                      /* disabled */
+
+    struct bwcpoint *parent;             /* watchpoint: bwc_watch (the page) */
+    struct bwcpoint *watchpoint;      /* bwc_watch_step: original watchpoint */
 } bwcpoint_t, *bwcpoint_p;
 
-static bwcpoint_t bwcpoint_list;
+static struct list_head bwcpoint_list = LIST_HEAD_INIT(bwcpoint_list);
+
+#define _pdb_bwcpoint_alloc(_var) \
+{ \
+    if ( (_var = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL)) == NULL ) \
+        printk("error: unable to allocate memory %d\n", __LINE__); \
+    else { \
+        memset(_var, 0, sizeof(bwcpoint_t)); \
+        INIT_LIST_HEAD(&_var->watchpt_read_list); \
+        INIT_LIST_HEAD(&_var->watchpt_write_list); \
+        INIT_LIST_HEAD(&_var->watchpt_access_list); \
+        INIT_LIST_HEAD(&_var->watchpt_disabled_list); \
+    } \
+}
+
+/***********************************************************************/
+
+static void _pdb_bwc_print_list (struct list_head *, char *, int);
+
+static void
+_pdb_bwc_print (bwcpoint_p bwc, char *label, int level)
+{
+    printk("%s%03d 0x%08lx:0x%02x %c\n", label, bwc->type,
+           bwc->address, bwc->length, bwc->error ? 'e' : '-');
+
+    if ( !list_empty(&bwc->watchpt_read_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_read_list, "r", level);
+    if ( !list_empty(&bwc->watchpt_write_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_write_list, "w", level);
+    if ( !list_empty(&bwc->watchpt_access_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_access_list, "a", level);
+    if ( !list_empty(&bwc->watchpt_disabled_list) )
+        _pdb_bwc_print_list(&bwc->watchpt_disabled_list, "d", level);
+}
+
+static void
+_pdb_bwc_print_list (struct list_head *bwc_list, char *label, int level)
+{
+    struct list_head *ptr;
+    int counter = 0;
+
+    list_for_each(ptr, bwc_list)
+    {
+        bwcpoint_p bwc = list_entry(ptr, bwcpoint_t, list);
+        printk("  %s[%02d]%s ", level > 0 ? "  " : "", counter++,
+                                level > 0 ? "" : "  ");
+        _pdb_bwc_print(bwc, label, level+1);
+    }
+
+    if (counter == 0)
+    {
+        printk("  empty list\n");
+    }
+}
 
 void
-pdb_initialize_bwcpoint (void)
-{
-    memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
-    INIT_LIST_HEAD(&bwcpoint_list.list);
-
-    return;
-}
-
+pdb_bwc_print_list (void)
+{
+    _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
+}
+
+bwcpoint_p
+pdb_search_watchpoint (u32 process, memory_t address)
+{
+    bwcpoint_p bwc_watch = (bwcpoint_p) 0;
+    bwcpoint_p bwc_entry = (bwcpoint_p) 0;
+    struct list_head *ptr;
+
+    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+        if (bwc_watch->address == (address & PAGE_MASK)) break;
+    }
+
+    if ( !bwc_watch )
+    {
+        return (bwcpoint_p) 0;
+    }
+
+#define __pdb_search_watchpoint_list(__list) \
+    list_for_each(ptr, (__list))  \
+    { \
+        bwc_entry = list_entry(ptr, bwcpoint_t, list); \
+        if ( bwc_entry->process == process &&          \
+             bwc_entry->address <= address &&          \
+             bwc_entry->address + bwc_entry->length > address ) \
+            return bwc_entry; \
+    }
+
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_read_list);
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_write_list);
+    __pdb_search_watchpoint_list(&bwc_watch->watchpt_access_list);
+
+#undef __pdb_search_watchpoint_list
+
+    return (bwcpoint_p) 0;
+}
+
+/*************************************************************/
 
 int
 pdb_suspend (struct task_struct *target)
@@ -134,6 +244,35 @@
     *(unsigned long *) stack = value;
 
     return;
+}
+
+int
+pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op)
+{
+    int rc = 0;
+
+    switch (op->reg)
+    {
+    case  0: op->value = _pdb_get_register(target, LINUX_EAX); break;
+    case  1: op->value = _pdb_get_register(target, LINUX_ECX); break;
+    case  2: op->value = _pdb_get_register(target, LINUX_EDX); break;
+    case  3: op->value = _pdb_get_register(target, LINUX_EBX); break;
+    case  4: op->value = _pdb_get_register(target, LINUX_ESP); break;
+    case  5: op->value = _pdb_get_register(target, LINUX_EBP); break;
+    case  6: op->value = _pdb_get_register(target, LINUX_ESI); break;
+    case  7: op->value = _pdb_get_register(target, LINUX_EDI); break;
+    case  8: op->value = _pdb_get_register(target, LINUX_EIP); break;
+    case  9: op->value = _pdb_get_register(target, LINUX_EFL); break;
+
+    case 10: op->value = _pdb_get_register(target, LINUX_CS); break;
+    case 11: op->value = _pdb_get_register(target, LINUX_SS); break;
+    case 12: op->value = _pdb_get_register(target, LINUX_DS); break;
+    case 13: op->value = _pdb_get_register(target, LINUX_ES); break;
+    case 14: op->value = _pdb_get_register(target, LINUX_FS); break;
+    case 15: op->value = _pdb_get_register(target, LINUX_GS); break;
+    }
+
+    return rc;
 }
 
 int
@@ -209,18 +348,14 @@
     eflags |= X86_EFLAGS_TF;
     _pdb_set_register(target, LINUX_EFL, eflags);
 
-    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
-    if ( bkpt == NULL )
-    {
-        printk("error: unable to allocation memory\n");
-        return -1;
-    }
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL )  return -1;
 
     bkpt->process = target->pid;
     bkpt->address = 0;
     bkpt->type    = BWC_DEBUG;
     
-    list_add(&bkpt->list, &bwcpoint_list.list);
+    list_add_tail(&bkpt->list, &bwcpoint_list);
 
     wake_up_process(target);
 
@@ -237,31 +372,27 @@
 
     printk("insert breakpoint %d:%lx len: %d\n", target->pid, address, length);
 
-    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
-    if ( bkpt == NULL )
-    {
-        printk("error: unable to allocation memory\n");
+    if ( length != 1 )
+    {
+        printk("error: breakpoint length should be 1\n");
         return -1;
     }
 
-    if ( length != 1 )
-    {
-        printk("error: breakpoint length should be 1\n");
-        kfree(bkpt);
-        return -1;
-    }
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL ) return -1;
 
     bkpt->process = target->pid;
     bkpt->address = address;
     bkpt->type    = BWC_INT3;
 
-    pdb_access_memory(target, address, &bkpt->old_value, 1, 0);
-    pdb_access_memory(target, address, &breakpoint_opcode, 1, 1);
+    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_READ);
+    pdb_access_memory(target, address, &breakpoint_opcode, 1, PDB_MEM_WRITE);
     
-    list_add(&bkpt->list, &bwcpoint_list.list);
+    list_add_tail(&bkpt->list, &bwcpoint_list);
 
     printk("breakpoint_set %d:%lx  OLD: 0x%x\n",
-           target->pid, address, bkpt->old_value);
+           target->pid, address, bkpt->orig_bkpt);
+    pdb_bwc_print_list();
 
     return rc;
 }
@@ -276,7 +407,7 @@
     printk ("remove breakpoint %d:%lx\n", target->pid, address);
 
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( target->pid == bkpt->process && 
@@ -285,17 +416,223 @@
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
+    if (entry == &bwcpoint_list)
     {
         printk ("error: no breakpoint found\n");
         return -1;
     }
 
+    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_WRITE);
+
     list_del(&bkpt->list);
-
-    pdb_access_memory(target, address, &bkpt->old_value, 1, 1);
-
     kfree(bkpt);
+
+    pdb_bwc_print_list();
+
+    return rc;
+}
+
+#define PDB_PTE_UPDATE   1
+#define PDB_PTE_RESTORE  2
+
+int
+pdb_change_pte (struct task_struct *target, bwcpoint_p bwc, int mode)
+{
+    int rc = 0;
+    pgd_t *pgd;
+    pud_t *pud;
+    pmd_t *pmd;
+    pte_t *ptep;
+
+    pgd = pgd_offset(target->mm, bwc->address);
+    if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))  return -1;
+
+    pud = pud_offset(pgd, bwc->address);
+    if (pud_none(*pud) || unlikely(pud_bad(*pud))) return -2;
+
+    pmd = pmd_offset(pud, bwc->address);
+    if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) return -3;
+
+    ptep = pte_offset_map(pmd, bwc->address);
+    if (!ptep)  return -4;
+
+    switch ( mode )
+    {
+    case PDB_PTE_UPDATE:      /* added or removed a watchpoint.  update pte. */
+    {
+        pte_t new_pte;
+
+        if ( pte_val(bwc->parent->orig_pte) == 0 )    /* new watchpoint page */
+        {
+            bwc->parent->orig_pte = *ptep;
+        }
+
+        new_pte = bwc->parent->orig_pte;
+
+        if ( !list_empty(&bwc->parent->watchpt_read_list)  || 
+             !list_empty(&bwc->parent->watchpt_access_list) )
+        {
+            new_pte = pte_rdprotect(new_pte);
+        }
+
+        if ( !list_empty(&bwc->parent->watchpt_write_list) ||
+             !list_empty(&bwc->parent->watchpt_access_list) )
+        {
+            new_pte = pte_wrprotect(new_pte);
+        }
+        
+        if ( pte_val(new_pte) != pte_val(*ptep) )
+        {
+            *ptep = new_pte;
+            flush_tlb_mm(target->mm);
+        }
+        break;
+    }
+    case PDB_PTE_RESTORE :   /* suspend watchpoint by restoring original pte */
+    {
+        *ptep = bwc->parent->orig_pte;
+        flush_tlb_mm(target->mm);
+        break;
+    }
+    default :
+    {
+        printk("(linux) unknown mode %d %d\n", mode, __LINE__);
+        break;
+    }
+    }
+
+    pte_unmap(ptep);                /* can i flush the tlb before pte_unmap? */
+
+    return rc;
+}
+
+int
+pdb_insert_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
+{
+    int rc = 0;
+
+    bwcpoint_p bwc_watch;
+    bwcpoint_p bwc_entry;
+    struct list_head *ptr;
+    unsigned long page = watchpt->address & PAGE_MASK;
+    struct list_head *watchpoint_list;
+    
+    printk("insert watchpoint: %d %x %x\n", 
+           watchpt->type, watchpt->address, watchpt->length);
+
+    list_for_each(ptr, &bwcpoint_list) /* find existing bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+
+        if (bwc_watch->address == page)  goto got_bwc_watch;
+    }
+
+    _pdb_bwcpoint_alloc(bwc_watch);                  /* create new bwc:watch */
+    if ( bwc_watch == NULL ) return -1;
+
+    bwc_watch->type    = BWC_WATCH;
+    bwc_watch->process = target->pid;
+    bwc_watch->address = page;
+
+    list_add_tail(&bwc_watch->list, &bwcpoint_list);
+
+ got_bwc_watch:
+
+    switch (watchpt->type)
+    {
+    case BWC_WATCH_READ:
+        watchpoint_list = &bwc_watch->watchpt_read_list; break;
+    case BWC_WATCH_WRITE: 
+        watchpoint_list = &bwc_watch->watchpt_write_list; break;
+    case BWC_WATCH_ACCESS:
+        watchpoint_list = &bwc_watch->watchpt_access_list; break;
+    default:
+        printk("unknown type %d\n", watchpt->type); return -2;
+    }
+
+    _pdb_bwcpoint_alloc(bwc_entry);                  /* create new bwc:entry */
+    if ( bwc_entry == NULL ) return -1;
+
+    bwc_entry->process = target->pid;
+    bwc_entry->address = watchpt->address;
+    bwc_entry->length  = watchpt->length;
+    bwc_entry->type    = watchpt->type;
+    bwc_entry->parent  = bwc_watch;
+
+    list_add_tail(&bwc_entry->list, watchpoint_list);
+    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
+
+    pdb_bwc_print_list();
+
+    return rc;
+}
+
+int 
+pdb_remove_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
+{
+    int rc = 0;
+    bwcpoint_p bwc_watch = (bwcpoint_p) NULL;
+    bwcpoint_p bwc_entry = (bwcpoint_p) NULL;
+    unsigned long page = watchpt->address & PAGE_MASK;
+    struct list_head *ptr;
+    struct list_head *watchpoint_list;
+
+    printk("remove watchpoint: %d %x %x\n", 
+           watchpt->type, watchpt->address, watchpt->length);
+
+    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
+    {
+        bwc_watch = list_entry(ptr, bwcpoint_t, list);
+        if (bwc_watch->address == page) break;
+    }
+
+    if ( !bwc_watch )
+    {
+        printk("(linux) delete watchpoint: can't find bwc page 0x%08x\n",
+               watchpt->address);
+        return -1;
+    }
+
+    switch (watchpt->type)
+    {
+    case BWC_WATCH_READ:
+        watchpoint_list = &bwc_watch->watchpt_read_list; break;
+    case BWC_WATCH_WRITE:
+        watchpoint_list = &bwc_watch->watchpt_write_list; break;
+    case BWC_WATCH_ACCESS:
+        watchpoint_list = &bwc_watch->watchpt_access_list; break;
+    default:
+        printk("unknown type %d\n", watchpt->type); return -2;
+    }
+
+    list_for_each(ptr, watchpoint_list)                   /* find watchpoint */
+    {
+        bwc_entry = list_entry(ptr, bwcpoint_t, list);
+        if ( bwc_entry->address == watchpt->address &&
+             bwc_entry->length  == watchpt->length ) break;
+    }
+
+    if ( !bwc_entry )                           /* or ptr == watchpoint_list */
+    {
+        printk("(linux) delete watchpoint: can't find watchpoint 0x%08x\n",
+               watchpt->address);
+        return -1;
+    }
+    
+    list_del(&bwc_entry->list);
+    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
+    kfree(bwc_entry);
+
+
+    if ( list_empty(&bwc_watch->watchpt_read_list)  &&
+         list_empty(&bwc_watch->watchpt_write_list) &&
+         list_empty(&bwc_watch->watchpt_access_list) )
+    {
+        list_del(&bwc_watch->list);
+        kfree(bwc_watch);
+    }
+
+    pdb_bwc_print_list();
 
     return rc;
 }
@@ -312,16 +649,24 @@
        switch (val) 
     {
        case DIE_DEBUG:
-               if (pdb_debug_fn(args->regs, args->trapnr, args->err))
+               if ( pdb_debug_fn(args->regs, args->trapnr, args->err) )
                        return NOTIFY_STOP;
                break;
     case DIE_TRAP:
-               if (args->trapnr == 3 && pdb_int3_fn(args->regs, args->err))
+               if ( args->trapnr == 3 && pdb_int3_fn(args->regs, args->err) )
                        return NOTIFY_STOP;
         break;
        case DIE_INT3:          /* without kprobes, we should never see 
DIE_INT3 */
+               if ( pdb_int3_fn(args->regs, args->err) )
+                       return NOTIFY_STOP;
+               break;
+       case DIE_PAGE_FAULT:
+               if ( pdb_page_fault_fn(args->regs, args->trapnr, args->err) )
+                       return NOTIFY_STOP;
+               break;
        case DIE_GPF:
-       case DIE_PAGE_FAULT:
+        printk("---------------GPF\n");
+        break;
        default:
                break;
        }
@@ -330,70 +675,110 @@
 }
 
 
-int
+static int
 pdb_debug_fn (struct pt_regs *regs, long error_code, 
                    unsigned int condition)
 {
     pdb_response_t resp;
     bwcpoint_p bkpt = NULL;
-
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+
+    printk("pdb_debug_fn\n");
+
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( current->pid == bkpt->process && 
-             bkpt->type == BWC_DEBUG )
+             (bkpt->type == BWC_DEBUG ||                      /* single step */
+              bkpt->type == BWC_WATCH_STEP))  /* single step over watchpoint */
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
+    if (entry == &bwcpoint_list)
     {
         printk("not my debug  0x%x 0x%lx\n", current->pid, regs->eip);
         return 0;
     }
 
-    list_del(&bkpt->list);
-
     pdb_suspend(current);
 
-    printk("(pdb) debug  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
+    printk("(pdb) %s  pid: %d, eip: 0x%08lx\n", 
+           bkpt->type == BWC_DEBUG ? "debug" : "watch-step",
+           current->pid, regs->eip);
 
     regs->eflags &= ~X86_EFLAGS_TF;
        set_tsk_thread_flag(current, TIF_SINGLESTEP);
 
-    resp.operation = PDB_OPCODE_STEP;
+    switch (bkpt->type)
+    {
+    case BWC_DEBUG:
+        resp.operation = PDB_OPCODE_STEP;
+        break;
+    case BWC_WATCH_STEP:
+    {
+        struct list_head *watchpoint_list;
+        bwcpoint_p watch_page = bkpt->watchpoint->parent;
+
+        switch (bkpt->watchpoint->type)
+        {
+        case BWC_WATCH_READ:
+            watchpoint_list = &watch_page->watchpt_read_list; break;
+        case BWC_WATCH_WRITE: 
+            watchpoint_list = &watch_page->watchpt_write_list; break;
+        case BWC_WATCH_ACCESS:
+            watchpoint_list = &watch_page->watchpt_access_list; break;
+        default:
+            printk("unknown type %d\n", bkpt->watchpoint->type); return 0;
+        }
+
+        resp.operation = PDB_OPCODE_WATCHPOINT;
+        list_del_init(&bkpt->watchpoint->list);
+        list_add_tail(&bkpt->watchpoint->list, watchpoint_list);
+        pdb_change_pte(current, bkpt->watchpoint, PDB_PTE_UPDATE);
+        pdb_bwc_print_list();
+        break;
+    }
+    default:
+        printk("unknown breakpoint type %d %d\n", __LINE__, bkpt->type);
+        return 0;
+    }
+
     resp.process   = current->pid;
     resp.status    = PDB_RESPONSE_OKAY;
 
     pdb_send_response(&resp);
 
+    list_del(&bkpt->list);
+    kfree(bkpt);
+
     return 1;
 }
 
 
-int
+static int
 pdb_int3_fn (struct pt_regs *regs, long error_code)
 {
     pdb_response_t resp;
     bwcpoint_p bkpt = NULL;
+    memory_t address = regs->eip - 1;
 
     struct list_head *entry;
-    list_for_each(entry, &bwcpoint_list.list)
+    list_for_each(entry, &bwcpoint_list)
     {
         bkpt = list_entry(entry, bwcpoint_t, list);
         if ( current->pid == bkpt->process && 
-             regs->eip == bkpt->address    &&
+             address == bkpt->address      &&
              bkpt->type == BWC_INT3 )
             break;
     }
     
-    if (bkpt == &bwcpoint_list || bkpt == NULL)
-    {
-        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, regs->eip);
+    if (entry == &bwcpoint_list)
+    {
+        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, address);
         return 0;
     }
 
-    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
+    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, address);
 
     pdb_suspend(current);
 
@@ -405,6 +790,54 @@
 
     return 1;
 }
+
+static int
+pdb_page_fault_fn (struct pt_regs *regs, long error_code, 
+                   unsigned int condition)
+{
+    unsigned long cr2;
+    unsigned long cr3;
+    bwcpoint_p bwc;
+    bwcpoint_p watchpt;
+    bwcpoint_p bkpt;
+
+    __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
+    __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
+
+    bwc = pdb_search_watchpoint(current->pid, cr2);
+    if ( !bwc )
+    {
+        return 0;                                                /* not mine */
+    }
+
+    printk("page_fault cr2:%08lx err:%lx eip:%08lx\n", 
+           cr2, error_code, regs->eip);
+
+    /* disable the watchpoint */
+    watchpt = bwc->watchpoint;
+    list_del_init(&bwc->list);
+    list_add_tail(&bwc->list, &bwc->parent->watchpt_disabled_list);
+    pdb_change_pte(current, bwc, PDB_PTE_RESTORE);
+
+    /* single step the faulting instruction */
+    regs->eflags |= X86_EFLAGS_TF;
+
+    /* create a bwcpoint entry so we know what to do once we regain control */
+    _pdb_bwcpoint_alloc(bkpt);
+    if ( bkpt == NULL )  return -1;
+
+    bkpt->process    = current->pid;
+    bkpt->address    = 0;
+    bkpt->type       = BWC_WATCH_STEP;
+    bkpt->watchpoint = bwc;
+
+    /* add to head so we see it first the next time we break */
+    list_add(&bkpt->list, &bwcpoint_list);                
+
+    pdb_bwc_print_list();
+    return 1;
+}
+
 
 /*
  * Local variables:
diff -r 84962f30285b -r a3fa9406d926 
tools/debugger/pdb/linux-2.6-module/module.c
--- a/tools/debugger/pdb/linux-2.6-module/module.c      Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/linux-2.6-module/module.c      Mon Aug 15 19:04:28 2005
@@ -98,6 +98,11 @@
         printk("(linux) detach 0x%x\n", request->process);
         resp.status = PDB_RESPONSE_OKAY;
         break;
+    case PDB_OPCODE_RD_REG :
+        resp.u.rd_reg.reg = request->u.rd_reg.reg;
+        pdb_read_register(target, &resp.u.rd_reg);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
     case PDB_OPCODE_RD_REGS :
         pdb_read_registers(target, &resp.u.rd_regs);
         resp.status = PDB_RESPONSE_OKAY;
@@ -108,14 +113,16 @@
         break;
     case PDB_OPCODE_RD_MEM :
         pdb_access_memory(target, request->u.rd_mem.address,
-                          &resp.u.rd_mem.data, request->u.rd_mem.length, 0);
+                          &resp.u.rd_mem.data, request->u.rd_mem.length, 
+                          PDB_MEM_READ);
         resp.u.rd_mem.address = request->u.rd_mem.address;
         resp.u.rd_mem.length  = request->u.rd_mem.length;
         resp.status = PDB_RESPONSE_OKAY;
         break;
     case PDB_OPCODE_WR_MEM :
         pdb_access_memory(target, request->u.wr_mem.address,
-                         &request->u.wr_mem.data, request->u.wr_mem.length, 1);
+                         &request->u.wr_mem.data, request->u.wr_mem.length, 
+                          PDB_MEM_WRITE);
         resp.status = PDB_RESPONSE_OKAY;
         break;
     case PDB_OPCODE_CONTINUE :
@@ -135,6 +142,14 @@
     case PDB_OPCODE_CLR_BKPT :
         pdb_remove_memory_breakpoint(target, request->u.bkpt.address,
                                      request->u.bkpt.length);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
+    case PDB_OPCODE_SET_WATCHPT :
+        pdb_insert_watchpoint(target, &request->u.watchpt);
+        resp.status = PDB_RESPONSE_OKAY;
+        break;
+    case PDB_OPCODE_CLR_WATCHPT :
+        pdb_remove_watchpoint(target, &request->u.watchpt);
         resp.status = PDB_RESPONSE_OKAY;
         break;
     default:
@@ -248,8 +263,6 @@
     pdb_sring_t *sring;
 
     printk("----\npdb initialize   %s %s\n", __DATE__, __TIME__);
-
-    pdb_initialize_bwcpoint();
 
     /*
     if ( xen_start_info.flags & SIF_INITDOMAIN )
diff -r 84962f30285b -r a3fa9406d926 
tools/debugger/pdb/linux-2.6-module/pdb_debug.h
--- a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h   Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_debug.h   Mon Aug 15 19:04:28 2005
@@ -6,6 +6,7 @@
 void pdb_initialize_bwcpoint (void);
 int pdb_suspend (struct task_struct *target);
 int pdb_resume (struct task_struct *target);
+int pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op);
 int pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op);
 int pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op);
 int pdb_read_memory (struct task_struct *target, pdb_op_rd_mem_req_p req, 
@@ -20,13 +21,13 @@
                                   memory_t address, u32 length);
 int pdb_remove_memory_breakpoint (struct task_struct *target,
                                   memory_t address, u32 length);
+int pdb_insert_watchpoint (struct task_struct *target,
+                           pdb_op_watchpt_p watchpt);
+int pdb_remove_watchpoint (struct task_struct *target,
+                           pdb_op_watchpt_p watchpt);
 
 int pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
                            void *data);
-
-int pdb_debug_fn (struct pt_regs *regs, long error_code,
-                  unsigned int condition);
-int pdb_int3_fn (struct pt_regs *regs, long error_code);
 
 /* module.c */
 void pdb_send_response (pdb_response_t *response);
diff -r 84962f30285b -r a3fa9406d926 
tools/debugger/pdb/linux-2.6-module/pdb_module.h
--- a/tools/debugger/pdb/linux-2.6-module/pdb_module.h  Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_module.h  Mon Aug 15 19:04:28 2005
@@ -14,20 +14,27 @@
 
 #define PDB_OPCODE_DETACH 3
 
-#define PDB_OPCODE_RD_REGS 4
+#define PDB_OPCODE_RD_REG 4
+typedef struct pdb_op_rd_reg
+{
+    u32 reg;
+    u32 value;
+} pdb_op_rd_reg_t, *pdb_op_rd_reg_p;
+
+#define PDB_OPCODE_RD_REGS 5
 typedef struct pdb_op_rd_regs
 {
     u32 reg[GDB_REGISTER_FRAME_SIZE];
 } pdb_op_rd_regs_t, *pdb_op_rd_regs_p;
 
-#define PDB_OPCODE_WR_REG 5
+#define PDB_OPCODE_WR_REG 6
 typedef struct pdb_op_wr_reg
 {
     u32 reg;
     u32 value;
 } pdb_op_wr_reg_t, *pdb_op_wr_reg_p;
 
-#define PDB_OPCODE_RD_MEM 6
+#define PDB_OPCODE_RD_MEM 7
 typedef struct pdb_op_rd_mem_req
 {
     u32 address;
@@ -41,7 +48,7 @@
     u8  data[1024];
 } pdb_op_rd_mem_resp_t, *pdb_op_rd_mem_resp_p;
 
-#define PDB_OPCODE_WR_MEM 7
+#define PDB_OPCODE_WR_MEM 8
 typedef struct pdb_op_wr_mem
 {
     u32 address;
@@ -49,16 +56,33 @@
     u8  data[1024];                                             /* arbitrary */
 } pdb_op_wr_mem_t, *pdb_op_wr_mem_p;
 
-#define PDB_OPCODE_CONTINUE 8
-#define PDB_OPCODE_STEP     9
+#define PDB_OPCODE_CONTINUE 9
+#define PDB_OPCODE_STEP     10
 
-#define PDB_OPCODE_SET_BKPT 10
-#define PDB_OPCODE_CLR_BKPT 11
+#define PDB_OPCODE_SET_BKPT 11
+#define PDB_OPCODE_CLR_BKPT 12
 typedef struct pdb_op_bkpt
 {
     u32 address;
     u32 length;
 } pdb_op_bkpt_t, *pdb_op_bkpt_p;
+
+#define PDB_OPCODE_SET_WATCHPT 13
+#define PDB_OPCODE_CLR_WATCHPT 14
+#define PDB_OPCODE_WATCHPOINT  15
+typedef struct pdb_op_watchpt
+{
+#define BWC_DEBUG 1
+#define BWC_INT3  3
+#define BWC_WATCH        100                         /* pdb: watchpoint page */
+#define BWC_WATCH_STEP   101                  /* pdb: watchpoint single step */
+#define BWC_WATCH_WRITE  102
+#define BWC_WATCH_READ   103
+#define BWC_WATCH_ACCESS 104
+    u32 type;
+    u32 address;
+    u32 length;
+} pdb_op_watchpt_t, *pdb_op_watchpt_p;
 
 
 typedef struct 
@@ -68,10 +92,12 @@
     union
     {
         pdb_op_attach_t     attach;
+        pdb_op_rd_reg_t     rd_reg;
         pdb_op_wr_reg_t     wr_reg;
         pdb_op_rd_mem_req_t rd_mem;
         pdb_op_wr_mem_t     wr_mem;
         pdb_op_bkpt_t       bkpt;
+        pdb_op_watchpt_t    watchpt;
     } u;
 } pdb_request_t, *pdb_request_p;
 
@@ -87,6 +113,7 @@
     s16  status;          /* PDB_RESPONSE_???    */
     union
     {
+        pdb_op_rd_reg_t      rd_reg;
         pdb_op_rd_regs_t     rd_regs;
         pdb_op_rd_mem_resp_t rd_mem;
     } u;
@@ -94,6 +121,11 @@
 
 
 DEFINE_RING_TYPES(pdb, pdb_request_t, pdb_response_t);
+
+
+/* from access_process_vm */
+#define PDB_MEM_READ  0
+#define PDB_MEM_WRITE 1
 
 #endif
 
diff -r 84962f30285b -r a3fa9406d926 
tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
--- a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch     Mon Aug 15 
18:56:10 2005
+++ b/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch     Mon Aug 15 
19:04:28 2005
@@ -1,7 +1,15 @@
 diff -u linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c 
linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c
 --- linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c     2005-07-31 
22:36:50.000000000 +0100
 +++ linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c 2005-08-01 
10:57:31.000000000 +0100
-@@ -172,6 +172,7 @@
+@@ -151,6 +151,7 @@
+ /* TLB flushing */
+ EXPORT_SYMBOL(flush_tlb_page);
+ #endif
++EXPORT_SYMBOL(flush_tlb_mm);
+ 
+ #ifdef CONFIG_X86_IO_APIC
+ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
+@@ -172,6 +173,7 @@
  EXPORT_SYMBOL_GPL(unset_nmi_callback);
  
  EXPORT_SYMBOL(register_die_notifier);
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/pdb_caml_domain.c
--- a/tools/debugger/pdb/pdb_caml_domain.c      Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/pdb_caml_domain.c      Mon Aug 15 19:04:28 2005
@@ -41,6 +41,54 @@
 
 
 /****************************************************************************/
+
+/*
+ * dom_read_register : context_t -> int -> int32
+ */
+value
+dom_read_register (value context, value reg)
+{
+    CAMLparam2(context, reg);
+    CAMLlocal1(result);
+
+    int my_reg = Int_val(reg);
+    cpu_user_regs_t *regs;
+    context_t ctx;
+
+    decode_context(&ctx, context);
+
+    if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
+    {
+        printf("(pdb) read registers error!\n");  fflush(stdout);
+        failwith("read registers error");
+    }
+
+    dump_regs(regs);
+
+    result = caml_alloc_tuple(16);
+
+    switch (my_reg)
+    {
+    case GDB_EAX: result = caml_copy_int32(regs->eax); break;
+    case GDB_ECX: result = caml_copy_int32(regs->ecx); break;
+    case GDB_EDX: result = caml_copy_int32(regs->edx); break;
+    case GDB_EBX: result = caml_copy_int32(regs->ebx); break;
+    case GDB_ESP: result = caml_copy_int32(regs->esp); break;
+    case GDB_EBP: result = caml_copy_int32(regs->ebp); break;
+    case GDB_ESI: result = caml_copy_int32(regs->esi); break;
+    case GDB_EDI: result = caml_copy_int32(regs->edi); break;
+    case GDB_EIP: result = caml_copy_int32(regs->eip); break;
+    case GDB_EFL: result = caml_copy_int32(regs->eflags); break;
+    case GDB_CS:  result = caml_copy_int32(regs->cs);  break;
+    case GDB_SS: result = caml_copy_int32(regs->ss); break;
+    case GDB_DS: result = caml_copy_int32(regs->ds); break;
+    case GDB_ES: result = caml_copy_int32(regs->es); break;
+    case GDB_FS: result = caml_copy_int32(regs->fs); break;
+    case GDB_GS: result = caml_copy_int32(regs->gs); break;
+    }
+
+    CAMLreturn(result);
+}
 
 /*
  * dom_read_registers : context_t -> int32
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/pdb_caml_process.c
--- a/tools/debugger/pdb/pdb_caml_process.c     Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/pdb_caml_process.c     Mon Aug 15 19:04:28 2005
@@ -113,6 +113,12 @@
         case PDB_OPCODE_DETACH :
             break;
             
+        case PDB_OPCODE_RD_REG :
+        {
+            sprintf(&msg[0], "%08x", _flip(resp->u.rd_reg.value));
+            break;
+        }
+
         case PDB_OPCODE_RD_REGS :
         {
             int loop;
@@ -161,16 +167,22 @@
         }
 
         case PDB_OPCODE_SET_BKPT :
-        {
-            break;
-        }
         case PDB_OPCODE_CLR_BKPT :
-        {
+        case PDB_OPCODE_SET_WATCHPT :
+        case PDB_OPCODE_CLR_WATCHPT :
+        {
+            break;
+        }
+
+        case PDB_OPCODE_WATCHPOINT :
+        {
+            sprintf(msg, "S05");
             break;
         }
 
         default :
-            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE\n");
+            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE %d\n",
+                   resp->operation);
             break;
         }
 
@@ -258,6 +270,32 @@
 
     CAMLreturn(Val_unit);
 }
+
+
+/*
+ * proc_read_register : context_t -> int -> unit
+ */
+value
+proc_read_register (value context, value reg)
+{
+    CAMLparam1(context);
+
+    pdb_request_t req;
+    context_t ctx;
+    int my_reg = Int_val(reg);
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_RD_REG;
+    req.process = ctx.process;
+    req.u.rd_reg.reg = my_reg;
+    req.u.rd_reg.value = 0;
+
+    send_request (ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
 
 
 /*
@@ -443,7 +481,7 @@
 
 
 /*
- * proc_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
+ * proc_insert_memory_breakpoint : context_t -> int32 -> int -> unit
  */
 value
 proc_insert_memory_breakpoint (value context, value address, value length)
@@ -466,7 +504,7 @@
 }
 
 /*
- * proc_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
+ * proc_remove_memory_breakpoint : context_t -> int32 -> int -> unit
  */
 value
 proc_remove_memory_breakpoint (value context, value address, value length)
@@ -482,6 +520,54 @@
     req.process = ctx.process;
     req.u.bkpt.address = (memory_t) Int32_val(address);
     req.u.bkpt.length  =  Int_val(length);
+
+    send_request(ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_insert_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
+ */
+value
+proc_insert_watchpoint (value context, value kind, value address, value length)
+{
+    CAMLparam3(context, address, length);
+
+    context_t ctx;
+    pdb_request_t req;
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_SET_WATCHPT;
+    req.process = ctx.process;
+    req.u.watchpt.type    =  Int_val(kind);
+    req.u.watchpt.address = (memory_t) Int32_val(address);
+    req.u.watchpt.length  =  Int_val(length);
+
+    send_request(ctx.ring, ctx.evtchn, &req);
+
+    CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_remove_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
+ */
+value
+proc_remove_watchpoint (value context, value kind, value address, value length)
+{
+    CAMLparam3(context, address, length);
+
+    context_t ctx;
+    pdb_request_t req;
+
+    decode_context(&ctx, context);
+
+    req.operation = PDB_OPCODE_CLR_WATCHPT;
+    req.process = ctx.process;
+    req.u.watchpt.type    =  Int_val(kind);
+    req.u.watchpt.address = (memory_t) Int32_val(address);
+    req.u.watchpt.length  =  Int_val(length);
 
     send_request(ctx.ring, ctx.evtchn, &req);
 
diff -r 84962f30285b -r a3fa9406d926 tools/debugger/pdb/readme
--- a/tools/debugger/pdb/readme Mon Aug 15 18:56:10 2005
+++ b/tools/debugger/pdb/readme Mon Aug 15 19:04:28 2005
@@ -1,9 +1,9 @@
 
-PDB 0.3 
+PDB 0.3.3
 http://www.cl.cam.ac.uk/netos/pdb
 
 Alex Ho  
-June 2005
+August 2005
 
 
 This is the latest incarnation of the pervasive debugger.
@@ -79,6 +79,11 @@
 Process
 
   PDB can also debug a process running in a Linux 2.6 domain. 
+  You will need to patch the Linux 2.6 domain U tree to export some
+  additional symbols for the pdb module
+
+  % make -C linux-2.6-patches
+
   After running PDB in domain 0, insert the pdb module in dom u:
   
   % insmod linux-2.6-module/pdb.ko
@@ -87,7 +92,14 @@
 
   (gdb) maint packet x context = process <domid> <pid>
 
+  Read, write, and access watchpoint should also work for processes, 
+  use the "rwatch", "watch" and "awatch" gdb commands respectively.
+
+  If you are having trouble with GDB 5.3 (i386-redhat-linux-gnu),
+  try GDB 6.3 (configured with --target=i386-linux-gnu).
+
+  
 To Do
 
-- watchpoints
+- watchpoints for domains
 - support for SMP

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] PDB: watchpoints for process context, Xen patchbot -unstable <=