aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debugger/pdb/PDB.ml
blob: 12ee1f00d8232ba1325e554ac70d172e2a302e43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
(** 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
 *)

exception Unimplemented of string
exception Unknown_context of string
exception Unknown_domain

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_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

(**
   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")


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
	    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 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"