Files
xen/tools/debugger/pdb/PDB.ml
T

343 lines
9.1 KiB
OCaml

(** PDB.ml
*
* Dispatch debugger commands to the appropriate context
*
* @author copyright (c) 2005 alex ho
* @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
* @version 1
*)
open Util
exception Unimplemented of string
exception Unknown_context of string
exception Unknown_domain
exception Unknown_process
type context_t =
| Void
| 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}"
| 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 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_process : Locate the socket associated with the context(s)
matching a particular (domain, process id) pair. if there are multiple
contexts (there shouldn't be), then return the first one.
*)
let find_process dom pid =
let find key ctx list =
match ctx with
| Process p ->
if (((Process.get_domain p) = dom) &&
((Process.get_process p) = pid))
then
key :: list
else
list
| _ -> list
in
let sock_list = Hashtbl.fold find hash [] in
match sock_list with
| hd::tl -> hd
| [] -> raise Unknown_process
(**
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_vcpu 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
(**
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_vcpu d)
| Process p ->
begin
let xdom_sock = find_xen_domain_context (Process.get_domain p) in
let xdom_ctx = find_context xdom_sock in
begin
match xdom_ctx with
| Xen_domain d ->
Process.attach_debugger p d
| _ -> failwith ("context has wrong xen domain type")
end;
raise No_reply
end
| _ -> raise (Unimplemented "attach debugger")
let detach_debugger ctx =
match ctx with
| Domain d ->
Domain.detach_debugger (Domain.get_domain d)
(Domain.get_vcpu d);
"OK"
| Process p ->
Process.detach_debugger p;
raise No_reply
| _ -> raise (Unimplemented "detach debugger")
let debug_contexts () =
print_endline "context list:";
let print_context key ctx =
match ctx with
| Void -> print_endline (Printf.sprintf " [%s] {void}"
(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))
in
Hashtbl.iter print_context hash
(** add_context : add a new context to the hash table.
* if there is an existing context for the same key then it
* is first removed implictly by the hash table replace function.
*)
let add_context (key:Unix.file_descr) context params =
match context with
| "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::vcpu::_ ->
let d = Domain(Domain.new_context dom vcpu) in
attach_debugger d;
Hashtbl.replace hash key d
| _ -> failwith "bogus parameters to domain context"
end
| "process" ->
begin
match params with
| dom::pid::_ ->
let p = Process(Process.new_context dom pid) in
Hashtbl.replace hash key p;
attach_debugger 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 read_register ctx register = (* register is int32 because of sscanf *)
match ctx with
| Void -> 0l (* default for startup *)
| Domain d -> Domain.read_register d register
| Process p ->
begin
Process.read_register p register;
raise No_reply
end
| _ -> raise (Unimplemented "read registers")
let read_registers ctx =
match ctx with
| Void -> Intel.null_registers (* default for startup *)
| Domain d -> Domain.read_registers d
| Process p ->
begin
Process.read_registers p;
raise No_reply
end
| _ -> raise (Unimplemented "read registers")
let write_register ctx register value =
match ctx with
| Domain d -> Domain.write_register d register value
| Process p ->
begin
Process.write_register p register value;
raise No_reply
end
| _ -> raise (Unimplemented "write register")
let read_memory ctx addr len =
match ctx with
| Domain d -> Domain.read_memory d addr len
| Process p ->
begin
Process.read_memory p addr len;
raise No_reply
end
| _ -> raise (Unimplemented "read memory")
let write_memory ctx addr values =
match ctx with
| Domain d -> Domain.write_memory d addr values
| Process p ->
begin
Process.write_memory p addr values;
raise No_reply
end
| _ -> 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 ->
begin
Process.insert_memory_breakpoint p addr len;
raise No_reply
end
| _ -> raise (Unimplemented "insert memory breakpoint")
let remove_memory_breakpoint ctx addr len =
match ctx with
| Domain d -> Domain.remove_memory_breakpoint d addr len
| Process p ->
begin
Process.remove_memory_breakpoint p addr len;
raise No_reply
end
| _ -> raise (Unimplemented "remove memory breakpoint")
let insert_watchpoint ctx kind addr len =
match ctx with
(* | Domain d -> Domain.insert_watchpoint d kind addr len TODO *)
| Process p ->
begin
Process.insert_watchpoint p kind addr len;
raise No_reply
end
| _ -> raise (Unimplemented "insert watchpoint")
let remove_watchpoint ctx kind addr len =
match ctx with
(* | Domain d -> Domain.remove_watchpoint d kind addr len TODO *)
| Process p ->
begin
Process.remove_watchpoint p kind addr len;
raise No_reply
end
| _ -> raise (Unimplemented "remove watchpoint")
let pause ctx =
match ctx with
| 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"