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
|
open Printf ;;
open Interp ;;
open Interp_ast ;;
open Interp_lib ;;
open Run_interp ;;
let startaddr = ref "0" ;;
let mainaddr = ref "0" ;;
let sections = ref [] ;;
let file = ref "" ;;
let rec foldli f acc ?(i=0) = function
| [] -> acc
| x::xs -> foldli f (f i acc x) ~i:(i+1) xs
;;
let big_endian = true ;;
let hex_to_big_int s = Big_int.big_int_of_int64 (Int64.of_string s) ;;
let big_int_to_vec b size =
(if big_endian then to_vec_inc else to_vec_dec)
size
(V_lit (L_aux (L_num b, Unknown)))
;;
let mem = ref Mem.empty ;;
let add_mem byte addr =
assert(byte >= 0 && byte < 256);
let vector = big_int_to_vec (Big_int.big_int_of_int byte) 8 in
let key = Id_aux (Id "MEM", Unknown), addr in
mem := Mem.add key vector !mem
;;
let add_section s =
match Str.split (Str.regexp ",") s with
| [name;offset;size;addr] ->
begin try
sections := (
int_of_string offset,
int_of_string size,
hex_to_big_int addr) ::
!sections
with Failure msg -> raise (Arg.Bad (msg ^ ": " ^ s))
end
| _ -> raise (Arg.Bad ("Wrong section format: "^s))
;;
let load_section ic (offset,size,addr) =
seek_in ic offset;
for i = 0 to size - 1 do
add_mem (input_byte ic) (Big_int.add_int_big_int i addr);
done
;;
(* use zero as a sentinel --- it might prevent a minimal loop from
* working in principle, but won't happen in practice *)
let lr_init_value = Big_int.zero_big_int
let init_reg () =
let init name value size =
(* fix index - this is necessary for CR, indexed from 32 *)
let offset = function
V_vector(_, inc, v) ->
V_vector(Big_int.big_int_of_int (64 - size), inc, v)
| _ -> assert false in
Id_aux(Id name, Unknown), offset (big_int_to_vec value size) in
List.fold_left (fun r (k,v) -> Reg.add k v r) Reg.empty [
(* XXX execute main() directly until we can handle the init phase *)
init "CIA" (hex_to_big_int !mainaddr) 64;
init "GPR1" Big_int.zero_big_int 64;
init "GPR31" Big_int.zero_big_int 64;
init "CTR" Big_int.zero_big_int 64;
init "CR" Big_int.zero_big_int 32;
init "LR" lr_init_value 64;
Id_aux(Id "mode64bit", Unknown), V_lit (L_aux (L_true, Unknown));
]
;;
let eager_eval = ref true
let args = [
("--file", Arg.Set_string file, "filename binary code to load in memory");
("--data", Arg.String add_section, "name,offset,size,addr add a data section");
("--code", Arg.String add_section, "name,offset,size,addr add a code section");
("--startaddr", Arg.Set_string startaddr, "addr initial address (UNUSED)");
("--mainaddr", Arg.Set_string mainaddr, "addr address of the main section (entry point; default: 0)");
("--quiet", Arg.Clear Run_interp.debug, " do not display interpreter actions");
("--interactive", Arg.Clear eager_eval , " interactive execution");
] ;;
let time_it action arg =
let start_time = Sys.time () in
ignore (action arg);
let finish_time = Sys.time () in
finish_time -. start_time
;;
let get_reg reg name =
let reg_content = Reg.find (Id_aux(Id name, Unknown)) reg in
match to_num true reg_content with
| V_lit(L_aux(L_num n, Unknown)) -> n
| _ -> assert false
;;
let rec fde_loop count entry mem reg ?mode prog =
debugf "\n**** instruction %d ****\n" count;
match Run_interp.run ~entry ~mem ~reg ~eager_eval:!eager_eval ?mode prog with
| false, _, _ -> eprintf "FAILURE\n"; exit 1
| true, mode, (reg, mem) ->
if Big_int.eq_big_int (get_reg reg "CIA") lr_init_value then
eprintf "\nSUCCESS: returned with value %s\n"
(Big_int.string_of_big_int (get_reg reg "GPR3"))
else
fde_loop (count+1) entry mem reg ~mode:mode prog
;;
let run () =
Arg.parse args (fun _ -> raise (Arg.Bad "anonymous parameter")) "" ;
if !file = "" then begin
Arg.usage args "";
exit 1;
end;
if !eager_eval then Run_interp.debug := true;
let ic = open_in_bin !file in
if !sections = [] then begin
sections := [(0, in_channel_length ic, Big_int.zero_big_int)];
end;
let total_size = List.fold_left (fun n (_,s,_) -> n+s) 0 !sections in
eprintf "Loading binary into memory (%d bytes)... %!" total_size;
let t = time_it (List.iter (load_section ic)) !sections in
eprintf "done. (%f seconds)\n%!" t;
close_in ic;
let reg = init_reg () in
(* entry point: unit -> unit fde *)
let entry = E_aux(E_app(Id_aux((Id "fde"),Unknown),
[E_aux(E_lit (L_aux(L_unit,Unknown)),(Unknown,None))]),(Unknown,None)) in
let name = Filename.basename !file in
let t =time_it (fun () -> fde_loop 0 entry !mem reg (name, Power.defs)) () in
eprintf "Execution time: %f seconds\n" t
;;
run () ;;
|