Added a new painter, for drawing emulation to terminal.
This commit is contained in:
parent
daad0a3062
commit
49ff6506e6
97
AsciiPainter.py
Normal file
97
AsciiPainter.py
Normal 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[]'
|
||||
|
|
@ -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)]
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
12
main.py
12
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__":
|
||||
|
|
Loading…
Reference in New Issue
Block a user