aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debugger/pdb/pdb_caml_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/debugger/pdb/pdb_caml_process.c')
-rw-r--r--tools/debugger/pdb/pdb_caml_process.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/tools/debugger/pdb/pdb_caml_process.c b/tools/debugger/pdb/pdb_caml_process.c
new file mode 100644
index 0000000000..e8506c7711
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_process.c
@@ -0,0 +1,543 @@
+/*
+ * pdb_caml_process.c
+ *
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ * PDB's OCaml interface library for debugging processes
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#include <xc.h>
+#include <xen/xen.h>
+#include <xen/io/domain_controller.h>
+#include <xen/linux/privcmd.h>
+#include "pdb_module.h"
+#include "pdb_caml_xen.h"
+
+/* this order comes from linux-2.6.11/include/asm-i386/ptrace.h */
+enum x86_registers { LINUX_EBX, LINUX_ECX, LINUX_EDX, LINUX_ESI, LINUX_EDI,
+ LINUX_EBP, LINUX_EAX, LINUX_DS, LINUX_ES, LINUX_FS,
+ LINUX_GS, LINUX_ORIG_EAX, LINUX_EIP, LINUX_CS, LINUX_EFL,
+ LINUX_ESP, LINUX_SS };
+#define FRAME_SIZE 17
+
+typedef struct
+{
+ int domain;
+ int process;
+ int evtchn;
+ pdb_front_ring_t *ring;
+} context_t;
+
+#define decode_context(_ctx, _ocaml) \
+{ \
+ (_ctx)->domain = Int_val(Field((_ocaml),0)); \
+ (_ctx)->process = Int_val(Field((_ocaml),1)); \
+ (_ctx)->evtchn = Int_val(Field((_ocaml),2)); \
+ (_ctx)->ring = (pdb_front_ring_t *)Int32_val(Field((_ocaml),3)); \
+}
+
+#define encode_context(_ctx, _ocaml) \
+{ \
+ (_ocaml) = caml_alloc_tuple(2); \
+ Store_field((_ocaml), 0, Val_int((_ctx)->domain)); \
+ Store_field((_ocaml), 1, Val_int((_ctx)->process)); \
+}
+
+/*
+ * send a request to a pdb domain backend.
+ *
+ * puts the request on a ring and kicks the backend using an event channel.
+ */
+static void
+send_request (pdb_front_ring_t *pdb_ring, int evtchn, pdb_request_t *request)
+{
+ pdb_request_t *req;
+
+ req = RING_GET_REQUEST(pdb_ring, pdb_ring->req_prod_pvt);
+
+ memcpy(req, request, sizeof(pdb_request_t));
+
+ pdb_ring->req_prod_pvt++;
+
+ RING_PUSH_REQUESTS(pdb_ring);
+ xc_evtchn_send(xc_handle, evtchn);
+}
+
+/*
+ * read a response from a pdb domain backend.
+ *
+ * grabs the response off a ring.
+ */
+static void
+read_response (pdb_front_ring_t *pdb_ring, pdb_response_p response)
+{
+ RING_IDX loop, rp;
+
+ rp = pdb_ring->sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for ( loop = pdb_ring->rsp_cons; loop != rp; loop++ )
+ {
+ pdb_response_p resp;
+
+ resp = RING_GET_RESPONSE(pdb_ring, loop);
+ memcpy(response, resp, sizeof(pdb_response_t));
+
+ /*
+ printf ("got response %x %x %x\n", response->operation,
+ response->status, response->value);
+ */
+ }
+ pdb_ring->rsp_cons = loop;
+}
+
+/*
+ * process_handle_response : int32 -> unit
+ */
+
+value
+process_handle_response (value ring)
+{
+ CAMLparam1(ring);
+
+ pdb_front_ring_t *my_ring = (pdb_front_ring_t *)Int32_val(ring);
+ pdb_response_t resp;
+
+ if ( my_ring )
+ read_response(my_ring, &resp);
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_attach_debugger : context_t -> unit
+ */
+value
+proc_attach_debugger (value context)
+{
+ CAMLparam1(context);
+ context_t ctx;
+ pdb_request_t req;
+ pdb_response_t resp;
+
+ decode_context(&ctx, context);
+
+ printf("(pdb) attach process [%d.%d] %d %p\n", ctx.domain, ctx.process,
+ ctx.evtchn, ctx.ring);
+ fflush(stdout);
+
+ req.operation = PDB_OPCODE_ATTACH;
+ req.domain = ctx.domain;
+ req.process = ctx.process;
+
+ send_request (ctx.ring, ctx.evtchn, &req);
+
+ printf("awaiting response\n");
+ fflush(stdout);
+
+ read_response (ctx.ring, &resp);
+
+ printf("response %d %d\n", resp.operation, resp.status);
+ fflush(stdout);
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * proc_detach_debugger : context_t -> unit
+ */
+value
+proc_detach_debugger (value context)
+{
+ CAMLparam1(context);
+ context_t ctx;
+ pdb_request_t req;
+
+ decode_context(&ctx, context);
+
+ printf("(pdb) detach process [%d.%d] %d %p\n", ctx.domain, ctx.process,
+ ctx.evtchn, ctx.ring);
+ fflush(stdout);
+
+ req.operation = PDB_OPCODE_DETACH;
+ req.domain = ctx.domain;
+ req.process = ctx.process;
+
+ send_request (ctx.ring, ctx.evtchn, &req);
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * proc_pause_target : int -> unit
+ */
+value
+proc_pause_target (value context)
+{
+ CAMLparam1(context);
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ printf("(pdb) pause target %d %d\n", ctx.domain, ctx.process);
+ fflush(stdout);
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * proc_read_registers : context_t -> int32
+ */
+value
+proc_read_registers (value context)
+{
+ CAMLparam1(context);
+ CAMLlocal1(result);
+
+ u32 regs[FRAME_SIZE];
+
+ pdb_request_t req;
+ context_t ctx;
+ int loop;
+
+ decode_context(&ctx, context);
+
+ req.operation = PDB_OPCODE_RD_REG;
+ req.domain = ctx.domain;
+ req.process = ctx.process;
+
+ for (loop = 0; loop < FRAME_SIZE; loop++)
+ {
+ pdb_response_t resp;
+
+ req.u.rd_reg.reg = loop;
+ send_request(ctx.ring, ctx.evtchn, &req);
+ read_response(ctx.ring, &resp);
+ regs[loop] = resp.value;
+ }
+
+ result = caml_alloc_tuple(16);
+
+ Store_field(result, 0, caml_copy_int32(regs[LINUX_EAX]));
+ Store_field(result, 1, caml_copy_int32(regs[LINUX_ECX]));
+ Store_field(result, 2, caml_copy_int32(regs[LINUX_EDX]));
+ Store_field(result, 3, caml_copy_int32(regs[LINUX_EBX]));
+ Store_field(result, 4, caml_copy_int32(regs[LINUX_ESP]));
+ Store_field(result, 5, caml_copy_int32(regs[LINUX_EBP]));
+ Store_field(result, 6, caml_copy_int32(regs[LINUX_ESI]));
+ Store_field(result, 7, caml_copy_int32(regs[LINUX_EDI]));
+ Store_field(result, 8, caml_copy_int32(regs[LINUX_EIP]));
+ Store_field(result, 9, caml_copy_int32(regs[LINUX_EFL]));
+ Store_field(result, 10, caml_copy_int32(regs[LINUX_CS])); /* 16 */
+ Store_field(result, 11, caml_copy_int32(regs[LINUX_SS])); /* 16 */
+ Store_field(result, 12, caml_copy_int32(regs[LINUX_DS])); /* 16 */
+ Store_field(result, 13, caml_copy_int32(regs[LINUX_ES])); /* 16 */
+ Store_field(result, 14, caml_copy_int32(regs[LINUX_FS])); /* 16 */
+ Store_field(result, 15, caml_copy_int32(regs[LINUX_GS])); /* 16 */
+
+ CAMLreturn(result);
+}
+
+
+/*
+ * proc_write_register : context_t -> register -> int32 -> unit
+ */
+value
+proc_write_register (value context, value reg, value newval)
+{
+ CAMLparam3(context, reg, newval);
+
+ int my_reg = Int_val(reg);
+ unsigned long my_newval = Int32_val(newval);
+
+ context_t ctx;
+ pdb_request_t req;
+ pdb_response_t resp;
+
+ 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;
+
+ switch (my_reg)
+ {
+ case GDB_EAX: req.u.wr_reg.reg = LINUX_EAX; break;
+ case GDB_ECX: req.u.wr_reg.reg = LINUX_ECX; break;
+ case GDB_EDX: req.u.wr_reg.reg = LINUX_EDX; break;
+ case GDB_EBX: req.u.wr_reg.reg = LINUX_EBX; break;
+
+ case GDB_ESP: req.u.wr_reg.reg = LINUX_ESP; break;
+ case GDB_EBP: req.u.wr_reg.reg = LINUX_EBP; break;
+ case GDB_ESI: req.u.wr_reg.reg = LINUX_ESI; break;
+ case GDB_EDI: req.u.wr_reg.reg = LINUX_EDI; break;
+
+ case GDB_EIP: req.u.wr_reg.reg = LINUX_EIP; break;
+ case GDB_EFL: req.u.wr_reg.reg = LINUX_EFL; break;
+
+ case GDB_CS: req.u.wr_reg.reg = LINUX_CS; break;
+ case GDB_SS: req.u.wr_reg.reg = LINUX_SS; break;
+ case GDB_DS: req.u.wr_reg.reg = LINUX_DS; break;
+ case GDB_ES: req.u.wr_reg.reg = LINUX_ES; break;
+ case GDB_FS: req.u.wr_reg.reg = LINUX_FS; break;
+ case GDB_GS: req.u.wr_reg.reg = LINUX_GS; break;
+ }
+
+ send_request(ctx.ring, ctx.evtchn, &req);
+ read_response(ctx.ring, &resp);
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * proc_read_memory : context_t -> int32 -> int -> int
+ */
+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");
+
+ 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);
+ }
+
+ CAMLreturn(result);
+}
+
+/*
+ * proc_write_memory : context_t -> int32 -> int list -> unit
+ */
+value
+proc_write_memory (value context, value address, value val_list)
+{
+ CAMLparam3(context, address, val_list);
+ CAMLlocal1(node);
+
+ context_t ctx;
+
+ char buffer[4096]; /* a big buffer */
+ memory_t my_address;
+ u32 length = 0;
+
+ printf ("(pdb) write memory\n");
+
+ decode_context(&ctx, context);
+
+ node = val_list;
+ if ( Int_val(node) == 0 ) /* gdb functionalty test uses empty list */
+ {
+ CAMLreturn(Val_unit);
+ }
+
+ 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");
+ }
+ */
+ {
+ int loop;
+ for (loop = 0; loop < length; loop++)
+ {
+ printf (" %02x", buffer[loop]);
+ }
+ printf ("\n");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+
+/*
+ * proc_continue_target : context_t -> unit
+ */
+value
+proc_continue_target (value context)
+{
+ CAMLparam1(context);
+
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ /*
+ if ( xendebug_continue(xc_handle, ctx.domain, ctx.vcpu) )
+ {
+ printf("(pdb) continue\n"); fflush(stdout);
+ failwith("continue");
+ }
+ */
+ printf ("CONTINUE\n");
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_step_target : context_t -> unit
+ */
+value
+proc_step_target (value context)
+{
+ CAMLparam1(context);
+
+ context_t ctx;
+
+ decode_context(&ctx, context);
+
+ /*
+ if ( xendebug_step(xc_handle, ctx.domain, ctx.vcpu) )
+ {
+ printf("(pdb) step\n"); fflush(stdout);
+ failwith("step");
+ }
+ */
+ printf ("STEP\n");
+
+ CAMLreturn(Val_unit);
+}
+
+
+
+/*
+ * proc_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+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);
+
+ decode_context(&ctx, context);
+
+ printf ("(pdb) insert memory breakpoint 0x%lx %d\n",
+ my_address, my_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");
+ }
+ */
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * proc_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+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);
+
+ 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");
+ }
+ */
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
+