summaryrefslogtreecommitdiff
path: root/example/program.py
diff options
context:
space:
mode:
Diffstat (limited to 'example/program.py')
-rw-r--r--example/program.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/example/program.py b/example/program.py
new file mode 100644
index 0000000..b3e6afb
--- /dev/null
+++ b/example/program.py
@@ -0,0 +1,130 @@
+from satispi import *
+
+class Program:
+ def __init__(self, instructions):
+ self.instructions = instructions
+ self.registers = set()
+ for pc in self.instructions:
+ if pc[0] == "label": continue
+ if pc[0] == "ite":
+ if isinstance(pc[1], str):
+ self.registers.add(pc[1])
+ else:
+ self.registers.update(a for a in pc[1:] if isinstance(a, str))
+ self.registers = sorted(self.registers)
+
+ @staticmethod
+ def from_file(path):
+ lines = [l.strip() for l in open(path, "r").readlines()]
+ lines = [l for l in lines if l and not l.startswith(";")]
+ instructions = []
+ for l in lines:
+ opcode, *args = l.split()
+ if opcode != "label":
+ args = [int(a[1:]) if a[0] == "$" else a for a in args]
+ instructions.append((opcode, *args))
+ return Program(instructions)
+
+ def get_op(self, pcidx):
+ return self.instructions[pcidx]
+
+ def label_to_pcidx(self, label):
+ for i, pc in enumerate(self.instructions):
+ if pc == ("label", label):
+ return i
+ raise NotImplementedError
+
+class State:
+ def __init__(self, program, pcidx, smtlib, parent):
+ self.program = program
+ self.pcidx = pcidx
+ self.smtlib = smtlib.copy()
+ self.parent = parent
+ self.idx = (parent.idx + 1) if parent is not None else 0
+
+ def step(self):
+ smtlib = self.smtlib
+ opcode, *args = self.program.get_op(self.pcidx)
+ if opcode == "ite": # ite cond tlabel flabel
+ cond = self.to_term(args[0])
+ true_idx = self.program.label_to_pcidx(args[1])
+ false_idx = self.program.label_to_pcidx(args[2])
+ delta = self.nops({})
+ true_delta = Term("and", delta, Term("distinct", cond, Literal("(_ bv0 32)")))
+ false_delta = Term("and", delta, Term("=", cond, Literal("(_ bv0 32)")))
+ if args[1] == args[2]:
+ return [State(self.program, true_idx, smtlib + [delta], self)]
+ return [State(self.program, true_idx, smtlib + [true_delta], self),
+ State(self.program, false_idx, smtlib + [false_delta], self)]
+
+ new_pcidx = self.pcidx + 1
+ if opcode == "label":
+ delta = self.nops({})
+ elif opcode == "end":
+ delta = self.nops({})
+ new_pcidx = self.pcidx
+ elif opcode == "load": # load dstreg addr
+ to_reg = self.nto_term(args[0])
+ value = Term("select", self.heap(), self.to_term(args[1]))
+ delta = self.nops({args[0]})
+ delta = Term("and", delta, Term("=", to_reg, value))
+ elif opcode == "store": # store addr val
+ addr = self.to_term(args[0])
+ value = self.to_term(args[1])
+ new_heap = Term("store", self.heap(), addr, value)
+ delta = self.nops({"@heap"})
+ delta = Term("and", delta, Term("=", self.nheap(), new_heap))
+ elif opcode in ("add", "sub", "eq", "xor", "mul"): # op reg delta
+ op = {"add": "bvadd", "sub": "bvsub", "eq": "=",
+ "xor": "bvxor", "mul": "bvmul"}[opcode]
+ old = self.to_term(args[0])
+ val = self.to_term(args[1])
+ new = Term(op, old, val)
+ if op == "=":
+ new = Term("ite", new, Literal("(_ bv1 32)"), Literal("(_ bv0 32)"))
+ delta = self.nops({args[0]})
+ delta = Term("and", delta, Term("=", self.nreg(args[0]), new))
+ elif opcode == "mov": # mov dst src
+ val = self.to_term(args[1])
+ delta = self.nops({args[0]})
+ delta = Term("and", delta, Term("=", self.nreg(args[0]), val))
+ else: print(opcode); raise NotImplementedError
+ return [State(self.program, new_pcidx, self.smtlib + [delta], self)]
+
+ def has_model(self):
+ return Solver.singleton().model(self.smtlib) is not None
+
+ def heap(self):
+ return Variable(f"heap_{self.idx}",
+ "(Array (_ BitVec 32) (_ BitVec 32))")
+
+ def reg(self, reg):
+ return Variable(f"reg_{reg}_{self.idx}", "(_ BitVec 32)")
+
+ def to_term(self, arg):
+ if isinstance(arg, int):
+ return Literal(f"(_ bv{arg} 32)")
+ return self.reg(arg)
+
+ def nheap(self):
+ return Variable(f"heap_{self.idx + 1}",
+ "(Array (_ BitVec 32) (_ BitVec 32))")
+
+ def nreg(self, reg):
+ return Variable(f"reg_{reg}_{self.idx + 1}", "(_ BitVec 32)")
+
+ def nto_term(self, arg):
+ if isinstance(arg, int):
+ return Literal(f"(_ bv{arg} 32)")
+ return self.nreg(arg)
+
+ def nops(self, except_for=set()):
+ term = Literal("true")
+ for reg in self.program.registers:
+ if reg in except_for: continue
+ term = Term("and", term,
+ Term("=", self.nreg(reg), self.reg(reg)))
+ if "@heap" not in except_for:
+ term = Term("and", term,
+ Term("=", self.nheap(), self.heap()))
+ return term
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback