|
| 1 | +open Core_kernel |
| 2 | +open Bap_core_theory |
| 3 | +open Bap.Std |
| 4 | + |
| 5 | +open KB.Syntax |
| 6 | +include Bap_main.Loggers() |
| 7 | + |
| 8 | +module Target = Bap_avr_target |
| 9 | +module MC = Disasm_expert.Basic |
| 10 | + |
| 11 | +type r1 |
| 12 | +type 'a bitv = 'a Theory.Bitv.t Theory.Value.sort |
| 13 | + |
| 14 | +let r1 : r1 bitv = Theory.Bitv.define 1 |
| 15 | + |
| 16 | +let make_regs regs = |
| 17 | + let regs = |
| 18 | + List.mapi regs ~f:(fun i r -> (i,r)) |> |
| 19 | + Map.of_alist_exn (module Int) in |
| 20 | + Map.find_exn regs |
| 21 | + |
| 22 | +let gpr = make_regs Target.gpr |
| 23 | +let regnum s = Scanf.sscanf s "R%d" ident |
| 24 | + |
| 25 | +let require_gpr insn pos f = |
| 26 | + match (MC.Insn.ops insn).(pos) with |
| 27 | + | Op.Reg r -> f (gpr (regnum (Reg.name r))) |
| 28 | + | _ -> KB.return Insn.empty |
| 29 | + |
| 30 | +let require_imm insn pos f = |
| 31 | + match (MC.Insn.ops insn).(pos) with |
| 32 | + | Op.Imm x -> f (Option.value_exn (Imm.to_int x)) |
| 33 | + | _ -> KB.return Insn.empty |
| 34 | + |
| 35 | +let hf = Theory.Var.define r1 "HF" |
| 36 | +let cf = Theory.Var.define r1 "CF" |
| 37 | +let nf = Theory.Var.define r1 "NF" |
| 38 | +let vf = Theory.Var.define r1 "VF" |
| 39 | +let sf = Theory.Var.define r1 "SF" |
| 40 | +let zf = Theory.Var.define r1 "ZF" |
| 41 | + |
| 42 | +module M8 = Bitvec.M8 |
| 43 | + |
| 44 | +module Avr(CT : Theory.Core) = struct |
| 45 | + open Target |
| 46 | + let rec seq = function |
| 47 | + | [] -> CT.perform Theory.Effect.Sort.bot |
| 48 | + | [x] -> x |
| 49 | + | x :: xs -> CT.seq x @@ seq xs |
| 50 | + |
| 51 | + let const x = CT.int r8 (M8.int x) |
| 52 | + |
| 53 | + let bit0 = CT.int r1 (Bitvec.M1.bool false) |
| 54 | + let bit1 = CT.int r1 (Bitvec.M1.bool true) |
| 55 | + let flag x = CT.ite x bit1 bit0 |
| 56 | + |
| 57 | + let nth x n = |
| 58 | + CT.(extract r1 (const n) (const n) x) |
| 59 | + |
| 60 | + let data xs = |
| 61 | + KB.Object.create Theory.Program.cls >>= fun lbl -> |
| 62 | + CT.blk lbl (seq xs) (seq []) |
| 63 | + |
| 64 | + let (&&) = CT.logand |
| 65 | + let (||) = CT.logor |
| 66 | + let not = CT.not |
| 67 | + |
| 68 | + let bit reg n body = |
| 69 | + nth CT.(var reg) n >>= fun expr -> |
| 70 | + Theory.Var.scoped r1 @@ fun v -> |
| 71 | + CT.let_ v !!expr (body (CT.var v)) |
| 72 | + |
| 73 | + let halfcarry ~r ~rd ~rr = |
| 74 | + bit r 3 @@ fun r3 -> |
| 75 | + bit rd 3 @@ fun rd3 -> |
| 76 | + bit rr 3 @@ fun rr3 -> |
| 77 | + rd3 && rr3 || rr3 && not r3 || not r3 && rd3 |
| 78 | + |
| 79 | + let fullcarry ~r ~rd ~rr = |
| 80 | + bit r 7 @@ fun r7 -> |
| 81 | + bit rd 7 @@ fun rd7 -> |
| 82 | + bit rr 7 @@ fun rr7 -> |
| 83 | + rd7 && rr7 || rr7 && not r7 || r7 && not rd7 |
| 84 | + |
| 85 | + let overflow ~r ~rd ~rr = |
| 86 | + bit r 7 @@ fun r7 -> |
| 87 | + bit rd 7 @@ fun rd7 -> |
| 88 | + bit rr 7 @@ fun rr7 -> |
| 89 | + rd7 && rr7 && not r7 || not rd7 && not rr7 && r7 |
| 90 | + |
| 91 | + |
| 92 | + let with_result rd f = |
| 93 | + Theory.Var.fresh (Theory.Var.sort rd) >>= fun v -> |
| 94 | + f v >>= fun effs -> |
| 95 | + data (effs @ CT.[set rd (var v)]) |
| 96 | + |
| 97 | + let (:=) = CT.set |
| 98 | + let (+) = CT.add |
| 99 | + |
| 100 | + |
| 101 | + let adc insn = |
| 102 | + require_gpr insn 1 @@ fun rd -> |
| 103 | + require_gpr insn 2 @@ fun rr -> |
| 104 | + with_result rd @@ fun r -> |
| 105 | + KB.return @@ |
| 106 | + CT.[ |
| 107 | + r := var rd + var rr + unsigned r8 (var cf); |
| 108 | + hf := halfcarry ~r ~rd ~rr; |
| 109 | + nf := nth (var r) 7; |
| 110 | + vf := overflow ~r ~rd ~rr; |
| 111 | + sf := var nf || var vf; |
| 112 | + zf := flag (is_zero (var r)); |
| 113 | + cf := fullcarry ~r ~rd ~rr; |
| 114 | + ] |
| 115 | + |
| 116 | + |
| 117 | + let add insn = |
| 118 | + require_gpr insn 1 @@ fun rd -> |
| 119 | + require_gpr insn 2 @@ fun rr -> |
| 120 | + with_result rd @@ fun r -> |
| 121 | + KB.return @@ |
| 122 | + CT.[ |
| 123 | + r := var rd + var rr; |
| 124 | + hf := halfcarry ~r ~rd ~rr; |
| 125 | + nf := nth (var r) 7; |
| 126 | + vf := overflow ~r ~rd ~rr; |
| 127 | + sf := var nf || var vf; |
| 128 | + zf := flag (is_zero (var r)); |
| 129 | + cf := fullcarry ~r ~rd ~rr; |
| 130 | + ] |
| 131 | + |
| 132 | + let ldi insn = |
| 133 | + require_gpr insn 0 @@ fun rd -> |
| 134 | + require_imm insn 1 @@ fun k -> |
| 135 | + data [ |
| 136 | + rd := const k |
| 137 | + ] |
| 138 | +end |
| 139 | + |
| 140 | +let lifter label : unit Theory.eff = |
| 141 | + KB.collect MC.Insn.slot label >>= function |
| 142 | + | None -> KB.return Insn.empty |
| 143 | + | Some insn -> |
| 144 | + Theory.instance () >>= Theory.require >>= fun (module Core) -> |
| 145 | + let module Avr = Avr(Core) in |
| 146 | + let open Avr in |
| 147 | + insn |> match MC.Insn.name insn with |
| 148 | + | "ADCRdRr" -> adc |
| 149 | + | "ADDRdRr" -> add |
| 150 | + | "LDIRdK" -> ldi |
| 151 | + | code -> |
| 152 | + info "unsupported opcode: %s" code; |
| 153 | + fun _ -> KB.return Insn.empty |
| 154 | + |
| 155 | +let load () = |
| 156 | + KB.promise Theory.Semantics.slot lifter |
0 commit comments