From 2136a8f965c54a89786a0ae5225686fcffd113b9 Mon Sep 17 00:00:00 2001 From: "ach61@arcadians.cl.cam.ac.uk" Date: Mon, 27 Jun 2005 21:30:47 +0000 Subject: bitkeeper revision 1.1726.3.1 (42c07007i9Bkz3ggP_PXIksWaGD1Eg) add framework for debugging processes --- .rootkeys | 13 + tools/debugger/pdb/Domain.ml | 29 +- tools/debugger/pdb/Intel.ml | 75 ++- tools/debugger/pdb/Makefile | 24 +- tools/debugger/pdb/PDB.ml | 264 ++++++---- tools/debugger/pdb/Process.ml | 41 +- tools/debugger/pdb/Process.mli | 19 + tools/debugger/pdb/Util.ml | 5 +- tools/debugger/pdb/Xen_domain.ml | 35 ++ tools/debugger/pdb/Xen_domain.mli | 17 + tools/debugger/pdb/debugger.ml | 57 ++- tools/debugger/pdb/evtchn.ml | 12 +- tools/debugger/pdb/evtchn.mli | 5 + tools/debugger/pdb/linux-2.6-module/Makefile | 18 + tools/debugger/pdb/linux-2.6-module/debug.c | 169 +++++++ tools/debugger/pdb/linux-2.6-module/module.c | 226 +++++++++ tools/debugger/pdb/linux-2.6-module/pdb_module.h | 65 +++ tools/debugger/pdb/pdb_caml_domain.c | 485 ++++++++++++++++++ tools/debugger/pdb/pdb_caml_evtchn.c | 178 +++++++ tools/debugger/pdb/pdb_caml_process.c | 543 ++++++++++++++++++++ tools/debugger/pdb/pdb_caml_xc.c | 612 +---------------------- tools/debugger/pdb/pdb_caml_xcs.c | 305 +++++++++++ tools/debugger/pdb/pdb_caml_xen.h | 18 + tools/debugger/pdb/pdb_xen.c | 14 - tools/debugger/pdb/server.ml | 56 ++- tools/debugger/pdb/xcs.ml | 85 ++++ tools/debugger/pdb/xcs.mli | 5 + xen/include/public/io/domain_controller.h | 14 + 28 files changed, 2589 insertions(+), 800 deletions(-) create mode 100644 tools/debugger/pdb/Xen_domain.ml create mode 100644 tools/debugger/pdb/Xen_domain.mli create mode 100644 tools/debugger/pdb/linux-2.6-module/Makefile create mode 100644 tools/debugger/pdb/linux-2.6-module/debug.c create mode 100644 tools/debugger/pdb/linux-2.6-module/module.c create mode 100644 tools/debugger/pdb/linux-2.6-module/pdb_module.h create mode 100644 tools/debugger/pdb/pdb_caml_domain.c create mode 100644 tools/debugger/pdb/pdb_caml_evtchn.c create mode 100644 tools/debugger/pdb/pdb_caml_process.c create mode 100644 tools/debugger/pdb/pdb_caml_xcs.c create mode 100644 tools/debugger/pdb/pdb_caml_xen.h create mode 100644 tools/debugger/pdb/xcs.ml create mode 100644 tools/debugger/pdb/xcs.mli 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 +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ®s) ) + { + 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, ®s) ) + { + 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 +#include +#include +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#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 @@ -18,38 +18,9 @@ #include #include -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, ®s) ) - { - 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, ®s) ) - { - 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); -} - /*********************************************************************/ @@ -321,153 +88,6 @@ dump_regs (cpu_user_regs_t *regs) return; } -/* - * 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 */ @@ -476,133 +96,12 @@ 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); } /****************************************************************************/ /****************************************************************************/ -/* - * 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 -#include -#include -#include -#include - -/* - * 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 */ @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +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 /* /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 " Sys.argv.(0)); + print_endline (Printf.sprintf "error: %s " 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 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__ */ -- cgit v1.2.3