Ejemplo n.º 1
0
def get_opcode_module(version_info=None, variant=None):
    if version_info is None:
        version_info = sys.version_info
        if variant is None and IS_PYPY:
            variant = "pypy"
            pass
        pass
    elif isinstance(version_info, float):
        int_vers = int(version_info * 10)
        version_info = [int_vers // 10, int_vers % 10]

    vers_str = version_tuple_to_str(version_info)
    if len(version_info) > 3 and version_info[3] != "final":
        vers_str += version_tuple_to_str(version_info, start=3)
    if variant is None:
        try:
            import platform

            variant = platform.python_implementation()
            if platform in ("Jython", "Pyston"):
                vers_str += variant
                pass
        except ImportError:
            # Python may be too old, e.g. < 2.6 or implementation may
            # just not have platform
            pass
    else:
        vers_str += variant

    return op_imports[canonic_python_version[vers_str]]
Ejemplo n.º 2
0
def sysinfo2magic(version_info=sys.version_info):
    """Convert a list sys.versions_info compatible list into a 'canonic'
    floating-point number which that can then be used to look up a
    magic number.  Note that this can raise an exception.
    """

    vers_str = version_tuple_to_str(version_info)
    if version_info[3] != "final":
        vers_str += version_tuple_to_str(version_info, start=3)

    if IS_PYPY:
        vers_str += "pypy"
    else:
        try:
            import platform

            platform = platform.python_implementation()
            if platform in ("Jython", "Pyston", "GraalVM"):
                vers_str += platform
                pass
        except ImportError:
            # Python may be too old, e.g. < 2.6 or implementation may
            # just not have platform
            pass

    return magics[vers_str]
Ejemplo n.º 3
0
def compile_file(source_path: str) -> str:
    if source_path.endswith(".py"):
        basename = source_path[:-3]
    else:
        basename = source_path

    if hasattr(sys, "pypy_version_info"):
        bytecode_path = "%s-pypy%s.pyc" % (basename, version_tuple_to_str())
    else:
        bytecode_path = "%s-%s.pyc" % (basename, version_tuple_to_str())

    print("compiling %s to %s" % (source_path, bytecode_path))
    py_compile.compile(source_path, bytecode_path, "exec")
    return bytecode_path
Ejemplo n.º 4
0
def get_scanner(version, is_pypy=False, show_asm=None):

    # If version is a string, turn that into the corresponding float.
    if isinstance(version, str):
        if version not in canonic_python_version:
            raise RuntimeError("Unknown Python version in xdis %s" % version)
        canonic_version = canonic_python_version[version]
        if canonic_version not in CANONIC2VERSION:
            raise RuntimeError("Unsupported Python version %s (canonic %s)" %
                               (version, canonic_version))
        version = CANONIC2VERSION[canonic_version]

    # Pick up appropriate scanner
    if version[:2] in PYTHON_VERSIONS:
        v_str = version_tuple_to_str(version, start=0, end=2, delimiter="")
        try:
            import importlib

            if is_pypy:
                scan = importlib.import_module("uncompyle6.scanners.pypy%s" %
                                               v_str)
            else:
                scan = importlib.import_module(
                    "uncompyle6.scanners.scanner%s" % v_str)
            if False:
                print(scan)  # Avoid unused scan
        except ImportError:
            if is_pypy:
                exec(
                    "import uncompyle6.scanners.pypy%s as scan" % v_str,
                    locals(),
                    globals(),
                )
            else:
                exec(
                    "import uncompyle6.scanners.scanner%s as scan" % v_str,
                    locals(),
                    globals(),
                )
        if is_pypy:
            scanner = eval("scan.ScannerPyPy%s(show_asm=show_asm)" % v_str,
                           locals(), globals())
        else:
            scanner = eval("scan.Scanner%s(show_asm=show_asm)" % v_str,
                           locals(), globals())
    else:
        raise RuntimeError(
            "Unsupported Python version, %s, for decompilation" %
            version_tuple_to_str(version))
    return scanner
Ejemplo n.º 5
0
    def to_native(self):
        if not (PYTHON_VERSION_TRIPLE >= (3, 8)):
            raise TypeError(
                "Python Interpreter needs to be in 3.8 or greater; is %s"
                % version_tuple_to_str()
            )

        code = deepcopy(self)
        code.freeze()
        try:
            code.check()
        except AssertionError as e:
            raise TypeError(e)

        return types.CodeType(
            code.co_argcount,
            code.co_posonlyargcount,
            code.co_kwonlyargcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            code.co_filename,
            code.co_name,
            code.co_firstlineno,
            code.co_lnotab,
            code.co_freevars,
            code.co_cellvars,
        )
Ejemplo n.º 6
0
    def test_basic(self):
        """Basic test of magic numbers"""
        if hasattr(sys, 'version_info'):
            version = version_tuple_to_str()
            if IS_PYPY:
                version += 'pypy'
            self.assertTrue(
                version in magics.magics.keys(),
                "version %s is not in magic.magics.keys: %s" %
                (version, magics.magics.keys()))

        self.assertEqual(magics.MAGIC,
                         magics.int2magic(magics.magic2int(magics.MAGIC)))
        lookup = str(PYTHON_VERSION)
        if IS_PYPY:
            lookup += 'pypy'
        self.assertTrue(
            lookup in magics.magics.keys(),
            "PYTHON VERSION %s is not in magic.magics.keys: %s" %
            (lookup, magics.magics.keys()))

        if not (3, 5, 2) <= sys.version_info < (3, 6, 0):
            self.assertEqual(
                magics.sysinfo2magic(), magics.MAGIC,
                "magic from imp.get_magic() for %s "
                "should be sysinfo2magic()" % lookup)
Ejemplo n.º 7
0
    def to_native(self, opts={}):
        if not (2, 0) <= PYTHON_VERSION_TRIPLE < (2, 8):
            raise TypeError(
                "Python Interpreter needs to be in range 2.0..2.7; is %s" %
                version_tuple_to_str())

        code = deepcopy(self)
        code.freeze()
        try:
            code.check()
        except AssertionError as e:
            raise TypeError(e)

        return types.CodeType(
            code.co_argcount,
            code.co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            code.co_varnames,
            code.co_filename,
            code.co_name,
            code.co_firstlineno,
            code.co_lnotab,
            code.co_freevars,
            code.co_cellvars,
        )
Ejemplo n.º 8
0
    def __init__(self, version, show_asm=None, is_pypy=False):
        self.version = version
        self.show_asm = show_asm
        self.is_pypy = is_pypy

        if version[:2] in PYTHON_VERSIONS:
            v_str = f"""opcode_{version_tuple_to_str(version, start=0, end=2, delimiter="")}"""
            if is_pypy:
                v_str += "pypy"
            exec("from xdis.opcodes import %s" % v_str)
            exec("self.opc = %s" % v_str)
        else:
            raise TypeError("%s is not a Python version I know about" %
                            version_tuple_to_str(version))

        self.opname = self.opc.opname

        # FIXME: This weird Python2 behavior is not Python3
        self.resetTokenClass()
Ejemplo n.º 9
0
def write_pycfile(fp,
                  code_list,
                  timestamp=None,
                  version_triple=xdis.PYTHON_VERSION_TRIPLE):

    version_str = version_tuple_to_str(version_triple, end=2)
    magic_bytes = magics[version_str]
    magic_int = magic2int(magic_bytes)
    fp.write(magic_bytes)

    if timestamp is None:
        timestamp = int(time.time())
    write_source_size = version_triple >= (3, 3)
    if version_triple >= (3, 7):
        if magic_int == 3393:
            fp.write(pack("I", timestamp))
            fp.write(pack("I", 0))
        else:
            # PEP 552. https://www.python.org/dev/peps/pep-0552/
            # 0 in the lowest-order bit means used old-style timestamps
            fp.write(pack("<I", 0))
            fp.write(pack("<I", timestamp))
    else:
        fp.write(pack("<I", timestamp))

    if write_source_size:
        fp.write(pack("<I", 0))  # size mod 2**32

    for co in code_list:
        try:
            co_obj = dumps(co, python_version=version_triple)
            if PYTHON3 and version_triple < (3, 0):
                co_obj = str.encode(co_obj)
                pass

            fp.write(co_obj)
        except:  # noqa
            pass
Ejemplo n.º 10
0
def test_if_in_for():
    code = bug.__code__
    scan = get_scanner(PYTHON_VERSION_TRIPLE)
    if (2, 7) <= PYTHON_VERSION_TRIPLE < (3, 1) and not IS_PYPY:
        scan.build_instructions(code)
        fjt = scan.find_jump_targets(False)

        ## FIXME: the data below is wrong.
        ## we get different results currenty as well.
        ## We need to probably fix both the code
        ## and the test below
        # assert {15: [3], 69: [66], 63: [18]} == fjt
        # assert scan.structs == \
        #   [{'start': 0, 'end': 72, 'type': 'root'},
        #    {'start': 15, 'end': 66, 'type': 'if-then'},
        #    {'start': 31, 'end': 59, 'type': 'for-loop'},
        #    {'start': 62, 'end': 63, 'type': 'for-else'}]

        code = bug_loop.__code__
        scan.build_instructions(code)
        fjt = scan.find_jump_targets(False)
        assert {64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
        assert scan.structs == [
            {
                'start': 0,
                'end': 80,
                'type': 'root'
            },
            {
                'start': 3,
                'end': 64,
                'type': 'if-then'
            },
            {
                'start': 6,
                'end': 15,
                'type': 'try'
            },
            {
                'start': 19,
                'end': 38,
                'type': 'except'
            },
            {
                'start': 45,
                'end': 67,
                'type': 'while-loop'
            },
            {
                'start': 70,
                'end': 64,
                'type': 'while-else'
            },
            # previous bug was not mistaking while-loop for if-then
            {
                'start': 48,
                'end': 67,
                'type': 'while-loop'
            }
        ]

    elif (3, 2) < PYTHON_VERSION_TRIPLE <= (3, 4):
        scan.build_instructions(code)
        fjt = scan.find_jump_targets(False)
        assert {69: [66], 63: [18]} == fjt
        assert scan.structs == \
          [{'end': 72, 'type': 'root', 'start': 0},
           {'end': 66, 'type': 'if-then', 'start': 6},
           {'end': 63, 'type': 'if-then', 'start': 18},
           {'end': 59, 'type': 'for-loop', 'start': 31},
           {'end': 63, 'type': 'for-else', 'start': 62}]
    else:
        print("FIXME: should fix for %s" % version_tuple_to_str())
        assert True
    return
Ejemplo n.º 11
0
            self.opc.STORE_SLICE_1,
            self.opc.STORE_SLICE_2,
            self.opc.STORE_SLICE_3,
            self.opc.STORE_SUBSCR,
            self.opc.UNPACK_SEQUENCE,
            self.opc.JUMP_ABSOLUTE,
        ])

        self.pop_jump_if_or_pop = frozenset(
            [self.opc.JUMP_IF_FALSE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP])

        return

    pass


if __name__ == "__main__":
    from xdis.version_info import PYTHON_VERSION_TRIPLE

    if PYTHON_VERSION_TRIPLE[:2] == (2, 7):
        import inspect

        co = inspect.currentframe().f_code
        tokens, customize = Scanner27().ingest(co)
        for t in tokens:
            print(t)
        pass
    else:
        print("Need to be Python 2.7 to demo; I am %s." %
              version_tuple_to_str())
Ejemplo n.º 12
0
def decompile(
    bytecode_version: str,
    co,
    out=None,
    showasm=None,
    showast={},
    timestamp=None,
    showgrammar=False,
    source_encoding=None,
    code_objects={},
    source_size=None,
    is_pypy=None,
    magic_int=None,
    mapstream=None,
    do_fragments=False,
) -> Any:
    """
    ingests and deparses a given code block 'co'

    if `bytecode_version` is None, use the current Python intepreter
    version.

    Caller is responsible for closing `out` and `mapstream`
    """
    if bytecode_version is None:
        bytecode_version = PYTHON_VERSION_TRIPLE

    # store final output stream for case of error
    real_out = out or sys.stdout

    def write(s):
        s += "\n"
        real_out.write(s)

    assert iscode(co), f"""{co} does not smell like code"""

    co_pypy_str = "PyPy " if is_pypy else ""
    run_pypy_str = "PyPy " if IS_PYPY else ""
    sys_version_lines = sys.version.split("\n")
    if source_encoding:
        write("# -*- coding: %s -*-" % source_encoding)
    write("# uncompyle6 version %s\n"
          "# %sPython bytecode %s%s\n# Decompiled from: %sPython %s" % (
              __version__,
              co_pypy_str,
              version_tuple_to_str(bytecode_version),
              " (%s)" % str(magic_int) if magic_int else "",
              run_pypy_str,
              "\n# ".join(sys_version_lines),
          ))
    if co.co_filename:
        write("# Embedded file name: %s" % co.co_filename)
    if timestamp:
        write("# Compiled at: %s" % datetime.datetime.fromtimestamp(timestamp))
    if source_size:
        write("# Size of source mod 2**32: %d bytes" % source_size)

    debug_opts = {"asm": showasm, "ast": showast, "grammar": showgrammar}

    try:
        if mapstream:
            if isinstance(mapstream, str):
                mapstream = _get_outstream(mapstream)

            deparsed = deparse_code_with_map(
                co,
                out,
                bytecode_version,
                debug_opts,
                code_objects=code_objects,
                is_pypy=is_pypy,
            )
            header_count = 3 + len(sys_version_lines)
            linemap = [(line_no,
                        deparsed.source_linemap[line_no] + header_count)
                       for line_no in sorted(deparsed.source_linemap.keys())]
            mapstream.write("\n\n# %s\n" % linemap)
        else:
            if do_fragments:
                deparse_fn = code_deparse_fragments
            else:
                deparse_fn = code_deparse
            deparsed = deparse_fn(co,
                                  out,
                                  bytecode_version,
                                  debug_opts=debug_opts,
                                  is_pypy=is_pypy)
            pass
        return deparsed
    except pysource.SourceWalkerError as e:
        # deparsing failed
        raise pysource.SourceWalkerError(str(e))
Ejemplo n.º 13
0
#!/usr/bin/env python
""" Trivial helper program to bytecompile
"""
from xdis.version_info import version_tuple_to_str
import os, sys, py_compile
assert len(sys.argv) == 2
path = sys.argv[1]
short = os.path.basename(path)
version = version_tuple_to_str(end=2)
if hasattr(sys, 'pypy_version_info'):
    cfile = "bytecode_pypy%s/%s" % (version, short) + 'c'
else:
    cfile = "bytecode_%s/%s" % (version, short) + 'c'
print("byte-compiling %s to %s" % (path, cfile))
py_compile.compile(path, cfile)
os.system("../bin/pydisasm %s" % cfile)
Ejemplo n.º 14
0
    (2, 5),
    (2, 6),
    (2, 7),
    (3, 0),
    (3, 1),
    (3, 2),
    (3, 3),
    (3, 4),
    (3, 5),
    (3, 6),
    (3, 7),
    (3, 8),
))

CANONIC2VERSION = dict(
    (canonic_python_version[version_tuple_to_str(python_version)],
     python_version) for python_version in PYTHON_VERSIONS)

# Magic changed mid version for Python 3.5.2. Compatibility was added for
# the older 3.5 interpreter magic.
CANONIC2VERSION["3.5.2"] = 3.5

# FIXME: DRY
if PYTHON3:
    intern = sys.intern
    L65536 = 65536

    def long(num):
        return num

else: