1
0

Added a new painter, for drawing emulation to terminal.

This commit is contained in:
Jon Michael Aanes 2018-01-03 18:58:53 +01:00
parent daad0a3062
commit 49ff6506e6
4 changed files with 109 additions and 8 deletions

97
AsciiPainter.py Normal file
View File

@ -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[]'

View File

@ -5,7 +5,7 @@ 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"]
class CodeParseException (BaseException): class CodeParseException (BaseException):
@ -158,3 +158,4 @@ class Emulator:
def getUsedRegisters (self): def getUsedRegisters (self):
return [reg_name for reg_name, reg_val in self.registers.iteritems() if not isinstance(reg_val, Junk.Junk)] return [reg_name for reg_name, reg_val in self.registers.iteritems() if not isinstance(reg_val, Junk.Junk)]

View File

@ -58,7 +58,7 @@ class TikzPainter:
pos -= 0.5 pos -= 0.5
return pos, x 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 x = (self.pos_x+1)*2.5-0.5
self.pos_x += 1 self.pos_x += 1
@ -114,13 +114,14 @@ class TikzPainter:
self.addText("\t\\node[text_node]() at ({}, {}){{TOS-{}}};\n", self.addText("\t\\node[text_node]() at ({}, {}){{TOS-{}}};\n",
x, pos, index) x, pos, index)
def to_string (self): def to_string (self, emu):
PRE = """ \\documentclass{standalone} PRE = """ \\documentclass{standalone}
\\usepackage{tikz} \\usepackage{tikz}
\\begin{document} \\begin{document}
\\begin{tikzpicture}["""+self.options+"]" \\begin{tikzpicture}["""+self.options+"]"
POST = """\\end{tikzpicture} POST = """\\end{tikzpicture}
\\end{document}""" \\end{document}"""
self.drawNames(emu)
return PRE + "".join(self.text) + POST return PRE + "".join(self.text) + POST
def __str__ (self): def __str__ (self):

12
main.py
View File

@ -7,6 +7,7 @@ import argparse
from Emulator import Emulator, CodeParseException, REGISTERS from Emulator import Emulator, CodeParseException, REGISTERS
from TikzPainter import TikzPainter from TikzPainter import TikzPainter
from AsciiPainter import AsciiPainter
import Junk import Junk
def parse_args (): def parse_args ():
@ -64,16 +65,17 @@ def main ():
emu.setRegs(**registers_init) emu.setRegs(**registers_init)
emu.setStack(Junk.Junk("junk..."), Junk.Junk("calling eip")) 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. # Iteratively draw states.
painter.drawState(emu) painter.saveState(emu)
for line_nr in emu: for line_nr in emu:
painter.drawState(emu, line_nr) painter.saveState(emu, line_nr)
painter.drawNames(emu)
# Display result # Display result
output_file.write(painter.to_string()) output_file.write(painter.to_string(emu))
output_file.close() output_file.close()
if __name__ == "__main__": if __name__ == "__main__":