import re import Junk from opcodes import OPCODES REGISTERS=["%rax", "%rbx", "%rcx", "%rdx", "%rsp", "%rbp", "%rsi", "%rdi", "%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: def __init__ (self, source_text, max_stack_size=1000): self.source = source_text self.registers = {} for reg_name in REGISTERS: self.registers[reg_name] = JUNK_VALUE self.stack = {} for i in range(max_stack_size): self.stack[i] = JUNK_VALUE self.code = [] self.labels = {} self.changes = {} self.status = {'i':True} self.last_sp = 0 self.max_stack_size = 0 index = 0 for line in iter(source_text.splitlines()): index = self.processSourceLine(line, index) def setStack (self, *stack_list, **kwargs): """ Sets various stack elements, starting from 0 and going up. Automatically sets rsp. This can be disabled by passing set_rsp=False. """ i = len(self.stack) for element in stack_list: i -= 1 self.stack[i] = element if (not 'set_rsp' in kwargs) or kwargs['set_rsp']: self.setRegs(rsp=i) self.last_sp = i-1 def setRegs (self, **reg_dict): for reg_name, reg_val in reg_dict.iteritems(): self.registers["%"+reg_name] = reg_val def getVal (self, val_text): if val_text[0] == "$": return int(val_text[1:]) elif val_text[0] == "%": return self.registers[val_text] else: raise ValueError('{} is not an usable value name'.format(val_text)) def compareVal (self, valT1, valT2): val1 = self.getVal(valT2) 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["l"] = val10 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): old_rip = self.registers['%rip'] self.last_sp = self.registers['%rsp'] if self.registers['%rip'] >= len(self.code): return None instruct = self.code[self.registers['%rip']] opcode = instruct[0] self.changes = {} OPCODES[opcode](self, *instruct[1:]) if self.registers['%rip'] == old_rip: self.registers['%rip'] += 1 else: self.changedRegisters(('%rip',"jump")) return old_rip def __iter__(self): return self def next(self): output = self.iterate() if output is None: raise StopIteration() else: return output def getUsedRegisters (self): return [reg_name for reg_name, reg_val in self.registers.iteritems() if reg_val!=JUNK_VALUE]