-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdebugger.py
executable file
·159 lines (119 loc) · 4.52 KB
/
debugger.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/python
import sys
from interpreter import vm as vm
class terminal:
def __init__(self):
self.__buffer = ""
def get_char(self):
if self.__buffer == "":
user_input = '!'
while len(user_input) > 0 and user_input[0] == '!':
user_input = raw_input()
if len(user_input) > 0 and user_input[0] == '!':
self.debugger.process_command(user_input)
self.__buffer = user_input + "\n"
answer = self.__buffer[0]
self.__buffer = self.__buffer[1:]
return answer
def print_char(self, character):
sys.stdout.write(character)
if self.debugger.is_debugging():
sys.stdout.write('\n')
class debugger:
def __init__(self, vm):
self.vm = vm
self.__function_names = {}
with open('notes/functions.txt', 'r') as f:
for line in f:
if len(line) == 0 or line[0] == '#' or line == '\n':
continue
a = line.strip().split(':')
self.__function_names[int(a[0])] = a[1]
self.__call_stack = []
self.__debugging = False
self.op_names = {0: ['halt', 0],
1: ['set ', 2],
2: ['push', 1],
3: ['pop ', 1],
4: ['eq ', 3],
5: ['gt ', 3],
6: ['jmp ', 1],
7: ['jt ', 2],
8: ['jf ', 2],
9: ['add ', 3],
10: ['add ', 3],
11: ['mod ', 3],
12: ['and ', 3],
13: ['or ', 3],
14: ['not ', 2],
15: ['rmem', 2],
16: ['wmem', 2],
17: ['call', 1],
18: ['ret ', 0],
19: ['out ', 1],
20: ['in ', 1],
21: ['noop', 0]}
def process_command(self, input_str):
def dump(args):
self.vm.dump_state(args[1])
def load(args):
self.vm.load_dump(args[1])
def start(args):
self.__debugging = True
def stop(args):
self.__debugging = False
def hijack(arb):
str_in = args[1]
in_codes = map(int, str_in.split(','))
# so we can end hijack code with a ret
self.vm.stack.push(self.vm.pointer)
for offset, code in enumerate(in_codes):
self.vm.memory.write(offset + 30100, code)
self.vm.pointer = 30100
commands = {'!dump': dump, '!start': start,
'!stop': stop, '!hijack': hijack,
'!load': load}
args = input_str.split(' ')
if args[0] not in commands:
print 'invalid command'
return
commands[args[0]](args)
def print_current(self):
pointer = self.vm.pointer
current_op = self.vm.memory.read(pointer)
[op_name, num_args] = self.op_names[current_op]
args = [self.vm.memory.read(pointer + 1 + i) for i in
xrange(num_args)]
def call(args):
callee = self.vm.resolve(args[0])
name = self.__function_names.get(callee, '')
return 'call %d %s' % (callee, name)
def wmem(args):
data = self.vm.resolve(args[1])
addr = self.vm.resolve(args[0])
return 'wmem %d %d' % (addr, data)
style_op = {'call': call, 'wmem': wmem}
if op_name in style_op:
print ' ' * len(self.__call_stack) + str(pointer) + ': ' + style_op[op_name](args)
def is_debugging(self):
return self.__debugging
def step(self):
if self.__debugging:
self.print_current()
# update depth after display
if self.vm.memory.read(self.vm.pointer) == 17:
self.__call_stack.append(self.vm.memory.read(self.vm.pointer + 1))
if self.vm.memory.read(self.vm.pointer) == 18 and len(self.__call_stack) > 0:
self.__call_stack.pop()
terminal = terminal()
in_fn = terminal.get_char
out_fn = terminal.print_char
emulator = vm(in_fn, out_fn)
debugger = debugger(emulator)
# terminal needs reference for access in cheatmode
terminal.debugger = debugger
# emulator.load_binary("challenge.bin")
emulator.load_dump('logs/boot.log')
while True:
emulator.step()
debugger.step()