1
0

Added Junk value, for which all operations are

defined to produce junk.
Any comparison involving junk triggers the i status register.
Any conditional jump triggered when the i register is true,
triggers a python level exception.
This commit is contained in:
Jon Michael Aanes 2015-12-19 16:55:14 +01:00
parent 6d7de5ae75
commit 8b146efe68
5 changed files with 145 additions and 33 deletions

View File

@ -1,24 +1,33 @@
import re import re
import Junk
from opcodes import OPCODES from opcodes import OPCODES
REGISTERS=["%rax", "%rbx", "%rcx", "%rdx", "%rsp", "%rbp", "%rsi", "%rdi", REGISTERS=["%rax", "%rbx", "%rcx", "%rdx", "%rsp", "%rbp", "%rsi", "%rdi",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"] "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"]
JUNK_VALUE = Junk.Junk()
class CodeParseException (BaseException):
def __init__ (self, line_nr, string):
self.line_nr = line_nr
self.string = string
class Emulator: class Emulator:
def __init__ (self, source_text, max_stack_size=1000): def __init__ (self, source_text, max_stack_size=1000):
self.source = source_text
self.registers = {} self.registers = {}
for reg_name in REGISTERS: for reg_name in REGISTERS:
self.registers[reg_name] = "Junk" self.registers[reg_name] = JUNK_VALUE
self.stack = {} self.stack = {}
for i in range(max_stack_size): for i in range(max_stack_size):
self.stack[i] = 0 self.stack[i] = JUNK_VALUE
self.code = [] self.code = []
self.labels = {} self.labels = {}
self.changes = {} self.changes = {}
self.status = {} self.status = {'i':True}
self.last_sp = 0 self.last_sp = 0
self.max_stack_size = 0 self.max_stack_size = 0
index = 0 index = 0
@ -48,14 +57,18 @@ class Emulator:
elif val_text[0] == "%": elif val_text[0] == "%":
return self.registers[val_text] return self.registers[val_text]
else: else:
raise "NOT A VALUE! UGHGUIHGUE!" raise ValueError('{} is not an usable value name'.format(val_text))
def compareVal (self, valT1, valT2): def compareVal (self, valT1, valT2):
val1 = self.getVal(valT2) val1 = self.getVal(valT2)
val2 = self.getVal(valT1) val2 = self.getVal(valT1)
if isinstance(val1,Junk.Junk) or isinstance(val2,Junk.Junk):
self.status["i"] = (True,)
return
self.status["g"] = val1>val2 self.status["g"] = val1>val2
self.status["l"] = val1<val2 self.status["l"] = val1<val2
self.status["e"] = val1==val2 self.status["e"] = val1==val2
self.status["i"] = False
def changedRegisters (self, *args): def changedRegisters (self, *args):
for reg, val in args: for reg, val in args:
@ -63,7 +76,7 @@ class Emulator:
def processSourceLine(self, line_text, index): def processSourceLine(self, line_text, index):
tokens = re.findall(r'[^\s,]+', line_text) tokens = re.findall(r'[^\s,]+', line_text)
if len(tokens) <= 0: if len(tokens) <= 0 or tokens[0][0] == '#':
return index return index
if tokens[0][-1] == ':': if tokens[0][-1] == ':':
self.labels[tokens[0][:-1]] = index self.labels[tokens[0][:-1]] = index
@ -96,6 +109,21 @@ class Emulator:
self.registers['%rsp'] += 1 self.registers['%rsp'] += 1
return temp return temp
def jump (self, label, cond_op="or", **conditions):
if len(conditions)>0 and self.status["i"]:
raise Junk.JunkComparisonException(*self.status['i'])
and_, or_ = True, False
for cnd_name, cnd_val in conditions.iteritems():
if self.status[cnd_name] == cnd_val:
or_ = True
else:
and_ = False
if or_ if cond_op=="or" else and_:
self.registers['%rip'] = self.labels[label]
return True
else:
return False
def iterate (self): def iterate (self):
old_rip = self.registers['%rip'] old_rip = self.registers['%rip']
self.last_sp = self.registers['%rsp'] self.last_sp = self.registers['%rsp']
@ -123,3 +151,6 @@ class Emulator:
raise StopIteration() raise StopIteration()
else: else:
return output return output
def getUsedRegisters (self):
return [reg_name for reg_name, reg_val in self.registers.iteritems() if reg_val!=JUNK_VALUE]

27
Junk.py Normal file
View File

@ -0,0 +1,27 @@
class JunkComparisonException (BaseException):
pass
class Junk:
def __init__ (self):
pass
def __str__ (self):
return "[Junk]"
def __repr__ (self):
return "[Junk]"
def __add__ (self, other):
return self
def __radd__ (self, other):
return self
def __sub__ (self, other):
return self
def __rsub__ (self, other):
return self

View File

@ -2,8 +2,9 @@
import sys import sys
import getopt import getopt
from Emulator import Emulator from Emulator import Emulator, CodeParseException
from TikzPainter import TikzPainter from TikzPainter import TikzPainter
from Junk import Junk, JunkComparisonException
if __name__ == "__main__": if __name__ == "__main__":
pass pass

View File

@ -45,33 +45,27 @@ def comp(emu, val1, val2):
@add_opcode("jg") @add_opcode("jg")
def jg(emu, label): def jg(emu, label):
if emu.status["g"]: emu.jump(label, g=True)
emu.registers['%rip'] = emu.labels[label]
@add_opcode("jl") @add_opcode("jl")
def jl(emu, label): def jl(emu, label):
if emu.status["l"]: emu.jump(label, l=True)
emu.registers['%rip'] = emu.labels[label]
@add_opcode("je") @add_opcode("je")
def je(emu, label): def je(emu, label):
if emu.status["e"]: emu.jump(label, e=True)
emu.registers['%rip'] = emu.labels[label]
@add_opcode("jge") @add_opcode("jge")
def jge(emu, label): def jge(emu, label):
if emu.status["g"] or emu.status["e"]: emu.jump(label, "or", g=True, e=True)
emu.registers['%rip'] = emu.labels[label]
@add_opcode("jle") @add_opcode("jle")
def jle(emu, label): def jle(emu, label):
if emu.status["l"] or emu.status["e"]: emu.jump(label, "or", l=True, e=True)
emu.registers['%rip'] = emu.labels[label]
@add_opcode("jne") @add_opcode("jne")
def jne(emu, label): def jne(emu, label):
if not emu.status["e"]: emu.jump(label, e=False)
emu.registers['%rip'] = emu.labels[label]
# Unconditional Jumping # Unconditional Jumping

View File

@ -1,5 +1,7 @@
import os,sys,inspect import os, sys, inspect
import traceback
sys.path.insert(1, os.path.join(sys.path[0], '..')) sys.path.insert(1, os.path.join(sys.path[0], '..'))
import infernal import infernal
################################################################################ ################################################################################
@ -9,16 +11,6 @@ tests = []
def add_test(name, result, register, code): def add_test(name, result, register, code):
tests.append((name, result, register, code)) tests.append((name, result, register, code))
def execute_test (register, code):
emu = infernal.Emulator(code)
emu.setStack("junk...", "calling eip")
emu.setRegs( rip = 0, rbp = 'old bp')
for line_nr in emu:
pass
return emu.getVal(register)
def printf (str, *args): def printf (str, *args):
print(str.format(*args)) print(str.format(*args))
@ -29,15 +21,32 @@ def execute_tests():
error_tests = 0 error_tests = 0
for name, result, register, code in tests: for name, result, register, code in tests:
total_tests += 1 total_tests += 1
line_nr = None
try: try:
output = execute_test(register, code) emu = infernal.Emulator(code)
emu.setStack("junk...", "calling eip")
emu.setRegs( rip = 0, rbp = 'old bp')
except infernal.CodeParseException as e:
error_tests += 1
printf("Encountered error when parsing {}, at line {}: {}",
name, e.line_nr, e.str)
try:
for line_nr in emu:
pass
if isinstance(result, BaseException):
printf("Error should have happened in {}, but did not", name)
failed_tests += 1
output = emu.getVal(register)
if output != result: if output != result:
failed_tests += 1 failed_tests += 1
printf("Failed in {}. {} was {}, should be {}", printf("Failed in {}. {} was {}, should be {}",
name, register, result, output) name, register, result, output)
except BaseException as e: except BaseException as e:
error_tests += 1 if not isinstance(e, result):
printf("Encountered error in {}: {}",name,e) error_tests += 1
printf("Encountered error in {}, at operation {}: {}",
name, emu.getVal('%rip'), e)
traceback.print_exc()
printf("Tests done! {}/{}.", printf("Tests done! {}/{}.",
total_tests - failed_tests - error_tests, total_tests) total_tests - failed_tests - error_tests, total_tests)
printf("{} failed, and {} encountered a python error", printf("{} failed, and {} encountered a python error",
@ -60,6 +69,56 @@ movq $20, %rax
addq %rax, %rsi addq %rax, %rsi
""") """)
################################################################################
add_test("invalid comparison 1", infernal.JunkComparisonException, "None", """
start: movq $100, %rsp # Set stack pointer to a random position.
popq %rsi # Move a Junk value into %rsi
cmpq $10, %rsi # Do a Junk comparison, which triggers the `i` comp
# virtual register.
jg start # Attempt to do a jump to the start, if (Junk-10)>0,
# which makes no sense, and thus throws an error.
""")
add_test("invalid addition 1", infernal.JunkComparisonException, "None", """
start: movq $100, %rsp # Set stack pointer to a random position.
popq %rsi # Move a Junk value into %rsi
addq %rsi, %rsp # Adds Junk to 101, which produces Junk.
cmpq $10, %rsp # Do a Junk comparison, which triggers the `i` comp
# virtual register.
jg start # Attempt to do a jump to the start, if (Junk-10)>0,
# which makes no sense, and thus throws an error.
""")
add_test("invalid addition 2", infernal.JunkComparisonException, "None", """
start: movq $100, %rsp # Set stack pointer to a random position.
popq %rsi # Move a Junk value into %rsi
addq %rsp, %rsi # Adds 101 to Junk, which produces Junk.
cmpq $10, %rsi # Do a Junk comparison, which triggers the `i` comp
# virtual register.
jg start # Attempt to do a jump to the start, if (Junk-10)>0,
# which makes no sense, and thus throws an error.
""")
add_test("invalid subtraction 1", infernal.JunkComparisonException, "None", """
start: movq $100, %rsp # Set stack pointer to a random position.
popq %rsi # Move a Junk value into %rsi
subq %rsi, %rsp # Adds Junk to 101, which produces Junk.
cmpq $10, %rsp # Do a Junk comparison, which triggers the `i` comp
# virtual register.
jg start # Attempt to do a jump to the start, if (Junk-10)>0,
# which makes no sense, and thus throws an error.
""")
add_test("invalid subtraction 2", infernal.JunkComparisonException, "None", """
start: movq $100, %rsp # Set stack pointer to a random position.
popq %rsi # Move a Junk value into %rsi
subq %rsp, %rsi # Adds 101 to Junk, which produces Junk.
cmpq $10, %rsi # Do a Junk comparison, which triggers the `i` comp
# virtual register.
jg start # Attempt to do a jump to the start, if (Junk-10)>0,
# which makes no sense, and thus throws an error.
""")
################################################################################ ################################################################################