aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debugger/pdb/PDB.ml
blob: da9ad7d2c685f2633d69c370355409bd6b93d667 (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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
(** 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"