// This script finds direct branches in a binary let array = import! "std/array.glu" let falcon = import! "scripts/falcon.glu" let function = import! "std/function.glu" let io = import! "std/io.glu" let list = import! "std/list.glu" let types = import! "std/types.glu" let { il, loader } = falcon let { Expression, Operation } = falcon.types let { List } = list let { (|>) } = function let {(++)} = import! "std/string.glu" let { Option, Bool } = types let append l m = match l with | Nil -> m | Cons hd tl -> Cons hd (append tl m) let flatten l = match l with | Nil -> Nil | Cons hd tl -> append hd (flatten tl) let filter f l = match l with | Nil -> Nil | Cons hd tl -> if f hd then Cons hd (filter f tl) else filter f tl let unwrap option = match option with | Some x -> x | None -> error "unwrapped option with value None" let is_some option = match option with | Some _ -> True | None -> False let foldl f x xs = match xs with | Cons y ys -> foldl f (f x y) ys | Nil -> x let map f l = match l with | Nil -> Nil | Cons hd tl -> Cons (f hd) (map f tl) let all_constants e : IlExpression -> Bool = match il.expression.match_ e with | Scalar s -> False | Constant c -> True | Add l r -> (all_constants l) && (all_constants r) | Sub l r -> (all_constants l) && (all_constants r) | Mul l r -> (all_constants l) && (all_constants r) | Divu l r -> (all_constants l) && (all_constants r) | Modu l r -> (all_constants l) && (all_constants r) | Divs l r -> (all_constants l) && (all_constants r) | Mods l r -> (all_constants l) && (all_constants r) | And l r -> (all_constants l) && (all_constants r) | Or l r -> (all_constants l) && (all_constants r) | Xor l r -> (all_constants l) && (all_constants r) | Shl l r -> (all_constants l) && (all_constants r) | Shr l r -> (all_constants l) && (all_constants r) | Cmpeq l r -> (all_constants l) && (all_constants r) | Cmpneq l r -> (all_constants l) && (all_constants r) | Cmpltu l r -> (all_constants l) && (all_constants r) | Cmplts l r -> (all_constants l) && (all_constants r) | Zext _ src -> (all_constants src) | Sext _ src -> (all_constants src) | Trun _ src -> (all_constants src) let filename = match falcon.env "FILENAME" with | Some filename -> filename | None -> error "Could not get filename" let function_name = match falcon.env "FUNCTION_NAME" with | Some function_name -> function_name | None -> "Could not get function name" let brc_is_direct instruction : IlInstruction -> Bool = match il.instruction.operation instruction |> il.operation.match_ with | Branch target -> all_constants target | _ -> error "brc_is_direct given non-brc instruction" let find_brcs function : IlFunction -> List IlInstruction = let is_brc i = match il.operation.match_ (il.instruction.operation i) with | Branch target -> Some i | _ -> None let control_flow_graph = il.function.control_flow_graph function let blocks = il.control_flow_graph.blocks control_flow_graph |> list.of let instructions = map il.block.instructions blocks |> map list.of |> flatten map is_brc instructions |> filter is_some |> map unwrap let find_function binary function_name = let find functions i name = if i == (array.len functions) then None else let function_entry = array.index functions i match loader.function_entry.name function_entry with | Some entry_name -> if entry_name == name then Some function_entry else find functions (i + 1) name | None -> find functions (i + 1) name find (loader.loader.function_entries binary) 0 function_name let binary = match loader.loader.from_file filename with | Some x -> x | None -> error "Failed to load binary" let function_entry = match find_function binary function_name with | Some function_entry -> function_entry | None -> error "failed to find function entry" let function = loader.function_entry.address function_entry |> loader.loader.function binary let brcs = find_brcs function |> filter brc_is_direct let strings = map il.instruction.str brcs let lines = foldl (\ l r -> l ++ "\n" ++ r) "" strings falcon.println lines