aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-06-27 21:30:47 +0000
committerach61@arcadians.cl.cam.ac.uk <ach61@arcadians.cl.cam.ac.uk>2005-06-27 21:30:47 +0000
commit2136a8f965c54a89786a0ae5225686fcffd113b9 (patch)
tree2aefa9672cae7fa543dbef1d4f85cf826c584648
parentf53c8860229c31c0b544dc37df6a88ffa17cff71 (diff)
downloadxen-2136a8f965c54a89786a0ae5225686fcffd113b9.tar.gz
xen-2136a8f965c54a89786a0ae5225686fcffd113b9.tar.bz2
xen-2136a8f965c54a89786a0ae5225686fcffd113b9.zip
bitkeeper revision 1.1726.3.1 (42c07007i9Bkz3ggP_PXIksWaGD1Eg)
add framework for debugging processes
-rw-r--r--.rootkeys13
-rw-r--r--tools/debugger/pdb/Domain.ml29
-rw-r--r--tools/debugger/pdb/Intel.ml75
-rw-r--r--tools/debugger/pdb/Makefile24
-rw-r--r--tools/debugger/pdb/PDB.ml264
-rw-r--r--tools/debugger/pdb/Process.ml41
-rw-r--r--tools/debugger/pdb/Process.mli19
-rw-r--r--tools/debugger/pdb/Util.ml5
-rw-r--r--tools/debugger/pdb/Xen_domain.ml35
-rw-r--r--tools/debugger/pdb/Xen_domain.mli17
-rw-r--r--tools/debugger/pdb/debugger.ml57
-rw-r--r--tools/debugger/pdb/evtchn.ml12
-rw-r--r--tools/debugger/pdb/evtchn.mli5
-rw-r--r--tools/debugger/pdb/linux-2.6-module/Makefile18
-rw-r--r--tools/debugger/pdb/linux-2.6-module/debug.c169
-rw-r--r--tools/debugger/pdb/linux-2.6-module/module.c226
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_module.h65
-rw-r--r--tools/debugger/pdb/pdb_caml_domain.c485
-rw-r--r--tools/debugger/pdb/pdb_caml_evtchn.c178
-rw-r--r--tools/debugger/pdb/pdb_caml_process.c543
-rw-r--r--tools/debugger/pdb/pdb_caml_xc.c612
-rw-r--r--tools/debugger/pdb/pdb_caml_xcs.c305
-rw-r--r--tools/debugger/pdb/pdb_caml_xen.h18
-rw-r--r--tools/debugger/pdb/pdb_xen.c14
-rw-r--r--tools/debugger/pdb/server.ml56
-rw-r--r--tools/debugger/pdb/xcs.ml85
-rw-r--r--tools/debugger/pdb/xcs.mli5
-rw-r--r--xen/include/public/io/domain_controller.h14
28 files changed, 2589 insertions, 800 deletions
diff --git a/.rootkeys b/.rootkeys
index 514a54af3d..2ca8f7ba23 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -538,13 +538,26 @@
42a0c8danHHGiNywdeer6j4jzxAc2A tools/debugger/pdb/Process.ml
42a0c8dav_08OtySI4kYP1lahlVrpQ tools/debugger/pdb/Process.mli
42a0c8da51EqubQT5PJ4sxCKLF3xSw tools/debugger/pdb/Util.ml
+42c06ff2SIoOLsDHH2ZyWKnYzA4Mkw tools/debugger/pdb/Xen_domain.ml
+42c06ff2OXdWXeLK8YWeIIiHk3N6Xw tools/debugger/pdb/Xen_domain.mli
42a0c8daxftpiXuvLmc9fOOEhdFWiQ tools/debugger/pdb/debugger.ml
42a0c8da81tzhpvIAfkx9nZqUNrQvg tools/debugger/pdb/evtchn.ml
42a0c8dasiso9c-2sCvHBzP6YVjATA tools/debugger/pdb/evtchn.mli
+42c06ff2FXdouy4s5_DM6rUgaeJrOA tools/debugger/pdb/linux-2.6-module/Makefile
+42c06ff27x60l_XDMTZRnv688McFfg tools/debugger/pdb/linux-2.6-module/debug.c
+42c06ff2crmxKZFQw7KCkQlLnJh2TQ tools/debugger/pdb/linux-2.6-module/module.c
+42c06ff2tC-1f7KRAGcEGrxjSao60g tools/debugger/pdb/linux-2.6-module/pdb_module.h
+42c06ff2n2Ib0UeptbyAYZoF9-gFMQ tools/debugger/pdb/pdb_caml_domain.c
+42c06ff2jKvaB6JHP-B_AR8f-7KeVQ tools/debugger/pdb/pdb_caml_evtchn.c
+42c06ff3XPemRQRAfNIEV2qw2o6IUw tools/debugger/pdb/pdb_caml_process.c
42a0c8daXD_6Y62A_u5-PO_Klrhi0w tools/debugger/pdb/pdb_caml_xc.c
+42c06ff3joi_6rE-l4jh76qYUihAZA tools/debugger/pdb/pdb_caml_xcs.c
+42c06ff3zUNt7tOZ-AgTTWcy9pirvg tools/debugger/pdb/pdb_caml_xen.h
42a0c8danJXun9ay5SPBhhkKvuUPfg tools/debugger/pdb/pdb_xen.c
42b03d06llc_GE7fXGQ6-rYR4VFAcw tools/debugger/pdb/readme
42a0c8dbjK6Du89D2SUcxsuAdlUu3w tools/debugger/pdb/server.ml
+42c06ff3v6Ks9EscwR6L0OTqdZn5kA tools/debugger/pdb/xcs.ml
+42c06ff3j-5U79rRFb4bGqx1Ajhw4Q tools/debugger/pdb/xcs.mli
401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile
401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
41597996VhTbNuHbuscYSfRb-WR6fA tools/examples/block-enbd
diff --git a/tools/debugger/pdb/Domain.ml b/tools/debugger/pdb/Domain.ml
index 700699a958..2701a12ce0 100644
--- a/tools/debugger/pdb/Domain.ml
+++ b/tools/debugger/pdb/Domain.ml
@@ -21,13 +21,10 @@ let default_context = { domain = 0; execution_domain = 0 }
let new_context dom exec_dom = {domain = dom; execution_domain = exec_dom}
let set_domain ctx value =
- ctx.domain <- value;
- print_endline (Printf.sprintf "ctx.domain <- %d" ctx.domain)
+ ctx.domain <- value
let set_execution_domain ctx value =
- ctx.execution_domain <- value;
- print_endline (Printf.sprintf "ctx.execution_domain <- %d"
- ctx.execution_domain)
+ ctx.execution_domain <- value
let get_domain ctx =
ctx.domain
@@ -39,25 +36,25 @@ let string_of_context ctx =
Printf.sprintf "{domain} domain: %d, execution_domain: %d"
ctx.domain ctx.execution_domain
-external read_registers : context_t -> registers = "read_registers"
+external read_registers : context_t -> registers = "dom_read_registers"
external write_register : context_t -> register -> int32 -> unit =
- "write_register"
+ "dom_write_register"
external read_memory : context_t -> int32 -> int -> int list =
- "read_memory"
+ "dom_read_memory"
external write_memory : context_t -> int32 -> int list -> unit =
- "write_memory"
+ "dom_write_memory"
-external continue : context_t -> unit = "continue_target"
-external step : context_t -> unit = "step_target"
+external continue : context_t -> unit = "dom_continue_target"
+external step : context_t -> unit = "dom_step_target"
external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
- "insert_memory_breakpoint"
+ "dom_insert_memory_breakpoint"
external remove_memory_breakpoint : context_t -> int32 -> int -> unit =
- "remove_memory_breakpoint"
+ "dom_remove_memory_breakpoint"
-external attach_debugger : int -> int -> unit = "attach_debugger"
-external detach_debugger : int -> int -> unit = "detach_debugger"
-external pause_target : int -> unit = "pause_target"
+external attach_debugger : int -> int -> unit = "dom_attach_debugger"
+external detach_debugger : int -> int -> unit = "dom_detach_debugger"
+external pause_target : int -> unit = "dom_pause_target"
let pause ctx =
pause_target ctx.domain
diff --git a/tools/debugger/pdb/Intel.ml b/tools/debugger/pdb/Intel.ml
index d82ef8b527..42c493ada0 100644
--- a/tools/debugger/pdb/Intel.ml
+++ b/tools/debugger/pdb/Intel.ml
@@ -9,63 +9,58 @@
type register =
- | EBX
+ | EAX
| ECX
| EDX
+ | EBX
+ | ESP
+ | EBP
| ESI
| EDI
- | EBP
- | EAX
- | Error_code
- | Entry_vector
| EIP
+ | EFL
| CS
- | EFLAGS
- | ESP
| SS
- | ES
| DS
+ | ES
| FS
| GS
type registers =
- { ebx : int32;
+ { eax : int32;
ecx : int32;
edx : int32;
+ ebx : int32;
+ esp : int32;
+ ebp : int32;
esi : int32;
edi : int32;
- ebp : int32;
- eax : int32;
- error_code : int32;
- entry_vector : int32;
eip : int32;
- cs : int32;
- eflags : int32;
- esp : int32;
- ss : int32;
- es : int32;
- ds : int32;
- fs : int32;
- gs : int32
+ efl : int32;
+ cs : int32;
+ ss : int32;
+ ds : int32;
+ es : int32;
+ fs : int32;
+ gs : int32
}
let null_registers =
- { ebx = 0l;
- ecx = 0l;
- edx = 0l;
- esi = 0l;
- edi = 0l;
- ebp = 0l;
- eax = 0l;
- error_code = 0l;
- entry_vector = 0l;
- eip = 0l;
- cs = 0l;
- eflags = 0l;
- esp = 0l;
- ss = 0l;
- es = 0l;
- ds = 0l;
- fs = 0l;
- gs = 0l
- }
+ { eax = 0l;
+ ecx = 0l;
+ edx = 0l;
+ ebx = 0l;
+ esp = 0l;
+ ebp = 0l;
+ esi = 0l;
+ edi = 0l;
+ eip = 0l;
+ efl = 0l;
+ cs = 0l;
+ ss = 0l;
+ ds = 0l;
+ es = 0l;
+ fs = 0l;
+ gs = 0l
+ }
+
diff --git a/tools/debugger/pdb/Makefile b/tools/debugger/pdb/Makefile
index 579c7da12c..12ec4be453 100644
--- a/tools/debugger/pdb/Makefile
+++ b/tools/debugger/pdb/Makefile
@@ -7,10 +7,8 @@ include $(XEN_ROOT)/tools/Rules.mk
# otherwise, ocamlmktop gets confused.
LDFLAGS =
-OCAML_ROOT=/usr/local
# force ocaml 3.08
-# OCAML_ROOT = /anfs/nos1/ach61/ocaml
-
+OCAML_ROOT = /usr/local
OCAMLC = $(OCAML_ROOT)/bin/ocamlc
OCAMLMKTOP = $(OCAML_ROOT)/bin/ocamlmktop
OCAMLLIBPATH= $(OCAML_ROOT)/lib/ocaml
@@ -18,6 +16,7 @@ OCAMLLIBPATH= $(OCAML_ROOT)/lib/ocaml
INCLUDES += -I $(XEN_XC)
INCLUDES += -I $(XEN_LIBXC)
INCLUDES += -I ../libxendebug
+INCLUDES += -I ./linux-2.6-module
INCLUDES += -I $(OCAML_ROOT)/lib/ocaml
CFLAGS += $(INCLUDES)
@@ -27,29 +26,26 @@ CFLAGS += -g
CLIBS += xc
CLIBS += xendebug
-CLIBS += pdb
LIBDIRS += $(XEN_LIBXC)
-LIBDIRS += $(XEN_LIBXUTIL)
LIBDIRS += ../libxendebug
-LIBDIRS += .
LIBS += unix str
-PRE_TARGETS = libpdb.a
-
-all : bc
+# bc = byte-code, dc = debug byte-code
+all : dc
-libpdb.a : pdb_xen.o
- ar rc $@ $^
- ranlib $@
-
-SOURCES += pdb_caml_xc.c pdb_xen.c
+SOURCES += pdb_caml_xc.c
+SOURCES += pdb_caml_domain.c pdb_caml_process.c
+SOURCES += pdb_caml_evtchn.c pdb_caml_xcs.c pdb_xen.c
SOURCES += Util.ml Intel.ml
SOURCES += evtchn.ml evtchn.mli
+SOURCES += xcs.ml xcs.mli
+SOURCES += Xen_domain.ml Xen_domain.mli
SOURCES += Domain.ml Process.ml
SOURCES += Domain.mli Process.mli
SOURCES += PDB.ml debugger.ml server.ml
+
RESULT = pdb
include $(OCAMLMAKEFILE)
diff --git a/tools/debugger/pdb/PDB.ml b/tools/debugger/pdb/PDB.ml
index 0ed121b7aa..12ee1f00d8 100644
--- a/tools/debugger/pdb/PDB.ml
+++ b/tools/debugger/pdb/PDB.ml
@@ -13,92 +13,105 @@ exception Unknown_domain
type context_t =
| Void
- | Event_channel
+ | Xen_virq
+ | Xen_xcs
+ | Xen_domain of Xen_domain.context_t
| Domain of Domain.context_t
| Process of Process.context_t
let string_of_context ctx =
match ctx with
| Void -> "{void}"
- | Event_channel -> "{event channel}"
+ | Xen_virq -> "{Xen virq evtchn}"
+ | Xen_xcs -> "{Xen xcs socket}"
+ | Xen_domain d -> Xen_domain.string_of_context d
| Domain d -> Domain.string_of_context d
| Process p -> Process.string_of_context p
+let hash = Hashtbl.create 10
-let read_registers ctx =
- match ctx with
- | Domain d -> Domain.read_registers d
- | _ -> Intel.null_registers
-
-let write_register ctx register value =
- match ctx with
- | Domain d -> Domain.write_register d register value
- | _ -> raise (Unimplemented "write register")
-
-
-let read_memory ctx addr len =
- match ctx with
- | Domain d -> Domain.read_memory d addr len
- | _ -> raise (Unimplemented "read memory")
-
-let write_memory ctx addr values =
- match ctx with
- | Domain d -> Domain.write_memory d addr values
- | _ -> raise (Unimplemented "write memory")
+(***************************************************************************)
-let continue ctx =
- match ctx with
- | Domain d -> Domain.continue d
- | _ -> raise (Unimplemented "continue")
-
-let step ctx =
- match ctx with
- | Domain d -> Domain.step d
- | _ -> raise (Unimplemented "step")
-
+let find_context key =
+ try
+ Hashtbl.find hash key
+ with
+ Not_found ->
+ print_endline "error: (find_context) PDB context not found";
+ raise Not_found
-let insert_memory_breakpoint ctx addr len =
- match ctx with
- | Domain d -> Domain.insert_memory_breakpoint d addr len
- | _ -> raise (Unimplemented "insert memory breakpoint")
+let delete_context key =
+ Hashtbl.remove hash key
-let remove_memory_breakpoint ctx addr len =
- match ctx with
- | Domain d -> Domain.remove_memory_breakpoint d addr len
- | _ -> raise (Unimplemented "remove memory breakpoint")
+(**
+ find_domain : Locate the socket associated with the context(s)
+ matching a particular (domain, vcpu) pair. if there are multiple
+ contexts (there shouldn't be), then return the first one.
+ *)
+let find_domain dom vcpu =
+ let find key ctx list =
+ match ctx with
+ | Domain d ->
+ if (((Domain.get_domain d) = dom) &&
+ ((Domain.get_execution_domain d) = vcpu))
+ then
+ key :: list
+ else
+ list
+ | _ -> list
+ in
+ let sock_list = Hashtbl.fold find hash [] in
+ match sock_list with
+ | hd::tl -> hd
+ | [] -> raise Unknown_domain
-let pause ctx =
- match ctx with
- | Domain d -> Domain.pause d
- | _ -> raise (Unimplemented "pause target")
+(**
+ find_xen_domain_context : fetch the socket associated with the
+ xen_domain context for a domain. if there are multiple contexts
+ (there shouldn't be), then return the first one.
+ *)
+let find_xen_domain_context domain =
+ let find key ctx list =
+ match ctx with
+ | Xen_domain d ->
+ if ((Xen_domain.get_domain d) = domain)
+ then
+ key :: list
+ else
+ list
+ | _ -> list
+ in
+ let sock_list = Hashtbl.fold find hash [] in
+ match sock_list with
+ | hd::tl -> hd
+ | [] -> raise Unknown_domain
let attach_debugger ctx =
match ctx with
| Domain d -> Domain.attach_debugger (Domain.get_domain d)
(Domain.get_execution_domain d)
+ | Process p ->
+ begin
+ let xdom_sock = find_xen_domain_context (Process.get_domain p) in
+ let xdom_ctx = find_context xdom_sock in
+ match xdom_ctx with
+ | Xen_domain d ->
+ Process.attach_debugger p d
+ | _ -> failwith ("context has wrong xen domain type")
+ end
| _ -> raise (Unimplemented "attach debugger")
let detach_debugger ctx =
match ctx with
| Domain d -> Domain.detach_debugger (Domain.get_domain d)
(Domain.get_execution_domain d)
+ | Process p -> Process.detach_debugger p
| _ -> raise (Unimplemented "detach debugger")
-external open_debugger : unit -> unit = "open_context"
-external close_debugger : unit -> unit = "close_context"
-
-(* this is just the domains right now... expand to other contexts later *)
-external debugger_status : unit -> unit = "debugger_status"
-
-
-(***********************************************************)
-
-
-let hash = Hashtbl.create 10
let debug_contexts () =
print_endline "context list:";
@@ -106,14 +119,19 @@ let debug_contexts () =
match ctx with
| Void -> print_endline (Printf.sprintf " [%s] {void}"
(Util.get_connection_info key))
- | Event_channel -> print_endline (Printf.sprintf " [%s] {event_channel}"
- (Util.get_connection_info key))
+ | Xen_virq -> print_endline (Printf.sprintf " [%s] {xen virq evtchn}"
+ (Util.get_connection_info key))
+ | Xen_xcs -> print_endline (Printf.sprintf " [%s] {xen xcs socket}"
+ (Util.get_connection_info key))
+ | Xen_domain d -> print_endline (Printf.sprintf " [%s] %s"
+ (Util.get_connection_info key)
+ (Xen_domain.string_of_context d))
+ | Domain d -> print_endline (Printf.sprintf " [%s] %s"
+ (Util.get_connection_info key)
+ (Domain.string_of_context d))
| Process p -> print_endline (Printf.sprintf " [%s] %s"
- (Util.get_connection_info key)
- (Process.string_of_context p))
- | Domain d -> print_endline (Printf.sprintf " [%s] %s"
- (Util.get_connection_info key)
- (Domain.string_of_context d))
+ (Util.get_connection_info key)
+ (Process.string_of_context p))
in
Hashtbl.iter print_context hash
@@ -123,13 +141,14 @@ let debug_contexts () =
*)
let add_context (key:Unix.file_descr) context params =
match context with
- | "void" -> Hashtbl.replace hash key Void
- | "event channel" -> Hashtbl.replace hash key Event_channel
+ | "void" -> Hashtbl.replace hash key Void
+ | "xen virq" -> Hashtbl.replace hash key Xen_virq
+ | "xen xcs" -> Hashtbl.replace hash key Xen_xcs
| "domain" ->
begin
match params with
- | dom::exec_dom::_ ->
- let d = Domain(Domain.new_context dom exec_dom) in
+ | dom::vcpu::_ ->
+ let d = Domain(Domain.new_context dom vcpu) in
attach_debugger d;
Hashtbl.replace hash key d
| _ -> failwith "bogus parameters to domain context"
@@ -138,43 +157,96 @@ let add_context (key:Unix.file_descr) context params =
begin
match params with
| dom::pid::_ ->
- let p = Process.new_context dom pid in
- Hashtbl.replace hash key (Process(p))
+ let p = Process(Process.new_context dom pid) in
+ attach_debugger p;
+ Hashtbl.replace hash key p
| _ -> failwith "bogus parameters to process context"
end
+ | "xen domain"
| _ -> raise (Unknown_context context)
+(*
+ * this is really bogus. add_xen_domain_context should really
+ * be a case within add_context. however, we need to pass in
+ * a pointer that can only be represented as an int32.
+ * this would require a different type for params... :(
+ * 31 bit integers suck.
+ *)
+let add_xen_domain_context (key:Unix.file_descr) dom evtchn sring =
+ let d = Xen_domain.new_context dom evtchn sring in
+ Hashtbl.replace hash key (Xen_domain(d))
+
+
let add_default_context sock =
add_context sock "void" []
-let find_context key =
- try
- Hashtbl.find hash key
- with
- Not_found ->
- print_endline "error: (find_context) PDB context not found";
- raise Not_found
+(***************************************************************************)
-let delete_context key =
- Hashtbl.remove hash key
+(***************************************************************************)
-(** find_domain : Locate the context(s) matching a particular domain
- * and execution_domain pair.
- *)
+let read_registers ctx =
+ match ctx with
+ | Void -> Intel.null_registers (* default for startup *)
+ | Domain d -> Domain.read_registers d
+ | Process p -> Process.read_registers p
+ | _ -> raise (Unimplemented "read registers")
+
+let write_register ctx register value =
+ match ctx with
+ | Domain d -> Domain.write_register d register value
+ | Process p -> Process.write_register p register value
+ | _ -> raise (Unimplemented "write register")
+
+
+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
+ | _ -> 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
+ | _ -> raise (Unimplemented "write memory")
+
+
+let continue ctx =
+ match ctx with
+ | Domain d -> Domain.continue d
+ | Process p -> Process.continue p
+ | _ -> raise (Unimplemented "continue")
+
+let step ctx =
+ match ctx with
+ | Domain d -> Domain.step d
+ | Process p -> Process.step p
+ | _ -> raise (Unimplemented "step")
+
+
+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
+ | _ -> 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
+ | _ -> raise (Unimplemented "remove memory breakpoint")
+
+
+let pause ctx =
+ match ctx with
+ | Domain d -> Domain.pause d
+ | Process p -> Process.pause p
+ | _ -> raise (Unimplemented "pause target")
+
+
+external open_debugger : unit -> unit = "open_context"
+external close_debugger : unit -> unit = "close_context"
+
+(* this is just the domains right now... expand to other contexts later *)
+external debugger_status : unit -> unit = "debugger_status"
-let find_domain dom exec_dom =
- let find key ctx list =
- match ctx with
- | Domain d ->
- if (((Domain.get_domain d) = dom) &&
- ((Domain.get_execution_domain d) = exec_dom))
- then
- key :: list
- else
- list
- | _ -> list
- in
- let sock_list = Hashtbl.fold find hash [] in
- match sock_list with
- | hd::tl -> hd
- | [] -> raise Unknown_domain
diff --git a/tools/debugger/pdb/Process.ml b/tools/debugger/pdb/Process.ml
index 79632b3298..943d816b24 100644
--- a/tools/debugger/pdb/Process.ml
+++ b/tools/debugger/pdb/Process.ml
@@ -12,13 +12,16 @@ open Intel
type context_t =
{
- mutable domain : int;
+ mutable domain : int;
mutable process : int;
+ mutable evtchn : int;
+ mutable ring : int32;
}
-let default_context = { domain = 0; process = 0 }
+let default_context = { domain = 0; process = 0; evtchn = 0; ring = 0l }
-let new_context dom proc = { domain = dom; process = proc }
+let new_context dom proc = { domain = dom; process = proc;
+ evtchn = 0; ring = 0l }
let string_of_context ctx =
Printf.sprintf "{process} domain: %d, process: %d"
@@ -37,3 +40,35 @@ let get_domain ctx =
let get_process ctx =
ctx.process
+
+external _attach_debugger : context_t -> unit = "proc_attach_debugger"
+external detach_debugger : context_t -> unit = "proc_detach_debugger"
+external pause_target : context_t -> unit = "proc_pause_target"
+
+(* save the event channel and ring for the domain for future use *)
+let attach_debugger proc_ctx dom_ctx =
+ print_endline (Printf.sprintf "%d %lx"
+ (Xen_domain.get_evtchn dom_ctx)
+ (Xen_domain.get_ring dom_ctx));
+ proc_ctx.evtchn <- Xen_domain.get_evtchn dom_ctx;
+ proc_ctx.ring <- Xen_domain.get_ring dom_ctx;
+ _attach_debugger proc_ctx
+
+external read_registers : context_t -> registers = "proc_read_registers"
+external write_register : context_t -> register -> int32 -> unit =
+ "proc_write_register"
+external read_memory : context_t -> int32 -> int -> int list =
+ "proc_read_memory"
+external write_memory : context_t -> int32 -> int list -> unit =
+ "proc_write_memory"
+
+external continue : context_t -> unit = "proc_continue_target"
+external step : context_t -> unit = "proc_step_target"
+
+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"
+
+let pause ctx =
+ pause_target ctx
diff --git a/tools/debugger/pdb/Process.mli b/tools/debugger/pdb/Process.mli
index 39b6221892..a32a814c70 100644
--- a/tools/debugger/pdb/Process.mli
+++ b/tools/debugger/pdb/Process.mli
@@ -7,6 +7,9 @@
* @version 1
*)
+open Int32
+open Intel
+
type context_t
val default_context : context_t
@@ -18,3 +21,19 @@ val set_process : context_t -> int -> unit
val get_process : context_t -> int
val string_of_context : context_t -> string
+
+val attach_debugger : context_t -> Xen_domain.context_t -> unit
+val detach_debugger : context_t -> unit
+val pause : context_t -> unit
+
+
+val read_registers : context_t -> registers
+val write_register : context_t -> register -> int32 -> unit
+val read_memory : context_t -> int32 -> int -> int list
+val write_memory : context_t -> int32 -> int list -> unit
+
+val continue : context_t -> unit
+val step : context_t -> unit
+
+val insert_memory_breakpoint : context_t -> int32 -> int -> unit
+val remove_memory_breakpoint : context_t -> int32 -> int -> unit
diff --git a/tools/debugger/pdb/Util.ml b/tools/debugger/pdb/Util.ml
index a5722242db..f723630646 100644
--- a/tools/debugger/pdb/Util.ml
+++ b/tools/debugger/pdb/Util.ml
@@ -103,7 +103,7 @@ let get_connection_info fd =
let get_local_info fd =
let sockname = Unix.getsockname fd in
match sockname with
- | Unix.ADDR_UNIX(s) -> s
+ | Unix.ADDR_UNIX(s) -> "unix"
| Unix.ADDR_INET(a,p) -> ((Unix.string_of_inet_addr a) ^ ":" ^
(string_of_int p))
and get_remote_info fd =
@@ -119,6 +119,9 @@ let get_connection_info fd =
| Unix.Unix_error (Unix.ENOTSOCK, s1, s2) ->
let s = Unix.fstat fd in
Printf.sprintf "dev: %d, inode: %d" s.Unix.st_dev s.Unix.st_ino
+ | Unix.Unix_error (Unix.EBADF, s1, s2) ->
+ let s = Unix.fstat fd in
+ Printf.sprintf "dev: %d, inode: %d" s.Unix.st_dev s.Unix.st_ino
| _ -> get_local_info fd
diff --git a/tools/debugger/pdb/Xen_domain.ml b/tools/debugger/pdb/Xen_domain.ml
new file mode 100644
index 0000000000..d014466448
--- /dev/null
+++ b/tools/debugger/pdb/Xen_domain.ml
@@ -0,0 +1,35 @@
+
+type context_t =
+{
+ mutable domain : int;
+ mutable evtchn : int;
+ mutable pdb_front_ring : int32
+}
+
+let default_context = { domain = 0; evtchn = 0; pdb_front_ring = 0l }
+
+let new_context dom evtchn ring =
+ {domain = dom; evtchn = evtchn; pdb_front_ring = ring}
+
+let set_domain ctx value =
+ ctx.domain <- value
+
+let set_evtchn ctx value =
+ ctx.evtchn <- value
+
+let set_ring ctx value =
+ ctx.pdb_front_ring <- value
+
+let get_domain ctx =
+ ctx.domain
+
+let get_evtchn ctx =
+ ctx.evtchn
+
+let get_ring ctx =
+ ctx.pdb_front_ring
+
+let string_of_context ctx =
+ Printf.sprintf "{xen domain assist} domain: %d" ctx.domain
+
+external process_response : int32 -> unit = "process_handle_response"
diff --git a/tools/debugger/pdb/Xen_domain.mli b/tools/debugger/pdb/Xen_domain.mli
new file mode 100644
index 0000000000..f99df1fd66
--- /dev/null
+++ b/tools/debugger/pdb/Xen_domain.mli
@@ -0,0 +1,17 @@
+
+type context_t
+
+val default_context : context_t
+val new_context : int -> int -> int32 -> context_t
+
+val set_domain : context_t -> int -> unit
+val get_domain : context_t -> int
+val set_evtchn : context_t -> int -> unit
+val get_evtchn : context_t -> int
+val set_ring : context_t -> int32 -> unit
+val get_ring : context_t -> int32
+
+val string_of_context : context_t -> string
+
+val process_response : int32 -> unit
+
diff --git a/tools/debugger/pdb/debugger.ml b/tools/debugger/pdb/debugger.ml
index 5a3002470b..3dd2159c57 100644
--- a/tools/debugger/pdb/debugger.ml
+++ b/tools/debugger/pdb/debugger.ml
@@ -77,7 +77,7 @@ let gdb_read_registers ctx =
(Printf.sprintf "%08lx" (Util.flip_int32 regs.esi)) ^
(Printf.sprintf "%08lx" (Util.flip_int32 regs.edi)) ^
(Printf.sprintf "%08lx" (Util.flip_int32 regs.eip)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.eflags)) ^
+ (Printf.sprintf "%08lx" (Util.flip_int32 regs.efl)) ^
(Printf.sprintf "%08lx" (Util.flip_int32 regs.cs)) ^
(Printf.sprintf "%08lx" (Util.flip_int32 regs.ss)) ^
(Printf.sprintf "%08lx" (Util.flip_int32 regs.ds)) ^
@@ -140,7 +140,7 @@ let gdb_write_register ctx command =
| 6 -> PDB.write_register ctx ESI new_val
| 7 -> PDB.write_register ctx EDI new_val
| 8 -> PDB.write_register ctx EIP new_val
- | 9 -> PDB.write_register ctx EFLAGS new_val
+ | 9 -> PDB.write_register ctx EFL new_val
| 10 -> PDB.write_register ctx CS new_val
| 11 -> PDB.write_register ctx SS new_val
| 12 -> PDB.write_register ctx DS new_val
@@ -195,13 +195,15 @@ let gdb_last_signal =
*)
let pdb_extensions command sock =
let process_extension key value =
- (* since this command can change the context, we need to grab it each time *)
+ (* since this command can change the context,
+ we need to grab it again each time *)
let ctx = PDB.find_context sock in
match key with
| "status" ->
- print_endline (string_of_context ctx);
PDB.debug_contexts ();
- debugger_status ()
+ (* print_endline ("debugger status");
+ debugger_status ()
+ *)
| "context" ->
PDB.add_context sock (List.hd value)
(int_list_of_string_list (List.tl value))
@@ -216,6 +218,7 @@ let pdb_extensions command sock =
| Unknown_context s ->
print_endline (Printf.sprintf "unknown context [%s]" s);
"E01"
+ | Unknown_domain -> "E01"
| Failure s -> "E01"
@@ -274,27 +277,47 @@ 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]"
command s);
- ""
+ "E03"
+(**
+ process_xen_domain
+
+ This is called whenever a domain debug assist responds to a
+ pdb packet.
+*)
+
+let process_xen_domain fd =
+ let channel = Evtchn.read fd in
+ let ctx = find_context fd in
+
+ begin
+ match ctx with
+ | Xen_domain d -> Xen_domain.process_response (Xen_domain.get_ring d)
+ | _ -> failwith ("process_xen_domain called without Xen_domain context")
+ end;
+
+ Evtchn.unmask fd channel (* allow next virq *)
+
(**
- process_evtchn
+ process_xen_virq
This is called each time a virq_pdb is sent from xen to dom 0.
It is sent by Xen when a domain hits a breakpoint.
- Think of this as the continuation function for a "c" or "s" command.
+ Think of this as the continuation function for a "c" or "s" command
+ issued to a domain.
*)
external query_domain_stop : unit -> (int * int) list = "query_domain_stop"
(* returns a list of paused domains : () -> (domain, vcpu) list *)
-let process_evtchn fd =
+let process_xen_virq fd =
let channel = Evtchn.read fd in
let find_pair (dom, vcpu) =
print_endline (Printf.sprintf "checking %d.%d" dom vcpu);
@@ -313,3 +336,17 @@ let process_evtchn fd =
Util.send_reply sock "S05";
Evtchn.unmask fd channel (* allow next virq *)
+
+(**
+ process_xen_xcs
+
+ This is called each time the software assist residing in a backend
+ domain starts up. The control message includes the address of a
+ shared ring page and our end of an event channel (which indicates
+ when data is available on the ring).
+*)
+
+let process_xen_xcs xcs_fd =
+ let (local_evtchn_fd, evtchn, dom, ring) = Xcs.read xcs_fd in
+ add_xen_domain_context local_evtchn_fd dom evtchn ring;
+ local_evtchn_fd
diff --git a/tools/debugger/pdb/evtchn.ml b/tools/debugger/pdb/evtchn.ml
index 5443accd9b..9cf441573a 100644
--- a/tools/debugger/pdb/evtchn.ml
+++ b/tools/debugger/pdb/evtchn.ml
@@ -14,6 +14,7 @@ let dev_minor = 201 (* EVTCHN_DEV_MINOR *)
let virq_pdb = 6 (* as defined VIRQ_PDB *)
external bind_virq : int -> int = "evtchn_bind_virq"
+external bind_interdomain : int -> int * int = "evtchn_bind_interdomain"
external bind : Unix.file_descr -> int -> unit = "evtchn_bind"
external unbind : Unix.file_descr -> int -> unit = "evtchn_unbind"
external ec_open : string -> int -> int -> Unix.file_descr = "evtchn_open"
@@ -21,10 +22,17 @@ external read : Unix.file_descr -> int = "evtchn_read"
external ec_close : Unix.file_descr -> unit = "evtchn_close"
external unmask : Unix.file_descr -> int -> unit = "evtchn_unmask"
+let _setup () =
+ let fd = ec_open dev_name dev_major dev_minor in
+ fd
+
+let _bind fd port =
+ bind fd port
+
let setup () =
let port = bind_virq virq_pdb in
- let fd = ec_open dev_name dev_major dev_minor in
- bind fd port;
+ let fd = _setup() in
+ _bind fd port;
fd
let teardown fd =
diff --git a/tools/debugger/pdb/evtchn.mli b/tools/debugger/pdb/evtchn.mli
index 18b3ed667b..3f9560f72c 100644
--- a/tools/debugger/pdb/evtchn.mli
+++ b/tools/debugger/pdb/evtchn.mli
@@ -7,6 +7,11 @@
* @version 1
*)
+val _setup : unit -> Unix.file_descr
+val _bind : Unix.file_descr -> int -> unit
+
+val bind_interdomain : int -> int * int
+
val setup : unit -> Unix.file_descr
val read : Unix.file_descr -> int
diff --git a/tools/debugger/pdb/linux-2.6-module/Makefile b/tools/debugger/pdb/linux-2.6-module/Makefile
new file mode 100644
index 0000000000..025afc1d75
--- /dev/null
+++ b/tools/debugger/pdb/linux-2.6-module/Makefile
@@ -0,0 +1,18 @@
+XEN_ROOT=/anfs/nos1/ach61/bk
+KDIR=$(XEN_ROOT)/linux-2.6.11-xenU
+
+obj-m += pdb.o
+pdb-objs += module.o
+pdb-objs += debug.o
+
+CFLAGS += -g
+CFLAGS += -Wall
+CFLAGS += -Werror
+
+module :
+# make KBUILD_VERBOSE=1 ARCH=xen -C $(KDIR) M=$(PWD) modules
+ make ARCH=xen -C $(KDIR) M=$(PWD) modules
+
+clean :
+ make -C $(KDIR) M=$(PWD) clean
+
diff --git a/tools/debugger/pdb/linux-2.6-module/debug.c b/tools/debugger/pdb/linux-2.6-module/debug.c
new file mode 100644
index 0000000000..744be03b73
--- /dev/null
+++ b/tools/debugger/pdb/linux-2.6-module/debug.c
@@ -0,0 +1,169 @@
+/*
+ * debug.c
+ * pdb debug functionality for processes.
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm-xen/asm-i386/ptrace.h>
+#include <asm-xen/xen-public/xen.h>
+
+#include "pdb_module.h"
+
+EXPORT_SYMBOL(pdb_attach);
+EXPORT_SYMBOL(pdb_detach);
+
+int
+pdb_attach (int pid)
+{
+ 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)
+{
+ 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);
+
+ return rc;
+}
+
+/*
+ * from linux-2.6.11/arch/i386/kernel/ptrace.c::getreg()
+ */
+int
+pdb_read_register (int pid, pdb_op_rd_reg_p op, unsigned long *dest)
+{
+ int rc = 0;
+ struct task_struct *target;
+ unsigned long offset;
+ unsigned char *stack = 0L;
+
+ *dest = ~0UL;
+
+ read_lock(&tasklist_lock);
+ target = find_task_by_pid(pid);
+ if (target)
+ get_task_struct(target);
+ read_unlock(&tasklist_lock);
+
+ switch (op->reg)
+ {
+ case FS:
+ *dest = target->thread.fs;
+ break;
+ case GS:
+ *dest = target->thread.gs;
+ break;
+ case DS:
+ case ES:
+ case SS:
+ case CS:
+ *dest = 0xffff;
+ /* fall through */
+ default:
+ 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;
+ *dest &= *((int *)stack);
+ }
+
+ /*
+ printk ("pdb read register: 0x%x %2d 0x%p 0x%lx\n",
+ pid, op->reg, stack, *dest);
+ */
+
+ 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)
+{
+ 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);
+ */
+
+ read_lock(&tasklist_lock);
+ target = find_task_by_pid(pid);
+ if (target)
+ get_task_struct(target);
+ read_unlock(&tasklist_lock);
+
+ switch (op->reg)
+ {
+ 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;
+ }
+
+ 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;
+
+ return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/linux-2.6-module/module.c b/tools/debugger/pdb/linux-2.6-module/module.c
new file mode 100644
index 0000000000..25273d321f
--- /dev/null
+++ b/tools/debugger/pdb/linux-2.6-module/module.c
@@ -0,0 +1,226 @@
+
+/*
+ * module.c
+ *
+ * Handles initial registration with pdb when the pdb module starts up
+ * and cleanup when the module goes away (sortof :)
+ * Also receives each request from pdb in domain 0 and dispatches to the
+ * appropriate debugger function.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <asm-xen/evtchn.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/xen-public/io/domain_controller.h>
+#include <asm-xen/xen-public/xen.h>
+
+#include <asm-xen/xen-public/io/ring.h>
+
+#include "pdb_module.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;
+
+/*
+ * send response to a pdb request
+ */
+static void
+pdb_send_response (pdb_response_t *response)
+{
+ pdb_response_t *resp;
+
+ resp = RING_GET_RESPONSE(&pdb_ring, pdb_ring.rsp_prod_pvt);
+
+ memcpy(resp, response, sizeof(pdb_response_t));
+
+ wmb(); /* Ensure other side can see the response fields. */
+ pdb_ring.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(&pdb_ring);
+ notify_via_evtchn(pdb_evtchn);
+ return;
+}
+
+/*
+ * handle a debug command from the front end
+ */
+static void
+pdb_process_request (pdb_request_t *request)
+{
+ pdb_response_t resp;
+
+ switch (request->operation)
+ {
+ case PDB_OPCODE_ATTACH :
+ pdb_attach(request->process);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ case PDB_OPCODE_DETACH :
+ pdb_detach(request->process);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ case PDB_OPCODE_RD_REG :
+ pdb_read_register(request->process, &request->u.rd_reg,
+ (unsigned long *)&resp.value);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ case PDB_OPCODE_WR_REG :
+ pdb_write_register(request->process, &request->u.wr_reg);
+ resp.status = PDB_RESPONSE_OKAY;
+ break;
+ default:
+ printk("(pdb) unknown request operation %d\n", request->operation);
+ resp.status = PDB_RESPONSE_ERROR;
+ }
+
+ resp.operation = request->operation;
+
+ pdb_send_response (&resp);
+ return;
+}
+
+/*
+ * receive a pdb request
+ */
+static irqreturn_t
+pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
+{
+ pdb_request_t *req;
+ RING_IDX i, rp;
+
+ rp = pdb_ring.sring->req_prod;
+ rmb();
+
+ for ( i = pdb_ring.req_cons;
+ (i != rp) && !RING_REQUEST_CONS_OVERFLOW(&pdb_ring, i);
+ i++ )
+ {
+ req = RING_GET_REQUEST(&pdb_ring, i);
+ pdb_process_request(req);
+
+ }
+ pdb_ring.req_cons = i;
+
+ return IRQ_HANDLED;
+}
+
+
+static void
+pdb_send_connection_status(int status, memory_t ring)
+{
+ ctrl_msg_t cmsg =
+ {
+ .type = CMSG_DEBUG,
+ .subtype = CMSG_DEBUG_CONNECTION_STATUS,
+ .length = sizeof(pdb_connection_t),
+ };
+ pdb_connection_t *conn = (pdb_connection_t *)cmsg.msg;
+
+ conn->status = status;
+ conn->ring = ring;
+ conn->evtchn = 0;
+
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+
+/*
+ * this is called each time a message is received on the control channel
+ */
+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:
+ /* initialize event channel created by the pdb server */
+
+ pdb_evtchn = ((pdb_connection_p) msg->msg)->evtchn;
+ pdb_irq = bind_evtchn_to_irq(pdb_evtchn);
+
+ if ( request_irq(pdb_irq, pdb_interrupt,
+ SA_SAMPLE_RANDOM, "pdb", NULL) )
+ {
+ printk("(pdb) request irq failed: %d %d\n", pdb_evtchn, pdb_irq);
+ }
+ break;
+
+ default:
+ printk ("(pdb) unknown xcs control message: %d\n", msg->subtype);
+ break;
+ }
+
+ return;
+}
+
+static int __init
+pdb_initialize(void)
+{
+ pdb_sring_t *sring;
+
+ printk("----\npdb initialize %s %s\n", __DATE__, __TIME__);
+
+ /*
+ if ( xen_start_info.flags & SIF_INITDOMAIN )
+ return 1;
+ */
+
+ (void)ctrl_if_register_receiver(CMSG_DEBUG, pdb_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* rings */
+ sring = (pdb_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(sring);
+ BACK_RING_INIT(&pdb_ring, sring, PAGE_SIZE);
+
+ /* notify pdb in dom 0 */
+ pdb_send_connection_status(PDB_CONNECTION_STATUS_UP,
+ virt_to_machine(pdb_ring.sring) >> PAGE_SHIFT);
+
+ return 0;
+}
+
+static void __exit
+pdb_terminate(void)
+{
+ printk("pdb cleanup\n");
+
+ (void)ctrl_if_unregister_receiver(CMSG_DEBUG, pdb_ctrlif_rx);
+
+ if (pdb_irq)
+ {
+ free_irq(pdb_irq, NULL);
+ pdb_irq = 0;
+ }
+
+ if (pdb_evtchn)
+ {
+ unbind_evtchn_from_irq(pdb_evtchn);
+ pdb_evtchn = 0;
+ }
+
+ pdb_send_connection_status(PDB_CONNECTION_STATUS_DOWN, 0);
+}
+
+
+module_init(pdb_initialize);
+module_exit(pdb_terminate);
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/linux-2.6-module/pdb_module.h b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
new file mode 100644
index 0000000000..4487e3e196
--- /dev/null
+++ b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
@@ -0,0 +1,65 @@
+
+#ifndef __XEN_PDB_H_
+#define __XEN_PDB_H_
+
+#define PDB_OPCODE_ATTACH 1
+#define PDB_OPCODE_DETACH 2
+
+#define PDB_OPCODE_RD_REG 3
+typedef struct pdb_op_rd_reg
+{
+ u32 reg;
+} pdb_op_rd_reg_t, *pdb_op_rd_reg_p;
+
+#define PDB_OPCODE_WR_REG 4
+typedef struct pdb_op_wr_reg
+{
+ u32 reg;
+ u32 value;
+} pdb_op_wr_reg_t, *pdb_op_wr_reg_p;
+
+typedef struct
+{
+ u8 operation; /* PDB_OPCODE_??? */
+ u32 domain;
+ u32 process;
+ union
+ {
+ pdb_op_rd_reg_t rd_reg;
+ pdb_op_wr_reg_t wr_reg;
+ } u;
+} PACKED pdb_request_t, *pdb_request_p;
+
+
+#define PDB_RESPONSE_OKAY 0
+#define PDB_RESPONSE_ERROR -1
+
+typedef struct {
+ u8 operation; /* copied from request */
+ s16 status; /* PDB_RESPONSE_??? */
+ u32 value;
+} PACKED 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_reg_p op, unsigned long *dest);
+int pdb_write_register (int pid, pdb_op_wr_reg_p op);
+
+
+#endif
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/pdb_caml_domain.c b/tools/debugger/pdb/pdb_caml_domain.c
new file mode 100644
index 0000000000..b54db73ca1
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_domain.c
@@ -0,0 +1,485 @@
+/*
+ * pdb_caml_xc.c
+ *
+ * http://www.cl.cam.ac.uk/netos/pdb
+ *
+ * PDB's OCaml interface library for debugging domains
+ */
+
+#include <xc.h>
+#include <xendebug.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#include "pdb_caml_xen.h"
+
+/* this order comes from xen/include/public/arch-x86_32.h */
+enum x86_registers { PDB_EBX, PDB_ECX, PDB_EDX, PDB_ESI, PDB_EDI,
+ PDB_EBP, PDB_EAX, PDB_Error_code, PDB_Entry_vector,
+ PDB_EIP, PDB_CS, PDB_EFLAGS, PDB_ESP, PDB_SS,
+ PDB_ES, PDB_DS, PDB_FS, PDB_GS };
+
+typedef struct
+{
+ int domain;
+ int vcpu;
+} context_t;
+
+#define decode_context(_ctx, _ocaml) \
+{ \
+ (_ctx)->domain = Int_val(Field((_ocaml),0)); \
+ (_ctx)->vcpu = Int_val(Field((_ocaml),1)); \
+}
+
+#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)->vcpu)); \
+}
+
+
+/****************************************************************************/
+
+/*
+ * dom_read_registers : context_t -> int32
+ */
+value
+dom_read_registers (value context)
+{
+ CAMLparam1(context);
+ CAMLlocal1(result);
+
+ 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);
+
+ Store_field(result, 0, caml_copy_int32(regs->eax));
+ Store_field(result, 1, caml_copy_int32(regs->ecx));
+ Store_field(result, 2, caml_copy_int32(regs->edx));
+ Store_field(result, 3, caml_copy_int32(regs->ebx));
+ Store_field(result, 4, caml_copy_int32(regs->esp));
+ Store_field(result, 5, caml_copy_int32(regs->ebp));
+ Store_field(result, 6, caml_copy_int32(regs->esi));
+ Store_field(result, 7, caml_copy_int32(regs->edi));
+ Store_field(result, 8, caml_copy_int32(regs->eip));
+ Store_field(result, 9, caml_copy_int32(regs->eflags));
+ Store_field(result, 10, caml_copy_int32(regs->cs)); /* 16 */
+ Store_field(result, 11, caml_copy_int32(regs->ss)); /* 16 */
+ Store_field(result, 12, caml_copy_int32(regs->ds)); /* 16 */
+ Store_field(result, 13, caml_copy_int32(regs->es)); /* 16 */
+ Store_field(result, 14, caml_copy_int32(regs->fs)); /* 16 */
+ Store_field(result, 15, caml_copy_int32(regs->gs)); /* 16 */
+
+ CAMLreturn(result);
+}
+
+
+/*
+ * dom_write_register : context_t -> register -> int32 -> unit
+ */
+value
+dom_write_register (value context, value reg, value newval)
+{
+ CAMLparam3(context, reg, newval);
+
+ int my_reg = Int_val(reg);
+ int val = Int32_val(newval);
+
+ context_t ctx;
+ cpu_user_regs_t *regs;
+
+ printf("(pdb) write register\n");
+
+ decode_context(&ctx, context);
+
+ if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
+ {
+ printf("(pdb) write register (get) error!\n"); fflush(stdout);
+ failwith("write register error");
+ }
+
+ switch (my_reg)
+ {
+ case PDB_EBX: regs->ebx = val; break;
+ case PDB_ECX: regs->ecx = val; break;
+ case PDB_EDX: regs->edx = val; break;
+ case PDB_ESI: regs->esi = val; break;
+ case PDB_EDI: regs->edi = val; break;
+
+ case PDB_EBP: regs->ebp = val; break;
+ case PDB_EAX: regs->eax = val; break;
+ case PDB_Error_code: regs->error_code = val; break;
+ case PDB_Entry_vector: regs->entry_vector = val; break;
+
+ case PDB_EIP: regs->eip = val; break;
+ case PDB_CS: regs->cs = val; break;
+ case PDB_EFLAGS: regs->eflags = val; break;
+ case PDB_ESP: regs->esp = val; break;
+ case PDB_SS: regs->ss = val; break;
+ case PDB_ES: regs->es = val; break;
+ case PDB_DS: regs->ds = val; break;
+ case PDB_FS: regs->fs = val; break;
+ case PDB_GS: regs->gs = val; break;
+ }
+
+ if ( xendebug_write_registers(xc_handle, ctx.domain, ctx.vcpu, regs) )
+ {
+ printf("(pdb) write register (set) error!\n"); fflush(stdout);
+ failwith("write register error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * dom_read_memory : context_t -> int32 -> int -> int
+ */
+value
+dom_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");
+ }
+
+ 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);
+}
+
+/*
+ * dom_write_memory : context_t -> int32 -> int list -> unit
+ */
+value
+dom_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");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * dom_continue_target : context_t -> unit
+ */
+value
+dom_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");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * dom_step_target : context_t -> unit
+ */
+value
+dom_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");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+
+/*
+ * dom_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+dom_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);
+}
+
+/*
+ * dom_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
+ */
+value
+dom_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);
+}
+
+/*
+ * dom_attach_debugger : int -> int -> unit
+ */
+value
+dom_attach_debugger (value domain, value vcpu)
+{
+ CAMLparam2(domain, vcpu);
+
+ int my_domain = Int_val(domain);
+ int my_vcpu = Int_val(vcpu);
+
+ printf ("(pdb) attach domain [%d.%d]\n", my_domain, my_vcpu);
+
+ if ( xendebug_attach(xc_handle, my_domain, my_vcpu) )
+ {
+ printf("(pdb) attach error!\n"); fflush(stdout);
+ failwith("attach error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * dom_detach_debugger : int -> int -> unit
+ */
+value
+dom_detach_debugger (value domain, value vcpu)
+{
+ CAMLparam2(domain, vcpu);
+
+ int my_domain = Int_val(domain);
+ int my_vcpu = Int_val(vcpu);
+
+ printf ("(pdb) detach domain [%d.%d]\n", my_domain, my_vcpu);
+
+ if ( xendebug_detach(xc_handle, my_domain, my_vcpu) )
+ {
+ printf("(pdb) detach error!\n"); fflush(stdout);
+ failwith("detach error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * dom_pause_target : int -> unit
+ */
+value
+dom_pause_target (value domid)
+{
+ CAMLparam1(domid);
+
+ int my_domid = Int_val(domid);
+
+ printf ("(pdb) pause target %d\n", my_domid);
+
+ xc_domain_pause(xc_handle, my_domid);
+
+ CAMLreturn(Val_unit);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+/*
+ * query_domain_stop : unit -> (int * int) list
+ */
+value
+query_domain_stop (value unit)
+{
+ CAMLparam1(unit);
+ CAMLlocal3(result, temp, node);
+
+ int max_domains = 20;
+ int dom_list[max_domains];
+ int loop, count;
+
+ count = xendebug_query_domain_stop(xc_handle, dom_list, max_domains);
+ if ( count < 0 )
+ {
+ printf("(pdb) query domain stop!\n"); fflush(stdout);
+ failwith("query domain stop");
+ }
+
+ printf ("QDS: %d\n", count);
+ for (loop = 0; loop < count; loop ++)
+ printf (" %d %d\n", loop, dom_list[loop]);
+
+ result = caml_alloc(2,0);
+ if ( count > 0 ) /* car */
+ {
+ node = caml_alloc(2,0);
+ Store_field(node, 0, Val_int(dom_list[0])); /* domain id */
+ Store_field(node, 1, Val_int(0)); /* vcpu */
+ Store_field(result, 0, node);
+ }
+ else
+ {
+ Store_field(result, 0, Val_int(0));
+ }
+ Store_field(result, 1, Val_int(0)); /* cdr */
+
+ for ( loop = 1; loop < count; loop++ )
+ {
+ temp = result;
+ result = caml_alloc(2,0);
+ node = caml_alloc(2,0);
+ Store_field(node, 0, Val_int(dom_list[loop])); /* domain id */
+ Store_field(node, 1, Val_int(0)); /* vcpu */
+ Store_field(result, 0, node);
+ Store_field(result, 1, temp);
+ }
+
+ CAMLreturn(result);
+}
+
+/****************************************************************************/
+
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/pdb_caml_evtchn.c b/tools/debugger/pdb/pdb_caml_evtchn.c
new file mode 100644
index 0000000000..62707739ca
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_evtchn.c
@@ -0,0 +1,178 @@
+#include <xc.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 <errno.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int xen_evtchn_bind (int evtchn_fd, int idx);
+int xen_evtchn_unbind (int evtchn_fd, int idx);
+
+int
+__evtchn_open (char *filename, int major, int minor)
+{
+ int evtchn_fd;
+ struct stat st;
+
+ /* Make sure any existing device file links to correct device. */
+ if ( (lstat(filename, &st) != 0) ||
+ !S_ISCHR(st.st_mode) ||
+ (st.st_rdev != makedev(major, minor)) )
+ {
+ (void)unlink(filename);
+ }
+
+ reopen:
+ evtchn_fd = open(filename, O_RDWR);
+ if ( evtchn_fd == -1 )
+ {
+ if ( (errno == ENOENT) &&
+ ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
+ (mknod(filename, S_IFCHR|0600, makedev(major,minor)) == 0) )
+ {
+ goto reopen;
+ }
+ return -errno;
+ }
+
+ return evtchn_fd;
+}
+
+/*
+ * evtchn_open : string -> int -> int -> Unix.file_descr
+ *
+ * OCaml's Unix library doesn't have mknod, so it makes more sense just write
+ * this in C. This code is from Keir/Andy.
+ */
+value
+evtchn_open (value filename, value major, value minor)
+{
+ CAMLparam3(filename, major, minor);
+
+ char *myfilename = String_val(filename);
+ int mymajor = Int_val(major);
+ int myminor = Int_val(minor);
+ int evtchn_fd;
+
+ evtchn_fd = __evtchn_open(myfilename, mymajor, myminor);
+
+ CAMLreturn(Val_int(evtchn_fd));
+}
+
+/*
+ * evtchn_bind : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_bind (value fd, value idx)
+{
+ CAMLparam2(fd, idx);
+
+ int myfd = Int_val(fd);
+ int myidx = Int_val(idx);
+
+ if ( xen_evtchn_bind(myfd, myidx) < 0 )
+ {
+ printf("(pdb) evtchn_bind error!\n"); fflush(stdout);
+ failwith("evtchn_bind error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_unbind : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_unbind (value fd, value idx)
+{
+ CAMLparam2(fd, idx);
+
+ int myfd = Int_val(fd);
+ int myidx = Int_val(idx);
+
+ if ( xen_evtchn_unbind(myfd, myidx) < 0 )
+ {
+ printf("(pdb) evtchn_unbind error!\n"); fflush(stdout);
+ failwith("evtchn_unbind error");
+ }
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_read : Unix.file_descr -> int
+ */
+value
+evtchn_read (value fd)
+{
+ CAMLparam1(fd);
+
+ u16 v;
+ int bytes;
+ int rc = -1;
+ int myfd = Int_val(fd);
+
+ while ( (bytes = read(myfd, &v, sizeof(v))) == -1 )
+ {
+ if ( errno == EINTR ) continue;
+ rc = -errno;
+ goto exit;
+ }
+
+ if ( bytes == sizeof(v) )
+ rc = v;
+
+ exit:
+ CAMLreturn(Val_int(rc));
+}
+
+
+/*
+ * evtchn_close : Unix.file_descr -> unit
+ */
+value
+evtchn_close (value fd)
+{
+ CAMLparam1(fd);
+ int myfd = Int_val(fd);
+
+ (void)close(myfd);
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * evtchn_unmask : Unix.file_descr -> int -> unit
+ */
+value
+evtchn_unmask (value fd, value idx)
+{
+ CAMLparam1(fd);
+
+ int myfd = Int_val(fd);
+ u16 myidx = Int_val(idx);
+
+ (void)write(myfd, &myidx, sizeof(myidx));
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
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:
+ */
+
+
diff --git a/tools/debugger/pdb/pdb_caml_xc.c b/tools/debugger/pdb/pdb_caml_xc.c
index 6ba82a92c2..7507d98808 100644
--- a/tools/debugger/pdb/pdb_caml_xc.c
+++ b/tools/debugger/pdb/pdb_caml_xc.c
@@ -3,7 +3,7 @@
*
* http://www.cl.cam.ac.uk/netos/pdb
*
- * OCaml to libxc interface library for PDB
+ * PDB's OCaml interface library for debugging domains
*/
#include <xc.h>
@@ -18,38 +18,9 @@
#include <caml/memory.h>
#include <caml/mlvalues.h>
-int pdb_evtchn_bind_virq (int xc_handle, int virq, int *port);
-int xen_evtchn_bind (int evtchn_fd, int idx);
-int xen_evtchn_unbind (int evtchn_fd, int idx);
+#include "pdb_caml_xen.h"
-/* this order comes from xen/include/public/arch-x86_32.h */
-enum x86_registers { PDB_EBX, PDB_ECX, PDB_EDX, PDB_ESI, PDB_EDI,
- PDB_EBP, PDB_EAX, PDB_Error_code, PDB_Entry_vector,
- PDB_EIP, PDB_CS, PDB_EFLAGS, PDB_ESP, PDB_SS,
- PDB_ES, PDB_DS, PDB_FS, PDB_GS };
-
-static void dump_regs (cpu_user_regs_t *ctx);
-
-static int xc_handle = -1;
-
-typedef struct
-{
- int domain;
- int vcpu;
-} context_t;
-
-#define decode_context(_ctx, _ocaml) \
-{ \
- (_ctx)->domain = Int_val(Field((_ocaml),0)); \
- (_ctx)->vcpu = Int_val(Field((_ocaml),1)); \
-}
-
-#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)->vcpu)); \
-}
+int xc_handle = -1;
/****************************************************************************/
@@ -91,210 +62,6 @@ close_context (value unit)
CAMLreturn(Val_unit);
}
-/*
- * read_registers : context_t -> int32
- */
-value
-read_registers (value context)
-{
- CAMLparam1(context);
- CAMLlocal1(result);
-
- 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(18); /* FIXME */
-
- Store_field(result, 0, caml_copy_int32(regs->ebx));
- Store_field(result, 1, caml_copy_int32(regs->ecx));
- Store_field(result, 2, caml_copy_int32(regs->edx));
- Store_field(result, 3, caml_copy_int32(regs->esi));
- Store_field(result, 4, caml_copy_int32(regs->edi));
- Store_field(result, 5, caml_copy_int32(regs->ebp));
- Store_field(result, 6, caml_copy_int32(regs->eax));
- Store_field(result, 7, caml_copy_int32(regs->error_code)); /* 16 */
- Store_field(result, 8, caml_copy_int32(regs->entry_vector)); /* 16 */
- Store_field(result, 9, caml_copy_int32(regs->eip));
- Store_field(result, 10, caml_copy_int32(regs->cs)); /* 16 */
- Store_field(result, 11, caml_copy_int32(regs->eflags));
- Store_field(result, 12, caml_copy_int32(regs->esp));
- Store_field(result, 13, caml_copy_int32(regs->ss)); /* 16 */
- Store_field(result, 14, caml_copy_int32(regs->es)); /* 16 */
- Store_field(result, 15, caml_copy_int32(regs->ds)); /* 16 */
- Store_field(result, 16, caml_copy_int32(regs->fs)); /* 16 */
- Store_field(result, 17, caml_copy_int32(regs->gs)); /* 16 */
-
- CAMLreturn(result);
-}
-
-
-/*
- * write_register : context_t -> register -> int32 -> unit
- */
-value
-write_register (value context, value reg, value newval)
-{
- CAMLparam3(context, reg, newval);
-
- int my_reg = Int_val(reg);
- int val = Int32_val(newval);
-
- context_t ctx;
- cpu_user_regs_t *regs;
-
- printf("(pdb) write register\n");
-
- decode_context(&ctx, context);
-
- if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
- {
- printf("(pdb) write register (get) error!\n"); fflush(stdout);
- failwith("write register error");
- }
-
- switch (my_reg)
- {
- case PDB_EBX: regs->ebx = val; break;
- case PDB_ECX: regs->ecx = val; break;
- case PDB_EDX: regs->edx = val; break;
- case PDB_ESI: regs->esi = val; break;
- case PDB_EDI: regs->edi = val; break;
-
- case PDB_EBP: regs->ebp = val; break;
- case PDB_EAX: regs->eax = val; break;
- case PDB_Error_code: regs->error_code = val; break;
- case PDB_Entry_vector: regs->entry_vector = val; break;
-
- case PDB_EIP: regs->eip = val; break;
- case PDB_CS: regs->cs = val; break;
- case PDB_EFLAGS: regs->eflags = val; break;
- case PDB_ESP: regs->esp = val; break;
- case PDB_SS: regs->ss = val; break;
- case PDB_ES: regs->es = val; break;
- case PDB_DS: regs->ds = val; break;
- case PDB_FS: regs->fs = val; break;
- case PDB_GS: regs->gs = val; break;
- }
-
- if ( xendebug_write_registers(xc_handle, ctx.domain, ctx.vcpu, regs) )
- {
- printf("(pdb) write register (set) error!\n"); fflush(stdout);
- failwith("write register error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * read_memory : context_t -> int32 -> int -> int
- */
-value
-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");
- }
-
- 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);
-}
-
-/*
- * write_memory : context_t -> int32 -> int list -> unit
- */
-value
-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");
- }
-
- CAMLreturn(Val_unit);
-}
-
/*********************************************************************/
@@ -322,153 +89,6 @@ dump_regs (cpu_user_regs_t *regs)
}
/*
- * continue_target : context_t -> unit
- */
-value
-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");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * step_target : context_t -> unit
- */
-value
-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");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-
-/*
- * insert_memory_breakpoint : context_t -> int32 -> int list -> unit
- */
-value
-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);
-}
-
-/*
- * remove_memory_breakpoint : context_t -> int32 -> int list -> unit
- */
-value
-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);
-}
-
-/*
- * attach_debugger : int -> int -> unit
- */
-value
-attach_debugger (value domain, value vcpu)
-{
- CAMLparam2(domain, vcpu);
-
- int my_domain = Int_val(domain);
- int my_vcpu = Int_val(vcpu);
-
- printf ("(pdb) attach domain [%d.%d]\n", my_domain, my_vcpu);
-
- if ( xendebug_attach(xc_handle, my_domain, my_vcpu) )
- {
- printf("(pdb) attach error!\n"); fflush(stdout);
- failwith("attach error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * detach_debugger : int -> int -> unit
- */
-value
-detach_debugger (value domain, value vcpu)
-{
- CAMLparam2(domain, vcpu);
-
- int my_domain = Int_val(domain);
- int my_vcpu = Int_val(vcpu);
-
- printf ("(pdb) detach domain [%d.%d]\n", my_domain, my_vcpu);
-
- if ( xendebug_detach(xc_handle, my_domain, my_vcpu) )
- {
- printf("(pdb) detach error!\n"); fflush(stdout);
- failwith("detach error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
* debugger_status : unit -> unit
*/
value
@@ -476,25 +96,6 @@ debugger_status (value unit)
{
CAMLparam1(unit);
- printf ("(pdb) debugger status\n");
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * pause_target : int -> unit
- */
-value
-pause_target (value domid)
-{
- CAMLparam1(domid);
-
- int my_domid = Int_val(domid);
-
- printf ("(pdb) pause target %d\n", my_domid);
-
- xc_domain_pause(xc_handle, my_domid);
-
CAMLreturn(Val_unit);
}
@@ -502,108 +103,6 @@ pause_target (value domid)
/****************************************************************************/
/*
- * query_domain_stop : unit -> (int * int) list
- */
-value
-query_domain_stop (value unit)
-{
- CAMLparam1(unit);
- CAMLlocal3(result, temp, node);
-
- int max_domains = 20;
- int dom_list[max_domains];
- int loop, count;
-
- count = xendebug_query_domain_stop(xc_handle, dom_list, max_domains);
- if ( count < 0 )
- {
- printf("(pdb) query domain stop!\n"); fflush(stdout);
- failwith("query domain stop");
- }
-
- printf ("QDS: %d\n", count);
- for (loop = 0; loop < count; loop ++)
- printf (" %d %d\n", loop, dom_list[loop]);
-
- result = caml_alloc(2,0);
- if ( count > 0 ) /* car */
- {
- node = caml_alloc(2,0);
- Store_field(node, 0, Val_int(dom_list[0])); /* domain id */
- Store_field(node, 1, Val_int(0)); /* vcpu */
- Store_field(result, 0, node);
- }
- else
- {
- Store_field(result, 0, Val_int(0));
- }
- Store_field(result, 1, Val_int(0)); /* cdr */
-
- for ( loop = 1; loop < count; loop++ )
- {
- temp = result;
- result = caml_alloc(2,0);
- node = caml_alloc(2,0);
- Store_field(node, 0, Val_int(dom_list[loop])); /* domain id */
- Store_field(node, 1, Val_int(0)); /* vcpu */
- Store_field(result, 0, node);
- Store_field(result, 1, temp);
- }
-
- CAMLreturn(result);
-}
-
-/****************************************************************************/
-/****************************************************************************/
-
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-/*
- * evtchn_open : string -> int -> int -> Unix.file_descr
- *
- * OCaml's Unix library doesn't have mknod, so it makes more sense just write
- * this in C. This code is from Keir/Andy.
- */
-value
-evtchn_open (value filename, value major, value minor)
-{
- CAMLparam3(filename, major, minor);
-
- char *myfilename = String_val(filename);
- int mymajor = Int_val(major);
- int myminor = Int_val(minor);
- int evtchn_fd;
- struct stat st;
-
- /* Make sure any existing device file links to correct device. */
- if ( (lstat(myfilename, &st) != 0) ||
- !S_ISCHR(st.st_mode) ||
- (st.st_rdev != makedev(mymajor, myminor)) )
- {
- (void)unlink(myfilename);
- }
-
- reopen:
- evtchn_fd = open(myfilename, O_RDWR);
- if ( evtchn_fd == -1 )
- {
- if ( (errno == ENOENT) &&
- ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
- (mknod(myfilename, S_IFCHR|0600, makedev(mymajor,myminor)) == 0) )
- {
- goto reopen;
- }
- return -errno;
- }
-
- CAMLreturn(Val_int(evtchn_fd));
-}
-
-/*
* evtchn_bind_virq : int -> int
*/
value
@@ -612,8 +111,9 @@ evtchn_bind_virq (value virq)
CAMLparam1(virq);
int port;
+ int my_virq = Int_val(virq);
- if ( pdb_evtchn_bind_virq(xc_handle, Int_val(virq), &port) < 0 )
+ if ( xc_evtchn_bind_virq(xc_handle, my_virq, &port) < 0 )
{
printf("(pdb) evtchn_bind_virq error!\n"); fflush(stdout);
failwith("evtchn_bind_virq error");
@@ -623,102 +123,40 @@ evtchn_bind_virq (value virq)
}
/*
- * evtchn_bind : Unix.file_descr -> int -> unit
+ * evtchn_bind_interdomain : int -> int * int
*/
value
-evtchn_bind (value fd, value idx)
+evtchn_bind_interdomain (value remote_domain)
{
- CAMLparam2(fd, idx);
-
- int myfd = Int_val(fd);
- int myidx = Int_val(idx);
-
- if ( xen_evtchn_bind(myfd, myidx) < 0 )
- {
- printf("(pdb) evtchn_bind error!\n"); fflush(stdout);
- failwith("evtchn_bind error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * evtchn_unbind : Unix.file_descr -> int -> unit
- */
-value
-evtchn_unbind (value fd, value idx)
-{
- CAMLparam2(fd, idx);
+ CAMLparam1(remote_domain);
+ CAMLlocal1(result);
- int myfd = Int_val(fd);
- int myidx = Int_val(idx);
+ int my_remote_domain = Int_val(remote_domain);
+ int local_domain = 0;
+ int local_port = 0;
+ int remote_port = 0;
- if ( xen_evtchn_unbind(myfd, myidx) < 0 )
+ if ( xc_evtchn_bind_interdomain(xc_handle, local_domain, my_remote_domain,
+ &local_port, &remote_port) < 0 )
{
- printf("(pdb) evtchn_unbind error!\n"); fflush(stdout);
- failwith("evtchn_unbind error");
+ printf("(pdb) evtchn_bind_interdomain error!\n"); fflush(stdout);
+ failwith("evtchn_bind_interdomain error");
}
- CAMLreturn(Val_unit);
-}
+ result = caml_alloc_tuple(2); /* FIXME */
+ Store_field(result, 0, Val_int(local_port));
+ Store_field(result, 1, Val_int(remote_port));
-/*
- * evtchn_read : Unix.file_descr -> int
- */
-value
-evtchn_read (value fd)
-{
- CAMLparam1(fd);
-
- u16 v;
- int bytes;
- int rc = -1;
- int myfd = Int_val(fd);
-
- while ( (bytes = read(myfd, &v, sizeof(v))) == -1 )
- {
- if ( errno == EINTR ) continue;
- rc = -errno;
- goto exit;
- }
-
- if ( bytes == sizeof(v) )
- rc = v;
-
- exit:
- CAMLreturn(Val_int(rc));
+ CAMLreturn(result);
}
-
-/*
- * evtchn_close : Unix.file_descr -> unit
- */
-value
-evtchn_close (value fd)
+void *
+map_ring(u32 dom, unsigned long mfn )
{
- CAMLparam1(fd);
- int myfd = Int_val(fd);
-
- (void)close(myfd);
-
- CAMLreturn(Val_unit);
+ return xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, mfn);
}
-/*
- * evtchn_unmask : Unix.file_descr -> int -> unit
- */
-value
-evtchn_unmask (value fd, value idx)
-{
- CAMLparam1(fd);
-
- int myfd = Int_val(fd);
- u16 myidx = Int_val(idx);
-
- (void)write(myfd, &myidx, sizeof(myidx));
-
- CAMLreturn(Val_unit);
-}
/*
* Local variables:
diff --git a/tools/debugger/pdb/pdb_caml_xcs.c b/tools/debugger/pdb/pdb_caml_xcs.c
new file mode 100644
index 0000000000..61944420b2
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_xcs.c
@@ -0,0 +1,305 @@
+/*
+ * xcs stuff
+ *
+ * this is responsible for establishing the initial connection
+ * between a backend domain and the pdb server.
+ *
+ * liberated from xu.c
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <xc.h>
+
+#include <xen/xen.h>
+#include <xen/io/domain_controller.h>
+#include <xen/linux/privcmd.h>
+
+#include <arpa/inet.h>
+#include <xcs_proto.h>
+
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+static int control_fd = -1;
+
+#include "pdb_module.h"
+#include "pdb_caml_xen.h"
+
+void *map_ring(u32 dom, unsigned long mfn );
+
+/*
+ * xcs_initialize_ring : int -> int32 -> int32
+ *
+ * initialize a communications ring
+ * (probably belongs in a different file :)
+ */
+
+value
+xcs_initialize_ring (value domain, value ring)
+{
+ CAMLparam2(domain, ring);
+ int my_domain = Int_val(domain);
+ memory_t my_ring = Int32_val(ring);
+
+ pdb_front_ring_t *front_ring;
+ pdb_sring_t *sring;
+
+ front_ring = (pdb_front_ring_t *)malloc(sizeof(pdb_front_ring_t));
+ if ( front_ring == NULL )
+ {
+ printf("(pdb) xcs initialize ring: malloc failed.\n"); fflush(stdout);
+ failwith("xcs initialize ring: malloc");
+ }
+
+ sring = map_ring(my_domain, my_ring);
+ if ( sring == NULL )
+ {
+ printf("(pdb) xcs initialize ring: map ring failed.\n");fflush(stdout);
+ failwith("xcs initialize ring: map ring");
+ }
+ FRONT_RING_INIT(front_ring, sring, PAGE_SIZE);
+
+ CAMLreturn(caml_copy_int32((unsigned long)front_ring));
+}
+
+
+/*
+ * xcs_write_message : Unix.file_descr -> xcs_message -> unit
+ *
+ * ack a packet
+ */
+value
+xcs_write_message (value data_fd, value msg)
+{
+ CAMLparam2(data_fd, msg);
+ int my_data_fd = Int_val(data_fd);
+ xcs_msg_t my_msg;
+ pdb_connection_p conn;
+
+ my_msg.type = XCS_REQUEST;
+ my_msg.u.control.remote_dom = Int_val(Field(msg,0));
+ my_msg.u.control.msg.type = CMSG_DEBUG;
+ my_msg.u.control.msg.subtype = CMSG_DEBUG_CONNECTION_STATUS;
+ my_msg.u.control.msg.id = 0;
+ my_msg.u.control.msg.length = sizeof(pdb_connection_t);
+
+ conn = (pdb_connection_p)my_msg.u.control.msg.msg;
+
+ conn->status = Int_val(Field(msg,1));
+ conn->ring = Int32_val(Field(msg,2));
+ conn->evtchn = Int_val(Field(msg,3));
+
+ send(my_data_fd, &my_msg, sizeof(xcs_msg_t), 0); /* ack */
+
+ CAMLreturn(Val_unit);
+}
+
+/*
+ * xcs_read_message : Unix.file_descr -> xcs_message
+ *
+ * read pending data on xcs socket.
+ */
+
+value
+xcs_read_message (value data_fd)
+{
+ CAMLparam1(data_fd);
+ CAMLlocal1(result);
+ int my_data_fd = Int_val(data_fd);
+ xcs_msg_t msg;
+
+ if ( read(my_data_fd, &msg, sizeof(xcs_msg_t)) < 0 )
+ {
+ perror("read");
+ failwith("xcs message: read");
+ }
+
+ switch (msg.type)
+ {
+ case XCS_REQUEST :
+ {
+ pdb_connection_p conn;
+
+ if ( msg.u.control.msg.type != CMSG_DEBUG ||
+ msg.u.control.msg.subtype != CMSG_DEBUG_CONNECTION_STATUS )
+ {
+ printf("bogus message type: %d %d\n",
+ msg.u.control.msg.type, msg.u.control.msg.subtype);
+ failwith("xcs message: invalid message type");
+ }
+
+ conn = (pdb_connection_p) msg.u.control.msg.msg;
+
+ result = caml_alloc_tuple(4); /* FIXME */
+ Store_field(result, 0, Val_int(msg.u.control.remote_dom)); /* domain */
+ Store_field(result, 1, Val_int(conn->status)); /* status */
+ Store_field(result, 2, caml_copy_int32(conn->ring)); /* ring */
+ Store_field(result, 3, Val_int(0)); /* OUT: evtchn */
+
+ break;
+ }
+ case XCS_RESPONSE :
+ {
+ printf("[XCS RESPONSE] type: %d, remote_dom: %d\n",
+ msg.type, msg.u.control.remote_dom);
+ printf("strange. we never initiate messages, so what is the ");
+ printf("domain responding to?\n");
+ failwith ("xcs message: resonse");
+ break;
+ }
+ default:
+ {
+ printf("[XCS IGNORE] type: %d\n", msg.type);
+ failwith ("xcs message: unknown");
+ break;
+ }
+ }
+
+ CAMLreturn(result);
+}
+
+/*
+ * xcs_connect : string -> int -> Unix.file_descr
+ */
+
+value
+xcs_connect (value path, value msg_type)
+{
+ CAMLparam2(path, msg_type);
+ char *my_path = String_val(path);
+ int my_msg_type = Int_val(msg_type);
+ struct sockaddr_un addr;
+ u32 session_id = 0;
+ int data_fd;
+ int ret, len;
+ xcs_msg_t msg;
+
+ /* setup control channel connection to xcs */
+
+ control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if ( control_fd < 0 )
+ {
+ printf("error creating xcs socket!\n");
+ goto fail;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, my_path);
+ len = sizeof(addr.sun_family) + strlen(addr.sun_path) + 1;
+
+ ret = connect(control_fd, (struct sockaddr *)&addr, len);
+ if (ret < 0)
+ {
+ printf("error connecting to xcs(ctrl)! (%d)\n", errno);
+ goto ctrl_fd_fail;
+ }
+
+ msg.type = XCS_CONNECT_CTRL;
+ msg.u.connect.session_id = session_id;
+ send(control_fd, &msg, sizeof(xcs_msg_t), 0);
+ /* bug: this should have a timeout & error! */
+ read(control_fd, &msg, sizeof(xcs_msg_t));
+
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("error connecting xcs control channel!\n");
+ goto ctrl_fd_fail;
+ }
+ session_id = msg.u.connect.session_id;
+
+
+ /* setup data channel connection to xcs */
+
+ data_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if ( data_fd < 0 )
+ {
+ printf("error creating xcs data socket!\n");
+ goto ctrl_fd_fail;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, my_path);
+ len = sizeof(addr.sun_family) + strlen(addr.sun_path) + 1;
+
+ ret = connect(data_fd, (struct sockaddr *)&addr, len);
+ if (ret < 0)
+ {
+ printf("error connecting to xcs(data)! (%d)\n", errno);
+ goto data_fd_fail;
+ }
+
+ msg.type = XCS_CONNECT_DATA;
+ msg.u.connect.session_id = session_id;
+ send(data_fd, &msg, sizeof(xcs_msg_t), 0);
+ read(data_fd, &msg, sizeof(xcs_msg_t)); /* same bug */
+
+ if ( msg.result != XCS_RSLT_OK )
+ {
+ printf("error connecting xcs control channel!\n");
+ goto ctrl_fd_fail;
+ }
+
+
+
+ /* now request all messages of a particular type */
+
+ msg.type = XCS_MSG_BIND;
+ msg.u.bind.port = PORT_WILDCARD;
+ msg.u.bind.type = my_msg_type;
+ send(control_fd, &msg, sizeof(xcs_msg_t), 0);
+ read(control_fd, &msg, sizeof(xcs_msg_t)); /* still buggy */
+
+ if (msg.result != XCS_RSLT_OK) {
+ printf ("error: MSG BIND\n");
+ goto bind_fail;
+ }
+
+ CAMLreturn(Val_int(data_fd));
+
+bind_fail:
+data_fd_fail:
+ close(data_fd);
+
+ctrl_fd_fail:
+ close(control_fd);
+
+fail:
+ failwith("xcs connection error"); /* should be more explicit */
+}
+
+
+/* xcs_disconnect: Unix.file_descr -> unit */
+
+value
+xcs_disconnect (value data_fd)
+{
+ CAMLparam1(data_fd);
+
+ int my_data_fd = Int_val(data_fd);
+
+ close(my_data_fd);
+ close(control_fd);
+ control_fd = -1;
+
+ CAMLreturn(Val_unit);
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tools/debugger/pdb/pdb_caml_xen.h b/tools/debugger/pdb/pdb_caml_xen.h
new file mode 100644
index 0000000000..b21bf938e6
--- /dev/null
+++ b/tools/debugger/pdb/pdb_caml_xen.h
@@ -0,0 +1,18 @@
+
+#ifndef _PDB_CAML_XEN_DEFINED_
+#define _PDB_CAML_XEN_DEFINED_
+
+enum gdb_registers { GDB_EAX, GDB_ECX, GDB_EDX, GDB_EBX,
+ GDB_ESP, GDB_EBP, GDB_ESI, GDB_EDI,
+ GDB_EIP, GDB_EFL,
+ GDB_CS, GDB_SS, GDB_DS, GDB_ES,
+ GDB_FS, GDB_GS };
+
+#define PAGE_SIZE 4096
+
+extern int xc_handle;
+
+void dump_regs (cpu_user_regs_t *ctx);
+
+#endif
+
diff --git a/tools/debugger/pdb/pdb_xen.c b/tools/debugger/pdb/pdb_xen.c
index 36671dacc0..f929010026 100644
--- a/tools/debugger/pdb/pdb_xen.c
+++ b/tools/debugger/pdb/pdb_xen.c
@@ -42,20 +42,6 @@ pdb_close (int xc_handle)
}
-int
-pdb_evtchn_bind_virq (int xc_handle, int virq, int *port)
-{
- int rc;
-
- if ( (rc = xc_evtchn_bind_virq(xc_handle, virq, port) < 0 ) )
- {
- fprintf(stderr, "(pdb) error binding virq to event channel: %d (%s)\n",
- errno, strerror(errno));
- }
- return rc;
-}
-
-
#include <sys/ioctl.h>
/* /dev/xen/evtchn ioctls */
diff --git a/tools/debugger/pdb/server.ml b/tools/debugger/pdb/server.ml
index 2d3a3c7c86..01b4c2565d 100644
--- a/tools/debugger/pdb/server.ml
+++ b/tools/debugger/pdb/server.ml
@@ -59,6 +59,7 @@ let process_input conn sock =
conn.length <- conn.length + length;
let re = Str.regexp "[^\\$]*\\$\\([^#]*\\)#\\(..\\)" in
+ (* interrupt the target if there was a ctrl-c *)
begin
try
let break = String.index conn.buffer '\003' + 1 in
@@ -118,9 +119,13 @@ let process_input conn sock =
* connection_hash is a hash (duh!) with one connection_t for each
* open connection.
*
- * in_list is a list of active sockets. it also contains two
- * magic entries: server_sock for accepting new entries and
- * event_sock for Xen event channel asynchronous notifications.
+ * in_list is a list of active sockets. it also contains a number
+ * of magic entries:
+ * - server_sock for accepting new client connections (e.g. gdb)
+ * - xen_virq_sock for Xen virq asynchronous notifications (via evtchn).
+ * This is used by context = domain
+ * - xcs_sock for xcs messages when a new backend domain registers
+ * This is used by context = process
*)
let main_server_loop sockaddr =
let connection_hash = Hashtbl.create 10
@@ -143,10 +148,20 @@ let main_server_loop sockaddr =
begin
try
match PDB.find_context sock with
- | PDB.Event_channel ->
- print_endline (Printf.sprintf "[%s] event channel"
+ | PDB.Xen_virq ->
+ print_endline (Printf.sprintf "[%s] Xen virq"
(Util.get_connection_info sock));
- Debugger.process_evtchn sock;
+ Debugger.process_xen_virq sock;
+ (new_list, closed_list)
+ | PDB.Xen_xcs ->
+ print_endline (Printf.sprintf "[%s] Xen xcs"
+ (Util.get_connection_info sock));
+ let new_xen_domain = Debugger.process_xen_xcs sock in
+ (new_xen_domain :: new_list, closed_list)
+ | PDB.Xen_domain d ->
+ print_endline (Printf.sprintf "[%s] Xen domain"
+ (Util.get_connection_info sock));
+ Debugger.process_xen_domain sock;
(new_list, closed_list)
| _ ->
let conn = Hashtbl.find connection_hash sock in
@@ -167,18 +182,22 @@ let main_server_loop sockaddr =
(new_list, sock :: closed_list)
end
in
+
let rec helper in_list server_sock =
- (*
- * List.iter (fun x->Printf.printf "{%s} "
- * (Util.get_connection_info x)) in_list;
- * Printf.printf "\n";
- *)
+
+ (*
+ List.iter (fun x->Printf.printf " {%s}\n"
+ (Util.get_connection_info x)) in_list;
+ Printf.printf "\n";
+ *)
+
let (rd_list, _, _) = select in_list [] [] (-1.0) in
let (new_list, closed_list) = List.fold_left (process_socket server_sock)
([],[]) rd_list in
let merge_list = Util.list_remove (new_list @ in_list) closed_list in
helper merge_list server_sock
in
+
try
let server_sock = socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
setsockopt server_sock SO_REUSEADDR true;
@@ -186,16 +205,19 @@ let main_server_loop sockaddr =
listen server_sock 2;
PDB.open_debugger ();
- let event_sock = Evtchn.setup () in
- PDB.add_context event_sock "event channel" [];
- helper [server_sock; event_sock] server_sock
+ let xen_virq_sock = Evtchn.setup () in
+ PDB.add_context xen_virq_sock "xen virq" [];
+
+ let xcs_sock = Xcs.setup () in
+ PDB.add_context xcs_sock "xen xcs" [];
+ helper [server_sock; xen_virq_sock; xcs_sock] server_sock
with
| Sys.Break ->
print_endline "break: cleaning up";
PDB.close_debugger ();
Hashtbl.iter (fun sock conn -> close sock) connection_hash
- | Unix_error(e,err,param) ->
- Printf.printf "unix error: [%s][%s][%s]\n" (error_message e) err param
+(* | Unix_error(e,err,param) ->
+ Printf.printf "unix error: [%s][%s][%s]\n" (error_message e) err param*)
| Sys_error s -> Printf.printf "sys error: [%s]\n" s
| Failure s -> Printf.printf "failure: [%s]\n" s
| End_of_file -> Printf.printf "end of file\n"
@@ -207,7 +229,7 @@ let get_port () =
int_of_string Sys.argv.(1)
else
begin
- print_endline (Printf.sprintf "syntax error: %s <port>" Sys.argv.(0));
+ print_endline (Printf.sprintf "error: %s <port>" Sys.argv.(0));
exit 1
end
diff --git a/tools/debugger/pdb/xcs.ml b/tools/debugger/pdb/xcs.ml
new file mode 100644
index 0000000000..ce8eaee1da
--- /dev/null
+++ b/tools/debugger/pdb/xcs.ml
@@ -0,0 +1,85 @@
+(** xcs.ml
+ *
+ * xen control switch interface
+ *
+ * @author copyright (c) 2005 alex ho
+ * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
+ * @version 1
+ *)
+
+open Int32
+
+let xcs_path = "/var/lib/xen/xcs_socket" (* XCS_SUN_PATH *)
+let xcs_type = 11 (* CMSG_DEBUG *)
+
+
+type xcs_message =
+ {
+ domain : int;
+ status : int;
+ ring : int32;
+ mutable evtchn : int;
+ }
+
+external connect : string -> int -> Unix.file_descr = "xcs_connect"
+external disconnect : Unix.file_descr -> unit = "xcs_disconnect"
+external read_message : Unix.file_descr -> xcs_message = "xcs_read_message"
+external write_message : Unix.file_descr -> xcs_message -> unit =
+ "xcs_write_message"
+external initialize_ring : int -> int32 -> int32 = "xcs_initialize_ring"
+
+(*
+ * initialize xcs stuff
+ *)
+let setup () =
+ connect xcs_path xcs_type
+
+
+(*
+ * adios
+ *)
+let teardown fd =
+ disconnect fd
+
+
+(*
+ * message from a domain backend
+ *)
+let read socket =
+ let xcs = read_message socket in
+ begin
+ match xcs.status with
+ | 1 -> (* PDB_CONNECTION_STATUS_UP *)
+ begin
+ print_endline (Printf.sprintf " new backend domain available (%d)"
+ xcs.domain);
+ let ring = initialize_ring xcs.domain xcs.ring in
+
+ let (local_evtchn, remote_evtchn) =
+ Evtchn.bind_interdomain xcs.domain in
+
+ xcs.evtchn <- remote_evtchn;
+ write_message socket xcs;
+
+ let evtchn_fd = Evtchn._setup () in
+ Evtchn._bind evtchn_fd local_evtchn;
+
+ (evtchn_fd, local_evtchn, xcs.domain, ring)
+ end
+ | 2 -> (* PDB_CONNECTION_STATUS_DOWN *)
+ begin
+ (* TODO:
+ unmap the ring
+ unbind event channel xen_evtchn_unbind
+ find the evtchn_fd for this domain and close it
+ finally, need to failwith something
+ *)
+ print_endline (Printf.sprintf " close connection from domain %d"
+ xcs.domain);
+ (socket, 0, 0, 0l)
+ end
+ | _ ->
+ failwith "xcs read: unknown xcs status"
+ end
+
+
diff --git a/tools/debugger/pdb/xcs.mli b/tools/debugger/pdb/xcs.mli
new file mode 100644
index 0000000000..98ea606e5e
--- /dev/null
+++ b/tools/debugger/pdb/xcs.mli
@@ -0,0 +1,5 @@
+
+
+val setup : unit -> Unix.file_descr
+val read : Unix.file_descr -> Unix.file_descr * int * int * int32
+val teardown : Unix.file_descr -> unit
diff --git a/xen/include/public/io/domain_controller.h b/xen/include/public/io/domain_controller.h
index 140bff4881..17dedb737a 100644
--- a/xen/include/public/io/domain_controller.h
+++ b/xen/include/public/io/domain_controller.h
@@ -62,6 +62,7 @@ typedef struct {
#define CMSG_USBIF_BE 8 /* USB controller backend */
#define CMSG_USBIF_FE 9 /* USB controller frontend */
#define CMSG_VCPU_HOTPLUG 10 /* Hotplug VCPU messages */
+#define CMSG_DEBUG 11 /* PDB backend */
/******************************************************************************
* CONSOLE DEFINITIONS
@@ -795,4 +796,17 @@ typedef struct {
} PACKED mem_request_t; /* 8 bytes */
+/******************************************************************************
+ * PDB INTERFACE DEFINITIONS
+ */
+
+#define CMSG_DEBUG_CONNECTION_STATUS 0
+typedef struct {
+#define PDB_CONNECTION_STATUS_UP 1
+#define PDB_CONNECTION_STATUS_DOWN 2
+ u32 status;
+ memory_t ring; /* status: UP */
+ u32 evtchn; /* status: UP */
+} PACKED pdb_connection_t, *pdb_connection_p;
+
#endif /* __XEN_PUBLIC_IO_DOMAIN_CONTROLLER_H__ */