Skip to content

Commit d0764a5

Browse files
authored
implements pcode floating-point and special operators (#1452)
Adds an `intrinsic` and `symbol-concat` primitives to Primus Lisp and uses them to implement all floating-point operators in pcode and cpuid routines for pcode-x86.
1 parent f1e1c13 commit d0764a5

File tree

5 files changed

+443
-56
lines changed

5 files changed

+443
-56
lines changed

lib/bap_primus/bap_primus_lisp_attribute.ml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ open Bap_core_theory
33
open Bap.Std
44

55
open Bap_primus_lisp_types
6-
76
module Name = KB.Name
87

98
type cls
@@ -14,7 +13,7 @@ let cls : (cls,unit) KB.cls = KB.Class.declare "attributes" ()
1413
type attrs = (cls,unit) KB.cls KB.Value.t
1514
type set = attrs
1615

17-
type error = ..
16+
type error = exn = ..
1817

1918
exception Unknown_attr of string * tree
2019
exception Failure of error * tree list
@@ -38,8 +37,6 @@ module Parse = struct
3837

3938
type error += Expect_atom | Expect_list
4039

41-
42-
4340
let atom = function
4441
| {data=Atom s} -> Some s
4542
| _ -> None
@@ -101,3 +98,11 @@ module Set = struct
10198

10299
include Self
103100
end
101+
102+
103+
let () = Caml.Printexc.register_printer (function
104+
| Failure (error,_) ->
105+
let msg = Format.asprintf "Attribute parse error: %s"
106+
(Caml.Printexc.to_string error) in
107+
Some msg
108+
| _ -> None)

plugins/bil/bil_ir.ml

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type t = cfg
2727

2828
let null = KB.Object.null Theory.Program.cls
2929
let is_null x = KB.Object.is_null x
30+
let is_call jmp = Option.is_some (Jmp.alt jmp)
3031
let is_empty = function
3132
| {entry; blks=[]} -> is_null entry
3233
| _ -> false
@@ -55,71 +56,103 @@ module BIR = struct
5556
Blk.Builder.result b :: blks |>
5657
List.rev
5758

58-
let resolve jmp = Option.(Jmp.(dst jmp >>| resolve))
59+
let dst jmp =
60+
match Option.(Jmp.(dst jmp >>| resolve)) with
61+
| Some First tid -> Some tid
62+
| _ -> None
63+
64+
let dsts blk =
65+
List.filter_map blk.jmps ~f:dst
66+
5967

6068
let references blks =
6169
List.fold ~init:Tid.Map.empty ~f:(fun refs {jmps} ->
6270
List.fold jmps ~init:refs ~f:(fun refs jmp ->
63-
match resolve jmp with
64-
| Some (First tid) when Set.mem blks tid ->
71+
match dst jmp with
72+
| Some tid when Map.mem blks tid ->
6573
Map.update refs tid ~f:(function
6674
| None -> 1
6775
| Some refs -> refs+1)
6876
| _ -> refs))
6977

70-
let names =
71-
List.fold ~init:Tid.Set.empty ~f:(fun blks {name} ->
72-
Set.add blks name)
78+
let graph = List.fold
79+
~init:(Theory.Label.null,Tid.Map.empty)
80+
~f:(fun (_,blks) blk ->
81+
blk.name, Map.add_exn blks blk.name blk)
7382

7483
let single_dst = function
7584
| [] | _ :: _ :: _ -> None
76-
| [x] -> match resolve x with
77-
| Some First tid -> Some tid
85+
| [x] -> match dst x with
86+
| Some tid when not (is_call x) -> Some tid
7887
| _ -> None
7988

89+
8090
let is_sub {weak; keep} = keep && weak
8191

8292
let can_contract refs b1 b2 =
83-
is_sub b1 && is_sub b2 && match single_dst b1.jmps with
93+
not (Tid.equal b1.name b2.name) &&
94+
b2.weak && match single_dst b1.jmps with
8495
| None -> false
8596
| Some dst ->
8697
Tid.equal dst b2.name &&
8798
match Map.find refs dst with
8899
| Some 1 -> true
89100
| _ -> false
90101

91-
(* pre: can_contract b1 b2 /\
92-
can_contract b2 b3 .. *)
93-
let contract blks = match List.hd blks, List.last blks with
94-
| Some first,Some last -> {
95-
first with
96-
defs = List.(rev@@concat_map blks ~f:(fun {defs} -> List.rev defs));
97-
jmps = last.jmps;
98-
}
99-
| _ -> assert false
100-
101-
let normalize blks =
102-
let names = names blks in
103-
let refs = references names blks in
104-
List.sort blks ~compare:(fun b1 b2 ->
105-
Tid.compare b1.name b2.name) |>
106-
List.group ~break:(fun b1 b2 ->
107-
not @@ can_contract refs b1 b2) |>
108-
List.map ~f:contract
102+
(* pre: can_contract b1 b2 *)
103+
let join x y = {
104+
x with
105+
defs = y.defs @ x.defs;
106+
jmps = y.jmps
107+
}
108+
109+
let (//) graph node =
110+
Map.remove graph node.name
111+
112+
let has_name name blk = Tid.equal name blk.name
113+
114+
let removed exit parent dst =
115+
if has_name exit dst then parent.name else exit
116+
117+
let contract refs graph ~entry ~exit =
118+
let rec contract output graph exit node =
119+
match Option.(single_dst node.jmps >>= Map.find graph) with
120+
| Some dst when can_contract refs node dst ->
121+
let node = join node dst in
122+
contract output (graph//dst) (removed exit node dst) node
123+
| _ -> follow output graph exit node
124+
and follow output graph exit node = List.fold (dsts node)
125+
~init:(node::output,graph//node,exit)
126+
~f:(fun (output,graph,exit) name ->
127+
match Map.find graph name with
128+
| None -> output,graph,exit
129+
| Some node -> contract output graph exit node) in
130+
contract [] graph exit (Map.find_exn graph entry)
131+
132+
let normalize entry blks =
133+
let exit,graph = graph blks in
134+
let refs = references graph blks in
135+
let blks,leftovers,exit = contract refs graph ~entry ~exit in
136+
assert (Map.is_empty leftovers);
137+
match blks with
138+
| blk::_ as blks when has_name exit blk -> blks
139+
| blks ->
140+
List.find_exn blks ~f:(has_name exit) ::
141+
List.filter blks ~f:(Fn.non (has_name exit))
109142

110143
let has_subs = List.exists ~f:is_sub
111144

112-
let normalize = function
145+
let normalize entry = function
113146
| [] | [_] as xs -> xs
114-
| xs -> if has_subs xs then normalize xs else xs
147+
| xs -> if has_subs xs then normalize entry xs else xs
115148

116149
(* postconditions:
117150
- the first block is the entry block
118151
- the last block is the exit block
119152
*)
120153
let reify {entry; blks} =
121154
if is_null entry then [] else
122-
normalize blks |>
155+
normalize entry blks |>
123156
List.fold ~init:(None,[]) ~f:(fun (s,blks) b ->
124157
match make_blk b with
125158
| [] -> assert false
@@ -168,8 +201,8 @@ let slot = graph
168201
module IR = struct
169202
include Theory.Empty
170203
let ret = Knowledge.return
171-
let blk ?(keep=true) tid =
172-
{name=tid; defs=[]; jmps=[]; keep; weak=false}
204+
let blk ?(keep=false) ?(weak=false) tid =
205+
{name=tid; defs=[]; jmps=[]; keep; weak}
173206

174207
let def = (fun x -> x.defs), (fun x d -> {x with defs = d})
175208
let jmp = (fun x -> x.jmps), (fun x d -> match x.jmps with
@@ -227,7 +260,7 @@ module IR = struct
227260
| `Relinked,blks -> KB.return blks
228261
| `Relink dst, blks ->
229262
let+ tid = fresh in
230-
blks @ [blk label ++ goto ~tid dst]
263+
blks @ [blk ~weak label ++ goto ~tid dst]
231264
| `Unbound,[] -> assert false
232265
| `Unbound,_ -> assert false in
233266
{entry = label; blks}
@@ -241,7 +274,7 @@ module IR = struct
241274
blks = [{
242275
name=entry;
243276
keep=false;
244-
weak=false;
277+
weak=true;
245278
jmps=[];
246279
defs=[Def.reify ~tid v x]
247280
}]
@@ -268,6 +301,7 @@ module IR = struct
268301
if <body> is empty.
269302
*)
270303
let repeat cnd body =
304+
let keep = true in
271305
cnd >>= fun cnd ->
272306
body >>| reify >>= function
273307
| {blks=[]} -> (* empty denotation *)
@@ -277,7 +311,7 @@ module IR = struct
277311
entry = head;
278312
blks = [{
279313
name = head;
280-
keep = true;
314+
keep;
281315
weak = false;
282316
defs = [];
283317
jmps = [goto ~cnd ~tid head]}]}
@@ -289,13 +323,14 @@ module IR = struct
289323
fresh >>= fun jmp3 ->
290324
data {
291325
entry = head;
292-
blks = blk tail ++ goto ~tid:jmp1 ~cnd loop ::
293-
blk head ++ goto ~tid:jmp2 tail ::
326+
blks = blk ~keep tail ++ goto ~tid:jmp1 ~cnd loop ::
327+
blk ~keep head ++ goto ~tid:jmp2 tail ::
294328
b ++ goto ~tid:jmp3 tail ::
295329
blks
296330
}
297331

298332
let branch cnd yes nay =
333+
let keep = true in
299334
fresh >>= fun head ->
300335
fresh >>= fun tail ->
301336
cnd >>= fun cnd ->
@@ -314,8 +349,8 @@ module IR = struct
314349
ret {
315350
entry = head;
316351
blks =
317-
blk tail ::
318-
blk head ++
352+
blk ~keep tail ::
353+
blk ~keep head ++
319354
jump ~tid:jmp1 lhs ++
320355
goto ~tid:jmp2 tail ::
321356
b ++ goto ~tid:jmp3 tail ::
@@ -328,8 +363,8 @@ module IR = struct
328363
ret {
329364
entry = head;
330365
blks =
331-
blk tail ::
332-
blk head ++
366+
blk ~keep tail ::
367+
blk ~keep head ++
333368
jump ~tid:jmp1 tail ++
334369
goto ~tid:jmp2 rhs ::
335370
b ++ goto ~tid:jmp3 tail ::
@@ -343,8 +378,8 @@ module IR = struct
343378
ret {
344379
entry = head;
345380
blks =
346-
blk tail ::
347-
blk head ++
381+
blk ~keep tail ::
382+
blk ~keep head ++
348383
jump ~tid:jmp1 lhs ++
349384
goto ~tid:jmp2 rhs ::
350385
yes ++ goto ~tid:jmp3 tail ::
@@ -357,8 +392,8 @@ module IR = struct
357392
ret {
358393
entry = head;
359394
blks = [
360-
blk tail;
361-
blk head ++ jump ~tid:jmp1 tail ++ goto ~tid:jmp2 tail
395+
blk ~keep tail;
396+
blk ~keep head ++ jump ~tid:jmp1 tail ++ goto ~tid:jmp2 tail
362397
]
363398
}
364399

@@ -368,11 +403,9 @@ module IR = struct
368403
fresh >>= fun tid ->
369404
ctrl {
370405
entry;
371-
blks = [blk ~keep:false entry ++ Jmp.reify ~tid ~dst:(Jmp.indirect dst) ()]
406+
blks = [blk entry ++ Jmp.reify ~tid ~dst:(Jmp.indirect dst) ()]
372407
}
373408

374-
let is_call jmp = Option.is_some (Jmp.alt jmp)
375-
376409
let is_unconditional jmp = match Jmp.cond jmp with
377410
| Int w when Word.(w = b1) -> true
378411
| _ -> false

0 commit comments

Comments
 (0)