diff --git a/AsciiPainter.py b/AsciiPainter.py new file mode 100644 index 0000000..ba80620 --- /dev/null +++ b/AsciiPainter.py @@ -0,0 +1,97 @@ + +import re +import subprocess + +NORMAL_COLOR = '\033[0m' + +REG_STATUS_TO_COLOR = { + "insert": '\033[32m', + "change": '\033[33m', + "remove": '\033[31m', + "none": '\033[0m', + "jump": '\033[36m' +} + +class AsciiPainter: + + def __init__ (self, registers=None, max_stack_size=8, stack_draw_mode="up"): + self.registers = registers if registers else REGISTERS + self.states = [] + self.max_stack_size = max_stack_size + self.stack_draw_mode = stack_draw_mode + + def saveState (self, emu, line_nr=None): + # Init state + state = [] + self.states.append(state) + # Write opcode to state + if line_nr != None: + signature = emu.getLineSignature(line_nr) + for token in signature: + state.append({ 'state': 'none', 'val': token }) + # + for i in range(3-len(state)): state.append({'state':'none', 'val': ''}) + for i in range(len(state)-3): state.pop() + state.append({'state':'none', 'val':''}) + # Write registers to state + for reg_name in self.registers: + if reg_name =="": + state.append({'state':'none', 'val':''}) + continue + reg_state = emu.regState(reg_name) + state.append({ 'state': reg_state, 'val': emu.getVal(reg_name) }) + # Write stack to state + stack_base_pointer = emu.getVal('%rbp') + print(emu.last_sp, emu.getVal('%rsp')) + base_sp = emu.getVal('%rsp') + assert(isinstance(emu.getVal('%rsp'), (int, long))) + state.append({'state':'none', 'val': ''}) + if emu.regState('m'+str(base_sp-1)) == 'remove': + state.append({'state': emu.regState('m'+str(base_sp-1)), 'val': emu.stack[base_sp-1]}) + else: + state.append({'state': 'none', 'val': ''}) + for index in range(0, self.max_stack_size): + stack_i = base_sp + index + print(index, stack_i) + if stack_i < emu.max_stack_size: + state.append({ 'state': emu.regState("m"+str(stack_i)), 'val': emu.stack[stack_i] }) + if stack_base_pointer == index: + stack_base_pointer = emu.stack[base_pointer] + # TODO: Draw stack frame seperators + else: + state.append({'state':'none', 'val': ''}) + + def to_string (self, emu): + number_states = len(self.states) + number_state_vars = len(self.states[0]) + + term_width = int(subprocess.check_output(['tput', 'cols'])) + number_states_pr_block = term_width / (10+2) - 1 + separator = '-' * term_width + l = [] + + for base_state in range(0, number_states, number_states_pr_block): + l.append(separator) + for var_i in range(0, number_state_vars): + l.append('{:10}'.format(self.nameOfVar(var_i-4))) + for state_i in range(0, min(number_states_pr_block, number_states - base_state)): + var = self.states[base_state+state_i][var_i] + l.append('{}{:>10}{} '.format(REG_STATUS_TO_COLOR[var['state']], var['val'], NORMAL_COLOR)) + l.append('\n') + l.append(separator) + + return ''.join(l) + + def nameOfVar (self, i): + if i < 0: return '' + if i < len(self.registers): + return self.registers[i] + elif i != len(self.registers): + state_i = i-len(self.registers) - 2 + return 'TOS{}{}'.format('+' if state_i < 0 else '-', abs(state_i)) + else: + return '' + + def __str__ (self): + return 'TikzPainter[]' + diff --git a/Emulator.py b/Emulator.py index b8334fd..0f0b6c2 100644 --- a/Emulator.py +++ b/Emulator.py @@ -5,7 +5,7 @@ import Junk from opcodes import OPCODES 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"] class CodeParseException (BaseException): @@ -158,3 +158,4 @@ class Emulator: def getUsedRegisters (self): return [reg_name for reg_name, reg_val in self.registers.iteritems() if not isinstance(reg_val, Junk.Junk)] + diff --git a/TikzPainter.py b/TikzPainter.py index a68a97c..e69743b 100644 --- a/TikzPainter.py +++ b/TikzPainter.py @@ -58,7 +58,7 @@ class TikzPainter: pos -= 0.5 return pos, x - def drawState (self, emu, line_nr=None): + def saveState (self, emu, line_nr=None): x = (self.pos_x+1)*2.5-0.5 self.pos_x += 1 @@ -114,13 +114,14 @@ class TikzPainter: self.addText("\t\\node[text_node]() at ({}, {}){{TOS-{}}};\n", x, pos, index) - def to_string (self): + def to_string (self, emu): PRE = """ \\documentclass{standalone} \\usepackage{tikz} \\begin{document} \\begin{tikzpicture}["""+self.options+"]" POST = """\\end{tikzpicture} \\end{document}""" + self.drawNames(emu) return PRE + "".join(self.text) + POST def __str__ (self): diff --git a/main.py b/main.py index bc24e67..a2f6349 100755 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ import argparse from Emulator import Emulator, CodeParseException, REGISTERS from TikzPainter import TikzPainter +from AsciiPainter import AsciiPainter import Junk def parse_args (): @@ -64,16 +65,17 @@ def main (): emu.setRegs(**registers_init) emu.setStack(Junk.Junk("junk..."), Junk.Junk("calling eip")) - painter = TikzPainter(registers_to_draw) + painter_class = TikzPainter # AsciiPainter + + painter = painter_class(registers_to_draw) # Iteratively draw states. - painter.drawState(emu) + painter.saveState(emu) for line_nr in emu: - painter.drawState(emu, line_nr) - painter.drawNames(emu) + painter.saveState(emu, line_nr) # Display result - output_file.write(painter.to_string()) + output_file.write(painter.to_string(emu)) output_file.close() if __name__ == "__main__":