Skip to content

Commit d028f7f

Browse files
authored
relaxes the speculative disassembler constraints (#1417)
This change allows jumps that are not known to be barriers to fall through to data. Since we treat bits with inconsistent encodings (e.g., thumb vs arm) is data, it helps a lot in disassembling interworked binaries, where we commonly fall into code from a different instruction set. This change relaxes a bit the inner invariants so that we now have to check if a jump is not followed by data, even if it is not a barrier.
1 parent 7259ea4 commit d028f7f

File tree

1 file changed

+63
-51
lines changed

1 file changed

+63
-51
lines changed

lib/bap_disasm/bap_disasm_driver.ml

Lines changed: 63 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ let pp_encoding ppf {coding} =
3939
let order_encoding = KB.Domain.order Theory.Language.domain
4040

4141
module Machine : sig
42+
43+
(*
44+
- Dest {dst; parent} - [dst] is either a destination of
45+
a [Jump t], when parent is [Some (Jump t)], or an initial
46+
root (function start), when parent is [None].
47+
48+
- Fall {dst; parent} - is a fallthrough task either from
49+
[parent];
50+
51+
- Jump {src; dsts} - is a jump from src to the set of dests,
52+
potentially delayed and waiting until its age is 0.
53+
*)
4254
type task = private
4355
| Dest of {dst : addr; parent : task option; encoding : encoding}
4456
| Fall of {dst : addr; parent : task; delay : slot; encoding : encoding}
@@ -148,44 +160,39 @@ end = struct
148160

149161
let sexp_of_task t = Sexp.Atom (Format.asprintf "%a" pp_task t)
150162

151-
let rec cancel task s =
152-
match task with
163+
164+
(** [revert t s] reverts the chain that produced the task [t].*)
165+
let rec revert task s = match task with
153166
| Dest {parent=None} -> s
154167
| Dest {parent=Some parent} | Fall {parent} | Jump {parent} ->
155168
match parent with
156-
| Dest _ | Fall _ -> cancel_parent parent s
157-
| Jump {dsts} -> match task with
169+
| Fall _ | Dest _ -> cancel parent s
170+
| Jump _ -> match task with
158171
| Fall {delay=(Ready (Some _) | Delay)} ->
159-
cancel_parent parent s
160-
| Fall _ when has_valid s dsts -> s
161-
| Fall _ | Dest _ -> cancel_parent parent s
162-
| Jump _ -> assert false
163-
and cancel_parent task s =
164-
cancel task (cancel_task task s)
165-
and cancel_task task s =
166-
match task with
167-
| Dest {dst} | Fall {dst} -> mark_data s dst
172+
cancel parent s
173+
| _ -> s
174+
175+
(** [cancel t s] marks the address of [t] as data and reverts [t] *)
176+
and cancel task s = revert task @@ match task with
177+
| Dest {dst} | Fall {dst} -> delete s dst
168178
| Jump {dsts} when has_valid s dsts -> s
169-
| Jump {src} -> mark_data s src
170-
and cancel_beg s addr = match Map.find s.begs addr with
179+
| Jump {src} -> delete s src
180+
181+
and revert_incoming s addr = match Map.find s.begs addr with
171182
| None -> s
172183
| Some tasks ->
173-
List.fold_right tasks ~f:cancel ~init:{
184+
List.fold_right tasks ~f:revert ~init:{
174185
s with begs = Map.remove s.begs addr;
175186
}
176-
and mark_data s addr =
177-
cancel_beg {
178-
s with
179-
data = Set.add s.data addr;
180-
begs = Map.remove s.begs addr;
181-
usat = Set.remove s.usat addr;
182-
code = Map.remove s.code addr;
183-
jmps = Map.filter_map (Map.remove s.jmps addr) ~f:(fun dsts ->
184-
let resolved = Set.remove dsts.resolved addr in
185-
if Set.is_empty resolved && not dsts.indirect
186-
then None
187-
else Some {dsts with resolved});
188-
} addr
187+
188+
and delete s addr = {
189+
(revert_incoming s addr) with
190+
data = Set.add s.data addr;
191+
begs = Map.remove s.begs addr;
192+
usat = Set.remove s.usat addr;
193+
code = Map.remove s.code addr;
194+
jmps = Map.remove s.jmps addr;
195+
}
189196

190197
let is_slot s addr = Set.mem s.dels addr
191198

@@ -197,10 +204,10 @@ end = struct
197204
| [] -> restart s
198205
| Dest {dst=next; encoding} as curr :: work
199206
when wrong_encoding s next encoding ->
200-
step @@ cancel curr {s with work}
207+
step @@ revert curr {s with work}
201208
| Dest {dst=next} as curr :: work
202209
when is_data s next || is_slot s next ->
203-
step @@ cancel curr {s with work}
210+
step @@ revert curr {s with work}
204211
| Dest {dst=next} as curr :: work ->
205212
let s = {s with begs = Map.add_multi s.begs next curr} in
206213
if is_visited s next
@@ -210,20 +217,20 @@ end = struct
210217
if is_code s next
211218
then
212219
if is_slot s next
213-
then step @@ cancel curr {s with work}
220+
then step @@ revert curr {s with work}
214221
else if wrong_encoding s next encoding
215-
then step @@ cancel curr {s with work}
222+
then step @@ revert curr {s with work}
216223
else step {s with begs = Map.add_multi s.begs next curr; work}
217-
else if is_data s next then step @@ cancel curr {s with work}
224+
else if is_data s next then step @@ revert curr {s with work}
218225
else {s with work; addr=next; curr}
219226
| (Jump {src; dsts} as jump) :: ([] as work)
220227
| (Jump {src; dsts; age=0} as jump) :: work ->
221228
if Set.mem s.data src
222-
then step @@ cancel jump {s with work}
229+
then step @@ revert jump {s with work}
223230
else
224231
let resolved = Set.diff dsts.resolved s.data in
225232
if Set.is_empty resolved && not dsts.indirect
226-
then step@@cancel jump {s with work}
233+
then step@@revert jump {s with work}
227234
else
228235
let dsts = {dsts with resolved} in
229236
let init = {s with jmps = Map.add_exn s.jmps src dsts; work} in
@@ -234,7 +241,7 @@ end = struct
234241
dst=next; parent = Some jump; encoding = dsts.encoding;
235242
} :: s.work})
236243
| Jump jmp as self :: Fall ({dst=next} as slot) :: work ->
237-
let s = cancel_beg s next in
244+
let s = revert_incoming s next in
238245
let delay = if jmp.age = 1 then Ready (Some self) else Delay in
239246
let jump = Jump {
240247
jmp with age = jmp.age-1; src = next;
@@ -267,11 +274,11 @@ end = struct
267274
let parent = s.curr in
268275
let src = Memory.min_addr mem in
269276
let jump = Jump {src; age=delay; dsts; parent; encoding} in
270-
let next = Addr.succ (Memory.max_addr mem) in
277+
let dst = Addr.succ (Memory.max_addr mem) in
271278
let next =
272279
if dsts.barrier && delay = 0
273-
then Dest {dst=next; parent=None; encoding=unknown}
274-
else Fall {dst=next; parent=jump; delay = Ready None; encoding} in
280+
then Dest {dst; parent=None; encoding=unknown}
281+
else Fall {dst; parent=jump; delay = Ready None; encoding} in
275282
step {s with work = jump :: next :: s.work }
276283

277284
let insert_delayed t = function
@@ -300,14 +307,14 @@ end = struct
300307
| _ -> next :: s.work in
301308
step @@ decoded {s with work} mem encoding
302309

303-
let failed s _encoding addr =
304-
step @@ cancel s.curr @@ mark_data s addr
310+
let failed s _ _ = step @@ cancel s.curr s
305311

306312
let skipped s addr =
307313
step {s with usat = Set.remove s.usat addr }
308314

309-
let stopped s _encoding =
310-
step @@ cancel s.curr @@ mark_data s s.addr
315+
316+
let stopped s _ =
317+
step @@ cancel s.curr s
311318

312319
let with_encoding encoding = function
313320
| Fall s -> Fall {s with encoding}
@@ -327,7 +334,7 @@ end = struct
327334
| Ok mem -> ready s (task_encoding s.curr) mem
328335
| Error _ ->
329336
let s = match s.curr with
330-
| Fall _ | Jump _ as task -> cancel task s
337+
| Fall _ | Jump _ as task -> revert task s
331338
| t -> {s with debt = t :: s.debt} in
332339
match s.work with
333340
| [] -> empty (step s)
@@ -502,13 +509,11 @@ let disassemble ~code ~data ~funs debt base : Machine.state KB.t =
502509
let encoding = Machine.encoding s in
503510
KB.provide Theory.Label.encoding label encoding.coding >>= fun () ->
504511
collect_dests encoding label >>= fun dests ->
505-
if Set.is_empty dests.resolved &&
506-
not dests.indirect then
507-
step d @@ Machine.moved s encoding mem
512+
if Set.is_empty dests.resolved && not dests.indirect
513+
then step d @@ Machine.moved s encoding mem
508514
else
509515
delay label >>= fun delay ->
510-
step d @@ Machine.jumped s encoding mem dests
511-
delay
516+
step d @@ Machine.jumped s encoding mem dests delay
512517
end @@ fun problem ->
513518
warning "rejecting %a due to a conflict %a"
514519
Memory.pp mem KB.Conflict.pp problem;
@@ -599,6 +604,11 @@ let scan_step ?(code=empty) ?(data=empty) ?(funs=empty) s mem =
599604
let begs = Set.of_map_keys begs - data in
600605
let funs = Set.union s.funs funs - data in
601606
let begs = Set.union s.begs begs - dels in
607+
let jmps = Map.filter_map jmps ~f:(fun dsts ->
608+
let resolved = dsts.resolved - data in
609+
if Set.is_empty resolved && not dsts.indirect
610+
then None
611+
else Some {dsts with resolved}) in
602612
let s = {funs; begs; data; jmps; mems = s.mems; debt} in
603613
commit_calls s.jmps >>| fun funs ->
604614
{s with funs = Set.union s.funs funs - dels}
@@ -689,7 +699,9 @@ let explore
689699
let last = Memory.max_addr mem in
690700
let next = Addr.succ last in
691701
let is_terminator =
692-
Set.mem begs next || Map.mem jmps curr in
702+
Set.mem begs next ||
703+
Map.mem jmps curr ||
704+
Set.mem data next in
693705
if is_terminator
694706
then KB.return (curr, len, insn::insns)
695707
else Dis.jump s (view next base)

0 commit comments

Comments
 (0)