def parse_position_one_arg(self, arg, old_mod=None, show_errmsg=True): """parse_position_one_arg(self, arg, show_errmsg) -> (module/function, file, lineno) See if arg is a line number, function name, or module name. Return what we've found. None can be returned as a value in the triple. """ modfunc, filename, lineno = (None, None, None) if self.curframe: g = self.curframe.f_globals l = self.curframe.f_locals else: g = globals() l = locals() pass try: # First see if argument is an integer lineno = int(eval(arg, g, l)) if old_mod is None: filename = self.curframe.f_code.co_filename pass except: try: modfunc = eval(arg, g, l) except: modfunc = arg pass msg = ('Object %s is not known yet as a function, module, ' 'or is not found along sys.path, ' 'and not a line number.') % str(repr(arg)) try: # See if argument is a module or function if inspect.isfunction(modfunc): pass elif inspect.ismodule(modfunc): filename = pyficache.pyc2py(modfunc.__file__) filename = self.core.canonic(filename) return (modfunc, filename, None) elif hasattr(modfunc, 'im_func'): modfunc = modfunc.__func__ pass else: if show_errmsg: self.errmsg(msg) return (None, None, None) code = modfunc.__code__ lineno = code.co_firstlineno filename = code.co_filename except: if show_errmsg: self.errmsg(msg) return (None, None, None) pass return (modfunc, self.core.canonic(filename), lineno)
def test_pyc2py(self): if PYTHON3: testdata = ( ("pyc/__pycache__/foo.cpython-%s.pyc" % PYVER, "pyc/foo.py"), ("__pycache__/pyo.cpython-%s.pyc" % PYVER, "pyo.py"), ("foo/__pycache__/bar.cpython-%s.pyo" % PYVER, "foo/bar.py"), ) else: testdata = ( ("pyc/foo.pyc", "pyc/foo.py"), ("pyo.pyc", "pyo.py"), ("foo.pyo", "foo.py"), ) for path, expect in testdata: self.assertEqual(pyficache.pyc2py(path), expect) return
def parse_position(errmsg, arg): """parse_position(errmsg, arg)->(fn, name, lineno) Parse arg as [filename|module:]lineno Make sure it works for C:\foo\bar.py:12 """ colon = arg.rfind(':') if colon >= 0: filename = arg[:colon].rstrip() m, f = lookupmodule(filename) if not f: errmsg("'%s' not found using sys.path" % filename) return (None, None, None) else: filename = pyficache.pyc2py(f) arg = arg[colon+1:].lstrip() pass try: lineno = int(arg) except TypeError: errmsg("Bad line number: %s", str(arg)) return (None, filename, None) return (None, filename, lineno) return (None, None, None)
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): proc = self.proc dbg_obj = self.core.debugger listsize = dbg_obj.settings['listsize'] filename, first, last = parse_list_cmd(proc, args, listsize) curframe = proc.curframe if filename is None: return # Sometimes such as due to decompilation we might not really # have an idea based on the listing where we really are. # Setting "show_marks" to false will disable marking breakpoint # and current line numbers. show_marks = True filename = pyficache.unmap_file(pyficache.pyc2py(filename)) if filename == "<string>" and proc.curframe.f_code: # Deparse the code object into a temp file and remap the line from code # into the corresponding line of the tempfile co = proc.curframe.f_code temp_filename, name_for_code = deparse_and_cache(co, proc.errmsg) if temp_filename: filename = temp_filename show_marks = False pass # We now have range information. Do the listing. max_line = pyficache.size(filename) if max_line is None: self.errmsg('No file %s found; using "deparse" command instead to show source' % filename) proc.commands['deparse'].run(['deparse']) return canonic_filename = os.path.realpath(os.path.normcase(filename)) if first > max_line: self.errmsg('Bad start line %d - file "%s" has only %d lines' % (first, filename, max_line)) return if last > max_line: self.msg('End position changed to last line %d ' % max_line) last = max_line bplist = self.core.bpmgr.bplist opts = { 'reload_on_change' : self.settings['reload'], 'output' : self.settings['highlight'], 'strip_nl' : False, } if 'style' in self.settings: opts['style'] = self.settings['style'] if first <= 0: first = 1 try: for lineno in range(first, last+1): line = pyficache.getline(filename, lineno, opts) if line is None: line = linecache.getline(filename, lineno, proc.frame.f_globals) pass if line is None: self.msg('[EOF]') break else: line = line.rstrip('\n') s = proc._saferepr(lineno).rjust(3) if len(s) < 5: s += ' ' if (show_marks and (canonic_filename, lineno,) in list(bplist.keys())): bp = bplist[(canonic_filename, lineno,)][0] a_pad = '%02d' % bp.number s += bp.icon_char() else: s += ' ' a_pad = ' ' pass if (curframe and lineno == inspect.getlineno(curframe) and show_marks): s += '->' if 'plain' != self.settings['highlight']: s = colorize('bold', s) else: s += a_pad pass self.msg(s + '\t' + line) proc.list_lineno = lineno pass pass pass except KeyboardInterrupt: pass return False
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 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
def resolve_location(proc, location, canonic=True): """Expand fields in Location namedtuple. If: '.': get fields from stack function/module: get fields from evaluation/introspection location file and line number: use that """ curframe = proc.curframe if location == '.': if not curframe: proc.errmsg("Don't have a stack to get location from") return INVALID_LOCATION filename = Mstack.frame2file(proc.core, curframe, canonic=canonic) lineno = inspect.getlineno(curframe) return Location(filename, lineno, False, None) assert isinstance(location, Location) is_address = False if proc.curframe: g = curframe.f_globals l = curframe.f_locals else: g = globals() l = locals() pass if location.method: # Validate arguments that can't be done in parsing filename = lineno = None msg = ('Object %s is not known yet as a function, ' % location.method) try: modfunc = eval(location.method, g, l) except: proc.errmsg(msg) return INVALID_LOCATION try: # Check if the converted string is a function or instance method if inspect.isfunction(modfunc) or hasattr(modfunc, 'im_func'): pass else: proc.errmsg(msg) return INVALID_LOCATION except: proc.errmsg(msg) return INVALID_LOCATION filename = proc.core.canonic(modfunc.func_code.co_filename) # FIXME: we may want to check lineno and # respect that in the future lineno = modfunc.func_code.co_firstlineno elif location.path: filename = proc.core.canonic(location.path) lineno = location.line_number modfunc = None msg = "%s is not known as a file" % location.path if not osp.isfile(filename): # See if argument is a module try: modfunc = eval(location.path, g, l) except: msg = ("Don't see '%s' as a existing file or as an module" % location.path) proc.errmsg(msg) return INVALID_LOCATION pass is_address = location.is_address if inspect.ismodule(modfunc): if hasattr(modfunc, '__file__'): filename = pyficache.pyc2py(modfunc.__file__) filename = proc.core.canonic(filename) if not lineno: # use first line of module file lineno = 1 is_address = False return Location(filename, lineno, is_address, modfunc) else: msg = ("module '%s' doesn't have a file associated with it" % location.path) proc.errmsg(msg) return INVALID_LOCATION maxline = pyficache.maxline(filename) if maxline and lineno > maxline: # NB: we use the gdb wording here proc.errmsg("Line number %d out of range; %s has %d lines." % (lineno, filename, maxline)) return INVALID_LOCATION elif location.line_number: filename = Mstack.frame2file(proc.core, curframe, canonic=canonic) lineno = location.line_number is_address = location.is_address modfunc = None return Location(filename, lineno, is_address, modfunc)
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): proc = self.proc dbg_obj = self.core.debugger listsize = dbg_obj.settings['listsize'] filename, first, last = parse_list_cmd(proc, args, listsize) curframe = proc.curframe if filename is None: return filename = pyficache.unmap_file(pyficache.pyc2py(filename)) # We now have range information. Do the listing. max_line = pyficache.size(filename) if max_line is None: self.errmsg( 'No file %s found; using "deparse" command instead to show source' % filename) proc.commands['deparse'].run(['deparse']) return canonic_filename = os.path.realpath(os.path.normcase(filename)) if first > max_line: self.errmsg('Bad start line %d - file "%s" has only %d lines' % (first, filename, max_line)) return if last > max_line: self.msg('End position changed to last line %d ' % max_line) last = max_line bplist = self.core.bpmgr.bplist opts = { 'reload_on_change': self.settings['reload'], 'output': self.settings['highlight'], 'strip_nl': False, } if 'style' in self.settings: opts['style'] = self.settings['style'] if first <= 0: first = 1 try: for lineno in range(first, last + 1): line = pyficache.getline(filename, lineno, opts) if line is None: line = linecache.getline(filename, lineno, proc.frame.f_globals) pass if line is None: self.msg('[EOF]') break else: line = line.rstrip('\n') s = proc._saferepr(lineno).rjust(3) if len(s) < 5: s += ' ' if ( canonic_filename, lineno, ) in list(bplist.keys()): bp = bplist[( canonic_filename, lineno, )][0] a_pad = '%02d' % bp.number s += bp.icon_char() else: s += ' ' a_pad = ' ' pass if curframe and lineno == inspect.getlineno(curframe): s += '->' if 'plain' != self.settings['highlight']: s = colorize('bold', s) else: s += a_pad pass self.msg(s + '\t' + line) proc.list_lineno = lineno pass pass pass except KeyboardInterrupt: pass return False
def resolve_location(proc, location): """Expand fields in Location namedtuple. If: '.': get fields from stack function/module: get fields from evaluation/introspection location file and line number: use that """ curframe = proc.curframe if location == '.': if not curframe: proc.errmsg("Don't have a stack to get location from") return INVALID_LOCATION filename = Mstack.frame2file(proc.core, curframe, canonic=False) lineno = inspect.getlineno(curframe) return Location(filename, lineno, False, None) assert isinstance(location, Location) is_address = False if proc.curframe: g = curframe.f_globals l = curframe.f_locals else: g = globals() l = locals() pass if location.method: # Validate arguments that can't be done in parsing filename = lineno = None msg = ('Object %s is not known yet as a function, ' % location.method) try: modfunc = eval(location.method, g, l) except: proc.errmsg(msg) return INVALID_LOCATION try: # Check if the converted string is a function or instance method if inspect.isfunction(modfunc) or hasattr(modfunc, 'im_func'): pass else: proc.errmsg(msg) return INVALID_LOCATION except: proc.errmsg(msg) return INVALID_LOCATION filename = proc.core.canonic(modfunc.__code__.co_filename) # FIXME: we may want to check lineno and # respect that in the future lineno = modfunc.__code__.co_firstlineno elif location.path: filename = proc.core.canonic(location.path) lineno = location.line_number modfunc = None msg = "%s is not known as a file" % location.path if not osp.isfile(filename): # See if argument is a module try: modfunc = eval(location.path, g, l) except: msg = ("Don't see '%s' as a existing file or as an module" % location.path) proc.errmsg(msg) return INVALID_LOCATION pass is_address = location.is_address if inspect.ismodule(modfunc): if hasattr(modfunc, '__file__'): filename = pyficache.pyc2py(modfunc.__file__) filename = proc.core.canonic(filename) if not lineno: # use first line of module file lineno = 1 is_address = False return Location(filename, lineno, is_address, modfunc) else: msg = ( "module '%s' doesn't have a file associated with it" % location.path) proc.errmsg(msg) return INVALID_LOCATION maxline = pyficache.maxline(filename) if maxline and lineno > maxline: # NB: we use the gdb wording here proc.errmsg("Line number %d out of range; %s has %d lines." % (lineno, filename, maxline)) return INVALID_LOCATION elif location.line_number: filename = Mstack.frame2file(proc.core, curframe, canonic=False) lineno = location.line_number is_address = location.is_address modfunc = None return Location(filename, lineno, is_address, modfunc)
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: 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 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) 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 uncompyle_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) try: uncompyle_file(mainpyfile, fd) mainpyfile = fd.name fd.close() except: print("%s: error uncompiling '%s'" % (__title__, mainpyfile), file=sys.stderr) fd.close() os.unlink(fd.name) # FIXME: remove the below line and continue with just the # bytecode sys.exit(1) 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__, 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 = 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): filename, first, last = self.parse_list_cmd(args[1:]) curframe = self.proc.curframe if filename is None: return m = re.search('^<frozen (.*)>', filename) if m and m.group(1): filename = m.group(1) canonic_filename = pyficache.unmap_file(filename) else: filename = pyc2py(filename) canonic_filename = os.path.realpath(os.path.normcase(filename)) max_line = pyficache.size(filename) # FIXME: Should use the below: # max_line = pyficache.maxline(filename) # We now have range information. Do the listing. if max_line is None: self.errmsg('No file %s found' % filename) return if first > max_line: self.errmsg('Bad start line %d - file "%s" has only %d lines' % (first, filename, max_line)) return if last > max_line: self.msg('End position changed to last line %d ' % max_line) last = max_line bplist = self.core.bpmgr.bplist opts = { 'reload_on_change' : self.settings['reload'], 'output' : self.settings['highlight'], 'strip_nl' : False, } if 'style' in self.settings: opts['style'] = self.settings['style'] try: match, reason = Mstack.check_path_with_frame(curframe, filename) if not match: if filename not in Mcmdproc.warned_file_mismatches: self.errmsg(reason) Mcmdproc.warned_file_mismatches.add(filename) except: pass try: for lineno in range(first, last+1): line = pyficache.getline(filename, lineno, opts) if line is None: line = linecache.getline(filename, lineno, self.proc.frame.f_globals) pass if line is None: self.msg('[EOF]') break else: line = line.rstrip('\n') s = self.proc._saferepr(lineno).rjust(3) if len(s) < 5: s += ' ' if (canonic_filename, lineno,) in list(bplist.keys()): bp = bplist[(canonic_filename, lineno,)][0] a_pad = '%02d' % bp.number s += bp.icon_char() else: s += ' ' a_pad = ' ' pass if curframe and lineno == inspect.getlineno(curframe): s += '->' if 'plain' != self.settings['highlight']: s = colorize('bold', s) else: s += a_pad pass self.msg(s + '\t' + line) self.proc.list_lineno = lineno pass pass except KeyboardInterrupt: pass return False