def main(): filename = sys.argv[1] fptr = open(filename, "r") source = fptr.read() fptr.seek(0) source_lines = format_source_lines(fptr.readlines()) fptr.close() draw_header("Source") display_source(source_lines) code = compile(source, filename, "exec") vm = BytecodeVM(code, source_lines, filename) WITH_DEBUGGER = False if not WITH_DEBUGGER: draw_header("Disassembly") dis.dis(code) # Configure the VM and set the settings based on command line. For now use defaults config = configure_vm() config.show_disassembly = True vm.config = config vm.execute() else: debugger = Debugger(code, source_lines, filename) debugger.execute(False)
def initialize_vm(self, code, source, filename): self.__vm = BytecodeVM(code, source, filename) config = VMConfig() self.__vm.config = config config.show_disassembly = True self.__vm.execute = self.execute
class Debugger: def __init__(self, code, source, filename): self.__breakpoints = {} self.__prompt = ">>> " self.__debugger_broken = False self.__code = code self.__source = source self.__filename = filename self.initialize_vm(code, source, filename) draw_header("Initializing Debugger...") self.__breakpoint_hit = None self.__vm_running = False def initialize_vm(self, code, source, filename): self.__vm = BytecodeVM(code, source, filename) config = VMConfig() self.__vm.config = config config.show_disassembly = True self.__vm.execute = self.execute def set_breakpoint(self, line_no): self.__breakpoints[line_no] = True def disable_breakpoint(self, line_no): if line_no not in self.__breakpoints.keys(): return self.__breakpoints[line_no] = False def clear_breakpoint(self, line_no): if line_no not in self.__breakpoints.keys(): return del self.__breakpoints[line_no] def clear_all_breakpoints(self): self.__breakpoints = {} def view_locals(self, local_var=None): draw_header("Locals") current_exec_frame = self.__vm.exec_frame while current_exec_frame is not None: locals = current_exec_frame.locals for k, v in locals.items(): if local_var is None or local_var == k: print("%s: %s" % (k, v)) current_exec_frame = current_exec_frame.parent_exec_frame def view_globals(self, global_var=None): globals = self.__vm.exec_frame.globals draw_header("Globals") for k, v in globals.items(): if global_var is None or global_var == k: print("%s: %s" % (k, v)) def set_local(self, local_var, val_to_set): val, exec_frame = self.__vm.exec_frame.get_local_var_value(local_var) t = type(val) try: exec_frame.set_local_var_value(local_var, t(val_to_set)) except: exec_frame.set_local_var_value(local_var, val_to_set) draw_header("Locals Changed") val, exec_frame = self.__vm.exec_frame.get_local_var_value(local_var) print("%s: %s" % (local_var, val)) def view_backtrace(self): stack_trace = [frame for frame in self.__vm.exec_frame_stack] stack_trace.append(self.__vm.exec_frame) stack_trace.reverse() draw_header("Stacktrace") backtrace = "" for i, frame in enumerate(stack_trace): backtrace += "\t<Frame %s - %s>" % (i, frame) + "\n" print(backtrace) def view_breakpoints(self): draw_header("Breakpoints Set") for bp, status in self.__breakpoints.items(): breakpoint_hit = self.__vm.exec_frame.line_no_obj.get_source_line(bp) breakpoint_hit = breakpoint_hit.strip() if status == True: status = "Enabled" else: status = "Disabled" print("Breakpoint Line %s: %s ---> %s" % (bp, status, breakpoint_hit)) def view_source(self, lineno): if lineno > 0: lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line(lineno) else: lines = self.__vm.exec_frame.line_no_obj.get_all_source_lines() print(lines) def display_help(self): print("\tnext - Execute Next Instruction") print("\trun - Run VM") print("\tset bp <loc> - Set Breakpoint at loc") print("\tdisable bp <loc> - Disable Breakpoint at loc") print("\tclear bp <loc> - Disable Breakpoint at loc") print("\tclear all bps - Clear all Breakpoints") print("\tview source <loc> - View Source. If no loc is specified entire source is shown") print("\tview locals - View the Local variables") print("\tview globals - View the Global variables") print("\tview local <var> - View local var") print("\tview global <var> - View global var") print("\tview backtrace - View the BackTrace") print("\tview bp - View Breakpoints") print("\thelp - Display this help") print("\tquit - Quit") def parse_command(self, cmd): if cmd == "next": return DebuggerCmds.VM_NEXT_INST elif cmd == "run": return DebuggerCmds.VM_RUN elif "set bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_SET_BP return (cmd, bp_location) elif "disable bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_DISABLE_BP return (cmd, bp_location) elif "clear bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_CLEAR_BP return (cmd, bp_location) elif cmd == "clear all bps": cmd = DebuggerCmds.VM_CLEAR_ALL_BP return cmd elif "view source" in cmd: parts = cmd.split() cmd = DebuggerCmds.VM_VIEW_SOURCE if len(parts) == 3: lineno = int(parts[2]) else: lineno = 0 return (cmd, lineno) elif cmd == "view locals": cmd = DebuggerCmds.VM_VIEW_LOCALS return cmd elif cmd == "view globals": cmd = DebuggerCmds.VM_VIEW_GLOBALS return cmd elif "view local" in cmd: parts = cmd.split(" ") var = parts[2] cmd = DebuggerCmds.VM_VIEW_LOCAL return (cmd, var) elif "view global" in cmd: parts = cmd.split(" ") var = parts[2] cmd = DebuggerCmds.VM_VIEW_GLOBAL return (cmd, var) elif "set local" in cmd: parts = cmd.split(" ") var = parts[2] val = parts[3] cmd = DebuggerCmds.VM_SET_LOCAL return (cmd, var, val) elif cmd == "view backtrace": cmd = DebuggerCmds.VM_VIEW_BACKTRACE return cmd elif cmd == "view bp": cmd = DebuggerCmds.VM_VIEW_BREAKPOINTS return cmd elif cmd == "help": cmd = DebuggerCmds.HELP return cmd elif cmd == "quit": cmd = DebuggerCmds.QUIT return cmd def display_prompt(self): cmd_str = input(self.__prompt) cmd_res = self.parse_command(cmd_str) return cmd_res def run_vm(self): # Run until any breakpoint is hit self.__vm_running = True while True: opmethod, oparg, current_lineno = self.__vm.get_opcode() # Check if any breakpoint got hit if current_lineno in self.__breakpoints.keys(): if self.__breakpoints[current_lineno] is True: breakpoint_hit = self.__vm.exec_frame.line_no_obj.get_source_line(current_lineno) draw_header("Breakpoint Hit: %s" % breakpoint_hit) lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line(current_lineno) print(lines) self.__breakpoint_hit = current_lineno return terminate = self.__vm.execute_opcode(opmethod, oparg) if terminate: break # Reinitialize for next execution self.initialize_vm(self.__code, self.__source, self.__filename) print("App exited...") self.__vm_running = False return def next_inst(self): if self.__vm_running is False: print("App is not running. Run it with 'run'") return current_lineno = self.__vm.exec_frame.line_no_obj.line_number(self.__vm.exec_frame.ip) lineno = current_lineno while lineno == current_lineno: opmethod, oparg, lineno = self.__vm.get_opcode() terminate = self.__vm.execute_opcode(opmethod, oparg) if terminate: # Reinitialize for next execution self.initialize_vm(self.__code, self.__source, self.__filename) print("App exited...") self.__vm_running = False return lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line(lineno) print(lines) def view_asm(self): if self.__breakpoint_hit is None: # Display the entire source frame for this self.__vm.exec_frame.line_no_obj.get_all_source_lines() else: self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line(self.__breakpoint_hit) def execute(self, call_from_vm = True): while True: arg1 = None if not call_from_vm: cmd_res = self.display_prompt() if isinstance(cmd_res, tuple): cmd = cmd_res[0] arg1 = cmd_res[1] else: cmd = cmd_res else: cmd = DebuggerCmds.VM_RUN if cmd is DebuggerCmds.VM_RUN: self.run_vm() elif cmd is DebuggerCmds.VM_NEXT_INST: self.next_inst() elif cmd is DebuggerCmds.VM_SET_BP: self.set_breakpoint(arg1) elif cmd is DebuggerCmds.VM_DISABLE_BP: self.disable_breakpoint(arg1) elif cmd is DebuggerCmds.VM_CLEAR_BP: self.clear_breakpoint(arg1) elif cmd is DebuggerCmds.VM_CLEAR_ALL_BP: self.clear_all_breakpoints() elif cmd is DebuggerCmds.VM_VIEW_LOCALS: self.view_locals() elif cmd is DebuggerCmds.VM_VIEW_LOCAL: self.view_locals(arg1) elif cmd is DebuggerCmds.VM_SET_LOCAL: val = cmd_res[2] self.set_local(arg1, val) elif cmd is DebuggerCmds.VM_VIEW_GLOBALS: self.view_globals() elif cmd is DebuggerCmds.VM_VIEW_GLOBAL: self.view_globals(arg1) elif cmd is DebuggerCmds.VM_VIEW_BACKTRACE: self.view_backtrace() elif cmd is DebuggerCmds.VM_VIEW_BREAKPOINTS: self.view_breakpoints() elif cmd is DebuggerCmds.VM_VIEW_SOURCE: self.view_source(arg1) elif cmd is DebuggerCmds.HELP: self.display_help() elif cmd is DebuggerCmds.QUIT: sys.exit(0) call_from_vm = False
class Debugger: def __init__(self, code, source, filename): self.__breakpoints = {} self.__prompt = ">>> " self.__debugger_broken = False self.__code = code self.__source = source self.__filename = filename self.initialize_vm(code, source, filename) draw_header("Initializing Debugger...") self.__breakpoint_hit = None self.__vm_running = False def initialize_vm(self, code, source, filename): self.__vm = BytecodeVM(code, source, filename) config = VMConfig() self.__vm.config = config config.show_disassembly = True self.__vm.execute = self.execute def set_breakpoint(self, line_no): self.__breakpoints[line_no] = True def disable_breakpoint(self, line_no): if line_no not in self.__breakpoints.keys(): return self.__breakpoints[line_no] = False def clear_breakpoint(self, line_no): if line_no not in self.__breakpoints.keys(): return del self.__breakpoints[line_no] def clear_all_breakpoints(self): self.__breakpoints = {} def view_locals(self, local_var=None): draw_header("Locals") current_exec_frame = self.__vm.exec_frame while current_exec_frame is not None: locals = current_exec_frame.locals for k, v in locals.items(): if local_var is None or local_var == k: print("%s: %s" % (k, v)) current_exec_frame = current_exec_frame.parent_exec_frame def view_globals(self, global_var=None): globals = self.__vm.exec_frame.globals draw_header("Globals") for k, v in globals.items(): if global_var is None or global_var == k: print("%s: %s" % (k, v)) def set_local(self, local_var, val_to_set): val, exec_frame = self.__vm.exec_frame.get_local_var_value(local_var) t = type(val) try: exec_frame.set_local_var_value(local_var, t(val_to_set)) except: exec_frame.set_local_var_value(local_var, val_to_set) draw_header("Locals Changed") val, exec_frame = self.__vm.exec_frame.get_local_var_value(local_var) print("%s: %s" % (local_var, val)) def view_backtrace(self): stack_trace = [frame for frame in self.__vm.exec_frame_stack] stack_trace.append(self.__vm.exec_frame) stack_trace.reverse() draw_header("Stacktrace") backtrace = "" for i, frame in enumerate(stack_trace): backtrace += "\t<Frame %s - %s>" % (i, frame) + "\n" print(backtrace) def view_breakpoints(self): draw_header("Breakpoints Set") for bp, status in self.__breakpoints.items(): breakpoint_hit = self.__vm.exec_frame.line_no_obj.get_source_line( bp) breakpoint_hit = breakpoint_hit.strip() if status == True: status = "Enabled" else: status = "Disabled" print("Breakpoint Line %s: %s ---> %s" % (bp, status, breakpoint_hit)) def view_source(self, lineno): if lineno > 0: lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line( lineno) else: lines = self.__vm.exec_frame.line_no_obj.get_all_source_lines() print(lines) def display_help(self): print("\tnext - Execute Next Instruction") print("\trun - Run VM") print("\tset bp <loc> - Set Breakpoint at loc") print("\tdisable bp <loc> - Disable Breakpoint at loc") print("\tclear bp <loc> - Disable Breakpoint at loc") print("\tclear all bps - Clear all Breakpoints") print( "\tview source <loc> - View Source. If no loc is specified entire source is shown" ) print("\tview locals - View the Local variables") print("\tview globals - View the Global variables") print("\tview local <var> - View local var") print("\tview global <var> - View global var") print("\tview backtrace - View the BackTrace") print("\tview bp - View Breakpoints") print("\thelp - Display this help") print("\tquit - Quit") def parse_command(self, cmd): if cmd == "next": return DebuggerCmds.VM_NEXT_INST elif cmd == "run": return DebuggerCmds.VM_RUN elif "set bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_SET_BP return (cmd, bp_location) elif "disable bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_DISABLE_BP return (cmd, bp_location) elif "clear bp" in cmd: parts = cmd.split(" ") bp_location = int(parts[2]) cmd = DebuggerCmds.VM_CLEAR_BP return (cmd, bp_location) elif cmd == "clear all bps": cmd = DebuggerCmds.VM_CLEAR_ALL_BP return cmd elif "view source" in cmd: parts = cmd.split() cmd = DebuggerCmds.VM_VIEW_SOURCE if len(parts) == 3: lineno = int(parts[2]) else: lineno = 0 return (cmd, lineno) elif cmd == "view locals": cmd = DebuggerCmds.VM_VIEW_LOCALS return cmd elif cmd == "view globals": cmd = DebuggerCmds.VM_VIEW_GLOBALS return cmd elif "view local" in cmd: parts = cmd.split(" ") var = parts[2] cmd = DebuggerCmds.VM_VIEW_LOCAL return (cmd, var) elif "view global" in cmd: parts = cmd.split(" ") var = parts[2] cmd = DebuggerCmds.VM_VIEW_GLOBAL return (cmd, var) elif "set local" in cmd: parts = cmd.split(" ") var = parts[2] val = parts[3] cmd = DebuggerCmds.VM_SET_LOCAL return (cmd, var, val) elif cmd == "view backtrace": cmd = DebuggerCmds.VM_VIEW_BACKTRACE return cmd elif cmd == "view bp": cmd = DebuggerCmds.VM_VIEW_BREAKPOINTS return cmd elif cmd == "help": cmd = DebuggerCmds.HELP return cmd elif cmd == "quit": cmd = DebuggerCmds.QUIT return cmd def display_prompt(self): cmd_str = input(self.__prompt) cmd_res = self.parse_command(cmd_str) return cmd_res def run_vm(self): # Run until any breakpoint is hit self.__vm_running = True while True: opmethod, oparg, current_lineno = self.__vm.get_opcode() # Check if any breakpoint got hit if current_lineno in self.__breakpoints.keys(): if self.__breakpoints[current_lineno] is True: breakpoint_hit = self.__vm.exec_frame.line_no_obj.get_source_line( current_lineno) draw_header("Breakpoint Hit: %s" % breakpoint_hit) lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line( current_lineno) print(lines) self.__breakpoint_hit = current_lineno return terminate = self.__vm.execute_opcode(opmethod, oparg) if terminate: break # Reinitialize for next execution self.initialize_vm(self.__code, self.__source, self.__filename) print("App exited...") self.__vm_running = False return def next_inst(self): if self.__vm_running is False: print("App is not running. Run it with 'run'") return current_lineno = self.__vm.exec_frame.line_no_obj.line_number( self.__vm.exec_frame.ip) lineno = current_lineno while lineno == current_lineno: opmethod, oparg, lineno = self.__vm.get_opcode() terminate = self.__vm.execute_opcode(opmethod, oparg) if terminate: # Reinitialize for next execution self.initialize_vm(self.__code, self.__source, self.__filename) print("App exited...") self.__vm_running = False return lines = self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line( lineno) print(lines) def view_asm(self): if self.__breakpoint_hit is None: # Display the entire source frame for this self.__vm.exec_frame.line_no_obj.get_all_source_lines() else: self.__vm.exec_frame.line_no_obj.get_source_sorrounding_line( self.__breakpoint_hit) def execute(self, call_from_vm=True): while True: arg1 = None if not call_from_vm: cmd_res = self.display_prompt() if isinstance(cmd_res, tuple): cmd = cmd_res[0] arg1 = cmd_res[1] else: cmd = cmd_res else: cmd = DebuggerCmds.VM_RUN if cmd is DebuggerCmds.VM_RUN: self.run_vm() elif cmd is DebuggerCmds.VM_NEXT_INST: self.next_inst() elif cmd is DebuggerCmds.VM_SET_BP: self.set_breakpoint(arg1) elif cmd is DebuggerCmds.VM_DISABLE_BP: self.disable_breakpoint(arg1) elif cmd is DebuggerCmds.VM_CLEAR_BP: self.clear_breakpoint(arg1) elif cmd is DebuggerCmds.VM_CLEAR_ALL_BP: self.clear_all_breakpoints() elif cmd is DebuggerCmds.VM_VIEW_LOCALS: self.view_locals() elif cmd is DebuggerCmds.VM_VIEW_LOCAL: self.view_locals(arg1) elif cmd is DebuggerCmds.VM_SET_LOCAL: val = cmd_res[2] self.set_local(arg1, val) elif cmd is DebuggerCmds.VM_VIEW_GLOBALS: self.view_globals() elif cmd is DebuggerCmds.VM_VIEW_GLOBAL: self.view_globals(arg1) elif cmd is DebuggerCmds.VM_VIEW_BACKTRACE: self.view_backtrace() elif cmd is DebuggerCmds.VM_VIEW_BREAKPOINTS: self.view_breakpoints() elif cmd is DebuggerCmds.VM_VIEW_SOURCE: self.view_source(arg1) elif cmd is DebuggerCmds.HELP: self.display_help() elif cmd is DebuggerCmds.QUIT: sys.exit(0) call_from_vm = False