예제 #1
0
def compare_code_with_srcfile(pyc_filename, src_filename, verify):
    """Compare a .pyc with a source code file. If everything is okay, None
    is returned. Otherwise a string message describing the mismatch is returned.
    """
    (
        version,
        timestamp,
        magic_int,
        code_obj1,
        is_pypy,
        source_size,
        sip_hash,
    ) = load_module(pyc_filename)
    if magic_int != PYTHON_MAGIC_INT:
        msg = (
            "Can't compare code - Python is running with magic %s, but code is magic %s "
            % (PYTHON_MAGIC_INT, magic_int)
        )
        return msg
    try:
        code_obj2 = load_file(src_filename)
    except SyntaxError, e:
        # src_filename can be the first of a group sometimes
        if version == 2.4:
            print(pyc_filename)
        return str(e).replace(src_filename, pyc_filename)
예제 #2
0
def decompile_file(
    filename: str,
    outstream=None,
    showasm=None,
    showast={},
    showgrammar=False,
    source_encoding=None,
    mapstream=None,
    do_fragments=False,
) -> Any:
    """
    decompile Python byte-code file (.pyc). Return objects to
    all of the deparsed objects found in `filename`.
    """

    filename = check_object_path(filename)
    code_objects = {}
    (version, timestamp, magic_int, co, is_pypy, source_size,
     sip_hash) = load_module(filename, code_objects)

    if isinstance(co, list):
        deparsed = []
        for con in co:
            deparsed.append(
                decompile(
                    version,
                    con,
                    outstream,
                    showasm,
                    showast,
                    timestamp,
                    showgrammar,
                    source_encoding,
                    code_objects=code_objects,
                    is_pypy=is_pypy,
                    magic_int=magic_int,
                    mapstream=mapstream,
                ), )
    else:
        deparsed = [
            decompile(
                version,
                co,
                outstream,
                showasm,
                showast,
                timestamp,
                showgrammar,
                source_encoding,
                code_objects=code_objects,
                source_size=source_size,
                is_pypy=is_pypy,
                magic_int=magic_int,
                mapstream=mapstream,
                do_fragments=do_fragments,
                compile_mode="exec",
            )
        ]
    co = None
    return deparsed
예제 #3
0
def compare_code_with_srcfile(pyc_filename, src_filename, verify):
    """Compare a .pyc with a source code file. If everything is okay, None
    is returned. Otherwise a string message describing the mismatch is returned.
    """
    (
        version,
        timestamp,
        magic_int,
        code_obj1,
        is_pypy,
        source_size,
        sip_hash,
    ) = load_module(pyc_filename)
    if magic_int != PYTHON_MAGIC_INT:
        msg = (
            "Can't compare code - Python is running with magic %s, but code is magic %s "
            % (PYTHON_MAGIC_INT, magic_int))
        return msg
    try:
        code_obj2 = load_file(src_filename)
    except SyntaxError as e:
        # src_filename can be the first of a group sometimes
        return str(e).replace(src_filename, pyc_filename)
    cmp_code_objects(version, is_pypy, code_obj1, code_obj2, verify)
    if verify == "verify-run":
        try:
            retcode = call("%s %s" % (sys.executable, src_filename),
                           shell=True)
            if retcode != 0:
                return "Child was terminated by signal %d" % retcode
            pass
        except OSError as e:
            return "Execution failed: %s" % e
        pass
    return None
예제 #4
0
def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version):
    """Bytecodes are the same except the magic number, so just change
    that"""
    (version, timestamp, magic_int, co, is_pypy,
     source_size) = load_module(input_pyc)
    assert version == float(
        src_version
    ), "Need Python %s bytecode; got bytecode for version %s" % (src_version,
                                                                 version)
    magic_int = magic2int(magics.magics[dest_version])
    write_bytecode_file(output_pyc, co, magic_int)
    print("Wrote %s" % output_pyc)
    return
예제 #5
0
def line_number_mapping(pyc_filename, src_filename):
    (
        version,
        timestamp,
        magic_int,
        code1,
        is_pypy,
        source_size,
        sip_hash,
    ) = load_module(pyc_filename)
    try:
        code2 = load_file(src_filename)
    except SyntaxError, e:
        return str(e)
예제 #6
0
def disassemble_file(filename, outstream=None):
    """
    disassemble Python byte-code file (.pyc)

    If given a Python source file (".py") file, we'll
    try to find the corresponding compiled object.
    """
    filename = check_object_path(filename)
    (version, timestamp, magic_int, co, is_pypy, source_size,
     sip_hash) = load_module(filename)
    if type(co) == list:
        for con in co:
            disco(version, con, outstream)
    else:
        disco(version, co, outstream, is_pypy=is_pypy)
    co = None
예제 #7
0
def frame2filesize(frame):
    if '__cached__' in frame.f_globals:
        bc_path = frame.f_globals['__cached__']
    else:
        bc_path = None
    path = frame.f_globals['__file__']
    fs_size = os.stat(path).st_size
    if bc_path:
        (version, timestamp, magic_int, co, is_pypy,
         bc_source_size) = xdis.load_module(bc_path,
                                            fast_load=True,
                                            get_code=False)
        return fs_size, bc_source_size
    elif os.path.exists(path):
        return fs_size, None
    else:
        return None, None
예제 #8
0
    def assert_runs_ok(self, path_or_code, raises=None, arg_type="string"):
        """Run `code` in our VM."""

        if arg_type == "bytecode-file":
            self.version, timestamp, magic_int, code, pypy, source_size, sip_hash = load_module(
                path_or_code)
        else:
            self.version = PYTHON_VERSION
            if arg_type == "source":
                code_str = open(path_or_code, "r").read()
            else:
                assert arg_type == "string", (
                    "arg_type parameter needs to be either: bytecode-file, source or string; got %s"
                    % arg_type)
                code_str = textwrap.dedent(path_or_code)

            code = compile(code_str, "<%s>" % self.id(), "exec", 0, 1)

        print("%s bytecode %s for %s %s " %
              (LINE_STR, self.version, code.co_filename, LINE_STR))

        vm = PyVM(python_version=self.version)

        vm_value = vm_exc = None
        try:
            vm_value = vm.run_code(code)
        except PyVMError:  # pragma: no cover
            # If the VM code raises an error, show it.
            self.assertTrue(False)
            raise
        except AssertionError:  # pragma: no cover
            # If test code fails an assert, show it.
            raise
        except Exception as e:
            # Otherwise, keep the exception for comparison later.
            if not CAPTURE_EXCEPTION:  # pragma: no cover
                raise
            vm_exc = e
        else:
            self.assertTrue(True)
예제 #9
0
def line_number_mapping(pyc_filename, src_filename):
    (
        version,
        timestamp,
        magic_int,
        code1,
        is_pypy,
        source_size,
        sip_hash,
    ) = load_module(pyc_filename)
    try:
        code2 = load_file(src_filename)
    except SyntaxError as e:
        return str(e)

    queue = deque([code1, code2])

    mappings = []

    opc = get_opcode(version, is_pypy)
    number_loop(queue, mappings, opc)
    return sorted(mappings, key=lambda x: x[1])
예제 #10
0
def frame2filesize(frame):
    if "__cached__" in frame.f_globals:
        bc_path = frame.f_globals["__cached__"]
    else:
        bc_path = None
    path = frame.f_globals["__file__"]
    source_path = getsourcefile(path)
    fs_size = os.stat(source_path).st_size
    if bc_path:
        (
            version,
            timestamp,
            magic_int,
            co,
            is_pypy,
            bc_source_size,
            sip_hash,
        ) = xdis.load_module(bc_path, fast_load=True, get_code=False)
        return fs_size, bc_source_size
    elif osp.exists(path):
        return fs_size, None
    else:
        return None, None
예제 #11
0
def test_roundtrip3():
    if not PYTHON3:
        print(
            "test skipped because Python 2.x has problems creating Python 3.x files"
        )
        return
    fp = NamedTemporaryFile(mode="wb+",
                            suffix=".pyc",
                            prefix="test_pyc-",
                            delete=False)
    orig_path = "testdata/test_pyc.pyc"
    version, timestamp, magic_int, co, is_pypy, source_size, sip_hash = load_module(
        orig_path)
    write_pycfile(fp, [co], timestamp, version)
    new_path = fp.name
    size = fp.tell()
    fp.close()
    print("Wrote Python %s bytecode file %s; %d bytes" %
          (version, fp.name, size))
    old_fp = open(orig_path, "rb")
    new_fp = open(new_path, "rb")
    compare_size = 590
    assert old_fp.read(compare_size) == new_fp.read(compare_size)
    os.unlink(new_path)
예제 #12
0
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
예제 #13
0
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
예제 #14
0
    def assert_ok(self, path_or_code, raises=None, arg_type="string"):
        """Run `code` in our VM and in real Python: they behave the same."""

        if arg_type == "bytecode-file":
            self.version, timestamp, magic_int, code, pypy, source_size, sip_hash = load_module(
                path_or_code)
        else:
            self.version = PYTHON_VERSION
            if arg_type == "source":
                code_str = open(path_or_code, "r").read()
            else:
                assert arg_type == "string", "arg_type parameter needs to be either: bytecode-file, source or string; got %s" % arg_type
                code_str = textwrap.dedent(path_or_code)

            code = compile(code_str, "<%s>" % self.id(), "exec", 0, 1)

        real_stdout = sys.stdout

        # Run the code through our VM.

        vm_stdout = six.StringIO()
        if CAPTURE_STDOUT:  # pragma: no branch
            sys.stdout = vm_stdout
        vm = PyVM(vmtest_testing=True)

        vm_value = vm_exc = None
        try:
            vm_value = vm.run_code(code)
        except PyVMError:  # pragma: no cover
            # If the VM code raises an error, show it.
            raise
        except AssertionError:  # pragma: no cover
            # If test code fails an assert, show it.
            raise
        except Exception as e:
            # Otherwise, keep the exception for comparison later.
            if not CAPTURE_EXCEPTION:  # pragma: no cover
                raise
            vm_exc = e
        finally:
            real_stdout.write("\n%s %s output %s\n\n" %
                              (LINE_STR, code.co_filename, LINE_STR))
            real_stdout.write(vm_stdout.getvalue())

        # Run the code through the real Python interpreter, for comparison.

        if self.version != PYTHON_VERSION:
            return

        py_stdout = six.StringIO()
        sys.stdout = py_stdout

        py_value = py_exc = None
        globs = {}
        try:
            py_value = eval(code, globs, globs)
        except AssertionError:  # pragma: no cover
            raise
        except Exception as e:
            py_exc = e

        sys.stdout = real_stdout

        self.assert_same_exception(vm_exc, py_exc)
        self.assertEqual(vm_stdout.getvalue(), py_stdout.getvalue())
        self.assertEqual(vm_value, py_value)
        if raises:
            self.assertIsInstance(vm_exc, raises)
        else:
            self.assertIsNone(vm_exc)
예제 #15
0
def asm_file(path):
    offset = 0
    methods = {}
    method_name = None
    asm = None
    backpatch_inst = set([])
    label = {}
    python_version = None
    lines = open(path).readlines()
    i = 0
    bytecode_seen = False
    while i < len(lines):
        line = lines[i]
        i += 1
        if line.startswith(".READ"):
            match = re.match("^.READ (.+)$", line)
            if match:
                input_pyc = match.group(1)
                print(f"Reading {input_pyc}")
                (version, timestamp, magic_int, co, is_pypy, source_size,
                 sip_hash) = load_module(input_pyc)
                if python_version and python_version != version:
                    TypeError(
                        f"We previously saw Python version {python_version} but we just loaded {version}.\n"
                    )
                python_version = version
                # FIXME: extract all code options below the top-level and asm.code_list

        elif line.startswith("#"):
            match = re.match("^# (Pypy )?Python bytecode ", line)
            if match:
                if match.group(1):
                    pypy_str = match.group(1)
                    is_pypy = len(pypy_str)
                else:
                    is_pypy = False
                    pypy_str = ""

                version = (line[len("# Python bytecode " +
                                    pypy_str):].strip().split()[0])

                python_version_pair = version_str_to_tuple(version, len=2)
                asm = Assembler(python_version_pair, is_pypy)
                if python_version_pair >= (3, 10):
                    TypeError(
                        f"Creating Python version {python_version} not supported yet. Feel free to fix and put in a PR.\n"
                    )
                asm.code_init(python_version_pair)
                bytecode_seen = True
            elif line.startswith("# Timestamp in code: "):
                text = line[len("# Timestamp in code: "):].strip()
                time_str = text.split()[0]
                if is_int(time_str):
                    asm.timestamp = int(time_str)
            elif line.startswith("# Method Name: "):
                if method_name:
                    co = create_code(asm, label, backpatch_inst)
                    asm.update_lists(co, label, backpatch_inst)
                    label = {}
                    backpatch_inst = set([])
                    methods[method_name] = co
                    offset = 0
                python_version_pair = version_str_to_tuple(version, len=2)
                asm.code_init(python_version_pair)
                asm.code.co_name = line[len("# Method Name: "):].strip()
                method_name = asm.code.co_name
            elif line.startswith("# SipHash: "):
                siphash = line[len("# ShipHash: "):].strip().split()[0]
                asm.siphash = ast.literal_eval(siphash)
                if asm.siphash != 0:
                    raise TypeError(
                        "SIP hashes not supported yet. Feel free to fix and in a PR.\n"
                    )

            elif line.startswith("# Filename: "):
                asm.code.co_filename = line[len("# Filename: "):].strip()
            elif line.startswith("# First Line: "):
                s = line[len("# First Line: "):].strip()
                first_lineno = int(s)
                asm.code.co_firstlineno = first_lineno
            elif line.startswith("# Argument count: "):
                argc = line[len("# Argument count: "):].strip().split()[0]
            elif line.startswith("# Position-only argument count: "):
                argc = (line[len("# Position-only argument count: "):].strip().
                        split()[0])
                asm.code.co_posonlyargcount = ast.literal_eval(argc)
            elif line.startswith("# Keyword-only argument count: "):
                argc = line[len("# Keyword-only argument count: "):].strip(
                ).split()[0]
                asm.code.co_kwonlyargcount = ast.literal_eval(argc)
            elif line.startswith("# Number of locals: "):
                l_str = line[len("# Number of locals: "):].strip()
                asm.code.co_nlocals = int(l_str)
            elif line.startswith("# Source code size mod 2**32: "):
                l_str = line[len("# Source code size mod 2**32: "
                                 ):-len(" bytes")].strip()
                asm.size = int(l_str)
            elif line.startswith("# Stack size: "):
                l_str = line[len("# Stack size: "):].strip()
                asm.code.co_stacksize = int(l_str)
            elif line.startswith("# Flags: "):
                flags = line[len("# Flags: "):].strip().split()[0]
                asm.code.co_flags = ast.literal_eval(flags)
            elif line.startswith("# Constants:"):
                count = 0
                while i < len(lines):
                    line = lines[i]
                    i += 1
                    match = re.match(r"^#\s+(\d+): (.+)$", line)
                    if match:
                        index = int(match.group(1))
                        assert index == count, (
                            "Constant index {%d} found on line {%d}"
                            "doesn't match expected constant index {%d}." %
                            (index, i, count))
                        expr = match.group(2)
                        match = re.match(
                            r"<(?:Code\d+ )?code object (\S+) at (0x[0-f]+)",
                            expr)
                        if match:
                            name = match.group(1)
                            m2 = re.match("^<(.+)>$", name)
                            if m2:
                                name = "%s_%s" % (m2.group(1), match.group(2))
                            if name in methods:
                                asm.code.co_consts.append(methods[name])
                            else:
                                print(
                                    f"line {i} ({asm.code.co_filename}, {method_name}): can't find method {name}"
                                )
                                bogus_name = f"**bogus {name}**"
                                print(
                                    f"\t appending {bogus_name} to list of constants"
                                )
                                asm.code.co_consts.append(bogus_name)
                        else:
                            asm.code.co_consts.append(ast.literal_eval(expr))
                        count += 1
                    else:
                        i -= 1
                        break
                    pass
                pass
            elif line.startswith("# Cell variables:"):
                i = update_code_tuple_field("co_cellvars", asm.code, lines, i)
            elif line.startswith("# Free variables:"):
                i = update_code_tuple_field("co_freevars", asm.code, lines, i)
            elif line.startswith("# Names:"):
                i = update_code_tuple_field("co_names", asm.code, lines, i)
            elif line.startswith("# Varnames:"):
                line = lines[i]
                asm.code.co_varnames = line[1:].strip().split(", ")
                i += 1
            elif line.startswith("# Positional arguments:"):
                line = lines[i]
                args = line[1:].strip().split(", ")
                asm.code.co_argcount = len(args)
                i += 1
        else:
            if not line.strip():
                continue

            match = re.match(r"^([^\s]+):$", line)
            if match:
                label[match.group(1)] = offset
                continue

            match = re.match(r"^\s*([\d]+):\s*$", line)
            if match:
                line_no = int(match.group(1))
                asm.code.co_lnotab[offset] = line_no
                continue

            # Opcode section
            assert (
                bytecode_seen
            ), "File needs to start out with: # Python bytecode <version>"
            fields = line.strip().split()
            line_no = None
            num_fields = len(fields)

            if num_fields > 1:
                if fields[0] == ">>":
                    fields = fields[1:]
                    num_fields -= 1
                if is_lineno(fields[0]) and is_int(fields[1]):
                    line_no = int(fields[0][:-1])
                    opname, operand = get_opname_operand(asm.opc, fields[2:])
                elif is_lineno(fields[0]):
                    line_no = int(fields[0][:-1])
                    fields = fields[1:]
                    if fields[0] == ">>":
                        fields = fields[1:]
                        if is_int(fields[0]):
                            fields = fields[1:]
                    opname, operand = get_opname_operand(asm.opc, fields)
                elif is_int(fields[0]):
                    opname, operand = get_opname_operand(asm.opc, fields[1:])
                else:
                    opname, operand = get_opname_operand(asm.opc, fields)
            else:
                opname, _ = get_opname_operand(asm.opc, fields)

            if opname in asm.opc.opname:
                inst = Instruction()
                inst.opname = opname.replace("+", "_")
                inst.opcode = asm.opc.opmap[inst.opname]
                if xdis.op_has_argument(inst.opcode, asm.opc):
                    inst.arg = operand
                else:
                    inst.arg = None
                inst.line_no = line_no
                asm.code.instructions.append(inst)
                if inst.opcode in asm.opc.JUMP_OPS:
                    if not is_int(operand):
                        backpatch_inst.add(inst)
                offset += xdis.op_size(inst.opcode, asm.opc)
            else:
                raise RuntimeError("Illegal opname %s in:\n%s" %
                                   (opname, line))
            pass
        pass
    # print(asm.code.co_lnotab)
    if asm:
        co = create_code(asm, label, backpatch_inst)
        asm.update_lists(co, label, backpatch_inst)
    asm.code_list.reverse()
    asm.status = "finished"
    return asm
예제 #16
0
파일: cli.py 프로젝트: rocky/python2-trepan
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
예제 #17
0
 def _load_pyc(self, filename):
     return xdis.load_module(filename)
예제 #18
0
파일: execfile.py 프로젝트: rocky/x-python
def run_python_file(filename,
                    args,
                    package=None,
                    callback=None,
                    format_instruction=format_instruction):
    """Run a python file as if it were the main program on the command line.

    `filename` is the path to the file to execute, it need not be a .py file.
    `args` is the argument array to present as sys.argv, including the first
    element naming the file being executed.  `package` is the name of the
    enclosing package, if any.

    If `callback` is not None, it is a function which is called back as the
    execution progresses. This can be used for example in a debugger, or
    for custom tracing or statistics gathering.
    """
    # Create a module to serve as __main__
    old_main_mod = sys.modules["__main__"]
    main_mod = imp.new_module("__main__")
    sys.modules["__main__"] = main_mod
    main_mod.__file__ = filename
    if package:
        main_mod.__package__ = package
    main_mod.__builtins__ = BUILTINS

    # set sys.argv and the first path element properly.
    old_argv = sys.argv
    old_path0 = sys.path[0]

    # note: the type of args is na tuple; we want type(sys.argv) == list
    sys.argv = [filename] + list(args)

    if package:
        sys.path[0] = ""
    else:
        sys.path[0] = os.path.abspath(os.path.dirname(filename))

    is_pypy = IS_PYPY
    try:
        # Open the source or bytecode file.
        try:
            mime = mimetypes.guess_type(filename)
            if mime == ("application/x-python-code", None):
                (
                    python_version,
                    timestamp,
                    magic_int,
                    code,
                    is_pypy,
                    source_size,
                    sip_hash,
                ) = load_module(filename)
                supported_versions, mess = get_supported_versions(
                    is_pypy, is_bytecode=True)
                if python_version not in supported_versions:
                    raise WrongBytecodeError(
                        "We only support byte code for %s: %r is %2.1f bytecode"
                        % (mess, filename, python_version))
                pass
            else:
                source_file = open_source(filename)
                try:
                    source = source_file.read()
                finally:
                    source_file.close()

                supported_versions, mess = get_supported_versions(
                    IS_PYPY, is_bytecode=False)
                if PYTHON_VERSION not in supported_versions:
                    raise CannotCompileError(
                        "We need %s to compile source code; you are running Python %s"
                        % (mess, PYTHON_VERSION))

                # We have the source.  `compile` still needs the last line to be clean,
                # so make sure it is, then compile a code object from it.
                if not source or source[-1] != "\n":
                    source += "\n"
                code = compile(source, filename, "exec")
                python_version = PYTHON_VERSION

        except (IOError, ImportError):
            raise NoSourceError("No file to run: %r" % filename)

        # Execute the source file.
        exec_code_object(
            code,
            main_mod.__dict__,
            python_version,
            is_pypy,
            callback,
            format_instruction=format_instruction,
        )

    finally:
        # Restore the old __main__
        sys.modules["__main__"] = old_main_mod

        # Restore the old argv and path
        sys.argv = old_argv
        sys.path[0] = old_path0