mirror of
https://github.com/sslab-gatech/winnie
synced 2026-06-08 17:35:47 +00:00
208 lines
7.1 KiB
Python
208 lines
7.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
from operator import add, sub, mul, mod, itruediv, pow, and_, or_, lshift, rshift
|
|
from operator import inv
|
|
|
|
global vars
|
|
vars = {}
|
|
|
|
|
|
def assign(a, b):
|
|
global vars
|
|
if not isinstance(a, str) or not a.startswith("$"):
|
|
raise ValueError("Cannot assign to a constant")
|
|
vars[a] = b
|
|
|
|
|
|
binary_ops = {
|
|
"+": add,
|
|
"-": sub,
|
|
"/": itruediv,
|
|
"*": mul,
|
|
"%": mod,
|
|
"**": pow,
|
|
"<<": lshift,
|
|
">>": rshift,
|
|
"&": and_,
|
|
"|": or_,
|
|
}
|
|
|
|
# Note:
|
|
# ^ means "dereference". In the airbag unit tests, this is accompanied by
|
|
# a memory region that can deal with dereferencing addresses (presumably).
|
|
# Their test uses FakeMemoryRegion, which appears to just return x+1 for
|
|
# any pointer x that is dereferenced. So we use lambda x: x+1 as a
|
|
# placeholder.
|
|
unary_ops = {
|
|
"~": inv,
|
|
"^": lambda x: x + 1,
|
|
}
|
|
|
|
|
|
def evaluate(pfstr):
|
|
global vars
|
|
stack = []
|
|
for tok in pfstr.split():
|
|
if tok == "=":
|
|
try:
|
|
b = stack.pop()
|
|
a = stack.pop()
|
|
except IndexError:
|
|
raise ValueError("Not enough values on the stack for requested operation")
|
|
|
|
if isinstance(b, str) and (b.startswith("$") or b.startswith(".")):
|
|
try:
|
|
b = vars[b]
|
|
except KeyError:
|
|
raise ValueError("Name %s referenced before assignment" % b)
|
|
|
|
assign(a, b)
|
|
elif tok in binary_ops:
|
|
try:
|
|
b = stack.pop()
|
|
a = stack.pop()
|
|
except IndexError:
|
|
raise ValueError("Not enough values on the stack for requested operation")
|
|
|
|
if isinstance(a, str) and (a.startswith("$") or a.startswith(".")):
|
|
try:
|
|
a = vars[a]
|
|
except KeyError:
|
|
raise ValueError("Name %s referenced before assignment" % a)
|
|
if isinstance(b, str) and (b.startswith("$") or b.startswith(".")):
|
|
try:
|
|
b = vars[b]
|
|
except KeyError:
|
|
raise ValueError("Name %s referenced before assignment" % b)
|
|
|
|
stack.append(binary_ops[tok](a, b))
|
|
elif tok in unary_ops:
|
|
try:
|
|
a = stack.pop()
|
|
except IndexError:
|
|
raise ValueError("Not enough values on the stack for requested operation")
|
|
|
|
if isinstance(a, str) and (a.startswith("$") or a.startswith(".")):
|
|
try:
|
|
a = vars[a]
|
|
except KeyError:
|
|
raise ValueError("Name %s referenced before assignment" % a)
|
|
|
|
stack.append(unary_ops[tok](a))
|
|
elif tok.startswith("$") or tok.startswith("."):
|
|
stack.append(tok)
|
|
else:
|
|
stack.append(int(tok, 0))
|
|
if stack:
|
|
raise ValueError("Values remain on the stack after processing")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pfstrs = [
|
|
("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =",
|
|
True),
|
|
("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =",
|
|
True),
|
|
("$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = $esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = $ebx $T0 28 - ^ =",
|
|
True),
|
|
]
|
|
|
|
vars["$ebp"] = 0xbfff0010
|
|
vars["$eip"] = 0x10000000
|
|
vars["$esp"] = 0xbfff0000
|
|
vars[".cbSavedRegs"] = 4
|
|
vars[".cbParams"] = 4
|
|
vars[".raSearchStart"] = 0xbfff0020
|
|
|
|
for (test, should_succeed) in pfstrs:
|
|
try:
|
|
evaluate(test)
|
|
if len(repr(test)) > 50:
|
|
test = test[:50] + "[...]"
|
|
if not should_succeed:
|
|
print('Test %-60s FAILED.' % repr(test))
|
|
else:
|
|
print('Test %-60s PASSED.' % repr(test))
|
|
except ValueError:
|
|
if should_succeed:
|
|
print('Test %-60s FAILED.' % repr(test))
|
|
else:
|
|
print('Test %-60s PASSED.' % repr(test))
|
|
|
|
validate_data_1 = {}
|
|
validate_data_1["$T0"] = 0xbfff0012
|
|
validate_data_1["$T1"] = 0xbfff0020
|
|
validate_data_1["$T2"] = 0xbfff0019
|
|
validate_data_1["$eip"] = 0xbfff0021
|
|
validate_data_1["$ebp"] = 0xbfff0012
|
|
validate_data_1["$esp"] = 0xbfff0024
|
|
validate_data_1["$L"] = 0xbfff000e
|
|
validate_data_1["$P"] = 0xbfff0028
|
|
validate_data_1["$ebx"] = 0xbffefff7
|
|
validate_data_1[".cbSavedRegs"] = 4
|
|
validate_data_1[".cbParams"] = 4
|
|
|
|
for k in validate_data_1:
|
|
assert vars[k] == validate_data_1[k]
|
|
|
|
vars = {}
|
|
|
|
validate_data_0 = {}
|
|
validate_data_0["$rAdd"] = 8
|
|
validate_data_0["$rAdd2"] = 4
|
|
validate_data_0["$rSub"] = 3
|
|
validate_data_0["$rMul"] = 54
|
|
validate_data_0["$rDivQ"] = 1
|
|
validate_data_0["$rDivM"] = 3
|
|
validate_data_0["$rDeref"] = 10
|
|
|
|
pfstrs = [
|
|
("$rAdd 2 2 + =", True), # $rAdd = 2 + 2 = 4
|
|
("$rAdd $rAdd 2 + =", True), # $rAdd = $rAdd + 2 = 6
|
|
("$rAdd 2 $rAdd + =", True), # $rAdd = 2 + $rAdd = 8
|
|
("99", False), # put some junk on the stack...
|
|
("$rAdd2 2 2 + =", True), # ...and make sure things still work
|
|
("$rAdd2\t2\n2 + =", True), # same but with different whitespace
|
|
("$rAdd2 2 2 + = ", True), # trailing whitespace
|
|
(" $rAdd2 2 2 + =", True), # leading whitespace
|
|
("$rAdd2 2 2 + =", True), # extra whitespace
|
|
("$T0 2 = +", False), # too few operands for add
|
|
("2 + =", False), # too few operands for add
|
|
("2 +", False), # too few operands for add
|
|
("+", False), # too few operands for add
|
|
("^", False), # too few operands for dereference
|
|
("=", False), # too few operands for assignment
|
|
("2 =", False), # too few operands for assignment
|
|
("2 2 + =", False), # too few operands for assignment
|
|
("2 2 =", False), # can't assign into a literal
|
|
("k 2 =", False), # can't assign into a constant
|
|
("2", False), # leftover data on stack
|
|
("2 2 +", False), # leftover data on stack
|
|
("$rAdd", False), # leftover data on stack
|
|
("0 $T1 0 0 + =", False), # leftover data on stack
|
|
("$T2 $T2 2 + =", False), # can't operate on an undefined value
|
|
("$rMul 9 6 * =", True), # $rMul = 9 * 6 = 54
|
|
("$rSub 9 6 - =", True), # $rSub = 9 - 6 = 3
|
|
("$rDivQ 9 6 / =", True), # $rDivQ = 9 / 6 = 1
|
|
("$rDivM 9 6 % =", True), # $rDivM = 9 % 6 = 3
|
|
("$rDeref 9 ^ =", True) # $rDeref = ^9 = 10 (FakeMemoryRegion)
|
|
]
|
|
|
|
for (test, should_succeed) in pfstrs:
|
|
try:
|
|
evaluate(test)
|
|
if len(repr(test)) > 50:
|
|
test = test[:50] + "[...]"
|
|
if not should_succeed:
|
|
print('Test %-60s FAILED.' % repr(test))
|
|
else:
|
|
print('Test %-60s PASSED.' % repr(test))
|
|
except ValueError:
|
|
if should_succeed:
|
|
print('Test %-60s FAILED.' % repr(test))
|
|
else:
|
|
print('Test %-60s PASSED.' % repr(test))
|
|
|
|
for k in validate_data_0:
|
|
assert vars[k] == validate_data_0[k]
|