callgen.ml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. (* abi fuzzer, generates two modules one calling
  2. * the other in two possibly different languages
  3. *)
  4. type _ bty =
  5. | Char: int bty
  6. | Short: int bty
  7. | Int: int bty
  8. | Long: int bty
  9. | Float: float bty
  10. | Double: float bty
  11. type _ sty =
  12. | Field: 'a bty * 'b sty -> ('a * 'b) sty
  13. | Empty: unit sty
  14. type _ aty =
  15. | Base: 'a bty -> 'a aty
  16. | Struct: 'a sty -> 'a aty
  17. type anyb = AB: _ bty -> anyb (* kinda boring... *)
  18. type anys = AS: _ sty -> anys
  19. type anya = AA: _ aty -> anya
  20. type testb = TB: 'a bty * 'a -> testb
  21. type testa = TA: 'a aty * 'a -> testa
  22. let align a x =
  23. let m = x mod a in
  24. if m <> 0 then x + (a-m) else x
  25. let btysize: type a. a bty -> int = function
  26. | Char -> 1
  27. | Short -> 2
  28. | Int -> 4
  29. | Long -> 8
  30. | Float -> 4
  31. | Double -> 8
  32. let btyalign = btysize
  33. let styempty: type a. a sty -> bool = function
  34. | Field _ -> false
  35. | Empty -> true
  36. let stysize s =
  37. let rec f: type a. int -> a sty -> int =
  38. fun sz -> function
  39. | Field (b, s) ->
  40. let a = btyalign b in
  41. f (align a sz + btysize b) s
  42. | Empty -> sz in
  43. f 0 s
  44. let rec styalign: type a. a sty -> int = function
  45. | Field (b, s) -> max (btyalign b) (styalign s)
  46. | Empty -> 1
  47. (* Generate types and test vectors. *)
  48. module Gen = struct
  49. module R = Random
  50. let init = function
  51. | None ->
  52. let f = open_in "/dev/urandom" in
  53. let seed =
  54. Char.code (input_char f) lsl 16 +
  55. Char.code (input_char f) lsl 8 +
  56. Char.code (input_char f) in
  57. close_in f;
  58. R.init seed;
  59. seed
  60. | Some seed ->
  61. R.init seed;
  62. seed
  63. let int sz =
  64. let bound = 1 lsl (8 * min sz 3 - 1) in
  65. let i = R.int bound in
  66. if R.bool () then - i else i
  67. let float () =
  68. let f = R.float 1000. in
  69. if R.bool () then -. f else f
  70. let testv: type a. a aty -> a =
  71. let tb: type a. a bty -> a = function (* eh, dry... *)
  72. | Float -> float ()
  73. | Double -> float ()
  74. | Char -> int (btysize Char)
  75. | Short -> int (btysize Short)
  76. | Int -> int (btysize Int)
  77. | Long -> int (btysize Long) in
  78. let rec ts: type a. a sty -> a = function
  79. | Field (b, s) -> (tb b, ts s)
  80. | Empty -> () in
  81. function
  82. | Base b -> tb b
  83. | Struct s -> ts s
  84. let b () = (* uniform *)
  85. match R.int 6 with
  86. | 0 -> AB Char
  87. | 1 -> AB Short
  88. | 2 -> AB Int
  89. | 3 -> AB Long
  90. | 4 -> AB Float
  91. | _ -> AB Double
  92. let smax = 5 (* max elements in structs *)
  93. let structp = 0.3 (* odds of having a struct type *)
  94. let amax = 8 (* max function arguments *)
  95. let s () =
  96. let rec f n =
  97. if n = 0 then AS Empty else
  98. let AB bt = b () in
  99. let AS st = f (n-1) in
  100. AS (Field (bt, st)) in
  101. f (1 + R.int (smax-1))
  102. let a () =
  103. if R.float 1.0 > structp then
  104. let AB bt = b () in
  105. AA (Base bt)
  106. else
  107. let AB bt = b () in
  108. let AS st = s () in
  109. AA (Struct (Field (bt, st)))
  110. let test () =
  111. let AA ty = a () in
  112. let t = testv ty in
  113. TA (ty, t)
  114. let tests () =
  115. let rec f n =
  116. if n = 0 then [] else
  117. test () :: f (n-1) in
  118. f (R.int amax)
  119. end
  120. (* Code generation for C *)
  121. module OutC = struct
  122. open Printf
  123. let ctypelong oc name =
  124. let cb: type a. a bty -> unit = function
  125. | Char -> fprintf oc "char"
  126. | Short -> fprintf oc "short"
  127. | Int -> fprintf oc "int"
  128. | Long -> fprintf oc "long"
  129. | Float -> fprintf oc "float"
  130. | Double -> fprintf oc "double" in
  131. let rec cs: type a. int -> a sty -> unit =
  132. fun i -> function
  133. | Field (b, s) ->
  134. cb b;
  135. fprintf oc " f%d; " i;
  136. cs (i+1) s;
  137. | Empty -> () in
  138. function
  139. | Base b ->
  140. cb b;
  141. | Struct s ->
  142. fprintf oc "struct %s { " name;
  143. cs 1 s;
  144. fprintf oc "}";
  145. ()
  146. let ctype: type a. out_channel -> string -> a aty -> unit =
  147. fun oc name -> function
  148. | Struct _ -> fprintf oc "struct %s" name
  149. | t -> ctypelong oc "" t
  150. let base: type a. out_channel -> a bty * a -> unit =
  151. fun oc -> function
  152. | Char, i -> fprintf oc "%d" i
  153. | Short, i -> fprintf oc "%d" i
  154. | Int, i -> fprintf oc "%d" i
  155. | Long, i -> fprintf oc "%d" i
  156. | Float, f -> fprintf oc "%ff" f
  157. | Double, f -> fprintf oc "%f" f
  158. let init oc name (TA (ty, t)) =
  159. let inits s =
  160. let rec f: type a. a sty * a -> unit = function
  161. | Field (b, s), (tb, ts) ->
  162. base oc (b, tb);
  163. fprintf oc ", ";
  164. f (s, ts)
  165. | Empty, () -> () in
  166. fprintf oc "{ ";
  167. f s;
  168. fprintf oc "}"; in
  169. ctype oc name ty;
  170. fprintf oc " %s = " name;
  171. begin match (ty, t) with
  172. | Base b, tb -> base oc (b, tb)
  173. | Struct s, ts -> inits (s, ts)
  174. end;
  175. fprintf oc ";\n";
  176. ()
  177. let extension = ".c"
  178. let comment oc s =
  179. fprintf oc "/* %s */\n" s
  180. let prelude oc = List.iter (fprintf oc "%s\n")
  181. [ "#include <stdio.h>"
  182. ; "#include <stdlib.h>"
  183. ; ""
  184. ; "static void fail(char *chk)"
  185. ; "{"
  186. ; "\tfprintf(stderr, \"fail: checking %s\\n\", chk);"
  187. ; "\tabort();"
  188. ; "}"
  189. ; ""
  190. ]
  191. let typedef oc name = function
  192. | TA (Struct ts, _) ->
  193. ctypelong oc name (Struct ts);
  194. fprintf oc ";\n";
  195. | _ -> ()
  196. let check oc name =
  197. let chkbase: type a. string -> a bty * a -> unit =
  198. fun name t ->
  199. fprintf oc "\tif (%s != " name;
  200. base oc t;
  201. fprintf oc ")\n\t\tfail(%S);\n" name; in
  202. function
  203. | TA (Base b, tb) -> chkbase name (b, tb)
  204. | TA (Struct s, ts) ->
  205. let rec f: type a. int -> a sty * a -> unit =
  206. fun i -> function
  207. | Field (b, s), (tb, ts) ->
  208. chkbase (Printf.sprintf "%s.f%d" name i) (b, tb);
  209. f (i+1) (s, ts);
  210. | Empty, () -> () in
  211. f 1 (s, ts)
  212. let argname i = "arg" ^ string_of_int (i+1)
  213. let proto oc (TA (tret, _)) args =
  214. ctype oc "ret" tret;
  215. fprintf oc " f(";
  216. let narg = List.length args in
  217. List.iteri (fun i (TA (targ, _)) ->
  218. ctype oc (argname i) targ;
  219. fprintf oc " %s" (argname i);
  220. if i <> narg-1 then
  221. fprintf oc ", ";
  222. ) args;
  223. fprintf oc ")";
  224. ()
  225. let caller oc ret args =
  226. let narg = List.length args in
  227. prelude oc;
  228. typedef oc "ret" ret;
  229. List.iteri (fun i arg ->
  230. typedef oc (argname i) arg;
  231. ) args;
  232. proto oc ret args;
  233. fprintf oc ";\n\nint main()\n{\n";
  234. List.iteri (fun i arg ->
  235. fprintf oc "\t";
  236. init oc (argname i) arg;
  237. ) args;
  238. fprintf oc "\t";
  239. let TA (tret, _) = ret in
  240. ctype oc "ret" tret;
  241. fprintf oc " ret;\n\n";
  242. fprintf oc "\tret = f(";
  243. List.iteri (fun i _ ->
  244. fprintf oc "%s" (argname i);
  245. if i <> narg-1 then
  246. fprintf oc ", ";
  247. ) args;
  248. fprintf oc ");\n";
  249. check oc "ret" ret;
  250. fprintf oc "\n\treturn 0;\n}\n";
  251. ()
  252. let callee oc ret args =
  253. prelude oc;
  254. typedef oc "ret" ret;
  255. List.iteri (fun i arg ->
  256. typedef oc (argname i) arg;
  257. ) args;
  258. fprintf oc "\n";
  259. proto oc ret args;
  260. fprintf oc "\n{\n\t";
  261. init oc "ret" ret;
  262. fprintf oc "\n";
  263. List.iteri (fun i arg ->
  264. check oc (argname i) arg;
  265. ) args;
  266. fprintf oc "\n\treturn ret;\n}\n";
  267. ()
  268. end
  269. (* Code generation for QBE *)
  270. module OutIL = struct
  271. open Printf
  272. let comment oc s =
  273. fprintf oc "# %s\n" s
  274. let tmp, lbl =
  275. let next = ref 0 in
  276. (fun () -> incr next; "%t" ^ (string_of_int !next)),
  277. (fun () -> incr next; "@l" ^ (string_of_int !next))
  278. let bvalue: type a. a bty * a -> string = function
  279. | Char, i -> sprintf "%d" i
  280. | Short, i -> sprintf "%d" i
  281. | Int, i -> sprintf "%d" i
  282. | Long, i -> sprintf "%d" i
  283. | Float, f -> sprintf "s_%f" f
  284. | Double, f -> sprintf "d_%f" f
  285. let btype: type a. a bty -> string = function
  286. | Char -> "w"
  287. | Short -> "w"
  288. | Int -> "w"
  289. | Long -> "l"
  290. | Float -> "s"
  291. | Double -> "d"
  292. let extension = ".ssa"
  293. let argname i = "arg" ^ string_of_int (i+1)
  294. let siter oc base s g =
  295. let rec f: type a. int -> int -> a sty * a -> unit =
  296. fun id off -> function
  297. | Field (b, s), (tb, ts) ->
  298. let off = align (btyalign b) off in
  299. let addr = tmp () in
  300. fprintf oc "\t%s =l add %d, %s\n" addr off base;
  301. g id addr (TB (b, tb));
  302. f (id + 1) (off + btysize b) (s, ts);
  303. | Empty, () -> () in
  304. f 0 0 s
  305. let bmemtype b =
  306. if AB b = AB Char then "b" else
  307. if AB b = AB Short then "h" else
  308. btype b
  309. let init oc = function
  310. | TA (Base b, tb) -> bvalue (b, tb)
  311. | TA (Struct s, ts) ->
  312. let base = tmp () in
  313. fprintf oc "\t%s =l alloc%d %d\n"
  314. base (styalign s) (stysize s);
  315. siter oc base (s, ts)
  316. begin fun _ addr (TB (b, tb)) ->
  317. fprintf oc "\tstore%s %s, %s\n"
  318. (bmemtype b) (bvalue (b, tb)) addr;
  319. end;
  320. base
  321. let check oc id name =
  322. let bcheck = fun id name (b, tb) ->
  323. let tcmp = tmp () in
  324. let nxtl = lbl () in
  325. fprintf oc "\t%s =w ceq%s %s, %s\n"
  326. tcmp (btype b) name (bvalue (b, tb));
  327. fprintf oc "\tstorew %d, %%failcode\n" id;
  328. fprintf oc "\tjnz %s, %s, @fail\n" tcmp nxtl;
  329. fprintf oc "%s\n" nxtl; in
  330. function
  331. | TA (Base Char, i) ->
  332. let tval = tmp () in
  333. fprintf oc "\t%s =w extsb %s\n" tval name;
  334. bcheck id tval (Int, i)
  335. | TA (Base Short, i) ->
  336. let tval = tmp () in
  337. fprintf oc "\t%s =w extsh %s\n" tval name;
  338. bcheck id tval (Int, i)
  339. | TA (Base b, tb) ->
  340. bcheck id name (b, tb)
  341. | TA (Struct s, ts) ->
  342. siter oc name (s, ts)
  343. begin fun id' addr (TB (b, tb)) ->
  344. let tval = tmp () in
  345. let lsuffix =
  346. if AB b = AB Char then "sb" else
  347. if AB b = AB Short then "sh" else
  348. "" in
  349. fprintf oc "\t%s =%s load%s %s\n"
  350. tval (btype b) lsuffix addr;
  351. bcheck (100*id + id'+1) tval (b, tb);
  352. end;
  353. ()
  354. let ttype name = function
  355. | TA (Base b, _) -> btype b
  356. | TA (Struct _, _) -> ":" ^ name
  357. let typedef oc name =
  358. let rec f: type a. a sty -> unit = function
  359. | Field (b, s) ->
  360. fprintf oc "%s" (bmemtype b);
  361. if not (styempty s) then
  362. fprintf oc ", ";
  363. f s;
  364. | Empty -> () in
  365. function
  366. | TA (Struct ts, _) ->
  367. fprintf oc "type :%s = { " name;
  368. f ts;
  369. fprintf oc " }\n";
  370. | _ -> ()
  371. let postlude oc = List.iter (fprintf oc "%s\n")
  372. [ "@fail"
  373. ; "# failure code"
  374. ; "\t%fcode =w loadw %failcode"
  375. ; "\t%f0 =w call $printf(l $failstr, w %fcode)"
  376. ; "\t%f1 =w call $abort()"
  377. ; "\tret 0"
  378. ; "}"
  379. ; ""
  380. ; "data $failstr = { b \"fail on check %d\\n\", b 0 }"
  381. ]
  382. let caller oc ret args =
  383. let narg = List.length args in
  384. List.iteri (fun i arg ->
  385. typedef oc (argname i) arg;
  386. ) args;
  387. typedef oc "ret" ret;
  388. fprintf oc "\nexport function w $main() {\n";
  389. fprintf oc "@start\n";
  390. fprintf oc "\t%%failcode =l alloc4 4\n";
  391. let targs = List.mapi (fun i arg ->
  392. comment oc ("define argument " ^ (string_of_int (i+1)));
  393. (ttype (argname i) arg, init oc arg)
  394. ) args in
  395. comment oc "call test function";
  396. fprintf oc "\t%%ret =%s call $f(" (ttype "ret" ret);
  397. List.iteri (fun i (ty, tmp) ->
  398. fprintf oc "%s %s" ty tmp;
  399. if i <> narg-1 then
  400. fprintf oc ", ";
  401. ) targs;
  402. fprintf oc ")\n";
  403. comment oc "check the return value";
  404. check oc 0 "%ret" ret;
  405. fprintf oc "\tret 0\n";
  406. postlude oc;
  407. ()
  408. let callee oc ret args =
  409. let narg = List.length args in
  410. List.iteri (fun i arg ->
  411. typedef oc (argname i) arg;
  412. ) args;
  413. typedef oc "ret" ret;
  414. fprintf oc "\nexport function %s $f(" (ttype "ret" ret);
  415. List.iteri (fun i arg ->
  416. let a = argname i in
  417. fprintf oc "%s %%%s" (ttype a arg) a;
  418. if i <> narg-1 then
  419. fprintf oc ", ";
  420. ) args;
  421. fprintf oc ") {\n";
  422. fprintf oc "@start\n";
  423. fprintf oc "\t%%failcode =l alloc4 4\n";
  424. List.iteri (fun i arg ->
  425. comment oc ("checking argument " ^ (string_of_int (i+1)));
  426. check oc (i+1) ("%" ^ argname i) arg;
  427. ) args;
  428. comment oc "define the return value";
  429. let rettmp = init oc ret in
  430. fprintf oc "\tret %s\n" rettmp;
  431. postlude oc;
  432. ()
  433. end
  434. module type OUT = sig
  435. val extension: string
  436. val comment: out_channel -> string -> unit
  437. val caller: out_channel -> testa -> testa list -> unit
  438. val callee: out_channel -> testa -> testa list -> unit
  439. end
  440. let _ =
  441. let usage code =
  442. Printf.eprintf "usage: abi.ml [-s SEED] DIR {c,ssa} {c,ssa}\n";
  443. exit code in
  444. let outmod = function
  445. | "c" -> (module OutC : OUT)
  446. | "ssa" -> (module OutIL: OUT)
  447. | _ -> usage 1 in
  448. let seed, dir, mcaller, mcallee =
  449. match Sys.argv with
  450. | [| _; "-s"; seed; dir; caller; callee |] ->
  451. let seed =
  452. try Some (int_of_string seed) with
  453. Failure _ -> usage 1 in
  454. seed, dir, outmod caller, outmod callee
  455. | [| _; dir; caller; callee |] ->
  456. None, dir, outmod caller, outmod callee
  457. | [| _; "-h" |] ->
  458. usage 0
  459. | _ ->
  460. usage 1 in
  461. let seed = Gen.init seed in
  462. let tret = Gen.test () in
  463. let targs = Gen.tests () in
  464. let module OCaller = (val mcaller : OUT) in
  465. let module OCallee = (val mcallee : OUT) in
  466. let ocaller = open_out (dir ^ "/caller" ^ OCaller.extension) in
  467. let ocallee = open_out (dir ^ "/callee" ^ OCallee.extension) in
  468. OCaller.comment ocaller (Printf.sprintf "seed %d" seed);
  469. OCallee.comment ocallee (Printf.sprintf "seed %d" seed);
  470. OCaller.caller ocaller tret targs;
  471. OCallee.callee ocallee tret targs;
  472. ()