ia64/xen-unstable

changeset 6197:a3fa9406d926

PDB: watchpoints for process context
author ach61@arcadians.cl.cam.ac.uk
date Mon Aug 15 19:04:28 2005 +0000 (2005-08-15)
parents 84962f30285b
children 8523b124c8f8
files tools/debugger/pdb/Domain.ml tools/debugger/pdb/Domain.mli tools/debugger/pdb/Makefile tools/debugger/pdb/PDB.ml tools/debugger/pdb/Process.ml tools/debugger/pdb/Process.mli tools/debugger/pdb/debugger.ml tools/debugger/pdb/linux-2.6-module/debug.c tools/debugger/pdb/linux-2.6-module/module.c tools/debugger/pdb/linux-2.6-module/pdb_debug.h tools/debugger/pdb/linux-2.6-module/pdb_module.h tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch tools/debugger/pdb/pdb_caml_domain.c tools/debugger/pdb/pdb_caml_process.c tools/debugger/pdb/readme
line diff
     1.1 --- a/tools/debugger/pdb/Domain.ml	Mon Aug 15 18:56:10 2005 +0000
     1.2 +++ b/tools/debugger/pdb/Domain.ml	Mon Aug 15 19:04:28 2005 +0000
     1.3 @@ -36,6 +36,7 @@ let string_of_context ctx =
     1.4        Printf.sprintf "{domain} domain: %d, vcpu: %d"
     1.5                        ctx.domain  ctx.vcpu
     1.6  
     1.7 +external read_register : context_t -> int -> int32 = "dom_read_register"
     1.8  external read_registers : context_t -> registers = "dom_read_registers"
     1.9  external write_register : context_t -> register -> int32 -> unit =
    1.10    "dom_write_register"
     2.1 --- a/tools/debugger/pdb/Domain.mli	Mon Aug 15 18:56:10 2005 +0000
     2.2 +++ b/tools/debugger/pdb/Domain.mli	Mon Aug 15 19:04:28 2005 +0000
     2.3 @@ -22,6 +22,7 @@ val get_vcpu : context_t -> int
     2.4  
     2.5  val string_of_context : context_t -> string
     2.6  
     2.7 +val read_register : context_t -> int -> int32
     2.8  val read_registers : context_t -> registers
     2.9  val write_register : context_t -> register -> int32 -> unit
    2.10  val read_memory : context_t -> int32 -> int -> int list
     3.1 --- a/tools/debugger/pdb/Makefile	Mon Aug 15 18:56:10 2005 +0000
     3.2 +++ b/tools/debugger/pdb/Makefile	Mon Aug 15 19:04:28 2005 +0000
     3.3 @@ -33,7 +33,8 @@ LIBDIRS    += ../libxendebug
     3.4  LIBS       += unix str
     3.5  
     3.6  # bc = byte-code, dc = debug byte-code
     3.7 -all : patches dc
     3.8 +# patches = patch linux domU source code
     3.9 +all : dc
    3.10  
    3.11  SOURCES    += pdb_caml_xc.c 
    3.12  SOURCES    += pdb_caml_domain.c pdb_caml_process.c
     4.1 --- a/tools/debugger/pdb/PDB.ml	Mon Aug 15 18:56:10 2005 +0000
     4.2 +++ b/tools/debugger/pdb/PDB.ml	Mon Aug 15 19:04:28 2005 +0000
     4.3 @@ -219,6 +219,17 @@ let add_default_context sock =
     4.4  
     4.5  (***************************************************************************)
     4.6  
     4.7 +let read_register ctx register =    (* register is int32 because of sscanf *)
     4.8 +  match ctx with
     4.9 +  | Void -> 0l                                      (* default for startup *)
    4.10 +  | Domain d  -> Domain.read_register d register
    4.11 +  | Process p ->
    4.12 +      begin
    4.13 +	Process.read_register p register;
    4.14 +	raise No_reply
    4.15 +      end
    4.16 +  | _ -> raise (Unimplemented "read registers")
    4.17 +
    4.18  let read_registers ctx =
    4.19    match ctx with
    4.20    | Void -> Intel.null_registers                    (* default for startup *)
    4.21 @@ -278,15 +289,43 @@ let step ctx =
    4.22  let insert_memory_breakpoint ctx addr len =
    4.23    match ctx with
    4.24    | Domain d  -> Domain.insert_memory_breakpoint d addr len
    4.25 -  | Process p  -> Process.insert_memory_breakpoint p addr len
    4.26 +  | Process p  ->
    4.27 +      begin
    4.28 +	Process.insert_memory_breakpoint p addr len;
    4.29 +	raise No_reply
    4.30 +      end
    4.31    | _ -> raise (Unimplemented "insert memory breakpoint")
    4.32  
    4.33  let remove_memory_breakpoint ctx addr len =
    4.34    match ctx with
    4.35    | Domain d  -> Domain.remove_memory_breakpoint d addr len
    4.36 -  | Process p  -> Process.remove_memory_breakpoint p addr len
    4.37 +  | Process p  ->
    4.38 +      begin
    4.39 +	Process.remove_memory_breakpoint p addr len;
    4.40 +	raise No_reply
    4.41 +      end
    4.42    | _ -> raise (Unimplemented "remove memory breakpoint")
    4.43  
    4.44 +let insert_watchpoint ctx kind addr len =
    4.45 +  match ctx with
    4.46 +(*  | Domain d  -> Domain.insert_watchpoint d kind addr len  TODO *)
    4.47 +  | Process p  ->
    4.48 +      begin
    4.49 +	Process.insert_watchpoint p kind addr len;
    4.50 +	raise No_reply
    4.51 +      end
    4.52 +  | _ -> raise (Unimplemented "insert watchpoint")
    4.53 +
    4.54 +let remove_watchpoint ctx kind addr len =
    4.55 +  match ctx with
    4.56 +(*  | Domain d  -> Domain.remove_watchpoint d kind addr len  TODO *)
    4.57 +  | Process p  ->
    4.58 +      begin
    4.59 +	Process.remove_watchpoint p kind addr len;
    4.60 +	raise No_reply
    4.61 +      end
    4.62 +  | _ -> raise (Unimplemented "remove watchpoint")
    4.63 +
    4.64  
    4.65  let pause ctx =
    4.66    match ctx with
     5.1 --- a/tools/debugger/pdb/Process.ml	Mon Aug 15 18:56:10 2005 +0000
     5.2 +++ b/tools/debugger/pdb/Process.ml	Mon Aug 15 19:04:28 2005 +0000
     5.3 @@ -54,6 +54,7 @@ let attach_debugger proc_ctx dom_ctx =
     5.4    proc_ctx.ring   <- Xen_domain.get_ring   dom_ctx;
     5.5    _attach_debugger proc_ctx
     5.6  
     5.7 +external read_register : context_t -> int -> unit = "proc_read_register"
     5.8  external read_registers : context_t -> unit = "proc_read_registers"
     5.9  external write_register : context_t -> register -> int32 -> unit =
    5.10    "proc_write_register"
    5.11 @@ -69,6 +70,10 @@ external insert_memory_breakpoint : cont
    5.12    "proc_insert_memory_breakpoint"
    5.13  external remove_memory_breakpoint : context_t -> int32 -> int -> unit = 
    5.14    "proc_remove_memory_breakpoint"
    5.15 +external insert_watchpoint : context_t -> int -> int32 -> int -> unit =
    5.16 +  "proc_insert_watchpoint"
    5.17 +external remove_watchpoint : context_t -> int -> int32 -> int -> unit =
    5.18 +  "proc_remove_watchpoint"
    5.19  
    5.20  let pause ctx =
    5.21    pause_target ctx
     6.1 --- a/tools/debugger/pdb/Process.mli	Mon Aug 15 18:56:10 2005 +0000
     6.2 +++ b/tools/debugger/pdb/Process.mli	Mon Aug 15 19:04:28 2005 +0000
     6.3 @@ -26,7 +26,7 @@ val attach_debugger : context_t -> Xen_d
     6.4  val detach_debugger : context_t -> unit
     6.5  val pause : context_t -> unit
     6.6  
     6.7 -
     6.8 +val read_register : context_t -> int -> unit
     6.9  val read_registers : context_t -> unit
    6.10  val write_register : context_t -> register -> int32 -> unit
    6.11  val read_memory : context_t -> int32 -> int -> unit
    6.12 @@ -37,3 +37,5 @@ val step : context_t -> unit
    6.13  
    6.14  val insert_memory_breakpoint : context_t -> int32 -> int -> unit
    6.15  val remove_memory_breakpoint : context_t -> int32 -> int -> unit
    6.16 +val insert_watchpoint : context_t -> int -> int32 -> int -> unit
    6.17 +val remove_watchpoint : context_t -> int -> int32 -> int -> unit
     7.1 --- a/tools/debugger/pdb/debugger.ml	Mon Aug 15 18:56:10 2005 +0000
     7.2 +++ b/tools/debugger/pdb/debugger.ml	Mon Aug 15 19:04:28 2005 +0000
     7.3 @@ -53,10 +53,20 @@ let gdb_step ctx =
     7.4    PDB.step ctx;
     7.5    raise No_reply
     7.6  
     7.7 +(**
     7.8 +   Read Register Command.
     7.9 +   return register as a 4-byte value.
    7.10 + *)
    7.11 +let gdb_read_register ctx command =
    7.12 +  let read_reg register =
    7.13 +    (Printf.sprintf "%08lx" (Util.flip_int32 (PDB.read_register ctx register)))
    7.14 +  in
    7.15 +  Scanf.sscanf command "p%x" read_reg
    7.16 +    
    7.17  
    7.18  (**
    7.19     Read Registers Command.
    7.20 -   returns 16 4-byte registers in a particular defined by gdb.
    7.21 +   returns 16 4-byte registers in a particular format defined by gdb.
    7.22   *)
    7.23  let gdb_read_registers ctx =
    7.24    let regs = PDB.read_registers ctx in
    7.25 @@ -100,7 +110,7 @@ let gdb_read_memory ctx command =
    7.26      with
    7.27        Failure s -> "E02"
    7.28    in
    7.29 -  Scanf.sscanf command "m%lx,%d" read_mem
    7.30 +  Scanf.sscanf command "m%lx,%x" read_mem
    7.31  
    7.32  
    7.33  
    7.34 @@ -218,16 +228,24 @@ let pdb_extensions command sock =
    7.35  (**
    7.36     Insert Breakpoint or Watchpoint Packet
    7.37   *)
    7.38 +
    7.39 +let bwc_watch_write  = 102                              (* from pdb_module.h *)
    7.40 +let bwc_watch_read   = 103
    7.41 +let bwc_watch_access = 104
    7.42 +
    7.43  let gdb_insert_bwcpoint ctx command =
    7.44    let insert cmd addr length =
    7.45      try
    7.46        match cmd with
    7.47        | 0 -> PDB.insert_memory_breakpoint ctx addr length; "OK"
    7.48 +      | 2 -> PDB.insert_watchpoint ctx bwc_watch_write  addr length; "OK"
    7.49 +      | 3 -> PDB.insert_watchpoint ctx bwc_watch_read   addr length; "OK"
    7.50 +      | 4 -> PDB.insert_watchpoint ctx bwc_watch_access addr length; "OK"
    7.51        | _ -> ""
    7.52      with
    7.53        Failure s -> "E03"
    7.54    in
    7.55 -  Scanf.sscanf command "Z%d,%lx,%d" insert
    7.56 +  Scanf.sscanf command "Z%d,%lx,%x" insert
    7.57  
    7.58  (**
    7.59     Remove Breakpoint or Watchpoint Packet
    7.60 @@ -237,6 +255,9 @@ let gdb_remove_bwcpoint ctx command =
    7.61      try
    7.62        match cmd with
    7.63        | 0 -> PDB.remove_memory_breakpoint ctx addr length; "OK"
    7.64 +      | 2 -> PDB.remove_watchpoint ctx bwc_watch_write  addr length; "OK"
    7.65 +      | 3 -> PDB.remove_watchpoint ctx bwc_watch_read   addr length; "OK"
    7.66 +      | 4 -> PDB.remove_watchpoint ctx bwc_watch_access addr length; "OK"
    7.67        | _ -> ""
    7.68      with
    7.69        Failure s -> "E04"
    7.70 @@ -260,6 +281,7 @@ let process_command command sock =
    7.71      | 'k' -> gdb_kill ()
    7.72      | 'm' -> gdb_read_memory ctx command
    7.73      | 'M' -> gdb_write_memory ctx command
    7.74 +    | 'p' -> gdb_read_register ctx command
    7.75      | 'P' -> gdb_write_register ctx command
    7.76      | 'q' -> gdb_query command
    7.77      | 's' -> gdb_step ctx
    7.78 @@ -270,7 +292,7 @@ let process_command command sock =
    7.79      | 'Z' -> gdb_insert_bwcpoint ctx command
    7.80      | _ -> 
    7.81  	print_endline (Printf.sprintf "unknown gdb command [%s]" command);
    7.82 -	"E02"
    7.83 +	""
    7.84    with
    7.85      Unimplemented s ->
    7.86        print_endline (Printf.sprintf "loser. unimplemented command [%s][%s]" 
     8.1 --- a/tools/debugger/pdb/linux-2.6-module/debug.c	Mon Aug 15 18:56:10 2005 +0000
     8.2 +++ b/tools/debugger/pdb/linux-2.6-module/debug.c	Mon Aug 15 19:04:28 2005 +0000
     8.3 @@ -9,33 +9,143 @@
     8.4  #include <asm-i386/kdebug.h>
     8.5  #include <asm-xen/asm-i386/processor.h>
     8.6  #include <asm-xen/asm-i386/ptrace.h>
     8.7 +#include <asm-xen/asm-i386/tlbflush.h>
     8.8  #include <asm-xen/xen-public/xen.h>
     8.9  #include "pdb_module.h"
    8.10  #include "pdb_debug.h"
    8.11  
    8.12 -#define BWC_DEBUG 1
    8.13 -#define BWC_INT3  3
    8.14 +
    8.15 +static int pdb_debug_fn (struct pt_regs *regs, long error_code,
    8.16 +                         unsigned int condition);
    8.17 +static int pdb_int3_fn (struct pt_regs *regs, long error_code);
    8.18 +static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
    8.19 +                              unsigned int condition);
    8.20 +
    8.21 +/***********************************************************************/
    8.22 +
    8.23  typedef struct bwcpoint                           /* break/watch/catch point */
    8.24  {
    8.25      struct list_head list;
    8.26      memory_t address;
    8.27 -    u32 domain;
    8.28 +    int length;
    8.29 +
    8.30 +    u8  type;                                                     /* BWC_??? */
    8.31 +    u8  mode;                   /* for BWC_PAGE, the current protection mode */
    8.32      u32 process;
    8.33 -    u8  old_value;                            /* old value for software bkpt */
    8.34 -    u8  type;                                                     /* BWC_??? */
    8.35 +    u8  error;                /* error occured when enabling: don't disable. */
    8.36 +
    8.37 +    /* original values */
    8.38 +    u8    orig_bkpt;                               /* single byte breakpoint */
    8.39 +    pte_t orig_pte;
    8.40 +
    8.41 +    struct list_head watchpt_read_list;     /* read watchpoints on this page */
    8.42 +    struct list_head watchpt_write_list;                            /* write */
    8.43 +    struct list_head watchpt_access_list;                          /* access */
    8.44 +    struct list_head watchpt_disabled_list;                      /* disabled */
    8.45 +
    8.46 +    struct bwcpoint *parent;             /* watchpoint: bwc_watch (the page) */
    8.47 +    struct bwcpoint *watchpoint;      /* bwc_watch_step: original watchpoint */
    8.48  } bwcpoint_t, *bwcpoint_p;
    8.49  
    8.50 -static bwcpoint_t bwcpoint_list;
    8.51 +static struct list_head bwcpoint_list = LIST_HEAD_INIT(bwcpoint_list);
    8.52 +
    8.53 +#define _pdb_bwcpoint_alloc(_var) \
    8.54 +{ \
    8.55 +    if ( (_var = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL)) == NULL ) \
    8.56 +        printk("error: unable to allocate memory %d\n", __LINE__); \
    8.57 +    else { \
    8.58 +        memset(_var, 0, sizeof(bwcpoint_t)); \
    8.59 +        INIT_LIST_HEAD(&_var->watchpt_read_list); \
    8.60 +        INIT_LIST_HEAD(&_var->watchpt_write_list); \
    8.61 +        INIT_LIST_HEAD(&_var->watchpt_access_list); \
    8.62 +        INIT_LIST_HEAD(&_var->watchpt_disabled_list); \
    8.63 +    } \
    8.64 +}
    8.65 +
    8.66 +/***********************************************************************/
    8.67 +
    8.68 +static void _pdb_bwc_print_list (struct list_head *, char *, int);
    8.69 +
    8.70 +static void
    8.71 +_pdb_bwc_print (bwcpoint_p bwc, char *label, int level)
    8.72 +{
    8.73 +    printk("%s%03d 0x%08lx:0x%02x %c\n", label, bwc->type,
    8.74 +           bwc->address, bwc->length, bwc->error ? 'e' : '-');
    8.75 +
    8.76 +    if ( !list_empty(&bwc->watchpt_read_list) )
    8.77 +        _pdb_bwc_print_list(&bwc->watchpt_read_list, "r", level);
    8.78 +    if ( !list_empty(&bwc->watchpt_write_list) )
    8.79 +        _pdb_bwc_print_list(&bwc->watchpt_write_list, "w", level);
    8.80 +    if ( !list_empty(&bwc->watchpt_access_list) )
    8.81 +        _pdb_bwc_print_list(&bwc->watchpt_access_list, "a", level);
    8.82 +    if ( !list_empty(&bwc->watchpt_disabled_list) )
    8.83 +        _pdb_bwc_print_list(&bwc->watchpt_disabled_list, "d", level);
    8.84 +}
    8.85 +
    8.86 +static void
    8.87 +_pdb_bwc_print_list (struct list_head *bwc_list, char *label, int level)
    8.88 +{
    8.89 +    struct list_head *ptr;
    8.90 +    int counter = 0;
    8.91 +
    8.92 +    list_for_each(ptr, bwc_list)
    8.93 +    {
    8.94 +        bwcpoint_p bwc = list_entry(ptr, bwcpoint_t, list);
    8.95 +        printk("  %s[%02d]%s ", level > 0 ? "  " : "", counter++,
    8.96 +                                level > 0 ? "" : "  ");
    8.97 +        _pdb_bwc_print(bwc, label, level+1);
    8.98 +    }
    8.99 +
   8.100 +    if (counter == 0)
   8.101 +    {
   8.102 +        printk("  empty list\n");
   8.103 +    }
   8.104 +}
   8.105  
   8.106  void
   8.107 -pdb_initialize_bwcpoint (void)
   8.108 +pdb_bwc_print_list (void)
   8.109  {
   8.110 -    memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
   8.111 -    INIT_LIST_HEAD(&bwcpoint_list.list);
   8.112 -
   8.113 -    return;
   8.114 +    _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
   8.115  }
   8.116  
   8.117 +bwcpoint_p
   8.118 +pdb_search_watchpoint (u32 process, memory_t address)
   8.119 +{
   8.120 +    bwcpoint_p bwc_watch = (bwcpoint_p) 0;
   8.121 +    bwcpoint_p bwc_entry = (bwcpoint_p) 0;
   8.122 +    struct list_head *ptr;
   8.123 +
   8.124 +    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
   8.125 +    {
   8.126 +        bwc_watch = list_entry(ptr, bwcpoint_t, list);
   8.127 +        if (bwc_watch->address == (address & PAGE_MASK)) break;
   8.128 +    }
   8.129 +
   8.130 +    if ( !bwc_watch )
   8.131 +    {
   8.132 +        return (bwcpoint_p) 0;
   8.133 +    }
   8.134 +
   8.135 +#define __pdb_search_watchpoint_list(__list) \
   8.136 +    list_for_each(ptr, (__list))  \
   8.137 +    { \
   8.138 +        bwc_entry = list_entry(ptr, bwcpoint_t, list); \
   8.139 +        if ( bwc_entry->process == process &&          \
   8.140 +             bwc_entry->address <= address &&          \
   8.141 +             bwc_entry->address + bwc_entry->length > address ) \
   8.142 +            return bwc_entry; \
   8.143 +    }
   8.144 +
   8.145 +    __pdb_search_watchpoint_list(&bwc_watch->watchpt_read_list);
   8.146 +    __pdb_search_watchpoint_list(&bwc_watch->watchpt_write_list);
   8.147 +    __pdb_search_watchpoint_list(&bwc_watch->watchpt_access_list);
   8.148 +
   8.149 +#undef __pdb_search_watchpoint_list
   8.150 +
   8.151 +    return (bwcpoint_p) 0;
   8.152 +}
   8.153 +
   8.154 +/*************************************************************/
   8.155  
   8.156  int
   8.157  pdb_suspend (struct task_struct *target)
   8.158 @@ -137,6 +247,35 @@ static void
   8.159  }
   8.160  
   8.161  int
   8.162 +pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op)
   8.163 +{
   8.164 +    int rc = 0;
   8.165 +
   8.166 +    switch (op->reg)
   8.167 +    {
   8.168 +    case  0: op->value = _pdb_get_register(target, LINUX_EAX); break;
   8.169 +    case  1: op->value = _pdb_get_register(target, LINUX_ECX); break;
   8.170 +    case  2: op->value = _pdb_get_register(target, LINUX_EDX); break;
   8.171 +    case  3: op->value = _pdb_get_register(target, LINUX_EBX); break;
   8.172 +    case  4: op->value = _pdb_get_register(target, LINUX_ESP); break;
   8.173 +    case  5: op->value = _pdb_get_register(target, LINUX_EBP); break;
   8.174 +    case  6: op->value = _pdb_get_register(target, LINUX_ESI); break;
   8.175 +    case  7: op->value = _pdb_get_register(target, LINUX_EDI); break;
   8.176 +    case  8: op->value = _pdb_get_register(target, LINUX_EIP); break;
   8.177 +    case  9: op->value = _pdb_get_register(target, LINUX_EFL); break;
   8.178 +
   8.179 +    case 10: op->value = _pdb_get_register(target, LINUX_CS); break;
   8.180 +    case 11: op->value = _pdb_get_register(target, LINUX_SS); break;
   8.181 +    case 12: op->value = _pdb_get_register(target, LINUX_DS); break;
   8.182 +    case 13: op->value = _pdb_get_register(target, LINUX_ES); break;
   8.183 +    case 14: op->value = _pdb_get_register(target, LINUX_FS); break;
   8.184 +    case 15: op->value = _pdb_get_register(target, LINUX_GS); break;
   8.185 +    }
   8.186 +
   8.187 +    return rc;
   8.188 +}
   8.189 +
   8.190 +int
   8.191  pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
   8.192  {
   8.193      int rc = 0;
   8.194 @@ -209,18 +348,14 @@ pdb_step (struct task_struct *target)
   8.195      eflags |= X86_EFLAGS_TF;
   8.196      _pdb_set_register(target, LINUX_EFL, eflags);
   8.197  
   8.198 -    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
   8.199 -    if ( bkpt == NULL )
   8.200 -    {
   8.201 -        printk("error: unable to allocation memory\n");
   8.202 -        return -1;
   8.203 -    }
   8.204 +    _pdb_bwcpoint_alloc(bkpt);
   8.205 +    if ( bkpt == NULL )  return -1;
   8.206  
   8.207      bkpt->process = target->pid;
   8.208      bkpt->address = 0;
   8.209      bkpt->type    = BWC_DEBUG;
   8.210      
   8.211 -    list_add(&bkpt->list, &bwcpoint_list.list);
   8.212 +    list_add_tail(&bkpt->list, &bwcpoint_list);
   8.213  
   8.214      wake_up_process(target);
   8.215  
   8.216 @@ -237,31 +372,27 @@ pdb_insert_memory_breakpoint (struct tas
   8.217  
   8.218      printk("insert breakpoint %d:%lx len: %d\n", target->pid, address, length);
   8.219  
   8.220 -    bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
   8.221 -    if ( bkpt == NULL )
   8.222 +    if ( length != 1 )
   8.223      {
   8.224 -        printk("error: unable to allocation memory\n");
   8.225 +        printk("error: breakpoint length should be 1\n");
   8.226          return -1;
   8.227      }
   8.228  
   8.229 -    if ( length != 1 )
   8.230 -    {
   8.231 -        printk("error: breakpoint length should be 1\n");
   8.232 -        kfree(bkpt);
   8.233 -        return -1;
   8.234 -    }
   8.235 +    _pdb_bwcpoint_alloc(bkpt);
   8.236 +    if ( bkpt == NULL ) return -1;
   8.237  
   8.238      bkpt->process = target->pid;
   8.239      bkpt->address = address;
   8.240      bkpt->type    = BWC_INT3;
   8.241  
   8.242 -    pdb_access_memory(target, address, &bkpt->old_value, 1, 0);
   8.243 -    pdb_access_memory(target, address, &breakpoint_opcode, 1, 1);
   8.244 +    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_READ);
   8.245 +    pdb_access_memory(target, address, &breakpoint_opcode, 1, PDB_MEM_WRITE);
   8.246      
   8.247 -    list_add(&bkpt->list, &bwcpoint_list.list);
   8.248 +    list_add_tail(&bkpt->list, &bwcpoint_list);
   8.249  
   8.250      printk("breakpoint_set %d:%lx  OLD: 0x%x\n",
   8.251 -           target->pid, address, bkpt->old_value);
   8.252 +           target->pid, address, bkpt->orig_bkpt);
   8.253 +    pdb_bwc_print_list();
   8.254  
   8.255      return rc;
   8.256  }
   8.257 @@ -276,7 +407,7 @@ pdb_remove_memory_breakpoint (struct tas
   8.258      printk ("remove breakpoint %d:%lx\n", target->pid, address);
   8.259  
   8.260      struct list_head *entry;
   8.261 -    list_for_each(entry, &bwcpoint_list.list)
   8.262 +    list_for_each(entry, &bwcpoint_list)
   8.263      {
   8.264          bkpt = list_entry(entry, bwcpoint_t, list);
   8.265          if ( target->pid == bkpt->process && 
   8.266 @@ -285,17 +416,223 @@ pdb_remove_memory_breakpoint (struct tas
   8.267              break;
   8.268      }
   8.269      
   8.270 -    if (bkpt == &bwcpoint_list || bkpt == NULL)
   8.271 +    if (entry == &bwcpoint_list)
   8.272      {
   8.273          printk ("error: no breakpoint found\n");
   8.274          return -1;
   8.275      }
   8.276  
   8.277 +    pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_WRITE);
   8.278 +
   8.279      list_del(&bkpt->list);
   8.280 +    kfree(bkpt);
   8.281 +
   8.282 +    pdb_bwc_print_list();
   8.283 +
   8.284 +    return rc;
   8.285 +}
   8.286 +
   8.287 +#define PDB_PTE_UPDATE   1
   8.288 +#define PDB_PTE_RESTORE  2
   8.289 +
   8.290 +int
   8.291 +pdb_change_pte (struct task_struct *target, bwcpoint_p bwc, int mode)
   8.292 +{
   8.293 +    int rc = 0;
   8.294 +    pgd_t *pgd;
   8.295 +    pud_t *pud;
   8.296 +    pmd_t *pmd;
   8.297 +    pte_t *ptep;
   8.298 +
   8.299 +    pgd = pgd_offset(target->mm, bwc->address);
   8.300 +    if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))  return -1;
   8.301 +
   8.302 +    pud = pud_offset(pgd, bwc->address);
   8.303 +    if (pud_none(*pud) || unlikely(pud_bad(*pud))) return -2;
   8.304 +
   8.305 +    pmd = pmd_offset(pud, bwc->address);
   8.306 +    if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) return -3;
   8.307 +
   8.308 +    ptep = pte_offset_map(pmd, bwc->address);
   8.309 +    if (!ptep)  return -4;
   8.310 +
   8.311 +    switch ( mode )
   8.312 +    {
   8.313 +    case PDB_PTE_UPDATE:      /* added or removed a watchpoint.  update pte. */
   8.314 +    {
   8.315 +        pte_t new_pte;
   8.316 +
   8.317 +        if ( pte_val(bwc->parent->orig_pte) == 0 )    /* new watchpoint page */
   8.318 +        {
   8.319 +            bwc->parent->orig_pte = *ptep;
   8.320 +        }
   8.321 +
   8.322 +        new_pte = bwc->parent->orig_pte;
   8.323 +
   8.324 +        if ( !list_empty(&bwc->parent->watchpt_read_list)  || 
   8.325 +             !list_empty(&bwc->parent->watchpt_access_list) )
   8.326 +        {
   8.327 +            new_pte = pte_rdprotect(new_pte);
   8.328 +        }
   8.329 +
   8.330 +        if ( !list_empty(&bwc->parent->watchpt_write_list) ||
   8.331 +             !list_empty(&bwc->parent->watchpt_access_list) )
   8.332 +        {
   8.333 +            new_pte = pte_wrprotect(new_pte);
   8.334 +        }
   8.335 +        
   8.336 +        if ( pte_val(new_pte) != pte_val(*ptep) )
   8.337 +        {
   8.338 +            *ptep = new_pte;
   8.339 +            flush_tlb_mm(target->mm);
   8.340 +        }
   8.341 +        break;
   8.342 +    }
   8.343 +    case PDB_PTE_RESTORE :   /* suspend watchpoint by restoring original pte */
   8.344 +    {
   8.345 +        *ptep = bwc->parent->orig_pte;
   8.346 +        flush_tlb_mm(target->mm);
   8.347 +        break;
   8.348 +    }
   8.349 +    default :
   8.350 +    {
   8.351 +        printk("(linux) unknown mode %d %d\n", mode, __LINE__);
   8.352 +        break;
   8.353 +    }
   8.354 +    }
   8.355 +
   8.356 +    pte_unmap(ptep);                /* can i flush the tlb before pte_unmap? */
   8.357 +
   8.358 +    return rc;
   8.359 +}
   8.360 +
   8.361 +int
   8.362 +pdb_insert_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
   8.363 +{
   8.364 +    int rc = 0;
   8.365 +
   8.366 +    bwcpoint_p bwc_watch;
   8.367 +    bwcpoint_p bwc_entry;
   8.368 +    struct list_head *ptr;
   8.369 +    unsigned long page = watchpt->address & PAGE_MASK;
   8.370 +    struct list_head *watchpoint_list;
   8.371 +    
   8.372 +    printk("insert watchpoint: %d %x %x\n", 
   8.373 +           watchpt->type, watchpt->address, watchpt->length);
   8.374 +
   8.375 +    list_for_each(ptr, &bwcpoint_list) /* find existing bwc page entry */
   8.376 +    {
   8.377 +        bwc_watch = list_entry(ptr, bwcpoint_t, list);
   8.378 +
   8.379 +        if (bwc_watch->address == page)  goto got_bwc_watch;
   8.380 +    }
   8.381  
   8.382 -    pdb_access_memory(target, address, &bkpt->old_value, 1, 1);
   8.383 +    _pdb_bwcpoint_alloc(bwc_watch);                  /* create new bwc:watch */
   8.384 +    if ( bwc_watch == NULL ) return -1;
   8.385 +
   8.386 +    bwc_watch->type    = BWC_WATCH;
   8.387 +    bwc_watch->process = target->pid;
   8.388 +    bwc_watch->address = page;
   8.389 +
   8.390 +    list_add_tail(&bwc_watch->list, &bwcpoint_list);
   8.391 +
   8.392 + got_bwc_watch:
   8.393 +
   8.394 +    switch (watchpt->type)
   8.395 +    {
   8.396 +    case BWC_WATCH_READ:
   8.397 +        watchpoint_list = &bwc_watch->watchpt_read_list; break;
   8.398 +    case BWC_WATCH_WRITE: 
   8.399 +        watchpoint_list = &bwc_watch->watchpt_write_list; break;
   8.400 +    case BWC_WATCH_ACCESS:
   8.401 +        watchpoint_list = &bwc_watch->watchpt_access_list; break;
   8.402 +    default:
   8.403 +        printk("unknown type %d\n", watchpt->type); return -2;
   8.404 +    }
   8.405 +
   8.406 +    _pdb_bwcpoint_alloc(bwc_entry);                  /* create new bwc:entry */
   8.407 +    if ( bwc_entry == NULL ) return -1;
   8.408 +
   8.409 +    bwc_entry->process = target->pid;
   8.410 +    bwc_entry->address = watchpt->address;
   8.411 +    bwc_entry->length  = watchpt->length;
   8.412 +    bwc_entry->type    = watchpt->type;
   8.413 +    bwc_entry->parent  = bwc_watch;
   8.414 +
   8.415 +    list_add_tail(&bwc_entry->list, watchpoint_list);
   8.416 +    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
   8.417 +
   8.418 +    pdb_bwc_print_list();
   8.419 +
   8.420 +    return rc;
   8.421 +}
   8.422 +
   8.423 +int 
   8.424 +pdb_remove_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
   8.425 +{
   8.426 +    int rc = 0;
   8.427 +    bwcpoint_p bwc_watch = (bwcpoint_p) NULL;
   8.428 +    bwcpoint_p bwc_entry = (bwcpoint_p) NULL;
   8.429 +    unsigned long page = watchpt->address & PAGE_MASK;
   8.430 +    struct list_head *ptr;
   8.431 +    struct list_head *watchpoint_list;
   8.432 +
   8.433 +    printk("remove watchpoint: %d %x %x\n", 
   8.434 +           watchpt->type, watchpt->address, watchpt->length);
   8.435  
   8.436 -    kfree(bkpt);
   8.437 +    list_for_each(ptr, &bwcpoint_list)                /* find bwc page entry */
   8.438 +    {
   8.439 +        bwc_watch = list_entry(ptr, bwcpoint_t, list);
   8.440 +        if (bwc_watch->address == page) break;
   8.441 +    }
   8.442 +
   8.443 +    if ( !bwc_watch )
   8.444 +    {
   8.445 +        printk("(linux) delete watchpoint: can't find bwc page 0x%08x\n",
   8.446 +               watchpt->address);
   8.447 +        return -1;
   8.448 +    }
   8.449 +
   8.450 +    switch (watchpt->type)
   8.451 +    {
   8.452 +    case BWC_WATCH_READ:
   8.453 +        watchpoint_list = &bwc_watch->watchpt_read_list; break;
   8.454 +    case BWC_WATCH_WRITE:
   8.455 +        watchpoint_list = &bwc_watch->watchpt_write_list; break;
   8.456 +    case BWC_WATCH_ACCESS:
   8.457 +        watchpoint_list = &bwc_watch->watchpt_access_list; break;
   8.458 +    default:
   8.459 +        printk("unknown type %d\n", watchpt->type); return -2;
   8.460 +    }
   8.461 +
   8.462 +    list_for_each(ptr, watchpoint_list)                   /* find watchpoint */
   8.463 +    {
   8.464 +        bwc_entry = list_entry(ptr, bwcpoint_t, list);
   8.465 +        if ( bwc_entry->address == watchpt->address &&
   8.466 +             bwc_entry->length  == watchpt->length ) break;
   8.467 +    }
   8.468 +
   8.469 +    if ( !bwc_entry )                           /* or ptr == watchpoint_list */
   8.470 +    {
   8.471 +        printk("(linux) delete watchpoint: can't find watchpoint 0x%08x\n",
   8.472 +               watchpt->address);
   8.473 +        return -1;
   8.474 +    }
   8.475 +    
   8.476 +    list_del(&bwc_entry->list);
   8.477 +    pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
   8.478 +    kfree(bwc_entry);
   8.479 +
   8.480 +
   8.481 +    if ( list_empty(&bwc_watch->watchpt_read_list)  &&
   8.482 +         list_empty(&bwc_watch->watchpt_write_list) &&
   8.483 +         list_empty(&bwc_watch->watchpt_access_list) )
   8.484 +    {
   8.485 +        list_del(&bwc_watch->list);
   8.486 +        kfree(bwc_watch);
   8.487 +    }
   8.488 +
   8.489 +    pdb_bwc_print_list();
   8.490  
   8.491      return rc;
   8.492  }
   8.493 @@ -312,16 +649,24 @@ pdb_exceptions_notify (struct notifier_b
   8.494  	switch (val) 
   8.495      {
   8.496  	case DIE_DEBUG:
   8.497 -		if (pdb_debug_fn(args->regs, args->trapnr, args->err))
   8.498 +		if ( pdb_debug_fn(args->regs, args->trapnr, args->err) )
   8.499  			return NOTIFY_STOP;
   8.500  		break;
   8.501      case DIE_TRAP:
   8.502 -		if (args->trapnr == 3 && pdb_int3_fn(args->regs, args->err))
   8.503 +		if ( args->trapnr == 3 && pdb_int3_fn(args->regs, args->err) )
   8.504  			return NOTIFY_STOP;
   8.505          break;
   8.506  	case DIE_INT3:          /* without kprobes, we should never see DIE_INT3 */
   8.507 +		if ( pdb_int3_fn(args->regs, args->err) )
   8.508 +			return NOTIFY_STOP;
   8.509 +		break;
   8.510 +	case DIE_PAGE_FAULT:
   8.511 +		if ( pdb_page_fault_fn(args->regs, args->trapnr, args->err) )
   8.512 +			return NOTIFY_STOP;
   8.513 +		break;
   8.514  	case DIE_GPF:
   8.515 -	case DIE_PAGE_FAULT:
   8.516 +        printk("---------------GPF\n");
   8.517 +        break;
   8.518  	default:
   8.519  		break;
   8.520  	}
   8.521 @@ -330,70 +675,110 @@ pdb_exceptions_notify (struct notifier_b
   8.522  }
   8.523  
   8.524  
   8.525 -int
   8.526 +static int
   8.527  pdb_debug_fn (struct pt_regs *regs, long error_code, 
   8.528                     unsigned int condition)
   8.529  {
   8.530      pdb_response_t resp;
   8.531      bwcpoint_p bkpt = NULL;
   8.532 +    struct list_head *entry;
   8.533  
   8.534 -    struct list_head *entry;
   8.535 -    list_for_each(entry, &bwcpoint_list.list)
   8.536 +    printk("pdb_debug_fn\n");
   8.537 +
   8.538 +    list_for_each(entry, &bwcpoint_list)
   8.539      {
   8.540          bkpt = list_entry(entry, bwcpoint_t, list);
   8.541          if ( current->pid == bkpt->process && 
   8.542 -             bkpt->type == BWC_DEBUG )
   8.543 +             (bkpt->type == BWC_DEBUG ||                      /* single step */
   8.544 +              bkpt->type == BWC_WATCH_STEP))  /* single step over watchpoint */
   8.545              break;
   8.546      }
   8.547      
   8.548 -    if (bkpt == &bwcpoint_list || bkpt == NULL)
   8.549 +    if (entry == &bwcpoint_list)
   8.550      {
   8.551          printk("not my debug  0x%x 0x%lx\n", current->pid, regs->eip);
   8.552          return 0;
   8.553      }
   8.554  
   8.555 -    list_del(&bkpt->list);
   8.556 -
   8.557      pdb_suspend(current);
   8.558  
   8.559 -    printk("(pdb) debug  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
   8.560 +    printk("(pdb) %s  pid: %d, eip: 0x%08lx\n", 
   8.561 +           bkpt->type == BWC_DEBUG ? "debug" : "watch-step",
   8.562 +           current->pid, regs->eip);
   8.563  
   8.564      regs->eflags &= ~X86_EFLAGS_TF;
   8.565  	set_tsk_thread_flag(current, TIF_SINGLESTEP);
   8.566  
   8.567 -    resp.operation = PDB_OPCODE_STEP;
   8.568 +    switch (bkpt->type)
   8.569 +    {
   8.570 +    case BWC_DEBUG:
   8.571 +        resp.operation = PDB_OPCODE_STEP;
   8.572 +        break;
   8.573 +    case BWC_WATCH_STEP:
   8.574 +    {
   8.575 +        struct list_head *watchpoint_list;
   8.576 +        bwcpoint_p watch_page = bkpt->watchpoint->parent;
   8.577 +
   8.578 +        switch (bkpt->watchpoint->type)
   8.579 +        {
   8.580 +        case BWC_WATCH_READ:
   8.581 +            watchpoint_list = &watch_page->watchpt_read_list; break;
   8.582 +        case BWC_WATCH_WRITE: 
   8.583 +            watchpoint_list = &watch_page->watchpt_write_list; break;
   8.584 +        case BWC_WATCH_ACCESS:
   8.585 +            watchpoint_list = &watch_page->watchpt_access_list; break;
   8.586 +        default:
   8.587 +            printk("unknown type %d\n", bkpt->watchpoint->type); return 0;
   8.588 +        }
   8.589 +
   8.590 +        resp.operation = PDB_OPCODE_WATCHPOINT;
   8.591 +        list_del_init(&bkpt->watchpoint->list);
   8.592 +        list_add_tail(&bkpt->watchpoint->list, watchpoint_list);
   8.593 +        pdb_change_pte(current, bkpt->watchpoint, PDB_PTE_UPDATE);
   8.594 +        pdb_bwc_print_list();
   8.595 +        break;
   8.596 +    }
   8.597 +    default:
   8.598 +        printk("unknown breakpoint type %d %d\n", __LINE__, bkpt->type);
   8.599 +        return 0;
   8.600 +    }
   8.601 +
   8.602      resp.process   = current->pid;
   8.603      resp.status    = PDB_RESPONSE_OKAY;
   8.604  
   8.605      pdb_send_response(&resp);
   8.606  
   8.607 +    list_del(&bkpt->list);
   8.608 +    kfree(bkpt);
   8.609 +
   8.610      return 1;
   8.611  }
   8.612  
   8.613  
   8.614 -int
   8.615 +static int
   8.616  pdb_int3_fn (struct pt_regs *regs, long error_code)
   8.617  {
   8.618      pdb_response_t resp;
   8.619      bwcpoint_p bkpt = NULL;
   8.620 +    memory_t address = regs->eip - 1;
   8.621  
   8.622      struct list_head *entry;
   8.623 -    list_for_each(entry, &bwcpoint_list.list)
   8.624 +    list_for_each(entry, &bwcpoint_list)
   8.625      {
   8.626          bkpt = list_entry(entry, bwcpoint_t, list);
   8.627          if ( current->pid == bkpt->process && 
   8.628 -             regs->eip == bkpt->address    &&
   8.629 +             address == bkpt->address      &&
   8.630               bkpt->type == BWC_INT3 )
   8.631              break;
   8.632      }
   8.633      
   8.634 -    if (bkpt == &bwcpoint_list || bkpt == NULL)
   8.635 +    if (entry == &bwcpoint_list)
   8.636      {
   8.637 -        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, regs->eip);
   8.638 +        printk("not my int3 bkpt  0x%x 0x%lx\n", current->pid, address);
   8.639          return 0;
   8.640      }
   8.641  
   8.642 -    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
   8.643 +    printk("(pdb) int3  pid: %d, eip: 0x%08lx\n", current->pid, address);
   8.644  
   8.645      pdb_suspend(current);
   8.646  
   8.647 @@ -406,6 +791,54 @@ pdb_int3_fn (struct pt_regs *regs, long 
   8.648      return 1;
   8.649  }
   8.650  
   8.651 +static int
   8.652 +pdb_page_fault_fn (struct pt_regs *regs, long error_code, 
   8.653 +                   unsigned int condition)
   8.654 +{
   8.655 +    unsigned long cr2;
   8.656 +    unsigned long cr3;
   8.657 +    bwcpoint_p bwc;
   8.658 +    bwcpoint_p watchpt;
   8.659 +    bwcpoint_p bkpt;
   8.660 +
   8.661 +    __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
   8.662 +    __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
   8.663 +
   8.664 +    bwc = pdb_search_watchpoint(current->pid, cr2);
   8.665 +    if ( !bwc )
   8.666 +    {
   8.667 +        return 0;                                                /* not mine */
   8.668 +    }
   8.669 +
   8.670 +    printk("page_fault cr2:%08lx err:%lx eip:%08lx\n", 
   8.671 +           cr2, error_code, regs->eip);
   8.672 +
   8.673 +    /* disable the watchpoint */
   8.674 +    watchpt = bwc->watchpoint;
   8.675 +    list_del_init(&bwc->list);
   8.676 +    list_add_tail(&bwc->list, &bwc->parent->watchpt_disabled_list);
   8.677 +    pdb_change_pte(current, bwc, PDB_PTE_RESTORE);
   8.678 +
   8.679 +    /* single step the faulting instruction */
   8.680 +    regs->eflags |= X86_EFLAGS_TF;
   8.681 +
   8.682 +    /* create a bwcpoint entry so we know what to do once we regain control */
   8.683 +    _pdb_bwcpoint_alloc(bkpt);
   8.684 +    if ( bkpt == NULL )  return -1;
   8.685 +
   8.686 +    bkpt->process    = current->pid;
   8.687 +    bkpt->address    = 0;
   8.688 +    bkpt->type       = BWC_WATCH_STEP;
   8.689 +    bkpt->watchpoint = bwc;
   8.690 +
   8.691 +    /* add to head so we see it first the next time we break */
   8.692 +    list_add(&bkpt->list, &bwcpoint_list);                
   8.693 +
   8.694 +    pdb_bwc_print_list();
   8.695 +    return 1;
   8.696 +}
   8.697 +
   8.698 +
   8.699  /*
   8.700   * Local variables:
   8.701   * mode: C
     9.1 --- a/tools/debugger/pdb/linux-2.6-module/module.c	Mon Aug 15 18:56:10 2005 +0000
     9.2 +++ b/tools/debugger/pdb/linux-2.6-module/module.c	Mon Aug 15 19:04:28 2005 +0000
     9.3 @@ -98,6 +98,11 @@ pdb_process_request (pdb_request_t *requ
     9.4          printk("(linux) detach 0x%x\n", request->process);
     9.5          resp.status = PDB_RESPONSE_OKAY;
     9.6          break;
     9.7 +    case PDB_OPCODE_RD_REG :
     9.8 +        resp.u.rd_reg.reg = request->u.rd_reg.reg;
     9.9 +        pdb_read_register(target, &resp.u.rd_reg);
    9.10 +        resp.status = PDB_RESPONSE_OKAY;
    9.11 +        break;
    9.12      case PDB_OPCODE_RD_REGS :
    9.13          pdb_read_registers(target, &resp.u.rd_regs);
    9.14          resp.status = PDB_RESPONSE_OKAY;
    9.15 @@ -108,14 +113,16 @@ pdb_process_request (pdb_request_t *requ
    9.16          break;
    9.17      case PDB_OPCODE_RD_MEM :
    9.18          pdb_access_memory(target, request->u.rd_mem.address,
    9.19 -                          &resp.u.rd_mem.data, request->u.rd_mem.length, 0);
    9.20 +                          &resp.u.rd_mem.data, request->u.rd_mem.length, 
    9.21 +                          PDB_MEM_READ);
    9.22          resp.u.rd_mem.address = request->u.rd_mem.address;
    9.23          resp.u.rd_mem.length  = request->u.rd_mem.length;
    9.24          resp.status = PDB_RESPONSE_OKAY;
    9.25          break;
    9.26      case PDB_OPCODE_WR_MEM :
    9.27          pdb_access_memory(target, request->u.wr_mem.address,
    9.28 -                         &request->u.wr_mem.data, request->u.wr_mem.length, 1);
    9.29 +                         &request->u.wr_mem.data, request->u.wr_mem.length, 
    9.30 +                          PDB_MEM_WRITE);
    9.31          resp.status = PDB_RESPONSE_OKAY;
    9.32          break;
    9.33      case PDB_OPCODE_CONTINUE :
    9.34 @@ -137,6 +144,14 @@ pdb_process_request (pdb_request_t *requ
    9.35                                       request->u.bkpt.length);
    9.36          resp.status = PDB_RESPONSE_OKAY;
    9.37          break;
    9.38 +    case PDB_OPCODE_SET_WATCHPT :
    9.39 +        pdb_insert_watchpoint(target, &request->u.watchpt);
    9.40 +        resp.status = PDB_RESPONSE_OKAY;
    9.41 +        break;
    9.42 +    case PDB_OPCODE_CLR_WATCHPT :
    9.43 +        pdb_remove_watchpoint(target, &request->u.watchpt);
    9.44 +        resp.status = PDB_RESPONSE_OKAY;
    9.45 +        break;
    9.46      default:
    9.47          printk("(pdb) unknown request operation %d\n", request->operation);
    9.48          resp.status = PDB_RESPONSE_ERROR;
    9.49 @@ -249,8 +264,6 @@ pdb_initialize (void)
    9.50  
    9.51      printk("----\npdb initialize   %s %s\n", __DATE__, __TIME__);
    9.52  
    9.53 -    pdb_initialize_bwcpoint();
    9.54 -
    9.55      /*
    9.56      if ( xen_start_info.flags & SIF_INITDOMAIN )
    9.57          return 1;
    10.1 --- a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h	Mon Aug 15 18:56:10 2005 +0000
    10.2 +++ b/tools/debugger/pdb/linux-2.6-module/pdb_debug.h	Mon Aug 15 19:04:28 2005 +0000
    10.3 @@ -6,6 +6,7 @@
    10.4  void pdb_initialize_bwcpoint (void);
    10.5  int pdb_suspend (struct task_struct *target);
    10.6  int pdb_resume (struct task_struct *target);
    10.7 +int pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op);
    10.8  int pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op);
    10.9  int pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op);
   10.10  int pdb_read_memory (struct task_struct *target, pdb_op_rd_mem_req_p req, 
   10.11 @@ -20,14 +21,14 @@ int pdb_insert_memory_breakpoint (struct
   10.12                                    memory_t address, u32 length);
   10.13  int pdb_remove_memory_breakpoint (struct task_struct *target,
   10.14                                    memory_t address, u32 length);
   10.15 +int pdb_insert_watchpoint (struct task_struct *target,
   10.16 +                           pdb_op_watchpt_p watchpt);
   10.17 +int pdb_remove_watchpoint (struct task_struct *target,
   10.18 +                           pdb_op_watchpt_p watchpt);
   10.19  
   10.20  int pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
   10.21                             void *data);
   10.22  
   10.23 -int pdb_debug_fn (struct pt_regs *regs, long error_code,
   10.24 -                  unsigned int condition);
   10.25 -int pdb_int3_fn (struct pt_regs *regs, long error_code);
   10.26 -
   10.27  /* module.c */
   10.28  void pdb_send_response (pdb_response_t *response);
   10.29  
    11.1 --- a/tools/debugger/pdb/linux-2.6-module/pdb_module.h	Mon Aug 15 18:56:10 2005 +0000
    11.2 +++ b/tools/debugger/pdb/linux-2.6-module/pdb_module.h	Mon Aug 15 19:04:28 2005 +0000
    11.3 @@ -14,20 +14,27 @@ typedef struct pdb_op_attach
    11.4  
    11.5  #define PDB_OPCODE_DETACH 3
    11.6  
    11.7 -#define PDB_OPCODE_RD_REGS 4
    11.8 +#define PDB_OPCODE_RD_REG 4
    11.9 +typedef struct pdb_op_rd_reg
   11.10 +{
   11.11 +    u32 reg;
   11.12 +    u32 value;
   11.13 +} pdb_op_rd_reg_t, *pdb_op_rd_reg_p;
   11.14 +
   11.15 +#define PDB_OPCODE_RD_REGS 5
   11.16  typedef struct pdb_op_rd_regs
   11.17  {
   11.18      u32 reg[GDB_REGISTER_FRAME_SIZE];
   11.19  } pdb_op_rd_regs_t, *pdb_op_rd_regs_p;
   11.20  
   11.21 -#define PDB_OPCODE_WR_REG 5
   11.22 +#define PDB_OPCODE_WR_REG 6
   11.23  typedef struct pdb_op_wr_reg
   11.24  {
   11.25      u32 reg;
   11.26      u32 value;
   11.27  } pdb_op_wr_reg_t, *pdb_op_wr_reg_p;
   11.28  
   11.29 -#define PDB_OPCODE_RD_MEM 6
   11.30 +#define PDB_OPCODE_RD_MEM 7
   11.31  typedef struct pdb_op_rd_mem_req
   11.32  {
   11.33      u32 address;
   11.34 @@ -41,7 +48,7 @@ typedef struct pdb_op_rd_mem_resp
   11.35      u8  data[1024];
   11.36  } pdb_op_rd_mem_resp_t, *pdb_op_rd_mem_resp_p;
   11.37  
   11.38 -#define PDB_OPCODE_WR_MEM 7
   11.39 +#define PDB_OPCODE_WR_MEM 8
   11.40  typedef struct pdb_op_wr_mem
   11.41  {
   11.42      u32 address;
   11.43 @@ -49,17 +56,34 @@ typedef struct pdb_op_wr_mem
   11.44      u8  data[1024];                                             /* arbitrary */
   11.45  } pdb_op_wr_mem_t, *pdb_op_wr_mem_p;
   11.46  
   11.47 -#define PDB_OPCODE_CONTINUE 8
   11.48 -#define PDB_OPCODE_STEP     9
   11.49 +#define PDB_OPCODE_CONTINUE 9
   11.50 +#define PDB_OPCODE_STEP     10
   11.51  
   11.52 -#define PDB_OPCODE_SET_BKPT 10
   11.53 -#define PDB_OPCODE_CLR_BKPT 11
   11.54 +#define PDB_OPCODE_SET_BKPT 11
   11.55 +#define PDB_OPCODE_CLR_BKPT 12
   11.56  typedef struct pdb_op_bkpt
   11.57  {
   11.58      u32 address;
   11.59      u32 length;
   11.60  } pdb_op_bkpt_t, *pdb_op_bkpt_p;
   11.61  
   11.62 +#define PDB_OPCODE_SET_WATCHPT 13
   11.63 +#define PDB_OPCODE_CLR_WATCHPT 14
   11.64 +#define PDB_OPCODE_WATCHPOINT  15
   11.65 +typedef struct pdb_op_watchpt
   11.66 +{
   11.67 +#define BWC_DEBUG 1
   11.68 +#define BWC_INT3  3
   11.69 +#define BWC_WATCH        100                         /* pdb: watchpoint page */
   11.70 +#define BWC_WATCH_STEP   101                  /* pdb: watchpoint single step */
   11.71 +#define BWC_WATCH_WRITE  102
   11.72 +#define BWC_WATCH_READ   103
   11.73 +#define BWC_WATCH_ACCESS 104
   11.74 +    u32 type;
   11.75 +    u32 address;
   11.76 +    u32 length;
   11.77 +} pdb_op_watchpt_t, *pdb_op_watchpt_p;
   11.78 +
   11.79  
   11.80  typedef struct 
   11.81  {
   11.82 @@ -68,10 +92,12 @@ typedef struct
   11.83      union
   11.84      {
   11.85          pdb_op_attach_t     attach;
   11.86 +        pdb_op_rd_reg_t     rd_reg;
   11.87          pdb_op_wr_reg_t     wr_reg;
   11.88          pdb_op_rd_mem_req_t rd_mem;
   11.89          pdb_op_wr_mem_t     wr_mem;
   11.90          pdb_op_bkpt_t       bkpt;
   11.91 +        pdb_op_watchpt_t    watchpt;
   11.92      } u;
   11.93  } pdb_request_t, *pdb_request_p;
   11.94  
   11.95 @@ -87,6 +113,7 @@ typedef struct {
   11.96      s16  status;          /* PDB_RESPONSE_???    */
   11.97      union
   11.98      {
   11.99 +        pdb_op_rd_reg_t      rd_reg;
  11.100          pdb_op_rd_regs_t     rd_regs;
  11.101          pdb_op_rd_mem_resp_t rd_mem;
  11.102      } u;
  11.103 @@ -95,6 +122,11 @@ typedef struct {
  11.104  
  11.105  DEFINE_RING_TYPES(pdb, pdb_request_t, pdb_response_t);
  11.106  
  11.107 +
  11.108 +/* from access_process_vm */
  11.109 +#define PDB_MEM_READ  0
  11.110 +#define PDB_MEM_WRITE 1
  11.111 +
  11.112  #endif
  11.113  
  11.114  
    12.1 --- a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch	Mon Aug 15 18:56:10 2005 +0000
    12.2 +++ b/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch	Mon Aug 15 19:04:28 2005 +0000
    12.3 @@ -1,7 +1,15 @@
    12.4  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
    12.5  --- linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c	2005-07-31 22:36:50.000000000 +0100
    12.6  +++ linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c	2005-08-01 10:57:31.000000000 +0100
    12.7 -@@ -172,6 +172,7 @@
    12.8 +@@ -151,6 +151,7 @@
    12.9 + /* TLB flushing */
   12.10 + EXPORT_SYMBOL(flush_tlb_page);
   12.11 + #endif
   12.12 ++EXPORT_SYMBOL(flush_tlb_mm);
   12.13 + 
   12.14 + #ifdef CONFIG_X86_IO_APIC
   12.15 + EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
   12.16 +@@ -172,6 +173,7 @@
   12.17   EXPORT_SYMBOL_GPL(unset_nmi_callback);
   12.18   
   12.19   EXPORT_SYMBOL(register_die_notifier);
    13.1 --- a/tools/debugger/pdb/pdb_caml_domain.c	Mon Aug 15 18:56:10 2005 +0000
    13.2 +++ b/tools/debugger/pdb/pdb_caml_domain.c	Mon Aug 15 19:04:28 2005 +0000
    13.3 @@ -43,6 +43,54 @@ typedef struct
    13.4  /****************************************************************************/
    13.5  
    13.6  /*
    13.7 + * dom_read_register : context_t -> int -> int32
    13.8 + */
    13.9 +value
   13.10 +dom_read_register (value context, value reg)
   13.11 +{
   13.12 +    CAMLparam2(context, reg);
   13.13 +    CAMLlocal1(result);
   13.14 +
   13.15 +    int my_reg = Int_val(reg);
   13.16 +    cpu_user_regs_t *regs;
   13.17 +    context_t ctx;
   13.18 +
   13.19 +    decode_context(&ctx, context);
   13.20 +
   13.21 +    if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
   13.22 +    {
   13.23 +        printf("(pdb) read registers error!\n");  fflush(stdout);
   13.24 +        failwith("read registers error");
   13.25 +    }
   13.26 +
   13.27 +    dump_regs(regs);
   13.28 +
   13.29 +    result = caml_alloc_tuple(16);
   13.30 +
   13.31 +    switch (my_reg)
   13.32 +    {
   13.33 +    case GDB_EAX: result = caml_copy_int32(regs->eax); break;
   13.34 +    case GDB_ECX: result = caml_copy_int32(regs->ecx); break;
   13.35 +    case GDB_EDX: result = caml_copy_int32(regs->edx); break;
   13.36 +    case GDB_EBX: result = caml_copy_int32(regs->ebx); break;
   13.37 +    case GDB_ESP: result = caml_copy_int32(regs->esp); break;
   13.38 +    case GDB_EBP: result = caml_copy_int32(regs->ebp); break;
   13.39 +    case GDB_ESI: result = caml_copy_int32(regs->esi); break;
   13.40 +    case GDB_EDI: result = caml_copy_int32(regs->edi); break;
   13.41 +    case GDB_EIP: result = caml_copy_int32(regs->eip); break;
   13.42 +    case GDB_EFL: result = caml_copy_int32(regs->eflags); break;
   13.43 +    case GDB_CS:  result = caml_copy_int32(regs->cs);  break;
   13.44 +    case GDB_SS: result = caml_copy_int32(regs->ss); break;
   13.45 +    case GDB_DS: result = caml_copy_int32(regs->ds); break;
   13.46 +    case GDB_ES: result = caml_copy_int32(regs->es); break;
   13.47 +    case GDB_FS: result = caml_copy_int32(regs->fs); break;
   13.48 +    case GDB_GS: result = caml_copy_int32(regs->gs); break;
   13.49 +    }
   13.50 +
   13.51 +    CAMLreturn(result);
   13.52 +}
   13.53 +
   13.54 +/*
   13.55   * dom_read_registers : context_t -> int32
   13.56   */
   13.57  value
    14.1 --- a/tools/debugger/pdb/pdb_caml_process.c	Mon Aug 15 18:56:10 2005 +0000
    14.2 +++ b/tools/debugger/pdb/pdb_caml_process.c	Mon Aug 15 19:04:28 2005 +0000
    14.3 @@ -113,6 +113,12 @@ process_handle_response (value ring)
    14.4          case PDB_OPCODE_DETACH :
    14.5              break;
    14.6              
    14.7 +        case PDB_OPCODE_RD_REG :
    14.8 +        {
    14.9 +            sprintf(&msg[0], "%08x", _flip(resp->u.rd_reg.value));
   14.10 +            break;
   14.11 +        }
   14.12 +
   14.13          case PDB_OPCODE_RD_REGS :
   14.14          {
   14.15              int loop;
   14.16 @@ -161,16 +167,22 @@ process_handle_response (value ring)
   14.17          }
   14.18  
   14.19          case PDB_OPCODE_SET_BKPT :
   14.20 -        {
   14.21 -            break;
   14.22 -        }
   14.23          case PDB_OPCODE_CLR_BKPT :
   14.24 +        case PDB_OPCODE_SET_WATCHPT :
   14.25 +        case PDB_OPCODE_CLR_WATCHPT :
   14.26          {
   14.27              break;
   14.28          }
   14.29  
   14.30 +        case PDB_OPCODE_WATCHPOINT :
   14.31 +        {
   14.32 +            sprintf(msg, "S05");
   14.33 +            break;
   14.34 +        }
   14.35 +
   14.36          default :
   14.37 -            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE\n");
   14.38 +            printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE %d\n",
   14.39 +                   resp->operation);
   14.40              break;
   14.41          }
   14.42  
   14.43 @@ -261,6 +273,32 @@ proc_pause_target (value context)
   14.44  
   14.45  
   14.46  /*
   14.47 + * proc_read_register : context_t -> int -> unit
   14.48 + */
   14.49 +value
   14.50 +proc_read_register (value context, value reg)
   14.51 +{
   14.52 +    CAMLparam1(context);
   14.53 +
   14.54 +    pdb_request_t req;
   14.55 +    context_t ctx;
   14.56 +    int my_reg = Int_val(reg);
   14.57 +
   14.58 +    decode_context(&ctx, context);
   14.59 +
   14.60 +    req.operation = PDB_OPCODE_RD_REG;
   14.61 +    req.process = ctx.process;
   14.62 +    req.u.rd_reg.reg = my_reg;
   14.63 +    req.u.rd_reg.value = 0;
   14.64 +
   14.65 +    send_request (ctx.ring, ctx.evtchn, &req);
   14.66 +
   14.67 +    CAMLreturn(Val_unit);
   14.68 +}
   14.69 +
   14.70 +
   14.71 +
   14.72 +/*
   14.73   * proc_read_registers : context_t -> unit
   14.74   */
   14.75  value
   14.76 @@ -443,7 +481,7 @@ proc_step_target (value context)
   14.77  
   14.78  
   14.79  /*
   14.80 - * proc_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
   14.81 + * proc_insert_memory_breakpoint : context_t -> int32 -> int -> unit
   14.82   */
   14.83  value
   14.84  proc_insert_memory_breakpoint (value context, value address, value length)
   14.85 @@ -466,7 +504,7 @@ proc_insert_memory_breakpoint (value con
   14.86  }
   14.87  
   14.88  /*
   14.89 - * proc_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
   14.90 + * proc_remove_memory_breakpoint : context_t -> int32 -> int -> unit
   14.91   */
   14.92  value
   14.93  proc_remove_memory_breakpoint (value context, value address, value length)
   14.94 @@ -488,6 +526,54 @@ proc_remove_memory_breakpoint (value con
   14.95      CAMLreturn(Val_unit);
   14.96  }
   14.97  
   14.98 +/*
   14.99 + * proc_insert_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
  14.100 + */
  14.101 +value
  14.102 +proc_insert_watchpoint (value context, value kind, value address, value length)
  14.103 +{
  14.104 +    CAMLparam3(context, address, length);
  14.105 +
  14.106 +    context_t ctx;
  14.107 +    pdb_request_t req;
  14.108 +
  14.109 +    decode_context(&ctx, context);
  14.110 +
  14.111 +    req.operation = PDB_OPCODE_SET_WATCHPT;
  14.112 +    req.process = ctx.process;
  14.113 +    req.u.watchpt.type    =  Int_val(kind);
  14.114 +    req.u.watchpt.address = (memory_t) Int32_val(address);
  14.115 +    req.u.watchpt.length  =  Int_val(length);
  14.116 +
  14.117 +    send_request(ctx.ring, ctx.evtchn, &req);
  14.118 +
  14.119 +    CAMLreturn(Val_unit);
  14.120 +}
  14.121 +
  14.122 +/*
  14.123 + * proc_remove_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
  14.124 + */
  14.125 +value
  14.126 +proc_remove_watchpoint (value context, value kind, value address, value length)
  14.127 +{
  14.128 +    CAMLparam3(context, address, length);
  14.129 +
  14.130 +    context_t ctx;
  14.131 +    pdb_request_t req;
  14.132 +
  14.133 +    decode_context(&ctx, context);
  14.134 +
  14.135 +    req.operation = PDB_OPCODE_CLR_WATCHPT;
  14.136 +    req.process = ctx.process;
  14.137 +    req.u.watchpt.type    =  Int_val(kind);
  14.138 +    req.u.watchpt.address = (memory_t) Int32_val(address);
  14.139 +    req.u.watchpt.length  =  Int_val(length);
  14.140 +
  14.141 +    send_request(ctx.ring, ctx.evtchn, &req);
  14.142 +
  14.143 +    CAMLreturn(Val_unit);
  14.144 +}
  14.145 +
  14.146  
  14.147  /*
  14.148   * Local variables:
    15.1 --- a/tools/debugger/pdb/readme	Mon Aug 15 18:56:10 2005 +0000
    15.2 +++ b/tools/debugger/pdb/readme	Mon Aug 15 19:04:28 2005 +0000
    15.3 @@ -1,9 +1,9 @@
    15.4  
    15.5 -PDB 0.3 
    15.6 +PDB 0.3.3
    15.7  http://www.cl.cam.ac.uk/netos/pdb
    15.8  
    15.9  Alex Ho  
   15.10 -June 2005
   15.11 +August 2005
   15.12  
   15.13  
   15.14  This is the latest incarnation of the pervasive debugger.
   15.15 @@ -79,6 +79,11 @@ Usage
   15.16  Process
   15.17  
   15.18    PDB can also debug a process running in a Linux 2.6 domain. 
   15.19 +  You will need to patch the Linux 2.6 domain U tree to export some
   15.20 +  additional symbols for the pdb module
   15.21 +
   15.22 +  % make -C linux-2.6-patches
   15.23 +
   15.24    After running PDB in domain 0, insert the pdb module in dom u:
   15.25    
   15.26    % insmod linux-2.6-module/pdb.ko
   15.27 @@ -87,7 +92,14 @@ Process
   15.28  
   15.29    (gdb) maint packet x context = process <domid> <pid>
   15.30  
   15.31 +  Read, write, and access watchpoint should also work for processes, 
   15.32 +  use the "rwatch", "watch" and "awatch" gdb commands respectively.
   15.33 +
   15.34 +  If you are having trouble with GDB 5.3 (i386-redhat-linux-gnu),
   15.35 +  try GDB 6.3 (configured with --target=i386-linux-gnu).
   15.36 +
   15.37 +  
   15.38  To Do
   15.39  
   15.40 -- watchpoints
   15.41 +- watchpoints for domains
   15.42  - support for SMP