added options for making the emulator less attention-demanding.
This commit is contained in:
parent
dda7b25c15
commit
6c38906a51
|
@ -10,7 +10,6 @@ import argparse
|
||||||
|
|
||||||
from llvm_emulator import stepper, parser
|
from llvm_emulator import stepper, parser
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
arg_parser = argparse.ArgumentParser(description='A hacky LLVM-- emulator/debugger')
|
arg_parser = argparse.ArgumentParser(description='A hacky LLVM-- emulator/debugger')
|
||||||
|
|
||||||
|
@ -18,6 +17,16 @@ def main():
|
||||||
action='store', type=str, dest='auto_path',
|
action='store', type=str, dest='auto_path',
|
||||||
help='Automatically step through llvm in the given file')
|
help='Automatically step through llvm in the given file')
|
||||||
|
|
||||||
|
arg_parser.add_argument('-s', '--step',
|
||||||
|
action='store', type=int, dest='auto_step',
|
||||||
|
default=100,
|
||||||
|
help='How often to prompt for continuation in auto-mode, 0 is never')
|
||||||
|
|
||||||
|
arg_parser.add_argument('-p', '--print',
|
||||||
|
action='store', type=int, dest='print_level',
|
||||||
|
default=3,
|
||||||
|
help='Verboseness of the emulator')
|
||||||
|
|
||||||
parse_res_raw = arg_parser.parse_args()
|
parse_res_raw = arg_parser.parse_args()
|
||||||
parse_res = vars(parse_res_raw)
|
parse_res = vars(parse_res_raw)
|
||||||
|
|
||||||
|
@ -26,12 +35,16 @@ def main():
|
||||||
llvm_parser.build()
|
llvm_parser.build()
|
||||||
|
|
||||||
if parse_res['auto_path'] is not None:
|
if parse_res['auto_path'] is not None:
|
||||||
go_auto(parse_res['auto_path'])
|
step_behavior = {
|
||||||
|
'step_ask': parse_res['auto_step'],
|
||||||
|
'step_print_level': parse_res['print_level']
|
||||||
|
}
|
||||||
|
go_auto(parse_res['auto_path'], step_behavior)
|
||||||
else:
|
else:
|
||||||
enter_interactive_mode()
|
enter_interactive_mode()
|
||||||
|
|
||||||
|
|
||||||
def go_auto(path_to_file):
|
def go_auto(path_to_file, step_behavior):
|
||||||
with open(path_to_file, 'r') as f:
|
with open(path_to_file, 'r') as f:
|
||||||
file_contents = f.read()
|
file_contents = f.read()
|
||||||
print('Parsing {}'
|
print('Parsing {}'
|
||||||
|
@ -39,7 +52,7 @@ def go_auto(path_to_file):
|
||||||
ast = llvm_parser.parse(file_contents)
|
ast = llvm_parser.parse(file_contents)
|
||||||
print('Beginning execution of {}'
|
print('Beginning execution of {}'
|
||||||
.format(path_to_file))
|
.format(path_to_file))
|
||||||
stepper.auto_step(ast)
|
stepper.auto_step(ast, step_behavior = step_behavior)
|
||||||
|
|
||||||
|
|
||||||
def enter_interactive_mode():
|
def enter_interactive_mode():
|
||||||
|
|
|
@ -2,21 +2,43 @@ from enum import Enum
|
||||||
|
|
||||||
from llvm_emulator import ll
|
from llvm_emulator import ll
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
def TODO(msg):
|
############
|
||||||
print('TODO: not implemented yet at {}'
|
# Messages #
|
||||||
.format(msg))
|
|
||||||
|
|
||||||
|
PRINT_LEVEL_NONE = 0
|
||||||
|
PRINT_LEVEL_ERR = 1
|
||||||
|
PRINT_LEVEL_WARN = 2
|
||||||
|
PRINT_LEVEL_INFO = 3
|
||||||
|
|
||||||
|
PRINT_LEVEL = PRINT_LEVEL_NONE
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
def eprint(*args, **kwargs):
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
def err(msg):
|
def err(msg):
|
||||||
print('ERROR: {}'
|
if PRINT_LEVEL >= PRINT_LEVEL_ERR:
|
||||||
|
eprint('ERROR: {}'
|
||||||
.format(msg))
|
.format(msg))
|
||||||
|
|
||||||
|
def TODO(msg):
|
||||||
|
err('TODO: not implemented yet at {}'
|
||||||
|
.format(msg))
|
||||||
|
|
||||||
def warn(msg):
|
def warn(msg):
|
||||||
print('WARNING: {}'
|
if PRINT_LEVEL >= PRINT_LEVEL_WARN:
|
||||||
|
eprint('WARNING: {}'
|
||||||
.format(msg))
|
.format(msg))
|
||||||
|
|
||||||
|
def info(*args, **kwargs):
|
||||||
|
if PRINT_LEVEL >= PRINT_LEVEL_INFO:
|
||||||
|
print(*args, **kwargs)
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Stuff? #
|
||||||
|
|
||||||
class Garbage(Enum):
|
class Garbage(Enum):
|
||||||
GARBAGE = '<<Unitialized memory>>'
|
GARBAGE = '<<Unitialized memory>>'
|
||||||
|
@ -50,14 +72,14 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
.format(ssa_target))
|
.format(ssa_target))
|
||||||
else:
|
else:
|
||||||
# TODO
|
# TODO
|
||||||
print('%{} <- {}'
|
info('%{} <- {}'
|
||||||
.format(ssa_target, res))
|
.format(ssa_target, res))
|
||||||
ssa_env[ssa_target] = res
|
ssa_env[ssa_target] = res
|
||||||
|
|
||||||
return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res
|
return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('Evaluating {}'
|
info('Evaluating {}'
|
||||||
.format(ll.insn2s(next_insn)))
|
.format(ll.insn2s(next_insn)))
|
||||||
|
|
||||||
res = None
|
res = None
|
||||||
|
@ -70,7 +92,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = eval_binop(bop, left_v, right_v)
|
res = eval_binop(bop, left_v, right_v)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('{} {}, {}'
|
info('{} {}, {}'
|
||||||
.format(bop, left_v, right_v))
|
.format(bop, left_v, right_v))
|
||||||
elif isinstance(next_insn, ll.Alloca):
|
elif isinstance(next_insn, ll.Alloca):
|
||||||
ty = next_insn.ty
|
ty = next_insn.ty
|
||||||
|
@ -78,7 +100,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
size = base_ty2size(base_ty)
|
size = base_ty2size(base_ty)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('alloca {} --> allocating {} cells'
|
info('alloca {} --> allocating {} cells'
|
||||||
.format(ll.ty2s(base_ty), size))
|
.format(ll.ty2s(base_ty), size))
|
||||||
|
|
||||||
ptr = len(heap)
|
ptr = len(heap)
|
||||||
|
@ -94,7 +116,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
location_v = eval_oper(location, ssa_env, global_env)
|
location_v = eval_oper(location, ssa_env, global_env)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('load heap[{}]'
|
info('load heap[{}]'
|
||||||
.format(location_v))
|
.format(location_v))
|
||||||
|
|
||||||
if size != 1:
|
if size != 1:
|
||||||
|
@ -118,7 +140,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
location_v = eval_oper(location, ssa_env, global_env)
|
location_v = eval_oper(location, ssa_env, global_env)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('heap[{}] <- {}'
|
info('heap[{}] <- {}'
|
||||||
.format(location_v, value_v))
|
.format(location_v, value_v))
|
||||||
if location_v == 0:
|
if location_v == 0:
|
||||||
err('You are not allowed to store at location 0 (Null)')
|
err('You are not allowed to store at location 0 (Null)')
|
||||||
|
@ -137,7 +159,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = eval_icmp(cnd, left_v, right_v)
|
res = eval_icmp(cnd, left_v, right_v)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('icmp {} {}, {}'
|
info('icmp {} {}, {}'
|
||||||
.format(cnd, left_v, right_v))
|
.format(cnd, left_v, right_v))
|
||||||
elif isinstance(next_insn, ll.Call):
|
elif isinstance(next_insn, ll.Call):
|
||||||
callee = next_insn.callee
|
callee = next_insn.callee
|
||||||
|
@ -174,7 +196,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res
|
return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res
|
||||||
|
|
||||||
parameters = function.parameters
|
parameters = function.parameters
|
||||||
print('call @{} ({})'
|
info('call @{} ({})'
|
||||||
.format(callee.val,
|
.format(callee.val,
|
||||||
', '.join('%{} <- {}'.format(par[1], arg)
|
', '.join('%{} <- {}'.format(par[1], arg)
|
||||||
for par, arg in zip(parameters, arguments_v))))
|
for par, arg in zip(parameters, arguments_v))))
|
||||||
|
@ -196,7 +218,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = oper_v
|
res = oper_v
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('bitcast {} {} to {}'
|
info('bitcast {} {} to {}'
|
||||||
.format(ll.ty2s(from_ty), oper_v, ll.ty2s(to_ty)))
|
.format(ll.ty2s(from_ty), oper_v, ll.ty2s(to_ty)))
|
||||||
elif isinstance(next_insn, ll.Gep):
|
elif isinstance(next_insn, ll.Gep):
|
||||||
res = 0
|
res = 0
|
||||||
|
@ -226,12 +248,12 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = gep_res
|
res = gep_res
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('Getting adress of {}{}'.
|
info('Getting adress of {}{}'.
|
||||||
format(ll.ty2s(actual_base_ty),
|
format(ll.ty2s(actual_base_ty),
|
||||||
''.join('[{}]'
|
''.join('[{}]'
|
||||||
.format(eval_oper(step_oper, ssa_env, global_env))
|
.format(eval_oper(step_oper, ssa_env, global_env))
|
||||||
for _, step_oper in steps)))
|
for _, step_oper in steps)))
|
||||||
print('Gep formula: {}'
|
info('Gep formula: {}'
|
||||||
.format(formula))
|
.format(formula))
|
||||||
elif isinstance(next_insn, ll.Zext):
|
elif isinstance(next_insn, ll.Zext):
|
||||||
oper = next_insn.oper
|
oper = next_insn.oper
|
||||||
|
@ -241,7 +263,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = oper_v
|
res = oper_v
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('zext {} {} to {}'
|
info('zext {} {} to {}'
|
||||||
.format(ll.ty2s(from_ty), oper_v, ll.ty2s(to_ty)))
|
.format(ll.ty2s(from_ty), oper_v, ll.ty2s(to_ty)))
|
||||||
elif isinstance(next_insn, ll.Ptrtoint):
|
elif isinstance(next_insn, ll.Ptrtoint):
|
||||||
oper = next_insn.oper
|
oper = next_insn.oper
|
||||||
|
@ -251,7 +273,7 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap,
|
||||||
res = oper_v
|
res = oper_v
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('ptrtoint {}* {} to {}'
|
info('ptrtoint {}* {} to {}'
|
||||||
.format(ll.ty2s(pointer_ty), oper_v, ll.ty2s(to_ty)))
|
.format(ll.ty2s(pointer_ty), oper_v, ll.ty2s(to_ty)))
|
||||||
elif isinstance(next_insn, ll.CallResult):
|
elif isinstance(next_insn, ll.CallResult):
|
||||||
res = next_insn.val
|
res = next_insn.val
|
||||||
|
@ -269,7 +291,7 @@ def terminate(terminator, blocks, stack_frames, ssa_env, global_env, heap, call_
|
||||||
if id is not None and id in ssa_env:
|
if id is not None and id in ssa_env:
|
||||||
del ssa_env[id]
|
del ssa_env[id]
|
||||||
|
|
||||||
print('Evaluating {}'
|
info('Evaluating {}'
|
||||||
.format(ll.terminator2s(terminator)))
|
.format(ll.terminator2s(terminator)))
|
||||||
|
|
||||||
if isinstance(terminator, ll.Ret):
|
if isinstance(terminator, ll.Ret):
|
||||||
|
@ -280,7 +302,7 @@ def terminate(terminator, blocks, stack_frames, ssa_env, global_env, heap, call_
|
||||||
oper_v = eval_oper(oper, ssa_env, global_env)
|
oper_v = eval_oper(oper, ssa_env, global_env)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('Returning {}'
|
info('Returning {}'
|
||||||
.format(oper_v))
|
.format(oper_v))
|
||||||
|
|
||||||
if len(stack_frames) == 0:
|
if len(stack_frames) == 0:
|
||||||
|
@ -309,7 +331,7 @@ def terminate(terminator, blocks, stack_frames, ssa_env, global_env, heap, call_
|
||||||
clear_block_from_ssa_env(new_insns, ssa_env)
|
clear_block_from_ssa_env(new_insns, ssa_env)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('Jumping unconditionally to {}'
|
info('Jumping unconditionally to {}'
|
||||||
.format(label))
|
.format(label))
|
||||||
|
|
||||||
return (new_insns, new_terminator, blocks, stack_frames,
|
return (new_insns, new_terminator, blocks, stack_frames,
|
||||||
|
@ -333,7 +355,7 @@ def terminate(terminator, blocks, stack_frames, ssa_env, global_env, heap, call_
|
||||||
clear_block_from_ssa_env(new_insns, ssa_env)
|
clear_block_from_ssa_env(new_insns, ssa_env)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
print('Operand was {}. Branching to {}'
|
info('Operand was {}. Branching to {}'
|
||||||
.format(operand_v, label))
|
.format(operand_v, label))
|
||||||
|
|
||||||
return (new_insns, new_terminator, blocks, stack_frames,
|
return (new_insns, new_terminator, blocks, stack_frames,
|
||||||
|
@ -532,7 +554,7 @@ def alloc_globals(gdecls, heap):
|
||||||
|
|
||||||
for gdecl in gdecls.values():
|
for gdecl in gdecls.values():
|
||||||
location = alloc_global(gdecl.body)
|
location = alloc_global(gdecl.body)
|
||||||
print('heap[{}] <- {}'
|
info('heap[{}] <- {}'
|
||||||
.format(location, ll.gdecl2s(gdecl)))
|
.format(location, ll.gdecl2s(gdecl)))
|
||||||
global_env[gdecl.name] = location
|
global_env[gdecl.name] = location
|
||||||
|
|
||||||
|
@ -549,7 +571,7 @@ def emulate_builtin(name, arguments_v, ssa_env, heap):
|
||||||
.format(name))
|
.format(name))
|
||||||
else:
|
else:
|
||||||
size = max(arguments_v[0], 1)
|
size = max(arguments_v[0], 1)
|
||||||
print('Allocating {} cells'
|
info('Allocating {} cells'
|
||||||
.format(size))
|
.format(size))
|
||||||
res = len(heap)
|
res = len(heap)
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
|
@ -562,7 +584,7 @@ def emulate_builtin(name, arguments_v, ssa_env, heap):
|
||||||
num_elements = arguments_v[0]
|
num_elements = arguments_v[0]
|
||||||
cells_per_element = arguments_v[1]
|
cells_per_element = arguments_v[1]
|
||||||
init_ptr = arguments_v[2]
|
init_ptr = arguments_v[2]
|
||||||
print('Allocating {} + {} + {} (size + pointer + content) cells'
|
info('Allocating {} + {} + {} (size + pointer + content) cells'
|
||||||
.format(1, 1, num_elements * cells_per_element))
|
.format(1, 1, num_elements * cells_per_element))
|
||||||
struct_begin = len(heap)
|
struct_begin = len(heap)
|
||||||
heap.append(num_elements)
|
heap.append(num_elements)
|
||||||
|
@ -588,7 +610,7 @@ def emulate_builtin(name, arguments_v, ssa_env, heap):
|
||||||
.format(array_begin, array_last,
|
.format(array_begin, array_last,
|
||||||
init_ptr, init_val_s))
|
init_ptr, init_val_s))
|
||||||
# TODO
|
# TODO
|
||||||
print('heap[{}] <- {}, heap[{}] <- {}, --- {}'
|
info('heap[{}] <- {}, heap[{}] <- {}, --- {}'
|
||||||
.format(struct_begin, num_elements,
|
.format(struct_begin, num_elements,
|
||||||
struct_begin + 1, array_begin,
|
struct_begin + 1, array_begin,
|
||||||
array_init_s))
|
array_init_s))
|
||||||
|
@ -599,10 +621,10 @@ def emulate_builtin(name, arguments_v, ssa_env, heap):
|
||||||
.format(name))
|
.format(name))
|
||||||
else:
|
else:
|
||||||
struct_begin = arguments_v[1]
|
struct_begin = arguments_v[1]
|
||||||
print('Printing string, heap[{}]:'
|
info('Printing string, heap[{}]:'
|
||||||
.format(struct_begin))
|
.format(struct_begin))
|
||||||
printee = heap[struct_begin + 1]
|
printee = heap[struct_begin + 1]
|
||||||
print(printee)
|
info(printee)
|
||||||
if not isinstance(printee, str):
|
if not isinstance(printee, str):
|
||||||
warn('What was printed, was not stored as a string in the heap')
|
warn('What was printed, was not stored as a string in the heap')
|
||||||
elif name in builtins:
|
elif name in builtins:
|
||||||
|
@ -616,7 +638,14 @@ def emulate_builtin(name, arguments_v, ssa_env, heap):
|
||||||
return res, new_heap, should_exit
|
return res, new_heap, should_exit
|
||||||
|
|
||||||
|
|
||||||
def auto_step(ast, function_name='tigermain', function_args=[1234, 5678]):
|
def auto_step(ast, function_name='tigermain', function_args=[1234, 5678], step_behavior={}):
|
||||||
|
# Set info-level
|
||||||
|
if True:
|
||||||
|
global PRINT_LEVEL
|
||||||
|
PRINT_LEVEL = step_behavior['step_print_level']
|
||||||
|
print(PRINT_LEVEL)
|
||||||
|
|
||||||
|
#
|
||||||
tdecls = ast.tdecls
|
tdecls = ast.tdecls
|
||||||
fdecls = ast.fdecls
|
fdecls = ast.fdecls
|
||||||
gdecls = ast.gdecls
|
gdecls = ast.gdecls
|
||||||
|
@ -633,9 +662,9 @@ def auto_step(ast, function_name='tigermain', function_args=[1234, 5678]):
|
||||||
call_res = []
|
call_res = []
|
||||||
|
|
||||||
global_env = alloc_globals(gdecls, heap)
|
global_env = alloc_globals(gdecls, heap)
|
||||||
print('Heap after globals are allocated:')
|
info('Heap after globals are allocated:')
|
||||||
print(heap)
|
info(heap)
|
||||||
print()
|
info()
|
||||||
|
|
||||||
step_cnt = 0
|
step_cnt = 0
|
||||||
while True:
|
while True:
|
||||||
|
@ -644,18 +673,18 @@ def auto_step(ast, function_name='tigermain', function_args=[1234, 5678]):
|
||||||
stack_frames, ssa_env,
|
stack_frames, ssa_env,
|
||||||
global_env, heap, tdecls,
|
global_env, heap, tdecls,
|
||||||
fdecls, call_res)
|
fdecls, call_res)
|
||||||
print()
|
info()
|
||||||
step_cnt += 1
|
step_cnt += 1
|
||||||
if terminator is None:
|
if terminator is None:
|
||||||
print('Stepping done!\nFinal ssa_env: {}'
|
info('Stepping done!\nFinal ssa_env: {}'
|
||||||
.format(ssa_env))
|
.format(ssa_env))
|
||||||
print('Final heap: {}'
|
info('Final heap: {}'
|
||||||
.format(heap))
|
.format(heap))
|
||||||
print('Program resulted in {} after {} steps'.
|
info('Program resulted in {} after {} steps'.
|
||||||
format(insns[0][1].val, step_cnt))
|
format(insns[0][1].val, step_cnt))
|
||||||
break
|
break
|
||||||
|
|
||||||
if step_cnt % 100 == 0:
|
if step_behavior['step_ask'] != 0 and step_cnt % step_behavior['step_ask'] == 0:
|
||||||
while True:
|
while True:
|
||||||
stop_q = input('We have now done {} steps. Continue? [Y/n]: '
|
stop_q = input('We have now done {} steps. Continue? [Y/n]: '
|
||||||
.format(step_cnt)).lower()
|
.format(step_cnt)).lower()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user