def run(self, args): """Current line number in source file""" if not self.proc.curframe: self.errmsg("No line number information available.") return # info line <loc> if len(args) == 0: # No line number. Use current frame line number line_number = inspect.getlineno(self.proc.curframe) filename = self.core.canonic_filename(self.proc.curframe) elif len(args) == 1: # lineinfo returns (item, file, lineno) or (None,) line_number, filename = self.lineinfo(args[2:]) if not filename: self.errmsg("Can't parse '%s'" % args[2]) pass filename = self.core.canonic(filename) else: self.errmsg("Wrong number of arguments.") return if not osp.isfile(filename): filename = search_file(filename, self.core.search_path, self.main_dirname) pass line_info = code_line_info(filename, line_number) msg1 = 'Line %d of "%s"' % ( line_number, self.core.filename(filename), ) if line_info: msg2 = "starts at offset %d of %s and contains %d instructions" % ( line_info[0].offsets[0], line_info[0].name, len(line_info[0].offsets), ) self.msg(wrapped_lines(msg1, msg2, self.settings["width"])) else: self.errmsg("No line information for line %d of %s" % (line_number, self.core.filename(filename))) if line_info and len(line_info) > 1: self.msg( wrapped_lines( "There are multiple line offsets for line number.", "Other line offsets: %s" % ", ".join([ "%s of %s" % (li.offsets[0], li.name) for li in line_info[1:] ]), self.settings["width"], )) return False
def set_break(cmd_obj, func, filename, lineno, condition, temporary, args, force=False): if lineno is None: part1 = ("I don't understand '%s' as a line number, function name," % ' '.join(args[1:])) msg = Mmisc.wrapped_lines(part1, "or file/module plus line number.", cmd_obj.settings['width']) cmd_obj.errmsg(msg) return False if filename is None: filename = cmd_obj.proc.curframe.f_code.co_filename filename = cmd_obj.core.canonic(filename) pass if func is None: try: ok_linenos = pyficache.trace_line_numbers(filename) except: ok_linenos = None if not ok_linenos or lineno not in ok_linenos: part1 = ('File %s' % cmd_obj.core.filename(filename)) msg = Mmisc.wrapped_lines(part1, "is not stoppable at line %d." % lineno, cmd_obj.settings['width']) cmd_obj.errmsg(msg) if force: cmd_obj.msg("Breakpoint set although it may never be reached") else: return False pass bp = cmd_obj.core.bpmgr.add_breakpoint(filename, lineno, temporary, condition, func) if func and inspect.isfunction(func): cmd_obj.msg('Breakpoint %d set on calling function %s()' % (bp.number, func.func_name)) part1 = 'Currently this is line %d of file' % lineno msg = Mmisc.wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings['width']) else: part1 = ('Breakpoint %d set at line %d of file' % (bp.number, lineno)) msg = Mmisc.wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings['width']) pass cmd_obj.msg(msg) return True
def run(self, args): """Execution status of the program.""" mainfile = self.core.filename(None) if self.core.is_running(): if mainfile: part1 = "Python program '%s' is stopped" % mainfile else: part1 = 'Program is stopped' pass if self.proc.event: msg = 'via a %s event.' % self.proc.event else: msg = '.' self.msg(Mmisc.wrapped_lines(part1, msg, self.settings['width'])) if self.proc.curframe: self.msg("PC offset is %d." % self.proc.curframe.f_lasti) if self.proc.event == 'return': val = self.proc.event_arg part1 = 'Return value is' self.msg(Mmisc.wrapped_lines(part1, self.proc._saferepr(val), self.settings['width'])) pass elif self.proc.event == 'exception': exc_type, exc_value, exc_tb = self.proc.event_arg self.msg('Exception type: %s' % self.proc._saferepr(exc_type)) if exc_value: self.msg('Exception value: %s' % self.proc._saferepr(exc_value)) pass pass self.msg('It stopped %s.' % self.core.stop_reason) if self.proc.event in ['signal', 'exception', 'c_exception']: self.msg('Note: we are stopped *after* running the ' 'line shown.') pass else: if mainfile: part1 = "Python program '%s'" % mainfile msg = "is not currently running. " self.msg(Mmisc.wrapped_lines(part1, msg, self.settings['width'])) else: self.msg('No Python program is currently running.') pass self.msg(self.core.execution_status) pass return False
def run(self, args): """Current line number in source file""" # info line identifier if not self.proc.curframe: self.errmsg("No line number information available.") return if len(args) == 3: # lineinfo returns (item, file, lineno) or (None,) answer = self.lineinfo(args[2]) if answer[0]: item, filename, lineno = answer if not os.path.isfile(filename): filename = Mclifns.search_file(filename, self.core.search_path, self.main_dirname) self.msg('Line %s of "%s" <%s>' % (lineno, filename, item)) return filename=self.core.canonic_filename(self.proc.curframe) if not os.path.isfile(filename): filename = Mclifns.search_file(filename, self.core.search_path, self.main_dirname) pass filename = self.core.canonic_filename(self.proc.curframe) msg1 = 'Line %d of \"%s\"' % (inspect.getlineno(self.proc.curframe), self.core.filename(filename)) msg2 = ('at instruction %d' % self.proc.curframe.f_lasti) if self.proc.event: msg2 += ', %s event' % self.proc.event pass self.msg(Mmisc.wrapped_lines(msg1, msg2, self.settings['width'])) return False
def run(self, args): """Current line number in source file""" # info line identifier if not self.proc.curframe: self.errmsg("No line number information available.") return if len(args) == 3: # lineinfo returns (item, file, lineno) or (None,) answer = self.lineinfo(args[2]) if answer[0]: item, filename, lineno = answer if not os.path.isfile(filename): filename = Mclifns.search_file(filename, self.core.search_path, self.main_dirname) self.msg('Line %s of "%s" <%s>' % (lineno, filename, item)) return filename = self.core.canonic_filename(self.proc.curframe) if not os.path.isfile(filename): filename = Mclifns.search_file(filename, self.core.search_path, self.main_dirname) pass filename = self.core.canonic_filename(self.proc.curframe) msg1 = 'Line %d of \"%s\"' % (inspect.getlineno( self.proc.curframe), self.core.filename(filename)) msg2 = ('at instruction %d' % self.proc.curframe.f_lasti) if self.proc.event: msg2 += ', %s event' % self.proc.event pass self.msg(Mmisc.wrapped_lines(msg1, msg2, self.settings['width'])) return False
def run(self, args): """Program counter.""" mainfile = self.core.filename(None) if self.core.is_running(): curframe = self.proc.curframe if curframe: line_no = inspect.getlineno(curframe) offset = curframe.f_lasti self.msg("PC offset is %d." % offset) offset = max(offset, 0) code = curframe.f_code co_code = code.co_code disassemble_bytes(self.msg, self.msg_nocr, co_code, offset, line_no, line_no-1, line_no+1, constants=code.co_consts, cells=code.co_cellvars, varnames=code.co_varnames, freevars=code.co_freevars, linestarts=dict(findlinestarts(code)), end_offset=offset+10) pass pass else: if mainfile: part1 = "Python program '%s'" % mainfile msg = "is not currently running. " self.msg(Mmisc.wrapped_lines(part1, msg, self.settings['width'])) else: self.msg('No Python program is currently running.') pass self.msg(self.core.execution_status) pass return False
def ok_for_running(self, cmd_obj, name, nargs): '''We separate some of the common debugger command checks here: whether it makes sense to run the command in this execution state, if the command has the right number of arguments and so on. ''' if hasattr(cmd_obj, 'execution_set'): if not (self.core.execution_status in cmd_obj.execution_set): part1 = ( "Command '%s' is not available for execution status:" % name) mess = Mmisc.wrapped_lines(part1, self.core.execution_status, self.debugger.settings['width']) self.errmsg(mess) return False pass if self.frame is None and cmd_obj.need_stack: self.intf[-1].errmsg("Command '%s' needs an execution stack." % name) return False if nargs < cmd_obj.min_args: self.errmsg( ("Command '%s' needs at least %d argument(s); " + "got %d.") % (name, cmd_obj.min_args, nargs)) return False elif cmd_obj.max_args is not None and nargs > cmd_obj.max_args: self.errmsg( ("Command '%s' can take at most %d argument(s);" + " got %d.") % (name, cmd_obj.max_args, nargs)) return False return True
def ok_for_running(self, cmd_obj, name, nargs): '''We separate some of the common debugger command checks here: whether it makes sense to run the command in this execution state, if the command has the right number of arguments and so on. ''' if hasattr(cmd_obj, 'execution_set'): if not (self.core.execution_status in cmd_obj.execution_set): part1 = ("Command '%s' is not available for execution status:" % name) mess = Mmisc.wrapped_lines(part1, self.core.execution_status, self.debugger.settings['width']) self.errmsg(mess) return False pass if self.frame is None and cmd_obj.need_stack: self.intf[-1].errmsg("Command '%s' needs an execution stack." % name) return False if nargs < cmd_obj.min_args: self.errmsg(("Command '%s' needs at least %d argument(s); " + "got %d.") % (name, cmd_obj.min_args, nargs)) return False elif cmd_obj.max_args is not None and nargs > cmd_obj.max_args: self.errmsg(("Command '%s' can take at most %d argument(s);" + " got %d.") % (name, cmd_obj.max_args, nargs)) return False return True
def run(self, args): mainfile = self.core.filename(None) if self.core.is_running(): if mainfile: part1 = "Python program '%s' is stopped" % mainfile else: part1 = "Program is stopped" pass if self.proc.event: msg = "via a %s event." % self.proc.event else: msg = "." self.msg(Mmisc.wrapped_lines(part1, msg, self.settings["width"])) if self.proc.curframe: self.msg("PC offset is %d." % self.proc.curframe.f_lasti) if self.proc.event == "return": val = self.proc.event_arg part1 = "Return value is" self.msg(Mmisc.wrapped_lines(part1, self.proc._saferepr(val), self.settings["width"])) pass elif self.proc.event == "exception": exc_type, exc_value, exc_tb = self.proc.event_arg self.msg("Exception type: %s" % self.proc._saferepr(exc_type)) if exc_value: self.msg("Exception value: %s" % self.proc._saferepr(exc_value)) pass pass self.msg("It stopped %s." % self.core.stop_reason) if self.proc.event in ["signal", "exception", "c_exception"]: self.msg("Note: we are stopped *after* running the " "line shown.") pass else: if mainfile: part1 = "Python program '%s'" % mainfile msg = "is not currently running. " self.msg(Mmisc.wrapped_lines(part1, msg, self.settings["width"])) else: self.msg("No Python program is currently running.") pass self.msg(self.core.execution_status) pass return False
def set_break(cmd_obj, func, filename, lineno, condition, temporary, args, force=False): if lineno is None: part1 = ("I don't understand '%s' as a line number, function name," % ' '.join(args[1:])) msg = Mmisc.wrapped_lines(part1, "or file/module plus line number.", cmd_obj.settings['width']) cmd_obj.errmsg(msg) return False if filename is None: filename = cmd_obj.proc.curframe.f_code.co_filename filename = cmd_obj.core.canonic(filename) pass if func is None: ok_linenos = pyficache.trace_line_numbers(filename) if not ok_linenos or lineno not in ok_linenos: part1 = ('File %s' % cmd_obj.core.filename(filename)) msg = Mmisc.wrapped_lines(part1, "is not stoppable at line %d." % lineno, cmd_obj.settings['width']) cmd_obj.errmsg(msg) if force: cmd_obj.msg("Breakpoint set although it may never be reached") else: return False pass bp = cmd_obj.core.bpmgr.add_breakpoint(filename, lineno, temporary, condition, func) if func and inspect.isfunction(func): cmd_obj.msg('Breakpoint %d set on calling function %s()' % (bp.number, func.func_name)) part1 = 'Currently this is line %d of file' % lineno msg = Mmisc.wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings['width']) else: part1 = ( 'Breakpoint %d set at line %d of file' % (bp.number, lineno)) msg = Mmisc.wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings['width']) pass cmd_obj.msg(msg) return True
def run(self, args): sys_argv = self.debugger.restart_argv() if sys_argv and len(sys_argv) > 0: confirmed = self.confirm('Restart (execv)', False) if confirmed: self.msg(Mmisc.wrapped_lines("Re exec'ing:", repr(sys_argv), self.settings['width'])) # Run atexit finalize routines. This seems to be Kosher: # http://mail.python.org/pipermail/python-dev/2009-February/085791.html # NOQA try: atexit._run_exitfuncs() except: pass os.execvp(sys_argv[0], sys_argv) pass pass else: self.errmsg("No executable file and command options recorded.") pass return
def ok_for_running(self, cmd_obj, name, cmd_hash): '''We separate some of the common debugger command checks here: whether it makes sense to run the command in this execution state, if the command has the right number of arguments and so on. ''' if hasattr(cmd_obj, 'execution_set'): if not (self.core.execution_status in cmd_obj.execution_set): part1 = ("Command '%s' is not available for execution " "status:" % name) Mmsg.errmsg( self, Mmisc.wrapped_lines(part1, self.core.execution_status, self.debugger.settings['width'])) return False pass if self.frame is None and cmd_obj.need_stack: self.intf[-1].errmsg("Command '%s' needs an execution stack." % name) return False return True
def run(self, args): mainfile = self.core.filename(None) if self.core.is_running(): proc = self.proc is_offset = True n = len(args) if n == 2: if args[0] == "=": args[0] = args[1] else: try: opts, args = getopt(args, "hlo", ["help", "line", "offset"]) except GetoptError as err: # print help information and exit: print( str(err) ) # will print something like "option -a not recognized" return for o, a in opts: if o in ("-h", "--help"): proc.commands["help"].run(["help", "set", "pc"]) return elif o in ( "-l", "--line", ): is_offset = False elif o in ("-o", "--offset"): is_offset = True else: self.errmsg("unhandled option '%s'" % o) pass pass pass frame = proc.frame if frame: code = frame.f_code if is_offset: min_value = 0 max_value = len(code.co_code) - 1 elif len(code.co_lnotab) > 0: min_value = code.co_firstlineno # FIXME: put this in a function in xdis somewhere. # Also: won't need ord() in Python 2.x # max_value = min_value + sum([ord(i) for i in code.co_lnotab[1::2]]) max_value = min_value + sum(code.co_lnotab[1::2]) else: min_value = max_value = code.co_firstline offset = get_an_int( self.errmsg, args[0], "The 'pc' command requires an integer offset or a line.", min_value, max_value, ) if offset is None: return None # FIXME: We check that offset points to an # opcode or a valid line as opposed to an operand if not is_offset: self.errmsg("Sorry, line numbers not handled right now.") return None self.list_offset = frame.f_lasti = offset frame.fallthrough = False self.list_lineno = frame.f_lineno = frame.line_number() self.msg("Execution set to resume at offset %d" % offset) self.return_status = "skip" return None else: self.errmsg("Oddly, a frame is not set - nothing done.") pass else: if mainfile: part1 = "Python program '%s'" % mainfile msg = "is not currently running. " self.msg(wrapped_lines(part1, msg, self.settings["width"])) else: self.msg("No Python program is currently running.") pass self.msg(self.core.execution_status) pass return None
def __init__( self, string_or_path: str, is_file: bool, trace_only: bool, args: List[str] ): """Create a debugger object. But depending on the value of key 'start' inside hash 'opts', we may or may not initially start debugging. See also TrepanXPy.start and TrepanXPy.stop. """ def instruction_fmt_func(frame, opc, byte_name, int_arg, arguments, offset, line_number, extra_debug, vm=None): return format_instruction_with_highlight( frame=frame, opc=opc, byte_name=byte_name, int_arg = int_arg, arguments = arguments, offset = offset, line_number = line_number, extra_debug = extra_debug, settings=self.settings, vm = vm, show_line = True ) self.mainpyfile = None self.thread = None completer = lambda text, state: self.complete(text, state) interface_opts = { "complete": completer, "debugger_name": "trepan-xpy", } interface = UserInterface(opts=interface_opts) self.intf = [interface] # main_dirname is the directory where the script resides. # Filenames in co_filename are often relative to this. self.main_dirname = os.curdir self.filename_cache: Dict[str, Any] = {} self.settings = DEBUGGER_SETTINGS self.core = TrepanXPyCore(self, {}) if trace_only: processor = XPyPrintProcessor(self.core) else: processor = XPyCommandProcessor(self.core) self.core.processor = processor self.callback_hook = self.core.trace_dispatch # Save information for restarting self.program_sys_argv = list(sys.argv) self.orig_sys_argv = list(sys.argv) if is_file: mainpyfile = self.core.canonic(string_or_path) run_fn = run_python_file else: mainpyfile = string_or_path run_fn = run_python_string while True: print("Running x-python %s with %s" % (string_or_path, args)) try: run_fn( string_or_path, args, callback=self.callback_hook, format_instruction=instruction_fmt_func, ) except DebuggerQuit: break except DebuggerRestart: self.core.execution_status = "Restart requested" if self.program_sys_argv: sys.argv = list(self.program_sys_argv) part1 = "Restarting %s with arguments:" % self.core.filename( mainpyfile ) args = " ".join(self.program_sys_argv[1:]) self.intf[-1].msg( wrapped_lines(part1, args, self.settings["width"]) ) else: break except (FileNotFoundError, NoSourceError) as e: self.intf[-1].msg(str(e)) sys.exit(1) except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break else: if trace_only: break msg = "The program finished - press enter to restart; anything else terminates. ? " response = input(msg) if response != "": break pass
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = Moptions.process_options(__title__, __version__, sys_argv) if opts.server: connection_opts={'IO': 'TCP', 'PORT': opts.port} intf = Mserver.ServerInterface(connection_opts=connection_opts) dbg_opts['interface'] = intf if 'FIFO' == intf.server_type: print('Starting FIFO server for process %s.' % os.getpid()) elif 'TCP' == intf.server_type: print('Starting TCP server listening on port %s.' % intf.inout.PORT) pass elif opts.client: Mclient.main(opts, sys_argv) return dbg_opts['orig_sys_argv'] = orig_sys_argv if dbg is None: dbg = Mdebugger.Debugger(dbg_opts) dbg.core.add_ignore(main) pass Moptions._postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not os.path.isfile(mainpyfile): mainpyfile=Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: print("%s: Python script file '%s' does not exist" % (__title__, mainpyfile,), file=sys.stderr) sys.exit(1) elif not is_readable: print("%s: Can't read Python script file '%s'" % (__title__, mainpyfile, ), file=sys.stderr) sys.exit(1) return if Mfile.is_compiled_py(mainpyfile): try: from uncompyle2 import uncompyle_file except ImportError: print("%s: Compiled python file '%s', but uncompyle2 not found" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) short_name = os.path.basename(mainpyfile).strip('.pyc') fd = tempfile.NamedTemporaryFile(suffix='.py', prefix=short_name + "_", delete=False) try: uncompyle_file(mainpyfile, fd) except: print("%s: error uncompyling '%s'" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) mainpyfile = fd.name fd.close() # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = Mfile.file_pyc2py(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): print("%s: Compiled Python script given and we can't use that." % __title__, file=sys.stderr) print("%s: Substituting non-compiled name: %s" % ( __title__, mainpyfile_noopt,), file=sys.stderr) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = os.path.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = 'No program' dbg.core.processor.process_commands() pass dbg.core.execution_status = 'Terminated' dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg(Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break except: # FIXME: Should be handled above without this mess exception_name = str(sys.exc_info()[0]) if exception_name == str(Mexcept.DebuggerQuit): break elif exception_name == str(Mexcept.DebuggerRestart): dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) pass else: raise pass # Restore old sys.argv sys.argv = orig_sys_argv return
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = Moptions.process_options(__title__, __version__, sys_argv) if opts.server: connection_opts={'IO': 'TCP', 'PORT': opts.port} intf = Mserver.ServerInterface(connection_opts=connection_opts) dbg_opts['interface'] = intf if 'FIFO' == intf.server_type: print('Starting FIFO server for process %s.' % os.getpid()) elif 'TCP' == intf.server_type: print('Starting TCP server listening on port %s.' % intf.inout.PORT) pass elif opts.client: Mclient.main(opts, sys_argv) return dbg_opts['orig_sys_argv'] = orig_sys_argv if dbg is None: dbg = Mdebugger.Debugger(dbg_opts) dbg.core.add_ignore(main) pass Moptions._postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not os.path.isfile(mainpyfile): mainpyfile=Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: print("%s: Python script file '%s' does not exist" % (__title__, mainpyfile,), file=sys.stderr) sys.exit(1) elif not is_readable: print("%s: Can't read Python script file '%s'" % (__title__, mainpyfile, ), file=sys.stderr) sys.exit(1) return if Mfile.is_compiled_py(mainpyfile): try: from uncompyle6 import uncompyle_file except ImportError: print("%s: Compiled python file '%s', but uncompyle6 not found" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) short_name = os.path.basename(mainpyfile).strip('.pyc') fd = tempfile.NamedTemporaryFile(suffix='.py', prefix=short_name + "_", delete=False) try: uncompyle_file(mainpyfile, fd) except: print("%s: error uncompyling '%s'" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) mainpyfile = fd.name fd.close() # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = pyficache.pyc2py(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): print("%s: Compiled Python script given and we can't use that." % __title__, file=sys.stderr) print("%s: Substituting non-compiled name: %s" % ( __title__, mainpyfile_noopt,), file=sys.stderr) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = os.path.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = 'No program' dbg.core.processor.process_commands() pass dbg.core.execution_status = 'Terminated' dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg(Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break except: # FIXME: Should be handled above without this mess exception_name = str(sys.exc_info()[0]) if exception_name == str(Mexcept.DebuggerQuit): break elif exception_name == str(Mexcept.DebuggerRestart): dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) pass else: raise pass # Restore old sys.argv sys.argv = orig_sys_argv return
def run(self, args): """Get file information""" if len(args) == 0: if not self.proc.curframe: self.errmsg("No frame - no default file.") return False filename = self.proc.curframe.f_code.co_filename else: filename = args[0] pass m = filename + " is" filename_cache = self.core.filename_cache if filename in filename_cache: m += " cached in debugger" if filename_cache[filename] != filename: m += " as:" m = Mmisc.wrapped_lines(m, filename_cache[filename] + ".", self.settings["width"]) else: m += "." pass self.msg(m) else: matches = [file for file in file_list() if file.endswith(filename)] if len(matches) > 1: self.msg("Multiple files found ending filename string:") for match_file in matches: self.msg("\t%s" % match_file) pass elif len(matches) == 1: canonic_name = pyficache.unmap_file(matches[0]) m += " matched debugger cache file:\n " + canonic_name self.msg(m) else: self.msg(m + " not cached in debugger.") pass canonic_name = self.core.canonic(filename) self.msg(Mmisc.wrapped_lines("Canonic name:", canonic_name, self.settings["width"])) for name in (canonic_name, filename): if name in sys.modules: for key in [k for k, v in list(sys.modules.items()) if name == v]: self.msg("module: %s", key) pass pass pass for arg in args[1:]: processed_arg = False if arg in ["all", "size"]: if pyficache.size(canonic_name): self.msg("File has %d lines." % pyficache.size(canonic_name)) pass processed_arg = True pass if arg in ["all", "sha1"]: self.msg("SHA1 is %s." % pyficache.sha1(canonic_name)) processed_arg = True pass if arg in ["all", "brkpts"]: lines = pyficache.trace_line_numbers(canonic_name) if lines: self.section("Possible breakpoint line numbers:") fmt_lines = columnize.columnize(lines, ljust=False, arrange_vertical=False, lineprefix=" ") self.msg(fmt_lines) pass processed_arg = True pass if not processed_arg: self.errmsg("Don't understand sub-option %s." % arg) pass pass return
def set_break( cmd_obj, func, filename, lineno, condition, temporary, args, force=False, offset=None, ): if lineno is None and offset is None: part1 = ( "I don't understand '%s' as a line number, offset, or function name," % " ".join(args[1:])) msg = wrapped_lines(part1, "or file/module plus line number.", cmd_obj.settings["width"]) cmd_obj.errmsg(msg) return False if filename is None: filename = cmd_obj.proc.curframe.f_code.co_filename filename = cmd_obj.core.canonic(filename) pass if func is None: if lineno: line_info = code_line_info(filename, lineno) if not line_info: part1 = "File %s" % cmd_obj.core.filename(filename) msg = wrapped_lines( part1, "is not stoppable at line %d." % lineno, cmd_obj.settings["width"], ) cmd_obj.errmsg(msg) if force: cmd_obj.msg( "Breakpoint set although it may never be reached") else: return False else: assert offset is not None lineno = code_offset_info(filename, offset) if lineno is None: part1 = "File %s" % cmd_obj.core.filename(filename) msg = wrapped_lines( part1, "has no line associated with offset %d." % offset, cmd_obj.settings["width"], ) cmd_obj.errmsg(msg) return False pass bp = cmd_obj.core.bpmgr.add_breakpoint( filename, lineno=lineno, offset=offset, temporary=temporary, condition=condition, func=func, ) if func and inspect.isfunction(func): cmd_obj.msg("Breakpoint %d set on calling function %s()" % (bp.number, func.__name__)) part1 = "Currently this is line %d of file" % lineno msg = wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings["width"]) cmd_obj.msg(msg) else: part1 = "Breakpoint %d set at line %d of file" % (bp.number, lineno) msg = wrapped_lines(part1, cmd_obj.core.filename(filename), cmd_obj.settings["width"]) cmd_obj.msg(msg) if func: func_str = " of %s" % pretty_modfunc_name(func) else: func_str = "" if offset is not None and offset >= 0: cmd_obj.msg("Breakpoint is at offset %d%s " % (offset, func_str)) pass return True
def test_wrapped_msg(self): """Test misc.wrapped_lines()""" self.assertEqual('hi there', Mmisc.wrapped_lines('hi', 'there', 80)) self.assertEqual('hi\n\tthere', Mmisc.wrapped_lines('hi', 'there', 5)) return
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = Moptions.process_options( __title__, __version__, sys_argv) if opts.server: connection_opts = {"IO": "TCP", "PORT": opts.port} intf = Mserver.ServerInterface(connection_opts=connection_opts) dbg_opts["interface"] = intf if "FIFO" == intf.server_type: print("Starting FIFO server for process %s." % os.getpid()) elif "TCP" == intf.server_type: print("Starting TCP server listening on port %s." % intf.inout.PORT) pass elif opts.client: Mclient.main(opts, sys_argv) return dbg_opts["orig_sys_argv"] = orig_sys_argv if dbg is None: dbg = Mdebugger.Debugger(dbg_opts) dbg.core.add_ignore(main) pass Moptions._postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not osp.isfile(mainpyfile): mainpyfile = Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: sys.stderr.write( "%s: Python script file '%s' does not exist\n" % (__title__, mainpyfile)) sys.exit(1) elif not is_readable: sys.stderr.write("%s: Can't read Python script file '%s'\n" % ( __title__, mainpyfile, )) sys.exit(1) return if Mfile.is_compiled_py(mainpyfile): try: from xdis import load_module from xdis_version import load_module, PYTHON_VERSION_TRIPLE, IS_PYPY, version_tuple_to_str ( python_version, timestamp, magic_int, co, is_pypy, source_size, ) = load_module(mainpyfile, code_objects=None, fast_load=True) assert is_pypy == IS_PYPY assert ( python_version == PYTHON_VERSION_TRIPLE ), "bytecode is for version %s but we are version %s" % ( python_version, version_tuple_to_str(), ) # We should we check version magic_int py_file = co.co_filename if osp.isabs(py_file): try_file = py_file else: mainpydir = osp.dirname(mainpyfile) dirnames = ([mainpydir] + os.environ["PATH"].split(os.pathsep) + ["."]) try_file = Mclifns.whence_file(py_file, dirnames) if osp.isfile(try_file): mainpyfile = try_file pass else: # Move onto the except branch raise IOError( "Python file name embedded in code %s not found" % try_file) except: try: from uncompyle6 import decompile_file except ImportError: sys.stderr.write( "%s: Compiled python file '%s', but uncompyle6 not found\n" % (__title__, mainpyfile)) sys.exit(1) return short_name = osp.basename(mainpyfile).strip(".pyc") fd = tempfile.NamedTemporaryFile( suffix=".py", prefix=short_name + "_", dir=dbg.settings["tempdir"], delete=False, ) try: decompile_file(mainpyfile, outstream=fd) mainpyfile = fd.name fd.close() except: sys.stderr.write("%s: error uncompyling '%s'\n" % (__title__, mainpyfile)) sys.exit(1) pass # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = pyficache.resolve_name_to_path(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): sys.stderr.write( "%s: Compiled Python script given and we can't use that.\n" % __title__) sys.stderr.write("%s: Substituting non-compiled name: %s\n" % (__title__, mainpyfile_noopt)) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = osp.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = "No program" dbg.core.processor.process_commands() pass dbg.core.execution_status = "Terminated" dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = "Restart requested" if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = "Restarting %s with arguments:" % dbg.core.filename( mainpyfile) args = " ".join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings["width"])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break except: # FIXME: Should be handled above without this mess exception_name = str(sys.exc_info()[0]) if exception_name == str(Mexcept.DebuggerQuit): break elif exception_name == str(Mexcept.DebuggerRestart): dbg.core.execution_status = "Restart requested" if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = "Restarting %s with arguments:" % dbg.core.filename( mainpyfile) args = " ".join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings["width"])) pass else: raise pass # Restore old sys.argv sys.argv = orig_sys_argv return
def run(self, args): # It does not make much sense to repeat the last help # command. Also, given that 'help' uses PAGER, the you may # enter an extra CR which would rerun the (long) help command. self.proc.last_command = '' if len(args) > 1: cmd_name = args[1] if cmd_name == '*': self.section("List of all debugger commands:") m = self.columnize_commands(list(self.proc.commands.keys())) self.msg_nocr(m) return elif cmd_name == 'aliases': self.show_aliases() return elif cmd_name == 'macros': self.show_macros() return elif cmd_name == 'syntax': self.show_command_syntax(args) return elif cmd_name in list(categories.keys()): self.show_category(cmd_name, args[2:]) return command_name = Mcmdproc.resolve_name(self.proc, cmd_name) if command_name: instance = self.proc.commands[command_name] if hasattr(instance, 'help'): return instance.help(args) else: doc = instance.__doc__ or instance.run.__doc__ doc = doc.rstrip('\n') self.rst_msg(doc.rstrip("\n")) aliases = [ key for key in self.proc.aliases if command_name == self.proc.aliases[key] ] if len(aliases) > 0: self.msg('') msg = Mmisc.wrapped_lines('Aliases:', ', '.join(aliases) + '.', self.settings['width']) self.msg(msg) pass pass else: cmds = [ cmd for cmd in list(self.proc.commands.keys()) if re.match('^' + cmd_name, cmd) ] if cmds is None: self.errmsg("No commands found matching /^%s/. " "Try \"help\"." % cmd_name) elif len(cmds) == 1: self.msg("Pattern '%s' matches command %s..." % ( cmd_name, cmds[0], )) args[1] = cmds[0] self.run(args) else: self.section("Command names matching /^%s/:" % cmd_name) self.msg_nocr(self.columnize_commands(cmds)) pass return else: self.list_categories() pass return False
def run(self, args): """Get file information""" if len(args) == 0: if not self.proc.curframe: self.errmsg("No frame - no default file.") return False filename = self.proc.curframe.f_code.co_filename else: filename = args[0] pass m = filename + ' is' filename_cache = self.core.filename_cache if filename in filename_cache: m += " cached in debugger" if filename_cache[filename] != filename: m += ' as:' m = Mmisc.wrapped_lines(m, filename_cache[filename] + '.', self.settings['width']) else: m += '.' pass self.msg(m) else: matches = [file for file in file_list() if file.endswith(filename)] if (len(matches) > 1): self.msg("Multiple files found ending filename string:") for match_file in matches: self.msg("\t%s" % match_file) pass elif len(matches) == 1: canonic_name = pyficache.unmap_file(matches[0]) m += " matched debugger cache file:\n " + canonic_name self.msg(m) else: self.msg(m + ' not cached in debugger.') pass canonic_name = self.core.canonic(filename) self.msg( Mmisc.wrapped_lines('Canonic name:', canonic_name, self.settings['width'])) for name in (canonic_name, filename): if name in sys.modules: for key in [ k for k, v in list(sys.modules.items()) if name == v ]: self.msg("module: %s", key) pass pass pass for arg in args[1:]: processed_arg = False if arg in ['all', 'size']: if pyficache.size(canonic_name): self.msg("File has %d lines." % pyficache.size(canonic_name)) pass processed_arg = True pass if arg in ['all', 'sha1']: self.msg("SHA1 is %s." % pyficache.sha1(canonic_name)) processed_arg = True pass if arg in ['all', 'brkpts']: lines = pyficache.trace_line_numbers(canonic_name) if lines: self.section("Possible breakpoint line numbers:") fmt_lines = columnize.columnize(lines, ljust=False, arrange_vertical=False, lineprefix=' ') self.msg(fmt_lines) pass processed_arg = True pass if not processed_arg: self.errmsg("Don't understand sub-option %s." % arg) pass pass return
def run(self, args): # It does not make much sense to repeat the last help # command. Also, given that 'help' uses PAGER, the you may # enter an extra CR which would rerun the (long) help command. self.proc.last_command='' if len(args) > 1: cmd_name = args[1] if cmd_name == '*': self.section("List of all debugger commands:") m = self.columnize_commands(list(self.proc.commands.keys())) self.msg_nocr(m) return elif cmd_name == 'aliases': self.show_aliases() return elif cmd_name == 'macros': self.show_macros() return elif cmd_name == 'syntax': self.show_command_syntax(args) return elif cmd_name in list(categories.keys()): self.show_category(cmd_name, args[2:]) return command_name = Mcmdproc.resolve_name(self.proc, cmd_name) if command_name: instance = self.proc.commands[command_name] if hasattr(instance, 'help'): return instance.help(args) else: doc = instance.__doc__ or instance.run.__doc__ doc = doc.rstrip('\n') self.rst_msg(doc.rstrip("\n")) aliases = [key for key in self.proc.aliases if command_name == self.proc.aliases[key]] if len(aliases) > 0: self.msg('') msg = Mmisc.wrapped_lines('Aliases:', ', '.join(aliases) + '.', self.settings['width']) self.msg(msg) pass pass else: cmds = [cmd for cmd in list(self.proc.commands.keys()) if re.match('^' + cmd_name, cmd) ] if cmds is None: self.errmsg("No commands found matching /^%s/. " "Try \"help\"." % cmd_name) elif len(cmds) == 1: self.msg("Pattern '%s' matches command %s..." % (cmd_name, cmds[0],)) args[1] = cmds[0] self.run(args) else: self.section("Command names matching /^%s/:" % cmd_name) self.msg_nocr(self.columnize_commands(cmds)) pass return else: self.list_categories() pass return False
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" global __title__ # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = process_options(__title__, __version__, sys_argv) dbg_opts['orig_sys_argv'] = sys_argv dbg_opts['interface'] = Mbullwinkle.BWInterface() dbg_opts['processor'] = 'bullwinkle' if dbg is None: dbg = Mdebugger.Debugger(dbg_opts) dbg.core.add_ignore(main) pass _postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not os.path.isfile(mainpyfile): mainpyfile = Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: print("%s: Python script file '%s' does not exist" % ( __title__, mainpyfile, )) sys.exit(1) elif not is_readable: print("%s: Can't read Python script file '%s'" % ( __title__, mainpyfile, )) sys.exit(1) return # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = pyficache.pyc2py(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): print("%s: Compiled Python script given and we can't use that." % __title__) print("%s: Substituting non-compiled name: %s" % ( __title__, mainpyfile_noopt, )) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = os.path.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = 'No program' dbg.core.processor.process_commands() pass dbg.core.execution_status = 'Terminated' dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break pass # Restore old sys.argv sys.argv = orig_sys_argv return
def run(self, args): """**info files** [*filename* [**all** | **brkpts** | **lines** | **sha1** | **size**]] Show information about the current file. If no filename is given and the program is running then the current file associated with the current stack entry is used. Sub options which can be shown about a file are: * **brkpts** Line numbers where there are statement boundaries. These lines can be used in breakpoint commands. * **sha1** A SHA1 hash of the source text. The following may be useful in comparing source code. * **size** The number of lines in the file. * **all** All of the above information. """ if len(args) == 0: if not self.proc.curframe: self.errmsg("No frame - no default file.") return False filename = self.proc.curframe.f_code.co_filename else: filename = args[0] pass m = filename + " is" filename_cache = self.core.filename_cache if filename in filename_cache: m += " cached in debugger" if filename_cache[filename] != filename: m += " as:" m = Mmisc.wrapped_lines(m, filename_cache[filename] + ".", self.settings["width"]) else: m += "." pass self.msg(m) else: matches = [file for file in file_list() if file.endswith(filename)] if len(matches) > 1: self.msg("Multiple files found ending filename string:") for match_file in matches: self.msg("\t%s" % match_file) pass elif len(matches) == 1: canonic_name = pyficache.unmap_file(matches[0]) m += " matched debugger cache file:\n " + canonic_name self.msg(m) else: self.msg(m + " not cached in debugger.") pass canonic_name = self.core.canonic(filename) self.msg( Mmisc.wrapped_lines("Canonic name:", canonic_name, self.settings["width"])) for name in (canonic_name, filename): if name in sys.modules: for key in [ k for k, v in list(sys.modules.items()) if name == v ]: self.msg("module: %s", key) pass pass pass for arg in args[1:]: processed_arg = False if arg in ["all", "size"]: if pyficache.size(canonic_name): self.msg("File has %d lines." % pyficache.size(canonic_name)) pass processed_arg = True pass if arg in ["all", "sha1"]: self.msg("SHA1 is %s." % pyficache.sha1(canonic_name)) processed_arg = True pass if arg in ["all", "brkpts"]: lines = pyficache.trace_line_numbers(canonic_name) if lines: self.section("Possible breakpoint line numbers:") fmt_lines = columnize.columnize( list(lines), ljust=False, arrange_vertical=False, lineprefix=" ", ) self.msg(fmt_lines) pass processed_arg = True pass if not processed_arg: self.errmsg("Don't understand sub-option %s." % arg) pass pass return
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" global __title__ # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = process_options(__title__, __version__, sys_argv) dbg_opts['orig_sys_argv'] = sys_argv dbg_opts['interface'] = Mbullwinkle.BWInterface() dbg_opts['processor'] = 'bullwinkle' if dbg is None: dbg = Mdebugger.Debugger(dbg_opts) dbg.core.add_ignore(main) pass _postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not os.path.isfile(mainpyfile): mainpyfile=Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: print("%s: Python script file '%s' does not exist" % (__title__, mainpyfile,)) sys.exit(1) elif not is_readable: print("%s: Can't read Python script file '%s'" % (__title__, mainpyfile,)) sys.exit(1) return # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = pyficache.pyc2py(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): print("%s: Compiled Python script given and we can't use that." % __title__) print("%s: Substituting non-compiled name: %s" % ( __title__, mainpyfile_noopt,)) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = os.path.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = 'No program' dbg.core.processor.process_commands() pass dbg.core.execution_status = 'Terminated' dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg(Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break pass # Restore old sys.argv sys.argv = orig_sys_argv return
def main(dbg=None, sys_argv=list(sys.argv)): """Routine which gets run if we were invoked directly""" global __title__ # Save the original just for use in the restart that works via exec. orig_sys_argv = list(sys_argv) opts, dbg_opts, sys_argv = Moptions.process_options( __title__, VERSION, sys_argv) if opts.server is not None: if opts.server == 'tcp': connection_opts = {'IO': 'TCP', 'PORT': opts.port} else: connection_opts = {'IO': 'FIFO'} intf = Mserver.ServerInterface(connection_opts=connection_opts) dbg_opts['interface'] = intf if 'FIFO' == intf.server_type: print('Starting FIFO server for process %s.' % os.getpid()) elif 'TCP' == intf.server_type: print('Starting TCP server listening on port %s.' % intf.inout.PORT) pass elif opts.client: Mclient.main(opts, sys_argv) return dbg_opts['orig_sys_argv'] = orig_sys_argv if dbg is None: dbg = Mdebugger.Trepan(dbg_opts) dbg.core.add_ignore(main) pass Moptions._postprocess_options(dbg, opts) # process_options has munged sys.argv to remove any options that # options that belong to this debugger. The original options to # invoke the debugger and script are in global sys_argv if len(sys_argv) == 0: # No program given to debug. Set to go into a command loop # anyway mainpyfile = None else: mainpyfile = sys_argv[0] # Get script filename. if not osp.isfile(mainpyfile): mainpyfile = Mclifns.whence_file(mainpyfile) is_readable = Mfile.readable(mainpyfile) if is_readable is None: print("%s: Python script file '%s' does not exist" % ( __title__, mainpyfile, )) sys.exit(1) elif not is_readable: print("%s: Can't read Python script file '%s'" % ( __title__, mainpyfile, )) sys.exit(1) return if Mfile.is_compiled_py(mainpyfile): try: from xdis import load_module, PYTHON_VERSION, IS_PYPY (python_version, timestamp, magic_int, co, is_pypy, source_size) = load_module(mainpyfile, code_objects=None, fast_load=True) assert is_pypy == IS_PYPY assert python_version == PYTHON_VERSION, \ "bytecode is for version %s but we are version %s" % ( python_version, PYTHON_VERSION) # We should we check version magic_int py_file = co.co_filename if osp.isabs(py_file): try_file = py_file else: mainpydir = osp.dirname(mainpyfile) tag = sys.implementation.cache_tag dirnames = [ osp.join(mainpydir, tag), mainpydir ] + os.environ['PATH'].split(osp.pathsep) + ['.'] try_file = Mclifns.whence_file(py_file, dirnames) if osp.isfile(try_file): mainpyfile = try_file pass else: # Move onto the except branch raise IOError( "Python file name embedded in code %s not found" % try_file) except IOError: try: from uncompyle6 import decompile_file except ImportError: print( "%s: Compiled python file '%s', but uncompyle6 not found" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) return short_name = osp.basename(mainpyfile).strip('.pyc') fd = tempfile.NamedTemporaryFile(suffix='.py', prefix=short_name + "_", delete=False) old_write = fd.file.write def write_wrapper(*args, **kwargs): if isinstance(args[0], str): new_args = list(args) new_args[0] = args[0].encode('utf-8') old_write(*new_args, **kwargs) else: old_write(*args, **kwargs) fd.file.write = write_wrapper # from io import StringIO # linemap_io = StringIO() try: decompile_file(mainpyfile, fd.file, mapstream=fd) except: print("%s: error decompiling '%s'" % (__title__, mainpyfile), file=sys.stderr) sys.exit(1) return # # Get the line associations between the original and # # decompiled program # mapline = linemap_io.getvalue() # fd.write(mapline + "\n\n") # linemap = eval(mapline[3:]) mainpyfile = fd.name fd.close() # Since we are actually running the recreated source, # there is little no need to remap line numbers. # The mapping is given at the end of the file. # However we should consider adding this information # and original file name. print( "%s: couldn't find Python source so we recreated it at '%s'" % (__title__, mainpyfile), file=sys.stderr) pass # If mainpyfile is an optimized Python script try to find and # use non-optimized alternative. mainpyfile_noopt = pyficache.pyc2py(mainpyfile) if mainpyfile != mainpyfile_noopt \ and Mfile.readable(mainpyfile_noopt): print("%s: Compiled Python script given and we can't use that." % __title__) print("%s: Substituting non-compiled name: %s" % ( __title__, mainpyfile_noopt, )) mainpyfile = mainpyfile_noopt pass # Replace trepan's dir with script's dir in front of # module search path. sys.path[0] = dbg.main_dirname = osp.dirname(mainpyfile) # XXX If a signal has been received we continue in the loop, otherwise # the loop exits for some reason. dbg.sig_received = False # if not mainpyfile: # print('For now, you need to specify a Python script name!') # sys.exit(2) # pass while True: # Run the debugged script over and over again until we get it # right. try: if dbg.program_sys_argv and mainpyfile: normal_termination = dbg.run_script(mainpyfile) if not normal_termination: break else: dbg.core.execution_status = 'No program' dbg.core.processor.process_commands() pass dbg.core.execution_status = 'Terminated' dbg.intf[-1].msg("The program finished - quit or restart") dbg.core.processor.process_commands() except Mexcept.DebuggerQuit: break except Mexcept.DebuggerRestart: dbg.core.execution_status = 'Restart requested' if dbg.program_sys_argv: sys.argv = list(dbg.program_sys_argv) part1 = ('Restarting %s with arguments:' % dbg.core.filename(mainpyfile)) args = ' '.join(dbg.program_sys_argv[1:]) dbg.intf[-1].msg( Mmisc.wrapped_lines(part1, args, dbg.settings['width'])) else: break except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. break pass # Restore old sys.argv sys.argv = orig_sys_argv return