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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
open Printf
open Interp_ast
open Interp_interface
open Interp_inter_imp
open Printing_functions
open Nat_big_num
module Reg = struct
include Map.Make(struct type t = string let compare = String.compare end)
let to_string id v =
sprintf "%s -> %s" id (register_value_to_string v)
let find id m =
(* eprintf "reg_find called with %s\n" id; *)
let v = find id m in
(* eprintf "%s -> %s\n" id (val_to_string v);*)
v
end ;;
let compare_addresses (Address_lifted(v1,n1)) (Address_lifted(v2,n2)) =
let rec comp v1s v2s = match (v1s,v2s) with
| ([],[]) -> 0
| ([],_) -> -1
| (_,[]) -> 1
| (v1::v1s,v2::v2s) ->
match Pervasives.compare v1 v2 with
| 0 -> comp v1s v2s
| ans -> ans in
match n1,n2 with
| Some(n1),Some(n2) -> compare n1 n2
| _ ->
let l1 = List.length v1 in
let l2 = List.length v2 in
if l1 > l2 then 1
else if l1 < l2 then -1
else comp v1 v2
let default_endian = ref E_big_endian
let default_order = ref D_increasing
module Mem = struct
include Map.Make(struct
type t = num
let compare v1 v2 = compare v1 v2
end)
let find idx m =
if mem idx m
then find idx m
else List.hd(memory_value_undef 1)
let to_string loc v =
sprintf "[%s] -> %s" (to_string loc)
(memory_value_to_string !default_endian [v])
end
let slice register_vector (start,stop) =
if register_vector.rv_dir = D_increasing
then slice_reg_value register_vector start stop
else
(*Interface turns start and stop into forms for
increasing because ppcmem only speaks increasing, so here we turn it back *)
let startd = register_vector.rv_start_internal- start in
let stopd = startd - (stop - start) in
(* let _ = Printf.eprintf "slice decreasing with %i, %i, %i\n" startd stopd register_vector.rv_start in*)
slice_reg_value register_vector start stop
let big_num_unit = of_int 1
let rec list_update index start stop e vals =
match vals with
| [] -> []
| x :: xs ->
if Nat_big_num.equal index stop
then e :: xs
else if Nat_big_num.greater_equal index start
then e :: (list_update (Nat_big_num.add index big_num_unit) start stop e xs)
else x :: (list_update (Nat_big_num.add index big_num_unit) start stop e xs)
let rec list_update_list index start stop es vals =
match vals with
| [] -> []
| x :: xs ->
match es with
| [] -> xs
| e::es ->
if Nat_big_num.equal index stop
then e::xs
else if Nat_big_num.greater_equal index start
then e :: (list_update_list (Nat_big_num.add index big_num_unit) start stop es xs)
else x :: (list_update_list (Nat_big_num.add index big_num_unit) start stop (e::es) xs)
let fupdate_slice reg_name original e (start,stop) =
if original.rv_dir = D_increasing
then update_reg_value_slice reg_name original start stop e
else
(*Interface turns start and stop into forms for
increasing because ppcmem only speaks increasing, so here we turn it back *)
let startd = original.rv_start_internal- start in
let stopd = startd - (stop - start) in
(* let _ = Printf.eprintf "fupdate_slice: starts at %i, %i -> %i,%i -> %i\n" original.rv_start_internal start startd stop stopd in *)
update_reg_value_slice reg_name original startd stopd e
let combine_slices (start, stop) (inner_start,inner_stop) =
(start + inner_start, start + inner_stop)
let unit_lit = (L_aux(L_unit,Interp_ast.Unknown))
let rec perform_action ((reg, mem, tagmem) as env) = function
(* registers *)
| Read_reg0(Reg0(id,_,_,_), _) -> (Some(Reg.find id reg), env)
| Read_reg0(Reg_slice(id, _, _, range), _)
| Read_reg0(Reg_field(id, _, _, _, range), _) -> (Some(slice (Reg.find id reg) range), env)
| Read_reg0(Reg_f_slice(id, _,_,_, range, mini_range), _) ->
(Some(slice (slice (Reg.find id reg) range) mini_range),env)
| Write_reg0(Reg0(id,_,_,_), value, _) -> (None, (Reg.add id value reg,mem,tagmem))
| Write_reg0((Reg_slice(id,_,_,range) as reg_n),value, _)
| Write_reg0((Reg_field(id,_,_,_,range) as reg_n),value,_)->
let old_val = Reg.find id reg in
let new_val = fupdate_slice reg_n old_val value range in
(None, (Reg.add id new_val reg, mem,tagmem))
| Write_reg0((Reg_f_slice(id,_,_,_,range,mini_range) as reg_n),value,_) ->
let old_val = Reg.find id reg in
let new_val = fupdate_slice reg_n old_val value (combine_slices range mini_range) in
(None,(Reg.add id new_val reg,mem,tagmem))
| Read_mem0(kind,location, length, _,_) ->
let address = match address_of_address_lifted location with
| Some a -> a
| None -> assert false (*TODO remember how to report an error *)in
let naddress = integer_of_address address in
(match kind with
| Read_tag ->
(Some (register_value_of_memory_value [(Mem.find naddress tagmem)] !default_order), env)
| _ ->
let rec reading (n : num) length =
if length = 0
then []
else (Mem.find n mem)::(reading (add n big_num_unit) (length - 1)) in
(Some (register_value_of_memory_value (reading naddress length) !default_order), env))
| Write_mem0(kind,location, length, _, bytes,_,_) ->
let address = match address_of_address_lifted location with
| Some a -> a
| None -> assert false (*TODO remember how to report an error *)in
let naddress = integer_of_address address in
(match kind with
| Write_tag ->
(match bytes with
| [b] -> (None,(reg,mem,Mem.add naddress b tagmem))
| _ -> assert false)
| _ ->
let rec writing location length bytes mem =
if length = 0
then mem
else match bytes with
| [] -> mem
| b::bytes ->
writing (add location big_num_unit) (length - 1) bytes (Mem.add location b mem) in
(None,(reg,writing naddress length bytes mem,tagmem)))
| _ -> (None, env)
;;
let interact_print = ref true
let result_print = ref true
let error_print = ref true
let interactf : ('a, out_channel, unit) format -> 'a =
function f -> if !interact_print then eprintf f else ifprintf stderr f
let errorf : ('a, out_channel, unit) format -> 'a =
function f -> if !error_print then eprintf f else ifprintf stderr f
let resultf : ('a, out_channel, unit) format -> 'a =
function f -> if !result_print then eprintf f else ifprintf stderr f
type interactive_mode = Step | Run | Next
let mode_to_string = function
| Step -> "step"
| Run -> "run"
| Next -> "next"
let run
(istate : instruction_state)
reg
mem
tagmem
eager_eval
track_dependencies
mode
name =
(* interactive loop for step-by-step execution *)
let usage = "Usage:
step go to next action [default]
next go to next break point
run complete current execution
track begin/end tracking register dependencies
bt print call stack
cont print continuation of the top stack frame
reg print content of environment
mem print content of memory
exh run interpreter exhaustively with unknown and print events
quit exit interpreter" in
let rec interact mode ((reg, mem, tagmem) as env) stack =
flush_all();
let command = Pervasives.read_line () in
let command' = if command = "" then mode_to_string mode else command in
begin match command' with
| "s" | "step" -> Step
| "n" | "next" -> Next
| "r" | "run" -> Run
| "rg" | "reg" | "registers" ->
Reg.iter (fun k v -> interactf "%s\n" (Reg.to_string k v)) reg;
interact mode env stack
| "m" | "mem" | "memory" ->
Mem.iter (fun k v -> interactf "%s\n" (Mem.to_string k v)) mem;
interact mode env stack
| "bt" | "backtrace" | "stack" ->
print_backtrace_compact (fun s -> interactf "%s" s) stack;
interact mode env stack
| "e" | "exh" | "exhaust" ->
interactf "interpreting exhaustively from current state\n";
let events = interp_exhaustive None stack in
interactf "%s" (format_events events);
interact mode env stack
| "c" | "cont" | "continuation" ->
(* print not-compacted continuation *)
print_continuation (fun s -> interactf "%s" s) stack;
interact mode env stack
| "track" | "t" ->
track_dependencies := not(!track_dependencies);
interact mode env stack
| "show_casts" ->
Pretty_interp.ignore_casts := false;
interact mode env stack
| "hide_casts" ->
Pretty_interp.ignore_casts := true;
interact mode env stack
| "q" | "quit" | "exit" -> exit 0
| _ -> interactf "%s\n" usage; interact mode env stack
end
in
let show act lhs arrow rhs = interactf "%s: %s %s %s\n"
(green act) lhs (blue arrow) rhs in
let left = "<-" and right = "->" in
let rec loop mode env = function
| Done ->
interactf "%s: %s\n" (grey name) (blue "done");
(true, mode, !track_dependencies, env)
| Error0 s ->
errorf "%s: %s: %s\n" (grey name) (red "error") s;
(false, mode, !track_dependencies, env)
| Escape (None, _) ->
show "exiting current instruction" "" "" "";
interactf "%s: %s\n" (grey name) (blue "done");
(true, mode, !track_dependencies, env)
| Fail0 (Some s) ->
errorf "%s: %s: %s\n" (grey name) (red "assertion failed") s;
(false, mode, !track_dependencies, env)
| Fail0 None ->
errorf "%s: %s: %s\n" (grey name) (red "assertion failed") "No message provided";
(false, mode, !track_dependencies, env)
| action ->
let (return,env') = perform_action env action in
let step ?(force=false) (state: instruction_state) =
let stack = match state with IState(stack,_) -> stack in
let (top_exp,(top_env,top_mem)) = top_frame_exp_state stack in
let loc = get_loc (compact_exp top_exp) in
if mode = Step || force then begin
interactf "%s\n" (Pretty_interp.pp_exp top_env Printing_functions.red top_exp);
interact mode env' state
end else
mode in
let (mode', env', next) =
(match action with
| Read_reg0(reg,next_thunk) ->
(match return with
| Some(value) ->
show "read_reg" (reg_name_to_string reg) right (register_value_to_string value);
let next = next_thunk value in
(step next, env', next)
| None -> assert false)
| Write_reg0(reg,value,next) ->
show "write_reg" (reg_name_to_string reg) left (register_value_to_string value);
(step next, env', next)
| Read_mem0(kind, (Address_lifted(location,_)), length, tracking, next_thunk) ->
(match return with
| Some(value) ->
show "read_mem"
(memory_value_to_string !default_endian location) right
(register_value_to_string value);
(match tracking with
| None -> ()
| Some(deps) ->
show "read_mem address depended on" (dependencies_to_string deps) "" "");
let next = next_thunk (memory_value_of_register_value value) in
(step next, env', next)
| None -> assert false)
| Write_mem0(kind,(Address_lifted(location,_)), length, tracking, value, v_tracking, next_thunk) ->
show "write_mem" (memory_value_to_string !default_endian location) left
(memory_value_to_string !default_endian value);
(match (tracking,v_tracking) with
| (None,None) -> ();
| (Some(deps),None) ->
show "write_mem address depended on" (dependencies_to_string deps) "" "";
| (None,Some(deps)) ->
show "write_mem value depended on" (dependencies_to_string deps) "" "";
| (Some(deps),Some(vdeps)) ->
show "write_mem address depended on" (dependencies_to_string deps) "" "";
show "write_mem value depended on" (dependencies_to_string vdeps) "" "";);
let next = next_thunk true in
(step next,env',next)
| Barrier0(bkind,next) ->
show "mem_barrier" "" "" "";
(step next, env, next)
| Internal(None,None, next) ->
show "stepped" "" "" "";
(step ~force:true next,env',next)
| Internal((Some fn),None,next) ->
show "evaluated" fn "" "";
(step ~force:true next, env',next)
| Internal(None,Some vdisp,next) ->
show "evaluated" (vdisp ()) "" "";
(step ~force:true next,env', next)
| Internal((Some fn),(Some vdisp),next) ->
show "evaluated" (fn ^ " " ^ (vdisp ())) "" "";
(step ~force:true next, env', next)
| Nondet_choice(nondets, next) ->
let choose_order = List.sort (fun (_,i1) (_,i2) -> Pervasives.compare i1 i2)
(List.combine nondets (List.map (fun _ -> Random.bits ()) nondets)) in
show "nondeterministic evaluation begun" "" "" "";
let (_,_,_,env') = List.fold_right (fun (next,_) (_,_,_,env') ->
loop mode env' (interp0 (make_mode (mode=Run) !track_dependencies !default_endian) next))
choose_order (false,mode,!track_dependencies,env'); in
show "nondeterministic evaluation ended" "" "" "";
(step next,env',next)
| Analysis_non_det (possible_istates, i_state) ->
let choose_order = List.sort (fun (_,i1) (_,i2) -> Pervasives.compare i1 i2)
(List.combine possible_istates (List.map (fun _ -> Random.bits ()) possible_istates)) in
if possible_istates = []
then (step i_state,env',i_state)
else begin
show "undefined triggered a non_det" "" "" "";
let (_,_,_,env') = List.fold_right (fun (next,_) (_,_,_,env') ->
loop mode env' (interp0 (make_mode (mode=Run) !track_dependencies !default_endian) next))
choose_order (false,mode,!track_dependencies,env'); in
(step i_state,env',i_state) end
| Escape(Some e,_) ->
show "exiting current evaluation" "" "" "";
step e,env', e
| Escape _ -> assert false
| Error0 _ -> failwith "Internal error"
| Fail0 _ -> failwith "Assertion in program failed"
| Done ->
show "done evalution" "" "" "";
assert false
| Footprint0 _ -> assert false
| Write_ea0 _ -> assert false
| Write_memv0 _ -> assert false)
(*| _ -> assert false*)
in
loop mode' env' (Interp_inter_imp.interp0 (make_mode (mode' = Run) !track_dependencies !default_endian) next) in
let mode = match mode with
| None -> if eager_eval then Run else Step
| Some m -> m in
let imode = make_mode eager_eval !track_dependencies !default_endian in
let (IState(instr_state,context)) = istate in
let (top_exp,(top_env,top_mem)) = top_frame_exp_state instr_state in
interactf "%s: %s %s\n" (grey name) (blue "evaluate")
(Pretty_interp.pp_exp top_env Printing_functions.red top_exp);
try
Printexc.record_backtrace true;
loop mode (reg, mem,tagmem) (Interp_inter_imp.interp0 imode istate)
with e ->
let trace = Printexc.get_backtrace () in
interactf "%s: %s %s\n%s\n" (grey name) (red "interpretor error") (Printexc.to_string e) trace;
(false, mode, !track_dependencies, (reg, mem, tagmem))
;;
|