|
1 | 1 | open Util |
| 2 | +module F = Format |
| 3 | +module L = Logger |
| 4 | + |
| 5 | +let parse_targets targets_file = |
| 6 | + (AUtil.readlines targets_file |
| 7 | + |> List.map (fun line -> |
| 8 | + let chunks = String.split_on_char ':' line in |
| 9 | + let filename = List.nth chunks 0 |> Filename.basename in |
| 10 | + let lineno = List.nth chunks 1 |> int_of_string in |
| 11 | + (filename, lineno)) |
| 12 | + |> List.sort_uniq compare |
| 13 | + |> List.hd) |
| 14 | + :: [] |
| 15 | + |
| 16 | +module BlockTrace = struct |
| 17 | + type t = int list |
| 18 | + |
| 19 | + let of_lines lines = |
| 20 | + (* SAFETY: if the file is generated, it has at least one line *) |
| 21 | + let lines = |
| 22 | + lines |
| 23 | + |> List.map (fun line -> |
| 24 | + match int_of_string_opt line with |
| 25 | + | Some n -> n |
| 26 | + | None -> |
| 27 | + F.eprintf "BlockTrace.of_lines: invalid line %s" line; |
| 28 | + exit 1) |
| 29 | + in |
| 30 | + match lines with |
| 31 | + | [] -> [] |
| 32 | + | _ -> |
| 33 | + let entrypoint = List.hd lines in |
| 34 | + let rec aux accu = function |
| 35 | + | [] -> accu |> List.map List.rev |
| 36 | + | hd :: tl when hd = entrypoint -> aux ([ hd ] :: accu) tl |
| 37 | + | hd :: tl -> ( |
| 38 | + match accu with |
| 39 | + | curr :: rest -> aux ((hd :: curr) :: rest) tl |
| 40 | + | _ -> failwith "unreachable") |
| 41 | + in |
| 42 | + |
| 43 | + (* [A;B;C;D;A;B;C] -> [[A;B;C;D]; [A;B;C]] *) |
| 44 | + aux [] lines |
| 45 | + |
| 46 | + (** Returns a list of traces. Note that a single coverage file (cov.cov) |
| 47 | + can contains many traces *) |
| 48 | + let read file = |
| 49 | + let lines = AUtil.readlines file in |
| 50 | + of_lines lines |
| 51 | + |
| 52 | + let empty = [] |
| 53 | + let union = List.append |
| 54 | + let diff _ _ = failwith "unneceesary" |
| 55 | + let cardinal = List.length |
| 56 | +end |
| 57 | + |
| 58 | +module IntInt = struct |
| 59 | + type t = int * int |
| 60 | + |
| 61 | + let compare = compare |
| 62 | + let equal = ( = ) |
| 63 | + let hash = Hashtbl.hash |
| 64 | +end |
| 65 | + |
| 66 | +module EdgeCoverage = struct |
| 67 | + include Set.Make (IntInt) |
| 68 | + |
| 69 | + let of_traces traces = |
| 70 | + traces |
| 71 | + |> List.map AUtil.pairs |
| 72 | + |> List.map of_list |
| 73 | + |> List.fold_left union empty |
| 74 | + |
| 75 | + let read file = |
| 76 | + let open AUtil in |
| 77 | + let traces = BlockTrace.read file in |
| 78 | + traces |> List.map pairs |> List.map of_list |> List.fold_left union empty |
| 79 | + |
| 80 | + let pp covset = iter (fun (i1, i2) -> L.debug "%d %d\n" i1 i2) covset |
| 81 | +end |
| 82 | + |
| 83 | +module type COVERAGE = sig |
| 84 | + type t |
| 85 | + |
| 86 | + val read : string -> t |
| 87 | + val empty : t |
| 88 | + val union : t -> t -> t |
| 89 | + val diff : t -> t -> t |
| 90 | + val cardinal : t -> int |
| 91 | +end |
| 92 | + |
| 93 | +module type PROGRESS = sig |
| 94 | + module Coverage : COVERAGE |
| 95 | + |
| 96 | + type t = { cov_sofar : Coverage.t; gen_count : int } |
| 97 | + |
| 98 | + val empty : t |
| 99 | + val inc_gen : t -> t |
| 100 | + val add_cov : Coverage.t -> t -> t |
| 101 | + val pp : Format.formatter -> t -> unit |
| 102 | +end |
| 103 | + |
| 104 | +module Progress (Coverage : COVERAGE) : |
| 105 | + PROGRESS with module Coverage = Coverage = struct |
| 106 | + module Coverage = Coverage |
| 107 | + |
| 108 | + type t = { cov_sofar : Coverage.t; gen_count : int } |
| 109 | + |
| 110 | + let empty = { cov_sofar = Coverage.empty; gen_count = 0 } |
| 111 | + let inc_gen p = { p with gen_count = p.gen_count + 1 } |
| 112 | + let add_cov cov p = { p with cov_sofar = Coverage.union p.cov_sofar cov } |
| 113 | + |
| 114 | + let pp fmt progress = |
| 115 | + F.fprintf fmt "generated: %d, coverage: %d" progress.gen_count |
| 116 | + (Coverage.cardinal progress.cov_sofar) |
| 117 | +end |
2 | 118 |
|
3 | 119 | (* Interprocedural call-flow graph *) |
4 | 120 |
|
@@ -330,3 +446,54 @@ module DistanceTable = struct |
330 | 446 | empty |
331 | 447 | |> map harmonic_avg |
332 | 448 | end |
| 449 | + |
| 450 | +let sliced_cfg_node_of_addr node_tbl distmap addr = |
| 451 | + match AddrToNode.find_opt node_tbl addr with |
| 452 | + | None -> None (* in CFG of a function other than the target function *) |
| 453 | + | Some node -> if DistanceTable.mem node distmap then Some node else None |
| 454 | + |
| 455 | +let load_cfgs_from_dir cfg_dir = |
| 456 | + Sys.readdir cfg_dir |
| 457 | + |> Array.to_list |
| 458 | + |> List.map (fun filename -> Filename.concat cfg_dir filename) |
| 459 | + |> List.filter (fun filename -> Filename.check_suffix filename ".dot") |
| 460 | + |> List.filter_map ControlFlowGraph.of_dot_file |
| 461 | + |
| 462 | +module CfgDistance = struct |
| 463 | + type t = float |
| 464 | + |
| 465 | + (** computes distance of a trace *) |
| 466 | + let distance_score (traces : BlockTrace.t list) node_tbl distmap = |
| 467 | + let nodes_in_trace = |
| 468 | + traces |
| 469 | + |> List.flatten |
| 470 | + |> List.sort_uniq compare |
| 471 | + |> List.filter_map (sliced_cfg_node_of_addr node_tbl distmap) |
| 472 | + in |
| 473 | + let dist_sum : float = |
| 474 | + nodes_in_trace |
| 475 | + |> List.fold_left |
| 476 | + (fun sum node -> |
| 477 | + let dist = DistanceTable.find_opt node distmap in |
| 478 | + match dist with None -> sum | Some dist -> sum +. dist) |
| 479 | + 0.0 |
| 480 | + in |
| 481 | + (* let min_dist = |
| 482 | + nodes_in_trace |
| 483 | + |> List.filter_map (fun node -> Cfg.NodeMap.find_opt node distmap) |
| 484 | + |> List.fold_left (fun accu dist -> Float.min accu dist) 65535.0 |
| 485 | + in *) |
| 486 | + if nodes_in_trace = [] then 65535.0 |
| 487 | + else |
| 488 | + let size = List.length nodes_in_trace |> float_of_int in |
| 489 | + dist_sum /. size |
| 490 | + |
| 491 | + let get_cover (traces : BlockTrace.t list) node_tbl distmap = |
| 492 | + traces |
| 493 | + |> List.exists |
| 494 | + (List.exists (fun addr -> |
| 495 | + let node = AddrToNode.find_opt node_tbl addr in |
| 496 | + match node with |
| 497 | + | None -> false |
| 498 | + | Some node -> DistanceTable.find_opt node distmap = Some 0.0)) |
| 499 | +end |
0 commit comments