Simplest: change workflow
This commit is contained in:
parent
aec0ab59ad
commit
9f09dec677
1 changed files with 63 additions and 124 deletions
|
@ -173,11 +173,12 @@ let interpret_var_expr c_var offset expr = BStd.Bil.(
|
|||
| _ -> None
|
||||
)
|
||||
|
||||
let process_def def (cur_offset: memory_offset)
|
||||
: ((cfa_pos * memory_offset) option) =
|
||||
let lose_track = Some (CfaLostTrack, Int64.zero) in
|
||||
(match Regs.X86_64.of_var (BStd.Def.lhs def) with
|
||||
| Some reg when reg = Regs.X86_64.rsp ->
|
||||
let process_def def (cur_cfa: cfa_pos)
|
||||
: (cfa_pos option) =
|
||||
let lose_track = Some (CfaLostTrack) in
|
||||
|
||||
(match cur_cfa, Regs.X86_64.of_var (BStd.Def.lhs def) with
|
||||
| RspOffset(cur_offset), Some reg when reg = Regs.X86_64.rsp ->
|
||||
let exp = BStd.Def.rhs def in
|
||||
let free_vars = BStd.Exp.free_vars exp in
|
||||
let free_x86_regs = Regs.X86_64.map_varset free_vars in
|
||||
|
@ -193,7 +194,7 @@ let process_def def (cur_offset: memory_offset)
|
|||
(match interpreted with
|
||||
| None -> lose_track
|
||||
| Some new_offset ->
|
||||
Some (RspOffset(new_offset), new_offset)
|
||||
Some (RspOffset(new_offset))
|
||||
)
|
||||
| _ -> lose_track
|
||||
)
|
||||
|
@ -201,11 +202,14 @@ let process_def def (cur_offset: memory_offset)
|
|||
)
|
||||
| _ -> None)
|
||||
|
||||
let process_jmp jmp (cur_offset: memory_offset)
|
||||
: ((cfa_pos * memory_offset) option) =
|
||||
let gen_change off =
|
||||
let new_offset = Int64.add cur_offset (Int64.of_int off) in
|
||||
Some (RspOffset(new_offset), new_offset)
|
||||
let process_jmp jmp (cur_cfa: cfa_pos)
|
||||
: (cfa_pos option) =
|
||||
let gen_change = match cur_cfa with
|
||||
| RspOffset cur_offset -> (fun off ->
|
||||
let new_offset = Int64.add cur_offset (Int64.of_int off) in
|
||||
Some (RspOffset(new_offset))
|
||||
)
|
||||
| _ -> (fun _ -> None)
|
||||
in
|
||||
|
||||
match (BStd.Jmp.kind jmp) with
|
||||
|
@ -213,14 +217,13 @@ let process_jmp jmp (cur_offset: memory_offset)
|
|||
| BStd.Ret ret -> gen_change (8)
|
||||
| _ -> None
|
||||
|
||||
let sym_of_blk next_instr_graph blk : cfa_changes_fde =
|
||||
(** Extracts the symbolic CFA changes of a block. These changes assume that
|
||||
at the beginning of the block, CFA = RspOffset(0) and will be offset
|
||||
after *)
|
||||
let process_blk
|
||||
next_instr_graph (block_init: cfa_pos) blk : (cfa_changes_fde * cfa_pos) =
|
||||
(** Extracts the CFA changes of a block. *)
|
||||
|
||||
let apply_offset cur_addr_opt ((accu:cfa_change list), cur_offset) = function
|
||||
| None -> (accu, cur_offset)
|
||||
| Some (pos, n_offset) ->
|
||||
let apply_offset cur_addr_opt ((accu:cfa_change list), cur_cfa) = function
|
||||
| None -> (accu, cur_cfa)
|
||||
| Some pos ->
|
||||
let cur_addr = (match cur_addr_opt with
|
||||
| None -> assert false
|
||||
| Some x -> to_int64_addr x) in
|
||||
|
@ -229,55 +232,27 @@ let sym_of_blk next_instr_graph blk : cfa_changes_fde =
|
|||
(change :: cur_accu))
|
||||
(AddrMap.find cur_addr next_instr_graph)
|
||||
accu),
|
||||
n_offset
|
||||
pos
|
||||
in
|
||||
|
||||
let fold_elt (accu, cur_offset) elt = match elt with
|
||||
let fold_elt (accu, cur_cfa) elt = match elt with
|
||||
| `Def(def) ->
|
||||
apply_offset
|
||||
(opt_addr_of def) (accu, cur_offset) @@ process_def def cur_offset
|
||||
(opt_addr_of def) (accu, cur_cfa) @@ process_def def cur_cfa
|
||||
| `Jmp(jmp) ->
|
||||
apply_offset
|
||||
(opt_addr_of jmp) (accu, cur_offset) @@ process_jmp jmp cur_offset
|
||||
| _ -> (accu, cur_offset)
|
||||
(opt_addr_of jmp) (accu, cur_cfa) @@ process_jmp jmp cur_cfa
|
||||
| _ -> (accu, cur_cfa)
|
||||
in
|
||||
|
||||
let elts_seq = BStd.Blk.elts blk in
|
||||
let out, end_offset = BStd.Seq.fold elts_seq
|
||||
~init:([], Int64.zero)
|
||||
let out, end_cfa = BStd.Seq.fold elts_seq
|
||||
~init:([], block_init)
|
||||
~f:fold_elt in
|
||||
out
|
||||
|
||||
let end_offset (changelist: cfa_changes_fde): memory_offset option =
|
||||
match changelist with
|
||||
| CfaChange(_, RspOffset(x)) :: _ -> Some x
|
||||
| _ -> None
|
||||
out, end_cfa
|
||||
|
||||
exception Inconsistent of BStd.tid
|
||||
|
||||
let rec dfs_propagate changemap propagated parent_val node graph =
|
||||
let c_tid = BStd.Term.tid @@ CFG.Node.label node in
|
||||
match TIdMap.find_opt c_tid propagated with
|
||||
| Some x ->
|
||||
if x = parent_val then
|
||||
(* Already propagated and consistent, all fine *)
|
||||
propagated
|
||||
else
|
||||
(* Already propagated with a different value: inconsistency *)
|
||||
raise (Inconsistent c_tid)
|
||||
| None ->
|
||||
let n_propagated = TIdMap.add c_tid parent_val propagated in
|
||||
let outwards = CFG.Node.outputs node graph in
|
||||
let self_entry = TIdMap.find c_tid changemap in
|
||||
let offset = (match end_offset self_entry with
|
||||
Some x -> x
|
||||
| None -> Int64.zero) in
|
||||
let cur_val = Int64.add parent_val offset in
|
||||
BStd.Seq.fold outwards
|
||||
~init:n_propagated
|
||||
~f:(fun accu edge ->
|
||||
dfs_propagate changemap accu cur_val (CFG.Edge.dst edge) graph)
|
||||
|
||||
let get_entry_blk graph =
|
||||
let entry = BStd.Seq.min_elt (CFG.nodes graph) ~cmp:(fun x y ->
|
||||
let ax = opt_addr_of @@ CFG.Node.label x
|
||||
|
@ -292,14 +267,7 @@ let get_entry_blk graph =
|
|||
| None -> assert false
|
||||
| Some x -> x
|
||||
|
||||
let same_keys map1 map2 =
|
||||
let exists_in_other other key _ =
|
||||
TIdMap.mem key other in
|
||||
|
||||
TIdMap.for_all (exists_in_other map2) map1
|
||||
&& TIdMap.for_all (exists_in_other map1) map2
|
||||
|
||||
let of_sub sub : cfa_changes_fde =
|
||||
let process_sub sub : cfa_changes_fde =
|
||||
(** Extracts the `cfa_changes_fde` of a subroutine *)
|
||||
|
||||
Format.eprintf "Sub %s...@." @@ BStd.Sub.name sub ;
|
||||
|
@ -308,77 +276,48 @@ let of_sub sub : cfa_changes_fde =
|
|||
let next_instr_graph = build_next_instr cfg in
|
||||
|
||||
let initial_cfa_rsp_offset = Int64.of_int 8 in
|
||||
let store_sym accu blk =
|
||||
let blk = CFG.Node.label blk in
|
||||
let res = sym_of_blk next_instr_graph blk in
|
||||
TIdMap.add (BStd.Term.tid blk) res accu
|
||||
in
|
||||
|
||||
let node_addr nd = opt_addr_of @@ CFG.Node.label nd in
|
||||
let rec dfs_process
|
||||
(sub_changes: (cfa_changes_fde * cfa_pos) TIdMap.t) node entry_offset =
|
||||
(** Processes one block *)
|
||||
|
||||
let merge_corrected blk_tid changes offset = match (changes, offset) with
|
||||
| Some changes, Some offset ->
|
||||
Some (
|
||||
List.map (fun (CfaChange(addr, pos)) -> match pos with
|
||||
RspOffset(off) -> CfaChange(addr,
|
||||
RspOffset(Int64.add off offset))
|
||||
| RbpOffset(off) -> CfaChange(addr, RbpOffset(off))
|
||||
| CfaLostTrack -> CfaChange(addr, CfaLostTrack)
|
||||
)
|
||||
changes
|
||||
)
|
||||
| _ -> None
|
||||
in
|
||||
let cur_blk = CFG.Node.label node in
|
||||
let tid = BStd.Term.tid @@ cur_blk in
|
||||
|
||||
let tid_match = BStd.Seq.fold (CFG.nodes cfg)
|
||||
~init:TIdMap.empty
|
||||
~f:(fun accu node ->
|
||||
let tid = BStd.Term.tid @@ CFG.Node.label node in
|
||||
TIdMap.add tid node accu)
|
||||
in
|
||||
|
||||
let blk_sym = BStd.Seq.fold
|
||||
~init:TIdMap.empty
|
||||
~f:store_sym
|
||||
@@ CFG.nodes cfg
|
||||
match (TIdMap.find_opt tid sub_changes) with
|
||||
| None ->
|
||||
(* Not yet visited: compute the changes *)
|
||||
let cur_blk_changes, end_cfa =
|
||||
process_blk next_instr_graph entry_offset cur_blk in
|
||||
let n_sub_changes =
|
||||
TIdMap.add tid (cur_blk_changes, entry_offset) sub_changes in
|
||||
BStd.Seq.fold (CFG.Node.succs node cfg)
|
||||
~f:(fun accu child -> dfs_process accu child end_cfa)
|
||||
~init:n_sub_changes
|
||||
| Some (_, former_entry_offset) ->
|
||||
(* Already visited: check that entry values are matching *)
|
||||
if entry_offset <> former_entry_offset then
|
||||
raise (Inconsistent tid)
|
||||
else
|
||||
sub_changes
|
||||
in
|
||||
|
||||
let entry_blk = get_entry_blk cfg in
|
||||
let offset_map = dfs_propagate
|
||||
blk_sym (TIdMap.empty) initial_cfa_rsp_offset entry_blk cfg in
|
||||
let initial_offset = (RspOffset initial_cfa_rsp_offset) in
|
||||
let changes_map = dfs_process TIdMap.empty entry_blk initial_offset in
|
||||
|
||||
let corrected = TIdMap.merge merge_corrected blk_sym offset_map in
|
||||
let merged_changes = TIdMap.fold
|
||||
(fun _ (cfa_changes, _) accu -> cfa_changes @ accu)
|
||||
changes_map
|
||||
[CfaChange(int64_addr_of sub, initial_offset)] in
|
||||
|
||||
let is_connex = same_keys tid_match corrected in
|
||||
if not is_connex then
|
||||
raise InvalidSub ;
|
||||
|
||||
let tid_list = TIdMap.bindings tid_match in
|
||||
let sorted_blk = List.sort (fun (tid1, bl1) (tid2, bl2) ->
|
||||
let res = match (node_addr bl1, node_addr bl2) with
|
||||
| Some addr1, Some addr2 -> compare addr1 addr2
|
||||
| Some _, None -> 1
|
||||
| None, Some _ -> -1
|
||||
| None, None -> compare tid1 tid2
|
||||
let sorted_changes = List.sort
|
||||
(fun (CfaChange (addr1, _)) (CfaChange (addr2, _)) ->
|
||||
compare addr1 addr2)
|
||||
merged_changes
|
||||
in
|
||||
-res)
|
||||
tid_list
|
||||
in
|
||||
|
||||
let out = List.fold_left
|
||||
(fun accu blk ->
|
||||
let changes = TIdMap.find blk corrected in
|
||||
List.fold_left (fun accu chg -> chg::accu)
|
||||
accu
|
||||
changes
|
||||
)
|
||||
[]
|
||||
(List.map (fun (x, y) -> x) sorted_blk) in
|
||||
|
||||
let init = [
|
||||
CfaChange(int64_addr_of sub, RspOffset(initial_cfa_rsp_offset))
|
||||
] in
|
||||
init @ out
|
||||
sorted_changes
|
||||
|
||||
let cleanup_fde (fde_changes: cfa_changes_fde) : cfa_changes_fde =
|
||||
(** Cleanup the result of `of_sub`.
|
||||
|
@ -429,7 +368,7 @@ let of_prog prog : cfa_changes =
|
|||
(** Extracts the `cfa_changes` of a program *)
|
||||
let fold_step accu sub =
|
||||
(try
|
||||
let res = cleanup_fde @@ of_sub sub in
|
||||
let res = cleanup_fde @@ process_sub sub in
|
||||
StrMap.add (BStd.Sub.name sub) res accu
|
||||
with InvalidSub -> accu)
|
||||
in
|
||||
|
|
Loading…
Reference in a new issue