Skip to content

Commit a9b8a32

Browse files
authored
uses the context variables to store the Primus Lisp state (#1344)
The Primus Lisp interpreter uses some state and was previously implemented as the knowledge monad transformed into the state monad. The new implementation just uses the newly introduces context variables, which is much easier and a little bit more performant. It also enables us to persist the interpreter state between the calls so that we can generate more efficient code (propagate consts between instructions), especially for the ghidra backend.
1 parent fdd4287 commit a9b8a32

File tree

1 file changed

+71
-65
lines changed

1 file changed

+71
-65
lines changed

lib/bap_primus/bap_primus_lisp_semantics.ml

Lines changed: 71 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,31 @@ module Def = Bap_primus_lisp_def
1414
module Type = Bap_primus_lisp_type
1515
module Key = Bap_primus_lisp_program.Items
1616

17-
module Meta = struct
18-
module State = struct
19-
type t = {
20-
binds : unit Theory.Value.t Map.M(Theory.Var.Top).t;
21-
arith : (module Bitvec.S);
22-
scope : unit Theory.var list Map.M(Theory.Var.Top).t;
23-
}
24-
end
25-
include Monad.State.T1(State)(KB)
26-
include Monad.State.Make(State)(KB)
17+
open KB.Syntax
18+
open KB.Let
19+
20+
module State = struct
21+
type t = {
22+
binds : unit Theory.Value.t Map.M(Theory.Var.Top).t;
23+
arith : (module Bitvec.S);
24+
scope : unit Theory.var list Map.M(Theory.Var.Top).t;
25+
}
26+
27+
let empty = {
28+
binds = Map.empty (module Theory.Var.Top);
29+
arith = (module Bitvec.M32);
30+
scope = Map.empty (module Theory.Var.Top);
31+
}
32+
33+
let var = KB.Context.declare ~package:"bap" "lisp-interpter-state"
34+
!!empty
35+
36+
37+
let get = KB.Context.get var
38+
let set = KB.Context.set var
39+
let update = KB.Context.update var
2740
end
2841

29-
open Meta.Syntax
30-
open Meta.Let
3142

3243
type value = unit Theory.Value.t
3344
type effect = unit Theory.Effect.t
@@ -48,6 +59,8 @@ let program =
4859
~equal:Program.equal
4960
~join:(fun x y -> Ok (Program.merge x y))
5061

62+
63+
5164
type program = {
5265
prog : Program.t;
5366
places : unit Theory.var Map.M(KB.Name).t;
@@ -60,14 +73,12 @@ let typed = KB.Class.property Theory.Source.cls "typed-program"
6073
~equal:(fun x y ->
6174
Program.equal x.prog y.prog)
6275

63-
let fail s = Meta.lift (KB.fail s)
64-
6576
let unresolved name problem =
6677
let msg =
6778
Format.asprintf "Failed to find a definition for %a. %a"
6879
KB.Name.pp name
6980
Resolve.pp_resolution problem in
70-
fail (Unresolved_definition msg)
81+
KB.fail (Unresolved_definition msg)
7182

7283
let resolve prog item name =
7384
match Resolve.semantics prog item name () with
@@ -203,9 +214,8 @@ let sym str =
203214
let v = update_value empty @@ fun v ->
204215
KB.Value.put symbol v (Some str) in
205216
match str with
206-
| "nil" -> Meta.return@@set_static v Bitvec.zero
217+
| "nil" -> KB.return@@set_static v Bitvec.zero
207218
| name ->
208-
Meta.lift @@
209219
intern name >>|
210220
set_static v
211221

@@ -214,11 +224,10 @@ let static x =
214224
KB.Value.get static_slot (res x)
215225

216226
let reify_sym x = match static x with
217-
| Some _ -> Meta.return x
227+
| Some _ -> KB.return x
218228
| None -> match KB.Value.get symbol (res x) with
219-
| None -> Meta.return x
229+
| None -> KB.return x
220230
| Some name ->
221-
Meta.lift @@
222231
intern name >>|
223232
set_static x
224233

@@ -248,22 +257,21 @@ let lookup_parameter prog v =
248257
let is_parameter prog v = Option.is_some (lookup_parameter prog v)
249258

250259
module Env = struct
251-
open Meta.State
252260

253261
let lookup v =
254262
let v = Theory.Var.forget v in
255-
Meta.get () >>| fun {binds} ->
263+
let+ {binds} = State.get in
256264
Map.find binds v
257265

258266

259267
let set v x =
260-
Meta.update @@ fun s -> {
268+
State.update @@ fun s -> {
261269
s with binds = Map.set s.binds
262270
(Theory.Var.forget v) x
263271
}
264272

265273
let del v =
266-
Meta.update @@ fun s -> {
274+
State.update @@ fun s -> {
267275
s with binds = Map.remove s.binds (Theory.Var.forget v)
268276
}
269277

@@ -277,15 +285,15 @@ module Env = struct
277285
Theory.Var.forget@@Theory.Var.define (bits s) (KB.Name.to_string n)
278286

279287
let set_args ws bs =
280-
Meta.get () >>= fun s ->
288+
let* s = State.get in
281289
let binds,old =
282290
List.fold bs ~init:(s.binds,[]) ~f:(fun (s,old) (v,x) ->
283291
let v = var ws v in
284292
Map.set s v x,(v,Map.find s v) :: old) in
285-
Meta.put {s with binds} >>| fun () ->
293+
State.set {s with binds} >>| fun () ->
286294
List.rev old
287295

288-
let del_args bs = Meta.update @@ fun s -> {
296+
let del_args bs = State.update @@ fun s -> {
289297
s with binds = List.fold bs ~init:s.binds ~f:(fun s (v,x) ->
290298
match x with
291299
| None -> Map.remove s v
@@ -298,51 +306,51 @@ module Scope = struct
298306

299307
let push orig =
300308
let orig = forget orig in
301-
Meta.lift@@Theory.Var.fresh (Theory.Var.sort orig) >>= fun v ->
302-
Meta.update (fun s -> {
309+
Theory.Var.fresh (Theory.Var.sort orig) >>= fun v ->
310+
State.update (fun s -> {
303311
s with scope = Map.update s.scope orig ~f:(function
304312
| None -> [v]
305313
| Some vs -> v::vs)
306314
}) >>| fun () ->
307315
v
308316

309317
let lookup orig =
310-
let+ {scope} = Meta.get () in
318+
let+ {scope} = State.get in
311319
match Map.find scope orig with
312320
| None | Some [] -> None
313321
| Some (x :: _) -> Some x
314322

315323
let pop orig =
316-
Meta.update @@ fun s -> {
324+
State.update @@ fun s -> {
317325
s with scope = Map.change s.scope (forget orig) ~f:(function
318326
| None | Some [] | Some [_] -> None
319327
| Some (_::xs) -> Some xs)
320328
}
321329

322330
let clear =
323-
let* s = Meta.get () in
324-
let+ () = Meta.put {
331+
let* s = State.get in
332+
let+ () = State.set {
325333
s with scope = Map.empty (module Theory.Var.Top)
326334
} in
327335
s.scope
328336

329-
let restore scope = Meta.update @@ fun s -> {
337+
let restore scope = State.update @@ fun s -> {
330338
s with scope
331339
}
332340

333341
end
334342

335343
module Prelude(CT : Theory.Core) = struct
336344
let null = KB.Object.null Theory.Program.cls
337-
let fresh = Meta.lift (KB.Object.create Theory.Program.cls)
345+
let fresh = KB.Object.create Theory.Program.cls
338346

339347
let rec seq = function
340-
| [] -> Meta.lift@@CT.perform Theory.Effect.Sort.bot
348+
| [] -> CT.perform Theory.Effect.Sort.bot
341349
| [x] -> x
342350
| x :: xs ->
343351
let* xs = seq xs in
344352
let* x = x in
345-
Meta.lift@@CT.seq (KB.return x) (KB.return xs)
353+
CT.seq (KB.return x) (KB.return xs)
346354

347355
let skip = CT.perform Theory.Effect.Sort.bot
348356
let pass = CT.perform Theory.Effect.Sort.bot
@@ -355,10 +363,10 @@ module Prelude(CT : Theory.Core) = struct
355363
let s = bits m in
356364
let m = Bitvec.modulus m in
357365
let x = Bitvec.(bigint x mod m) in
358-
pure @@ Meta.lift (CT.int s x) >>| fun r ->
366+
pure @@ CT.int s x >>| fun r ->
359367
set_static r x
360368

361-
let (:=) v x = Meta.lift@@CT.set v x
369+
let (:=) v x = CT.set v x
362370

363371
let full eff res =
364372
seq eff >>= fun eff ->
@@ -367,14 +375,14 @@ module Prelude(CT : Theory.Core) = struct
367375

368376
let data xs =
369377
let* data = seq xs in
370-
Meta.lift@@CT.blk null !data skip
378+
CT.blk null !data skip
371379

372380
let ctrl xs =
373381
let* ctrl = seq xs in
374-
Meta.lift@@CT.blk null pass !ctrl
382+
CT.blk null pass !ctrl
375383

376384
let blk lbl xs = seq [
377-
Meta.lift@@CT.blk lbl pass skip;
385+
CT.blk lbl pass skip;
378386
seq xs;
379387
]
380388

@@ -386,9 +394,9 @@ module Prelude(CT : Theory.Core) = struct
386394
let coerce_bits s x f =
387395
let open Theory.Value.Match in
388396
let| () = can Theory.Bitv.refine x @@ fun x ->
389-
Meta.lift@@CT.cast s CT.b0 !x >>= f in
397+
CT.cast s CT.b0 !x >>= f in
390398
let| () = can Theory.Bool.refine x @@ fun cnd ->
391-
Meta.lift@@CT.ite !cnd
399+
CT.ite !cnd
392400
(CT.int s Bitvec.one)
393401
(CT.int s Bitvec.zero) >>= fun x ->
394402
f x in
@@ -398,7 +406,7 @@ module Prelude(CT : Theory.Core) = struct
398406
let open Theory.Value.Match in
399407
let| () = can Theory.Bool.refine x f in
400408
let| () = can Theory.Bitv.refine x @@ fun x ->
401-
Meta.lift@@CT.non_zero !x >>= fun x -> f x in
409+
CT.non_zero !x >>= fun x -> f x in
402410
undefined
403411

404412
let is_static eff = Option.is_some (static eff)
@@ -417,7 +425,7 @@ module Prelude(CT : Theory.Core) = struct
417425
let word = Theory.Target.bits target in
418426
let {prog; places} = program in
419427
let var ?t n = make_var ?t places target n in
420-
let rec eval : ast -> unit Theory.Effect.t Meta.t = function
428+
let rec eval : ast -> unit Theory.Effect.t KB.t = function
421429
| {data=Int {data={exp=x; typ=Type m}}} -> bigint x m
422430
| {data=Int {data={exp=x}}} -> bigint x word
423431
| {data=Var {data={exp=n; typ=Type t}}} -> lookup@@var ~t n
@@ -443,15 +451,15 @@ module Prelude(CT : Theory.Core) = struct
443451
else eval yes
444452
| None ->
445453
coerce_bool (res cnd) @@ fun cres ->
446-
Meta.lift@@Theory.Var.fresh Theory.Bool.t >>= fun c ->
454+
Theory.Var.fresh Theory.Bool.t >>= fun c ->
447455
let* yes = eval yes in
448456
let* nay = eval nay in
449457
full [
450458
!!cnd;
451459
data [c := !cres];
452-
Meta.lift@@CT.branch (CT.var c) !yes !nay;
460+
CT.branch (CT.var c) !yes !nay;
453461
] @@
454-
Meta.lift@@CT.ite (CT.var c) !(res yes) !(res nay)
462+
CT.ite (CT.var c) !(res yes) !(res nay)
455463
and rep cnd body =
456464
let* r = eval cnd in
457465
match static r with
@@ -466,10 +474,10 @@ module Prelude(CT : Theory.Core) = struct
466474
let* head = fresh and* loop = fresh and* tail = fresh in
467475
coerce_bool (res r) @@ fun cres ->
468476
full [
469-
blk head [ctrl [Meta.lift@@CT.goto tail]];
477+
blk head [ctrl [CT.goto tail]];
470478
blk loop [!!body];
471479
blk tail [!!r; ctrl [
472-
Meta.lift@@CT.branch !cres (CT.goto head) skip
480+
CT.branch !cres (CT.goto head) skip
473481
]]
474482
] !!cres
475483
and call ?(toplevel=false) name xs =
@@ -490,27 +498,26 @@ module Prelude(CT : Theory.Core) = struct
490498
| None ->
491499
match Resolve.semantics prog Key.semantics name () with
492500
| Some Ok (sema,()) ->
493-
Meta.lift@@
494501
Def.Sema.apply sema defn xs
495502
| Some (Error problem) -> unresolved name problem
496503
| None ->
497504
let msg = Format.asprintf "No definition is found for %a"
498505
KB.Name.pp name in
499-
fail (Unresolved_definition msg)
506+
KB.fail (Unresolved_definition msg)
500507
and app name xs =
501508
map xs >>= fun (aeff,xs) ->
502509
call name xs >>= fun peff ->
503510
full [!!aeff; !!peff] !!(res peff)
504511
and map args =
505512
seq [] >>= fun eff ->
506-
Meta.List.fold args ~init:(eff,[]) ~f:(fun (eff,args) arg ->
513+
KB.List.fold args ~init:(eff,[]) ~f:(fun (eff,args) arg ->
507514
let* eff' = eval arg in
508515
let+ eff = seq [!!eff; !!eff'] in
509516
(eff,forget (res eff')::args)) >>| fun (eff,args) ->
510517
eff, List.rev args
511518
and seq_ xs =
512519
pure nil >>= fun init ->
513-
Meta.List.fold ~init xs ~f:(fun eff x ->
520+
KB.List.fold ~init xs ~f:(fun eff x ->
514521
let* eff' = eval x in
515522
full [!!eff; !!eff'] !!(res eff'))
516523
and msg fmt args =
@@ -524,7 +531,7 @@ module Prelude(CT : Theory.Core) = struct
524531
| None -> Format.printf "@[<hv>%a@]" KB.Value.pp v);
525532
Format.fprintf ppf "@\n";
526533
!!aeff
527-
and err msg = fail (User_error msg)
534+
and err msg = KB.fail (User_error msg)
528535
and lookup v =
529536
Scope.lookup v >>= function
530537
| Some v -> lookup v
@@ -533,7 +540,7 @@ module Prelude(CT : Theory.Core) = struct
533540
| Some v -> pure !!v
534541
| None -> match lookup_parameter prog v with
535542
| Some def -> eval def >>= assign target v
536-
| None -> pure@@Meta.lift@@CT.var v
543+
| None -> pure@@CT.var v
537544
and set_ v x =
538545
Scope.lookup v >>= function
539546
| Some v -> eval x >>= assign target ~local:true v
@@ -690,17 +697,16 @@ let provide_semantics ?(stdout=Format.std_formatter) () =
690697
KB.collect Property.args obj >>= fun args ->
691698
KB.collect Theory.Unit.target unit >>= fun target ->
692699
let bits = Theory.Target.bits target in
693-
let module Arith = Bitvec.Make(struct
694-
let modulus = Bitvec.modulus bits
695-
end) in
696-
let meta = Meta.State.{
700+
KB.Context.set State.var State.{
697701
binds = Map.empty (module Theory.Var.Top);
698702
scope = Map.empty (module Theory.Var.Top);
699-
arith = (module Arith);
700-
} in
701-
Theory.instance () >>= Theory.require >>= fun (module Core) ->
703+
arith = (module (Bitvec.Make(struct
704+
let modulus = Bitvec.modulus bits
705+
end)));
706+
} >>= fun () ->
707+
let* (module Core) = Theory.current in
702708
let open Prelude(Core) in
703-
Meta.run (reify stdout prog obj target name args) meta >>= fun (res,_) ->
709+
reify stdout prog obj target name args >>= fun res ->
704710
KB.collect Disasm_expert.Basic.Insn.slot obj >>| function
705711
| Some basic when Insn.(res <> empty) ->
706712
Insn.with_basic res basic

0 commit comments

Comments
 (0)