aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debugger
diff options
context:
space:
mode:
authorach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-07-28 21:28:23 +0000
committerach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-07-28 21:28:23 +0000
commit476167d4df2ede61a1f5dc19f876c2b3a727548d (patch)
tree48850892164b8d0d2be38a386194abad9f4539ab /tools/debugger
parentfcb76453f3084edc2af3c7f7227fdd95405e11aa (diff)
downloadxen-476167d4df2ede61a1f5dc19f876c2b3a727548d.tar.gz
xen-476167d4df2ede61a1f5dc19f876c2b3a727548d.tar.bz2
xen-476167d4df2ede61a1f5dc19f876c2b3a727548d.zip
PDB: process targets
Diffstat (limited to 'tools/debugger')
-rw-r--r--tools/debugger/libxendebug/xendebug.c1
-rw-r--r--tools/debugger/pdb/PDB.ml22
-rw-r--r--tools/debugger/pdb/Process.ml2
-rw-r--r--tools/debugger/pdb/Process.mli2
-rw-r--r--tools/debugger/pdb/debugger.ml3
-rw-r--r--tools/debugger/pdb/linux-2.6-module/debug.c389
-rw-r--r--tools/debugger/pdb/linux-2.6-module/module.c132
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_module.h71
-rw-r--r--tools/debugger/pdb/pdb_caml_process.c230
-rw-r--r--tools/debugger/pdb/pdb_caml_xcs.c4
-rw-r--r--tools/debugger/pdb/readme15
11 files changed, 616 insertions, 255 deletions
diff --git a/tools/debugger/libxendebug/xendebug.c b/tools/debugger/libxendebug/xendebug.c
index 6b116dfbc8..176aff9b79 100644
--- a/tools/debugger/libxendebug/xendebug.c
+++ b/tools/debugger/libxendebug/xendebug.c
@@ -42,7 +42,6 @@ typedef struct bwcpoint /* break/watch/catch point */
struct list_head list;
memory_t address;
u32 domain;
- u16 vcpu;
u8 old_value; /* old value for software bkpt */
} bwcpoint_t, *bwcpoint_p;
diff --git a/tools/debugger/pdb/PDB.ml b/tools/debugger/pdb/PDB.ml
index 6abddd750f..3c4b063362 100644
--- a/tools/debugger/pdb/PDB.ml
+++ b/tools/debugger/pdb/PDB.ml
@@ -138,9 +138,13 @@ let attach_debugger ctx =
let detach_debugger ctx =
match ctx with
- | Domain d -> Domain.detach_debugger (Domain.get_domain d)
- (Domain.get_vcpu d)
- | Process p -> Process.detach_debugger p
+ | Domain d ->
+ Domain.detach_debugger (Domain.get_domain d)
+ (Domain.get_vcpu d);
+ "OK"
+ | Process p ->
+ Process.detach_debugger p;
+ raise No_reply
| _ -> raise (Unimplemented "detach debugger")
@@ -240,13 +244,21 @@ let write_register ctx register value =
let read_memory ctx addr len =
match ctx with
| Domain d -> Domain.read_memory d addr len
- | Process p -> Process.read_memory p addr len
+ | Process p ->
+ begin
+ Process.read_memory p addr len;
+ raise No_reply
+ end
| _ -> raise (Unimplemented "read memory")
let write_memory ctx addr values =
match ctx with
| Domain d -> Domain.write_memory d addr values
- | Process p -> Process.write_memory p addr values
+ | Process p ->
+ begin
+ Process.write_memory p addr values;
+ raise No_reply
+ end
| _ -> raise (Unimplemented "write memory")
diff --git a/tools/debugger/pdb/Process.ml b/tools/debugger/pdb/Process.ml
index aa686ebae4..5585da0c5c 100644
--- a/tools/debugger/pdb/Process.ml
+++ b/tools/debugger/pdb/Process.ml
@@ -57,7 +57,7 @@ let attach_debugger proc_ctx dom_ctx =
external read_registers : context_t -> unit = "proc_read_registers"
external write_register : context_t -> register -> int32 -> unit =
"proc_write_register"
-external read_memory : context_t -> int32 -> int -> int list =
+external read_memory : context_t -> int32 -> int -> unit =
"proc_read_memory"
external write_memory : context_t -> int32 -> int list -> unit =
"proc_write_memory"
diff --git a/tools/debugger/pdb/Process.mli b/tools/debugger/pdb/Process.mli
index 065e933bce..ed5b8bfe87 100644
--- a/tools/debugger/pdb/Process.mli
+++ b/tools/debugger/pdb/Process.mli
@@ -29,7 +29,7 @@ val pause : context_t -> unit
val read_registers : context_t -> unit
val write_register : context_t -> register -> int32 -> unit
-val read_memory : context_t -> int32 -> int -> int list
+val read_memory : context_t -> int32 -> int -> unit
val write_memory : context_t -> int32 -> int list -> unit
val continue : context_t -> unit
diff --git a/tools/debugger/pdb/debugger.ml b/tools/debugger/pdb/debugger.ml
index bafef4de06..6d20b68294 100644
--- a/tools/debugger/pdb/debugger.ml
+++ b/tools/debugger/pdb/debugger.ml
@@ -25,8 +25,7 @@ let exit_debugger () =
hash. It will be cleaned up with the socket is closed.
*)
let gdb_detach ctx =
- PDB.detach_debugger ctx;
- raise No_reply
+ PDB.detach_debugger ctx
(**
Kill Command
diff --git a/tools/debugger/pdb/linux-2.6-module/debug.c b/tools/debugger/pdb/linux-2.6-module/debug.c
index ba1825cc30..983e02dccc 100644
--- a/tools/debugger/pdb/linux-2.6-module/debug.c
+++ b/tools/debugger/pdb/linux-2.6-module/debug.c
@@ -3,49 +3,54 @@
* pdb debug functionality for processes.
*/
-
#include <linux/module.h>
+#include <linux/mm.h>
#include <linux/sched.h>
+#include <asm-i386/kdebug.h>
+#include <asm-xen/asm-i386/processor.h>
#include <asm-xen/asm-i386/ptrace.h>
#include <asm-xen/xen-public/xen.h>
-
#include "pdb_module.h"
+#include "pdb_debug.h"
+
+#define BWC_DEBUG 1
+#define BWC_INT3 3
+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 */
+ u8 type; /* BWC_??? */
+} bwcpoint_t, *bwcpoint_p;
+
+static bwcpoint_t bwcpoint_list;
+
+void
+pdb_initialize_bwcpoint (void)
+{
+ memset((void *) &bwcpoint_list, 0, sizeof(bwcpoint_t));
+ INIT_LIST_HEAD(&bwcpoint_list.list);
+
+ return;
+}
-EXPORT_SYMBOL(pdb_attach);
-EXPORT_SYMBOL(pdb_detach);
int
-pdb_attach (int pid)
+pdb_suspend (struct task_struct *target)
{
- struct task_struct *target;
u32 rc = 0;
- printk ("pdb attach: 0x%x\n", pid);
-
- read_lock(&tasklist_lock);
- target = find_task_by_pid(pid);
- if (target)
- get_task_struct(target);
- read_unlock(&tasklist_lock);
-
force_sig(SIGSTOP, target); /* force_sig_specific ??? */
return rc;
}
int
-pdb_detach (int pid)
+pdb_resume (struct task_struct *target)
{
int rc = 0;
- struct task_struct *target;
-
- printk ("pdb detach: 0x%x\n", pid);
-
- read_lock(&tasklist_lock);
- target = find_task_by_pid(pid);
- if (target)
- get_task_struct(target);
- read_unlock(&tasklist_lock);
wake_up_process(target);
@@ -55,7 +60,6 @@ pdb_detach (int pid)
/*
* from linux-2.6.11/arch/i386/kernel/ptrace.c::getreg()
*/
-
static unsigned long
_pdb_get_register (struct task_struct *target, int reg)
{
@@ -65,20 +69,20 @@ _pdb_get_register (struct task_struct *target, int reg)
switch (reg)
{
- case FS:
+ case LINUX_FS:
result = target->thread.fs;
break;
- case GS:
+ case LINUX_GS:
result = target->thread.gs;
break;
- case DS:
- case ES:
- case SS:
- case CS:
+ case LINUX_DS:
+ case LINUX_ES:
+ case LINUX_SS:
+ case LINUX_CS:
result = 0xffff;
/* fall through */
default:
- if (reg > GS)
+ if (reg > LINUX_GS)
reg -= 2;
offset = reg * sizeof(long);
@@ -91,17 +95,51 @@ _pdb_get_register (struct task_struct *target, int reg)
return result;
}
+/*
+ * from linux-2.6.11/arch/i386/kernel/ptrace.c::putreg()
+ */
+static void
+_pdb_set_register (struct task_struct *target, int reg, unsigned long val)
+{
+ unsigned long offset;
+ unsigned char *stack;
+ unsigned long value = val;
+
+ switch (reg)
+ {
+ case LINUX_FS:
+ target->thread.fs = value;
+ return;
+ case LINUX_GS:
+ target->thread.gs = value;
+ return;
+ case LINUX_DS:
+ case LINUX_ES:
+ value &= 0xffff;
+ break;
+ case LINUX_SS:
+ case LINUX_CS:
+ value &= 0xffff;
+ break;
+ case LINUX_EFL:
+ break;
+ }
+
+ if (reg > LINUX_GS)
+ reg -= 2;
+ offset = reg * sizeof(long);
+ offset -= sizeof(struct pt_regs);
+ stack = (unsigned char *)target->thread.esp0;
+ stack += offset;
+ *(unsigned long *) stack = value;
+
+ return;
+}
+
int
-pdb_read_register (int pid, pdb_op_rd_regs_p op)
+pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
{
int rc = 0;
- struct task_struct *target;
-
- read_lock(&tasklist_lock);
- target = find_task_by_pid(pid);
- if (target)
- get_task_struct(target);
- read_unlock(&tasklist_lock);
op->reg[ 0] = _pdb_get_register(target, LINUX_EAX);
op->reg[ 1] = _pdb_get_register(target, LINUX_ECX);
@@ -124,59 +162,250 @@ pdb_read_register (int pid, pdb_op_rd_regs_p op)
return rc;
}
-/*
- * from linux-2.6.11/arch/i386/kernel/ptrace.c::putreg()
- */
int
-pdb_write_register (int pid, pdb_op_wr_reg_p op)
+pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op)
{
int rc = 0;
- struct task_struct *target;
- unsigned long offset;
- unsigned char *stack;
- unsigned long value = op->value;
- /*
- printk ("pdb write register: 0x%x %2d 0x%lx\n", pid, op->reg, value);
- */
+ _pdb_set_register(target, op->reg, op->value);
+
+ return rc;
+}
+
+int
+pdb_access_memory (struct task_struct *target, unsigned long address,
+ void *buffer, int length, int write)
+{
+ int rc = 0;
+
+ access_process_vm(target, address, buffer, length, write);
+
+ return rc;
+}
+
+int
+pdb_continue (struct task_struct *target)
+{
+ int rc = 0;
+ unsigned long eflags;
+
+ eflags = _pdb_get_register(target, LINUX_EFL);
+ eflags &= ~X86_EFLAGS_TF;
+ _pdb_set_register(target, LINUX_EFL, eflags);
+
+ wake_up_process(target);
- read_lock(&tasklist_lock);
- target = find_task_by_pid(pid);
- if (target)
- get_task_struct(target);
- read_unlock(&tasklist_lock);
+ return rc;
+}
- switch (op->reg)
+int
+pdb_step (struct task_struct *target)
+{
+ int rc = 0;
+ unsigned long eflags;
+ bwcpoint_p bkpt;
+
+ eflags = _pdb_get_register(target, LINUX_EFL);
+ eflags |= X86_EFLAGS_TF;
+ _pdb_set_register(target, LINUX_EFL, eflags);
+
+ bkpt = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL);
+ if ( bkpt == NULL )
{
- case FS:
- target->thread.fs = value;
- return rc;
- case GS:
- target->thread.gs = value;
- return rc;
- case DS:
- case ES:
- value &= 0xffff;
- break;
- case SS:
- case CS:
- value &= 0xffff;
- break;
- case EFL:
- break;
+ printk("error: unable to allocation memory\n");
+ return -1;
}
- if (op->reg > GS)
- op->reg -= 2;
- offset = op->reg * sizeof(long);
- offset -= sizeof(struct pt_regs);
- stack = (unsigned char *)target->thread.esp0;
- stack += offset;
- *(unsigned long *) stack = op->value;
+ bkpt->process = target->pid;
+ bkpt->address = 0;
+ bkpt->type = BWC_DEBUG;
+
+ list_add(&bkpt->list, &bwcpoint_list.list);
+
+ wake_up_process(target);
+
+ return rc;
+}
+
+int
+pdb_insert_memory_breakpoint (struct task_struct *target,
+ memory_t address, u32 length)
+{
+ int rc = 0;
+ bwcpoint_p bkpt;
+ u8 breakpoint_opcode = 0xcc;
+
+ 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;
+ }
+
+ 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);
+
+ list_add(&bkpt->list, &bwcpoint_list.list);
+
+ printk("breakpoint_set %d:%lx OLD: 0x%x\n",
+ target->pid, address, bkpt->old_value);
+
+ return rc;
+}
+
+int
+pdb_remove_memory_breakpoint (struct task_struct *target,
+ memory_t address, u32 length)
+{
+ int rc = 0;
+ bwcpoint_p bkpt = NULL;
+
+ printk ("remove breakpoint %d:%lx\n", target->pid, address);
+
+ struct list_head *entry;
+ list_for_each(entry, &bwcpoint_list.list)
+ {
+ bkpt = list_entry(entry, bwcpoint_t, list);
+ if ( target->pid == bkpt->process &&
+ address == bkpt->address &&
+ bkpt->type == BWC_INT3 )
+ break;
+ }
+
+ if (bkpt == &bwcpoint_list || bkpt == NULL)
+ {
+ printk ("error: no breakpoint found\n");
+ return -1;
+ }
+
+ list_del(&bkpt->list);
+
+ pdb_access_memory(target, address, &bkpt->old_value, 1, 1);
+
+ kfree(bkpt);
return rc;
}
+
+/***************************************************************/
+
+int
+pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
+ void *data)
+{
+ struct die_args *args = (struct die_args *)data;
+
+ switch (val)
+ {
+ case DIE_DEBUG:
+ 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))
+ return NOTIFY_STOP;
+ break;
+ case DIE_INT3: /* without kprobes, we should never see DIE_INT3 */
+ case DIE_GPF:
+ case DIE_PAGE_FAULT:
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+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)
+ {
+ bkpt = list_entry(entry, bwcpoint_t, list);
+ if ( current->pid == bkpt->process &&
+ bkpt->type == BWC_DEBUG )
+ break;
+ }
+
+ if (bkpt == &bwcpoint_list || bkpt == NULL)
+ {
+ 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);
+
+ regs->eflags &= ~X86_EFLAGS_TF;
+ set_tsk_thread_flag(current, TIF_SINGLESTEP);
+
+ resp.operation = PDB_OPCODE_STEP;
+ resp.process = current->pid;
+ resp.status = PDB_RESPONSE_OKAY;
+
+ pdb_send_response(&resp);
+
+ return 1;
+}
+
+
+int
+pdb_int3_fn (struct pt_regs *regs, long error_code)
+{
+ pdb_response_t resp;
+ bwcpoint_p bkpt = NULL;
+
+ struct list_head *entry;
+ list_for_each(entry, &bwcpoint_list.list)
+ {
+ bkpt = list_entry(entry, bwcpoint_t, list);
+ if ( current->pid == bkpt->process &&
+ regs->eip == bkpt->address &&
+ bkpt->type == BWC_INT3 )
+ break;
+ }
+
+ if (bkpt == &bwcpoint_list || bkpt == NULL)
+ {
+ printk("not my int3 bkpt 0x%x 0x%lx\n", current->pid, regs->eip);
+ return 0;
+ }
+
+ printk("(pdb) int3 pid: %d, eip: 0x%08lx\n", current->pid, regs->eip);
+
+ pdb_suspend(current);
+
+ resp.operation = PDB_OPCODE_CONTINUE;
+ resp.process = current->pid;
+ resp.status = PDB_RESPONSE_OKAY;
+
+ pdb_send_response(&resp);
+
+ 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 6da9df82f5..811c95a26d 100644
--- a/tools/debugger/pdb/linux-2.6-module/module.c
+++ b/tools/debugger/pdb/linux-2.6-module/module.c
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <asm-i386/kdebug.h>
+
#include <asm-xen/evtchn.h>
#include <asm-xen/ctrl_if.h>
#include <asm-xen/hypervisor.h>
@@ -20,17 +22,23 @@
#include <asm-xen/xen-public/io/ring.h>
#include "pdb_module.h"
+#include "pdb_debug.h"
#define PDB_RING_SIZE __RING_SIZE((pdb_sring_t *)0, PAGE_SIZE)
static pdb_back_ring_t pdb_ring;
static unsigned int pdb_evtchn;
static unsigned int pdb_irq;
+static unsigned int pdb_domain;
+
+/* work queue */
+static void pdb_work_handler(void *unused);
+static DECLARE_WORK(pdb_deferred_work, pdb_work_handler, NULL);
/*
* send response to a pdb request
*/
-static void
+void
pdb_send_response (pdb_response_t *response)
{
pdb_response_t *resp;
@@ -38,6 +46,7 @@ pdb_send_response (pdb_response_t *response)
resp = RING_GET_RESPONSE(&pdb_ring, pdb_ring.rsp_prod_pvt);
memcpy(resp, response, sizeof(pdb_response_t));
+ resp->domain = pdb_domain;
wmb(); /* Ensure other side can see the response fields. */
pdb_ring.rsp_prod_pvt++;
@@ -53,43 +62,98 @@ static void
pdb_process_request (pdb_request_t *request)
{
pdb_response_t resp;
+ struct task_struct *target;
+
+ read_lock(&tasklist_lock);
+ target = find_task_by_pid(request->process);
+ if (target)
+ get_task_struct(target);
+ read_unlock(&tasklist_lock);
resp.operation = request->operation;
- resp.domain = request->domain;
resp.process = request->process;
+ if (!target)
+ {
+ printk ("(linux) target not found 0x%x\n", request->process);
+ resp.status = PDB_RESPONSE_ERROR;
+ goto response;
+ }
+
switch (request->operation)
{
+ case PDB_OPCODE_PAUSE :
+ pdb_suspend(target);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
case PDB_OPCODE_ATTACH :
- pdb_attach(request->process);
+ pdb_suspend(target);
+ pdb_domain = request->u.attach.domain;
+ printk("(linux) attach dom:0x%x pid:0x%x\n",
+ pdb_domain, request->process);
resp.status = PDB_RESPONSE_OKAY;
break;
case PDB_OPCODE_DETACH :
- pdb_detach(request->process);
+ pdb_resume(target);
+ printk("(linux) detach 0x%x\n", request->process);
resp.status = PDB_RESPONSE_OKAY;
break;
case PDB_OPCODE_RD_REGS :
- pdb_read_register(request->process, &resp.u.rd_regs);
+ pdb_read_registers(target, &resp.u.rd_regs);
resp.status = PDB_RESPONSE_OKAY;
break;
case PDB_OPCODE_WR_REG :
- pdb_write_register(request->process, &request->u.wr_reg);
+ pdb_write_register(target, &request->u.wr_reg);
+ resp.status = PDB_RESPONSE_OKAY;
+ 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.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);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ case PDB_OPCODE_CONTINUE :
+ pdb_continue(target);
+ goto no_response;
+ break;
+ case PDB_OPCODE_STEP :
+ pdb_step(target);
+ resp.status = PDB_RESPONSE_OKAY;
+ goto no_response;
+ break;
+ case PDB_OPCODE_SET_BKPT :
+ pdb_insert_memory_breakpoint(target, request->u.bkpt.address,
+ request->u.bkpt.length);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ case PDB_OPCODE_CLR_BKPT :
+ pdb_remove_memory_breakpoint(target, request->u.bkpt.address,
+ request->u.bkpt.length);
resp.status = PDB_RESPONSE_OKAY;
break;
default:
printk("(pdb) unknown request operation %d\n", request->operation);
resp.status = PDB_RESPONSE_ERROR;
}
-
+
+ response:
pdb_send_response (&resp);
+
+ no_response:
return;
}
/*
- * receive a pdb request
+ * work queue
*/
-static irqreturn_t
-pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
+static void
+pdb_work_handler (void *unused)
{
pdb_request_t *req;
RING_IDX i, rp;
@@ -106,11 +170,19 @@ pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
}
pdb_ring.req_cons = i;
+}
+
+/*
+ * receive a pdb request
+ */
+static irqreturn_t
+pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ schedule_work(&pdb_deferred_work);
return IRQ_HANDLED;
}
-
static void
pdb_send_connection_status(int status, memory_t ring)
{
@@ -136,8 +208,6 @@ pdb_send_connection_status(int status, memory_t ring)
static void
pdb_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
{
-printk ("pdb ctrlif rx\n");
-
switch (msg->subtype)
{
case CMSG_DEBUG_CONNECTION_STATUS:
@@ -161,18 +231,35 @@ printk ("pdb ctrlif rx\n");
return;
}
+
+/********************************************************************/
+
+static struct notifier_block pdb_exceptions_nb =
+{
+ .notifier_call = pdb_exceptions_notify,
+ .priority = 0x1 /* low priority */
+};
+
+
static int __init
-pdb_initialize(void)
+pdb_initialize (void)
{
+ int err;
pdb_sring_t *sring;
printk("----\npdb initialize %s %s\n", __DATE__, __TIME__);
+ pdb_initialize_bwcpoint();
+
/*
if ( xen_start_info.flags & SIF_INITDOMAIN )
return 1;
*/
+ pdb_evtchn = 0;
+ pdb_irq = 0;
+ pdb_domain = 0;
+
(void)ctrl_if_register_receiver(CMSG_DEBUG, pdb_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
@@ -185,12 +272,21 @@ pdb_initialize(void)
pdb_send_connection_status(PDB_CONNECTION_STATUS_UP,
virt_to_machine(pdb_ring.sring) >> PAGE_SHIFT);
- return 0;
+ /* handler for int1 & int3 */
+ err = register_die_notifier(&pdb_exceptions_nb);
+
+ return err;
}
+extern struct notifier_block *i386die_chain;
+extern spinlock_t die_notifier_lock;
+
static void __exit
pdb_terminate(void)
{
+ int err = 0;
+ unsigned long flags;
+
printk("pdb cleanup\n");
(void)ctrl_if_unregister_receiver(CMSG_DEBUG, pdb_ctrlif_rx);
@@ -208,6 +304,12 @@ pdb_terminate(void)
}
pdb_send_connection_status(PDB_CONNECTION_STATUS_DOWN, 0);
+
+ spin_lock_irqsave(&die_notifier_lock, flags);
+ err = notifier_chain_unregister(&i386die_chain, &pdb_exceptions_nb);
+ spin_unlock_irqrestore(&die_notifier_lock, flags);
+
+ return;
}
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 0c11e6eab5..fc95bdb47a 100644
--- a/tools/debugger/pdb/linux-2.6-module/pdb_module.h
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
@@ -1,35 +1,80 @@
-#ifndef __XEN_PDB_H_
-#define __XEN_PDB_H_
+#ifndef __PDB_MODULE_H_
+#define __PDB_MODULE_H_
#include "../pdb_caml_xen.h"
-#define PDB_OPCODE_ATTACH 1
-#define PDB_OPCODE_DETACH 2
+#define PDB_OPCODE_PAUSE 1
-#define PDB_OPCODE_RD_REGS 3
+#define PDB_OPCODE_ATTACH 2
+typedef struct pdb_op_attach
+{
+ u32 domain;
+} pdb_op_attach_t, *pdb_op_attach_p;
+
+#define PDB_OPCODE_DETACH 3
+
+#define PDB_OPCODE_RD_REGS 4
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 4
+#define PDB_OPCODE_WR_REG 5
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
+typedef struct pdb_op_rd_mem_req
+{
+ u32 address;
+ u32 length;
+} pdb_op_rd_mem_req_t, *pdb_op_rd_mem_req_p;
+
+typedef struct pdb_op_rd_mem_resp
+{
+ u32 address;
+ u32 length;
+ u8 data[1024];
+} pdb_op_rd_mem_resp_t, *pdb_op_rd_mem_resp_p;
+
+#define PDB_OPCODE_WR_MEM 7
+typedef struct pdb_op_wr_mem
+{
+ u32 address;
+ u32 length;
+ 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_SET_BKPT 10
+#define PDB_OPCODE_CLR_BKPT 11
+typedef struct pdb_op_bkpt
+{
+ u32 address;
+ u32 length;
+} pdb_op_bkpt_t, *pdb_op_bkpt_p;
+
+
typedef struct
{
u8 operation; /* PDB_OPCODE_??? */
- u32 domain;
u32 process;
union
{
- pdb_op_wr_reg_t wr_reg;
+ pdb_op_attach_t attach;
+ 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;
} u;
} pdb_request_t, *pdb_request_p;
+
#define PDB_RESPONSE_OKAY 0
@@ -42,20 +87,14 @@ typedef struct {
s16 status; /* PDB_RESPONSE_??? */
union
{
- pdb_op_rd_regs_t rd_regs;
+ pdb_op_rd_regs_t rd_regs;
+ pdb_op_rd_mem_resp_t rd_mem;
} u;
} pdb_response_t, *pdb_response_p;
DEFINE_RING_TYPES(pdb, pdb_request_t, pdb_response_t);
-
-int pdb_attach (int pid);
-int pdb_detach (int pid);
-int pdb_read_register (int pid, pdb_op_rd_regs_p op);
-int pdb_write_register (int pid, pdb_op_wr_reg_p op);
-
-
#endif
diff --git a/tools/debugger/pdb/pdb_caml_process.c b/tools/debugger/pdb/pdb_caml_process.c
index ad1c8bfb6d..0f911fa754 100644
--- a/tools/debugger/pdb/pdb_caml_process.c
+++ b/tools/debugger/pdb/pdb_caml_process.c
@@ -96,17 +96,19 @@ process_handle_response (value ring)
memset(msg, 0, sizeof(msg));
rp = my_ring->sring->rsp_prod;
- rmb(); /* Ensure we see queued responses up to 'rp'. */
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+ /* default response is OK unless the command has something
+ more interesting to say */
sprintf(msg, "OK");
- /* for ( loop = my_ring->rsp_cons; loop != rp; loop++ ) */
if (my_ring->rsp_cons != rp)
{
resp = RING_GET_RESPONSE(my_ring, my_ring->rsp_cons);
switch (resp->operation)
{
+ case PDB_OPCODE_PAUSE :
case PDB_OPCODE_ATTACH :
case PDB_OPCODE_DETACH :
break;
@@ -123,21 +125,57 @@ process_handle_response (value ring)
break;
}
-
case PDB_OPCODE_WR_REG :
{
- printf("(linux) wr regs\n");
/* should check the return status */
break;
}
+
+ case PDB_OPCODE_RD_MEM :
+ {
+ int loop;
+ pdb_op_rd_mem_resp_p mem = &resp->u.rd_mem;
+
+ for (loop = 0; loop < mem->length; loop ++)
+ {
+ sprintf(&msg[loop * 2], "%02x", mem->data[loop]);
+ }
+ break;
+ }
+ case PDB_OPCODE_WR_MEM :
+ {
+ /* should check the return status */
+ break;
+ }
+
+ /* this is equivalent to process_xen_virq */
+ case PDB_OPCODE_CONTINUE :
+ {
+ sprintf(msg, "S05");
+ break;
+ }
+ case PDB_OPCODE_STEP :
+ {
+ sprintf(msg, "S05");
+ break;
+ }
+
+ case PDB_OPCODE_SET_BKPT :
+ {
+ break;
+ }
+ case PDB_OPCODE_CLR_BKPT :
+ {
+ break;
+ }
+
default :
- printf("(process) UNKNOWN MESSAGE TYPE IN RESPONSE\n");
+ printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE\n");
break;
}
my_ring->rsp_cons++;
}
- /* my_ring->rsp_cons = loop; */
msglen = strlen(msg);
result = caml_alloc(3,0);
@@ -164,7 +202,7 @@ proc_attach_debugger (value context)
decode_context(&ctx, context);
req.operation = PDB_OPCODE_ATTACH;
- req.domain = ctx.domain;
+ req.u.attach.domain = ctx.domain;
req.process = ctx.process;
send_request (ctx.ring, ctx.evtchn, &req);
@@ -190,7 +228,6 @@ proc_detach_debugger (value context)
fflush(stdout);
req.operation = PDB_OPCODE_DETACH;
- req.domain = ctx.domain;
req.process = ctx.process;
send_request (ctx.ring, ctx.evtchn, &req);
@@ -207,12 +244,18 @@ proc_pause_target (value context)
{
CAMLparam1(context);
context_t ctx;
+ pdb_request_t req;
decode_context(&ctx, context);
printf("(pdb) pause target %d %d\n", ctx.domain, ctx.process);
fflush(stdout);
+ req.operation = PDB_OPCODE_PAUSE;
+ req.process = ctx.process;
+
+ send_request (ctx.ring, ctx.evtchn, &req);
+
CAMLreturn(Val_unit);
}
@@ -231,7 +274,6 @@ proc_read_registers (value context)
decode_context(&ctx, context);
req.operation = PDB_OPCODE_RD_REGS;
- req.domain = ctx.domain;
req.process = ctx.process;
send_request (ctx.ring, ctx.evtchn, &req);
@@ -257,7 +299,6 @@ proc_write_register (value context, value reg, value newval)
decode_context(&ctx, context);
req.operation = PDB_OPCODE_WR_REG;
- req.domain = ctx.domain;
req.process = ctx.process;
req.u.wr_reg.value = my_newval;
@@ -291,65 +332,29 @@ proc_write_register (value context, value reg, value newval)
/*
- * proc_read_memory : context_t -> int32 -> int -> int
+ * proc_read_memory : context_t -> int32 -> int -> unit
*/
value
proc_read_memory (value context, value address, value length)
{
CAMLparam3(context, address, length);
- CAMLlocal2(result, temp);
context_t ctx;
- int loop;
- char *buffer;
- /* memory_t my_address = Int32_val(address); */
- u32 my_length = Int_val(length);
-
- printf ("(pdb) read memory\n");
+ pdb_request_t req;
decode_context(&ctx, context);
- buffer = malloc(my_length);
- if ( buffer == NULL )
- {
- printf("(pdb) read memory: malloc failed.\n"); fflush(stdout);
- failwith("read memory error");
- }
-
- /*
- if ( xendebug_read_memory(xc_handle, ctx.domain, ctx.vcpu,
- my_address, my_length, buffer) )
- {
- printf("(pdb) read memory error!\n"); fflush(stdout);
- failwith("read memory error");
- }
- */
-
- memset(buffer, 0xff, my_length);
-
- result = caml_alloc(2,0);
- if ( my_length > 0 ) /* car */
- {
- Store_field(result, 0, Val_int(buffer[my_length - 1] & 0xff));
- }
- else
-
- {
- Store_field(result, 0, Val_int(0));
- }
- Store_field(result, 1, Val_int(0)); /* cdr */
-
- for (loop = 1; loop < my_length; loop++)
- {
- temp = result;
- result = caml_alloc(2,0);
- Store_field(result, 0, Val_int(buffer[my_length - loop - 1] & 0xff));
- Store_field(result, 1, temp);
- }
+ req.operation = PDB_OPCODE_RD_MEM;
+ req.process = ctx.process;
+ req.u.rd_mem.address = Int32_val(address);
+ req.u.rd_mem.length = Int_val(length);
- CAMLreturn(result);
+ send_request(ctx.ring, ctx.evtchn, &req);
+
+ CAMLreturn(Val_unit);
}
+
/*
* proc_write_memory : context_t -> int32 -> int list -> unit
*/
@@ -360,52 +365,39 @@ proc_write_memory (value context, value address, value val_list)
CAMLlocal1(node);
context_t ctx;
-
- char buffer[4096]; /* a big buffer */
- memory_t my_address;
+ pdb_request_t req;
u32 length = 0;
- printf ("(pdb) write memory\n");
-
decode_context(&ctx, context);
+ req.operation = PDB_OPCODE_WR_MEM;
+ req.process = ctx.process;
+
node = val_list;
if ( Int_val(node) == 0 ) /* gdb functionalty test uses empty list */
{
- CAMLreturn(Val_unit);
+ req.u.wr_mem.address = Int32_val(address);
+ req.u.wr_mem.length = 0;
}
-
- while ( Int_val(Field(node,1)) != 0 )
- {
- buffer[length++] = Int_val(Field(node, 0));
- node = Field(node,1);
- }
- buffer[length++] = Int_val(Field(node, 0));
-
- my_address = (memory_t) Int32_val(address);
-
- /*
- if ( xendebug_write_memory(xc_handle, ctx.domain, ctx.vcpu,
- my_address, length, buffer) )
- {
- printf("(pdb) write memory error!\n"); fflush(stdout);
- failwith("write memory error");
- }
- */
+ else
{
- int loop;
- for (loop = 0; loop < length; loop++)
+ while ( Int_val(Field(node,1)) != 0 )
{
- printf (" %02x", buffer[loop]);
+ req.u.wr_mem.data[length++] = Int_val(Field(node, 0));
+ node = Field(node,1);
}
- printf ("\n");
+ req.u.wr_mem.data[length++] = Int_val(Field(node, 0));
+
+ req.u.wr_mem.address = Int32_val(address);
+ req.u.wr_mem.length = length;
}
-
+
+ send_request(ctx.ring, ctx.evtchn, &req);
+
CAMLreturn(Val_unit);
}
-
/*
* proc_continue_target : context_t -> unit
*/
@@ -415,17 +407,14 @@ proc_continue_target (value context)
CAMLparam1(context);
context_t ctx;
+ pdb_request_t req;
decode_context(&ctx, context);
- /*
- if ( xendebug_continue(xc_handle, ctx.domain, ctx.vcpu) )
- {
- printf("(pdb) continue\n"); fflush(stdout);
- failwith("continue");
- }
- */
- printf ("CONTINUE\n");
+ req.operation = PDB_OPCODE_CONTINUE;
+ req.process = ctx.process;
+
+ send_request(ctx.ring, ctx.evtchn, &req);
CAMLreturn(Val_unit);
}
@@ -439,17 +428,14 @@ proc_step_target (value context)
CAMLparam1(context);
context_t ctx;
+ pdb_request_t req;
decode_context(&ctx, context);
- /*
- if ( xendebug_step(xc_handle, ctx.domain, ctx.vcpu) )
- {
- printf("(pdb) step\n"); fflush(stdout);
- failwith("step");
- }
- */
- printf ("STEP\n");
+ req.operation = PDB_OPCODE_STEP;
+ req.process = ctx.process;
+
+ send_request(ctx.ring, ctx.evtchn, &req);
CAMLreturn(Val_unit);
}
@@ -465,22 +451,16 @@ proc_insert_memory_breakpoint (value context, value address, value length)
CAMLparam3(context, address, length);
context_t ctx;
- memory_t my_address = (memory_t) Int32_val(address);
- int my_length = Int_val(length);
+ pdb_request_t req;
decode_context(&ctx, context);
- printf ("(pdb) insert memory breakpoint 0x%lx %d\n",
- my_address, my_length);
+ req.operation = PDB_OPCODE_SET_BKPT;
+ req.process = ctx.process;
+ req.u.bkpt.address = (memory_t) Int32_val(address);
+ req.u.bkpt.length = Int_val(length);
- /*
- if ( xendebug_insert_memory_breakpoint(xc_handle, ctx.domain, ctx.vcpu,
- my_address, my_length) )
- {
- printf("(pdb) error: insert memory breakpoint\n"); fflush(stdout);
- failwith("insert memory breakpoint");
- }
- */
+ send_request(ctx.ring, ctx.evtchn, &req);
CAMLreturn(Val_unit);
}
@@ -494,24 +474,16 @@ proc_remove_memory_breakpoint (value context, value address, value length)
CAMLparam3(context, address, length);
context_t ctx;
-
- memory_t my_address = (memory_t) Int32_val(address);
- int my_length = Int_val(length);
-
- printf ("(pdb) remove memory breakpoint 0x%lx %d\n",
- my_address, my_length);
+ pdb_request_t req;
decode_context(&ctx, context);
- /*
- if ( xendebug_remove_memory_breakpoint(xc_handle,
- ctx.domain, ctx.vcpu,
- my_address, my_length) )
- {
- printf("(pdb) error: remove memory breakpoint\n"); fflush(stdout);
- failwith("remove memory breakpoint");
- }
- */
+ req.operation = PDB_OPCODE_CLR_BKPT;
+ req.process = ctx.process;
+ req.u.bkpt.address = (memory_t) Int32_val(address);
+ req.u.bkpt.length = Int_val(length);
+
+ send_request(ctx.ring, ctx.evtchn, &req);
CAMLreturn(Val_unit);
}
diff --git a/tools/debugger/pdb/pdb_caml_xcs.c b/tools/debugger/pdb/pdb_caml_xcs.c
index 84fba85abc..a1ba0808d2 100644
--- a/tools/debugger/pdb/pdb_caml_xcs.c
+++ b/tools/debugger/pdb/pdb_caml_xcs.c
@@ -201,7 +201,7 @@ xcs_connect (value path, value msg_type)
ret = connect(control_fd, (struct sockaddr *)&addr, len);
if (ret < 0)
{
- printf("error connecting to xcs(ctrl)! (%d)\n", errno);
+ printf("error connecting to xcs (ctrl)! (%d)\n", errno);
goto ctrl_fd_fail;
}
@@ -235,7 +235,7 @@ xcs_connect (value path, value msg_type)
ret = connect(data_fd, (struct sockaddr *)&addr, len);
if (ret < 0)
{
- printf("error connecting to xcs(data)! (%d)\n", errno);
+ printf("error connecting to xcs (data)! (%d)\n", errno);
goto data_fd_fail;
}
diff --git a/tools/debugger/pdb/readme b/tools/debugger/pdb/readme
index be1c44279e..9ed26be4a6 100644
--- a/tools/debugger/pdb/readme
+++ b/tools/debugger/pdb/readme
@@ -31,7 +31,7 @@ Installation
Build the target domains with debugging symbols.
make CONFIG_DEBUG_INFO=true CONFIG_FRAME_POINTER=false linux-2.6-xenU-build
- You can also change linux-2.6.11-xenU/Makefile
+ You can also change linux-2.6.12-xenU/Makefile
CONFIG_CC_OPTIMIZE_FOR_SIZE from -O2 to -O
- Build PDB
@@ -46,7 +46,7 @@ Usage
domain-0.xeno# ./pdb <port>
- Run GDB
- hostname% gdb <xeno.bk>/dist/install/boot/vmlinux-syms-2.6.11.11-xenU
+ hostname% gdb <xeno.bk>/dist/install/boot/vmlinux-syms-2.6.12-xenU
(gdb) target remote domain-0.xeno:<port>
@@ -76,9 +76,18 @@ Usage
continue
print
+Process
+
+ PDB can also debug a process running in a Linux 2.6 domain.
+ After running PDB in domain 0, insert the pdb module in dom u:
+
+ % insmod linux-2.6-module/pdb.ko
+
+ Load GDB with the appropriate symbols, and attach with
+
+ (gdb) maint packet x context = process <domid> <pid>
To Do
- watchpoints
- support for SMP
-- support for user applications