Fix rbp pop heuristic

Add criterion to rbp pop detection:
  iii) that are the last references to %rbp in a `Def` in the
    subroutine's CFG (cf (ii)).
This commit is contained in:
Théophile Bastian 2019-06-11 18:44:05 +02:00
parent 4d6187ac21
commit db32807dd0
1 changed files with 31 additions and 12 deletions

View File

@ -264,6 +264,11 @@ let build_next_instr sub_ranges (disasm: BStd.disasm): AddrSet.t AddrMap.t =
~init:AddrMap.empty ~init:AddrMap.empty
~f:build_of_block ~f:build_of_block
type rbp_pop_state =
| SomePop of BStd.tid
| SomeRbpUse
| NoPop
let find_rbp_pop_set cfg entry = let find_rbp_pop_set cfg entry =
(** Returns a BStd.Tid.Set.t of the terms actually "popping" %rbp, that is, (** Returns a BStd.Tid.Set.t of the terms actually "popping" %rbp, that is,
the terms that should trigger a change to RbpUndef of the %rbp register. the terms that should trigger a change to RbpUndef of the %rbp register.
@ -273,6 +278,8 @@ let find_rbp_pop_set cfg entry =
ii) that are the last of this kind in the subroutine's CFG (ie. such that ii) that are the last of this kind in the subroutine's CFG (ie. such that
there is not another instruction matching (i) that is reachable through there is not another instruction matching (i) that is reachable through
the CFG from the current instruction). the CFG from the current instruction).
iii) that are the last references to %rbp in a `Def` in the subroutine's
CFG (cf (ii)).
*) *)
let def_is_rbp_pop def = let def_is_rbp_pop def =
@ -302,20 +309,30 @@ let find_rbp_pop_set cfg entry =
) )
in in
let def_uses_rbp def =
let def_vars = BStd.Var.Set.add
(BStd.Def.free_vars def)
(BStd.Def.lhs def) in
BStd.Var.Set.exists def_vars (fun var -> match Regs.X86_64.of_var var with
| Some x when x = Regs.X86_64.rbp -> true
| _ -> false)
in
let block_find_rbp_pop block = let block_find_rbp_pop block =
let fold_elt = function let fold_elt = function
| `Def(def) when (def_is_rbp_pop def) -> Some (BStd.Term.tid def) | `Def(def) when (def_is_rbp_pop def) -> SomePop (BStd.Term.tid def)
| _ -> None | `Def(def) when (def_uses_rbp def) -> SomeRbpUse
| _ -> NoPop
in in
let elts_seq = BStd.Blk.elts block in let elts_seq = BStd.Blk.elts block in
let last_pop = BStd.Seq.fold elts_seq let last_pop = BStd.Seq.fold elts_seq
~init:None ~init:NoPop
~f:(fun accu elt -> ~f:(fun accu elt ->
(match fold_elt elt with (match fold_elt elt with
| None -> accu | NoPop -> accu
| Some tid -> Some tid)) | SomeRbpUse -> SomeRbpUse
| SomePop tid -> SomePop tid))
in in
last_pop last_pop
in in
@ -330,7 +347,7 @@ let find_rbp_pop_set cfg entry =
BStd.Tid.Set.empty, true, visited BStd.Tid.Set.empty, true, visited
| false -> | false ->
let visited = BStd.Blk.Set.add visited block in let visited = BStd.Blk.Set.add visited block in
let pop_set, has_pop, visited = let pop_set, eligible, visited =
BStd.Seq.fold (CFG.Node.succs node cfg) BStd.Seq.fold (CFG.Node.succs node cfg)
~f:(fun (pre_pop_set, pre_has_pop, visited) child -> ~f:(fun (pre_pop_set, pre_has_pop, visited) child ->
let cur_pop_set, cur_has_pop, visited = let cur_pop_set, cur_has_pop, visited =
@ -341,14 +358,15 @@ let find_rbp_pop_set cfg entry =
) )
~init:(BStd.Tid.Set.empty, false, visited) ~init:(BStd.Tid.Set.empty, false, visited)
in in
let pop_set, has_pop = (match has_pop with let pop_set, eligible = (match eligible with
| false -> (* No rbp pop below, we seek rbp pops in this block *) | false -> (* No rbp pop below, we seek rbp pops in this block *)
(match block_find_rbp_pop block with (match block_find_rbp_pop block with
| None -> pop_set, false | NoPop -> pop_set, false
| Some tid -> BStd.Tid.Set.add pop_set tid, true | SomeRbpUse -> pop_set, true
| SomePop tid -> BStd.Tid.Set.add pop_set tid, true
) )
| true -> pop_set, has_pop) in | true -> pop_set, eligible) in
pop_set, has_pop, visited pop_set, eligible, visited
) )
in in
@ -739,8 +757,9 @@ let process_sub sub next_instr_graph : subroutine_cfa_data =
(* Already visited: check that entry values are matching *) (* Already visited: check that entry values are matching *)
if entry_offset <> former_entry_offset then ( if entry_offset <> former_entry_offset then (
if allow_rbp then if allow_rbp then
Format.eprintf "Found inconsistency (0x%Lx): %a -- %a@." Format.eprintf "Found inconsistency (0x%Lx <%a>): %a -- %a@."
(int64_addr_of cur_blk) (int64_addr_of cur_blk)
BStd.Tid.pp tid
pp_reg_pos entry_offset pp_reg_pos former_entry_offset ; pp_reg_pos entry_offset pp_reg_pos former_entry_offset ;
raise (Inconsistent tid) raise (Inconsistent tid)
) )