aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-08-15 19:04:28 +0000
committerach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-08-15 19:04:28 +0000
commit48664deb37128132802d3c3143d5a2609ab1e9d7 (patch)
treeac57bd2f916380c71ef33366d740b4973e8c2d67
parent5237d0572c91f3cbfea0852a740e1633377bdc87 (diff)
downloadxen-48664deb37128132802d3c3143d5a2609ab1e9d7.tar.gz
xen-48664deb37128132802d3c3143d5a2609ab1e9d7.tar.bz2
xen-48664deb37128132802d3c3143d5a2609ab1e9d7.zip
PDB: watchpoints for process context
-rw-r--r--tools/debugger/pdb/Domain.ml1
-rw-r--r--tools/debugger/pdb/Domain.mli1
-rw-r--r--tools/debugger/pdb/Makefile3
-rw-r--r--tools/debugger/pdb/PDB.ml43
-rw-r--r--tools/debugger/pdb/Process.ml5
-rw-r--r--tools/debugger/pdb/Process.mli4
-rw-r--r--tools/debugger/pdb/debugger.ml30
-rw-r--r--tools/debugger/pdb/linux-2.6-module/debug.c535
-rw-r--r--tools/debugger/pdb/linux-2.6-module/module.c21
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_debug.h9
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_module.h48
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch10
-rw-r--r--tools/debugger/pdb/pdb_caml_domain.c48
-rw-r--r--tools/debugger/pdb/pdb_caml_process.c94
-rw-r--r--tools/debugger/pdb/readme18
15 files changed, 787 insertions, 83 deletions
diff --git a/tools/debugger/pdb/Domain.ml b/tools/debugger/pdb/Domain.ml
index 29754b47f8..dc3fd2fb30 100644
--- a/tools/debugger/pdb/Domain.ml
+++ b/tools/debugger/pdb/Domain.ml
@@ -36,6 +36,7 @@ let string_of_context ctx =
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 --git a/tools/debugger/pdb/Domain.mli b/tools/debugger/pdb/Domain.mli
index f9c92a30f5..d9cf115c4f 100644
--- a/tools/debugger/pdb/Domain.mli
+++ b/tools/debugger/pdb/Domain.mli
@@ -22,6 +22,7 @@ val get_vcpu : context_t -> int
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 --git a/tools/debugger/pdb/Makefile b/tools/debugger/pdb/Makefile
index 9652a11013..85f8beaff7 100644
--- a/tools/debugger/pdb/Makefile
+++ b/tools/debugger/pdb/Makefile
@@ -33,7 +33,8 @@ LIBDIRS += ../libxendebug
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 --git a/tools/debugger/pdb/PDB.ml b/tools/debugger/pdb/PDB.ml
index 3c4b063362..da9ad7d2c6 100644
--- a/tools/debugger/pdb/PDB.ml
+++ b/tools/debugger/pdb/PDB.ml
@@ -219,6 +219,17 @@ let add_default_context sock =
(***************************************************************************)
+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,15 +289,43 @@ let step ctx =
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 =
match ctx with
diff --git a/tools/debugger/pdb/Process.ml b/tools/debugger/pdb/Process.ml
index 5585da0c5c..ad98241de4 100644
--- a/tools/debugger/pdb/Process.ml
+++ b/tools/debugger/pdb/Process.ml
@@ -54,6 +54,7 @@ let attach_debugger proc_ctx dom_ctx =
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 @@ external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
"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 --git a/tools/debugger/pdb/Process.mli b/tools/debugger/pdb/Process.mli
index ed5b8bfe87..733b681f59 100644
--- a/tools/debugger/pdb/Process.mli
+++ b/tools/debugger/pdb/Process.mli
@@ -26,7 +26,7 @@ val attach_debugger : context_t -> Xen_domain.context_t -> unit
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 step : context_t -> unit
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 --git a/tools/debugger/pdb/debugger.ml b/tools/debugger/pdb/debugger.ml
index 6d20b68294..aa741a4566 100644
--- a/tools/debugger/pdb/debugger.ml
+++ b/tools/debugger/pdb/debugger.ml
@@ -53,10 +53,20 @@ let gdb_step ctx =
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 @@ let gdb_read_memory ctx command =
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 @@ let pdb_extensions command sock =
(**
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 @@ let gdb_remove_bwcpoint ctx command =
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 @@ let process_command command sock =
| '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 @@ let process_command command sock =
| '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 --git a/tools/debugger/pdb/linux-2.6-module/debug.c b/tools/debugger/pdb/linux-2.6-module/debug.c
index 983e02dccc..ae1064ebad 100644
--- a/tools/debugger/pdb/linux-2.6-module/debug.c
+++ b/tools/debugger/pdb/linux-2.6-module/debug.c
@@ -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;
- u32 process;
- u8 old_value; /* old value for software bkpt */
+ int length;
+
u8 type; /* BWC_??? */
+ u8 mode; /* for BWC_PAGE, the current protection mode */
+ u32 process;
+ 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)
+pdb_bwc_print_list (void)
+{
+ _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
+}
+
+bwcpoint_p
+pdb_search_watchpoint (u32 process, memory_t address)
{
- memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
- INIT_LIST_HEAD(&bwcpoint_list.list);
+ bwcpoint_p bwc_watch = (bwcpoint_p) 0;
+ bwcpoint_p bwc_entry = (bwcpoint_p) 0;
+ struct list_head *ptr;
- return;
+ 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)
@@ -137,6 +247,35 @@ _pdb_set_register (struct task_struct *target, int reg, unsigned long val)
}
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
pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
{
int rc = 0;
@@ -209,18 +348,14 @@ pdb_step (struct task_struct *target)
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 @@ pdb_insert_memory_breakpoint (struct task_struct *target,
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");
- 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 @@ pdb_remove_memory_breakpoint (struct task_struct *target,
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 @@ pdb_remove_memory_breakpoint (struct task_struct *target,
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);
+ kfree(bkpt);
- pdb_access_memory(target, address, &bkpt->old_value, 1, 1);
+ pdb_bwc_print_list();
- kfree(bkpt);
+ 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 @@ pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
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 */
- case DIE_GPF:
+ 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:
+ printk("---------------GPF\n");
+ break;
default:
break;
}
@@ -330,70 +675,110 @@ pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
}
-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)
+ if (entry == &bwcpoint_list)
{
- printk("not my int3 bkpt 0x%x 0x%lx\n", current->pid, regs->eip);
+ 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);
@@ -406,6 +791,54 @@ pdb_int3_fn (struct pt_regs *regs, long error_code)
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:
* mode: C
diff --git a/tools/debugger/pdb/linux-2.6-module/module.c b/tools/debugger/pdb/linux-2.6-module/module.c
index c75b9cd647..b8093f9d3f 100644
--- a/tools/debugger/pdb/linux-2.6-module/module.c
+++ b/tools/debugger/pdb/linux-2.6-module/module.c
@@ -98,6 +98,11 @@ pdb_process_request (pdb_request_t *request)
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 @@ pdb_process_request (pdb_request_t *request)
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 :
@@ -137,6 +144,14 @@ pdb_process_request (pdb_request_t *request)
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:
printk("(pdb) unknown request operation %d\n", request->operation);
resp.status = PDB_RESPONSE_ERROR;
@@ -249,8 +264,6 @@ pdb_initialize (void)
printk("----\npdb initialize %s %s\n", __DATE__, __TIME__);
- pdb_initialize_bwcpoint();
-
/*
if ( xen_start_info.flags & SIF_INITDOMAIN )
return 1;
diff --git a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h b/tools/debugger/pdb/linux-2.6-module/pdb_debug.h
index dfcbc4375f..2d30eae625 100644
--- a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_debug.h
@@ -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,14 +21,14 @@ int pdb_insert_memory_breakpoint (struct task_struct *target,
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 --git a/tools/debugger/pdb/linux-2.6-module/pdb_module.h b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
index fc95bdb47a..a7e679ecdf 100644
--- a/tools/debugger/pdb/linux-2.6-module/pdb_module.h
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
@@ -14,20 +14,27 @@ typedef struct pdb_op_attach
#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 @@ typedef struct pdb_op_rd_mem_resp
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,17 +56,34 @@ typedef struct pdb_op_wr_mem
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 @@ typedef struct
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 @@ typedef struct {
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;
@@ -95,6 +122,11 @@ typedef struct {
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 --git a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch b/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
index 031d41b917..0efd8db532 100644
--- a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
+++ b/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
@@ -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 --git a/tools/debugger/pdb/pdb_caml_domain.c b/tools/debugger/pdb/pdb_caml_domain.c
index 7621eb45f6..934524ba0c 100644
--- a/tools/debugger/pdb/pdb_caml_domain.c
+++ b/tools/debugger/pdb/pdb_caml_domain.c
@@ -43,6 +43,54 @@ typedef struct
/****************************************************************************/
/*
+ * 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
*/
value
diff --git a/tools/debugger/pdb/pdb_caml_process.c b/tools/debugger/pdb/pdb_caml_process.c
index 0f911fa754..760a182732 100644
--- a/tools/debugger/pdb/pdb_caml_process.c
+++ b/tools/debugger/pdb/pdb_caml_process.c
@@ -113,6 +113,12 @@ process_handle_response (value ring)
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 @@ process_handle_response (value ring)
}
case PDB_OPCODE_SET_BKPT :
+ case PDB_OPCODE_CLR_BKPT :
+ case PDB_OPCODE_SET_WATCHPT :
+ case PDB_OPCODE_CLR_WATCHPT :
{
break;
}
- case PDB_OPCODE_CLR_BKPT :
+
+ 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;
}
@@ -261,6 +273,32 @@ proc_pause_target (value context)
/*
+ * 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);
+}
+
+
+
+/*
* proc_read_registers : context_t -> unit
*/
value
@@ -443,7 +481,7 @@ proc_step_target (value context)
/*
- * 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_insert_memory_breakpoint (value context, value address, value length)
}
/*
- * 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)
@@ -488,6 +526,54 @@ proc_remove_memory_breakpoint (value context, value address, value length)
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);
+
+ CAMLreturn(Val_unit);
+}
+
/*
* Local variables:
diff --git a/tools/debugger/pdb/readme b/tools/debugger/pdb/readme
index 9ed26be4a6..6ea537b404 100644
--- a/tools/debugger/pdb/readme
+++ b/tools/debugger/pdb/readme
@@ -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 @@ Usage
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 @@ Process
(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