Exemplo n.º 1
0
def test_opcode():
    opc = get_opcode(PYTHON_VERSION, IS_PYPY)
    opmap = dict([(k.replace('+', '_'), v) for (k, v) in dis.opmap.items()])

    print("Extra in dis:", set(opmap.items()) - set(opc.opmap.items()))
    print("Extra in xdis:", set(opc.opmap.items()) - set(opmap.items()))

    for item in opmap.items():
        assert item in opc.opmap.items(), item

    fields_str = "hascompare hasconst hasfree hasjabs hasjrel haslocal"
    # PyPy 2.7.13 changes opcodes mid-version. It is too complicated
    # to figure out where the change actually occurred
    # Pypy 3.6.9 may or may not have JUMP_IF_NOT_DEBUG
    if not (IS_PYPY and PYTHON_VERSION in (2.7, 3.6)):
        assert all(item in opmap.items() for item in opc.opmap.items())
    elif (IS_PYPY and PYTHON_VERSION == 3.6):
        # Don't count JUMP_IF_NOT_DEBUG mismatch
        fields_str = "hascompare hasconst hasfree hasjabs haslocal"

    assert all(item in opc.opmap.items() for item in opmap.items())

    fields = fields_str.split()
    for field in fields:
        opc_set = set(getattr(opc, field))
        dis_set = set(getattr(dis, field))
        assert opc_set == dis_set, \
            ("diff in %s: %s" %
             (field, ', '.join([opc.opname[i]
                                         for i in list(opc_set ^ dis_set)])))
Exemplo n.º 2
0
 def __init__(self, python_version, is_pypy):
     self.opc = get_opcode(python_version, is_pypy)
     self.code_list = []
     self.codes = []  # FIXME use a better name
     self.status = "unfinished"
     self.size = 0  # Size of source code. Only relevant in version 3 and above
     self.python_version = python_version
     self.timestamp = None
     self.backpatch = []  # list of backpatch dicts, one for each function
     self.label = []  # list of label dists, one for each function
     self.code = None
     self.siphash = None
Exemplo n.º 3
0
def test_stack_effect_fixed():
    """Check stack effect of opcodes that don't vary in the stack effect.
    This we get from tables that are derived the Python Interpreter C source.
    Thanks to the Maynard project for this idea.
    """
    versions = ((2, 5), (2, 6), (2, 7), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4),
                (3, 5), (3, 6), (3, 7), (3, 8), (3, 9))
    for version in versions:
        v_str = "%s%s" % (version[0], version[1])
        opc = get_opcode(version, False)
        se_file_py = osp.realpath(
            osp.join(srcdir, "stackeffect", "se%s.py" % v_str))
        opcode_stack_effect = eval(open(se_file_py).read())
        assert len(opcode_stack_effect) == 256

        for opcode in range(256):
            check_effect = opcode_stack_effect[opcode]
            if check_effect == -100:
                continue

            opname = opc.opname[opcode]
            # FIXME: not sure what's up with these in 2.6
            if opname.startswith("SLICE"):
                continue

            if op_has_argument(opcode, opc):
                effect = xstack_effect(opcode, opc, 10)
            else:
                effect = xstack_effect(opcode, opc)

            pass

        for opname, opcode, in opc.opmap.items():
            if op_has_argument(opcode, opc):
                continue
            # These are are not in the C code although they are documented as opcodes
            elif opname in ("STOP_CODE", "NOP"):
                continue
            # FIXME: not sure what's up with these in 2.6
            elif opname.startswith("SLICE"):
                continue

            effect = xstack_effect(opcode, opc)
            check_effect = opcode_stack_effect[opcode]
            assert check_effect == effect, (
                "in version %s %d (%s) not okay; effect xstack_effect is %d; C source has %d"
                % (opc.version, opcode, opname, effect, check_effect))
            # print("version %s: %d (%s) is good: effect %d" % (version, opcode, opname, effect))
            pass
        pass
    return
Exemplo n.º 4
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])
Exemplo n.º 5
0
# std
import os
import difflib
import subprocess
import tempfile
import functools

# uncompyle6 / xdis
from uncompyle6 import code_deparse
from xdis.version_info import PYTHON_VERSION_TRIPLE, PYTHON3, IS_PYPY

# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
from xdis import Bytecode, get_opcode

opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY)
Bytecode = functools.partial(Bytecode, opc=opc)
import six

if PYTHON3:
    from io import StringIO
else:
    from StringIO import StringIO


def _dis_to_text(co):
    return Bytecode(co).dis()


def print_diff(original, uncompyled):
    """
Exemplo n.º 6
0
# std
import os
import difflib
import subprocess
import tempfile
import functools

# decompyle3 / xdis
from decompyle3 import PYTHON_VERSION, IS_PYPY, code_deparse

# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
from xdis import Bytecode, get_opcode

opc = get_opcode(PYTHON_VERSION, IS_PYPY)
Bytecode = functools.partial(Bytecode, opc=opc)
import six


def _dis_to_text(co):
    return Bytecode(co).dis()


def print_diff(original, uncompyled):
    """
    Try and display a pretty html line difference between the original and
    uncompyled code and bytecode if elinks and BeautifulSoup are installed
    otherwise just show the diff.

    :param original: Text describing the original code object.
    :param uncompyled: Text describing the uncompyled code object.
    """
Exemplo n.º 7
0
def dis(
    msg,
    msg_nocr,
    section,
    errmsg,
    x=None,
    start_line=-1,
    end_line=None,
    relative_pos=False,
    highlight="light",
    start_offset=0,
    end_offset=None,
    include_header=False,
    asm_format="extended",
):
    """Disassemble classes, methods, functions, or code.

    With no argument, disassemble the last traceback.

    """
    lasti = -1
    if x is None:
        distb()
        return None, None
    if start_offset is None:
        start_offset = 0
    mess = ""
    if start_line > 1:
        mess += "from line %d " % start_line
    elif start_offset > 1:
        mess = "from offset %d " % start_offset
    if end_line:
        mess += "to line %d" % end_line
    elif end_offset:
        mess += "to offset %d" % end_offset

    sectioned = False

    # Try to dogpaddle to the code object for the type setting x
    if hasattr(types, "InstanceType") and isinstance(x, types.InstanceType):
        x = x.__class__
    if inspect.ismethod(x):
        section("Disassembly of %s: %s" % (x, mess))
        sectioned = True
        x = x.__func__.__code__
    elif inspect.isfunction(x) or inspect.isgeneratorfunction(x):
        section("Disassembly of %s: %s" % (x, mess))
        x = x.__code__
        sectioned = True
    elif inspect.isgenerator(x):
        section("Disassembly of %s: %s" % (x, mess))
        frame = x.gi_frame
        lasti = frame.f_last_i
        x = x.gi_code
        sectioned = True
    elif inspect.isframe(x):
        section("Disassembly of %s: %s" % (x, mess))
        sectioned = True
        if hasattr(x, "f_lasti"):
            lasti = x.f_lasti
            if lasti == -1:
                lasti = 0
            pass
        opc = get_opcode(PYTHON_VERSION_TRIPLE, IS_PYPY)
        x = x.f_code
        if include_header:
            header_lines = Bytecode(x, opc).info().split("\n")
            header = "\n".join([format_token(Comment, h) for h in header_lines])
            msg(header)
        pass
    elif inspect.iscode(x):
        pass

    if hasattr(x, "__dict__"):  # Class or module
        items = sorted(x.__dict__.items())
        for name, x1 in items:
            if isinstance(x1, _have_code):
                if not sectioned:
                    section("Disassembly of %s: " % x)
                try:
                    dis(
                        msg,
                        msg_nocr,
                        section,
                        errmsg,
                        x1,
                        start_line=start_line,
                        end_line=end_line,
                        relative_pos=relative_pos,
                        asm_format=asm_format,
                    )
                    msg("")
                except TypeError:
                    _, msg, _ = sys.exc_info()
                    errmsg("Sorry:", msg)
                    pass
                pass
            pass
        pass
    elif hasattr(x, "co_code"):  # Code object
        if not sectioned:
            section("Disassembly of %s: " % x)
        return disassemble(
            msg,
            msg_nocr,
            section,
            x,
            lasti=lasti,
            start_line=start_line,
            end_line=end_line,
            relative_pos=relative_pos,
            highlight=highlight,
            start_offset=start_offset,
            end_offset=end_offset,
            asm_format=asm_format,
        )
    elif isinstance(x, str):  # Source code
        return disassemble_string(
            msg,
            msg_nocr,
            x,
        )
    else:
        errmsg("Don't know how to disassemble %s objects." % type(x).__name__)
    return None, None
Exemplo n.º 8
0
        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)

    queue = deque([code1, code2])

    mappings = []

    opc = get_opcode(version, is_pypy)
    number_loop(queue, mappings, opc)
    return sorted(mappings, key=lambda x: x[1])


def number_loop(queue, mappings, opc):
    while len(queue) > 0:
        code1 = queue.popleft()
        code2 = queue.popleft()
        assert code1.co_name == code2.co_name
        linestarts_orig = findlinestarts(code1)
        linestarts_uncompiled = list(findlinestarts(code2))
        mappings += [[line, offset2line(offset, linestarts_uncompiled)]
                     for offset, line in linestarts_orig]
        bytecode1 = Bytecode(code1, opc)
        bytecode2 = Bytecode(code2, opc)
Exemplo n.º 9
0
#!/usr/bin/env python
"""
This is a translation into Python of the seXY.c programs.
However this can only used in Python 3.4 and above which has dis.stack_effect().
"""
from xdis import PYTHON_VERSION
import dis
NOTFIXED = -100
from xdis.cross_dis import op_has_argument
from xdis import get_opcode

print("# Python %s Stack effects\n" % PYTHON_VERSION)
assert PYTHON_VERSION >= 3.4, "This only works for Python version 3.4 and above; you have version %s." % PYTHON_VERSION
print("[")
opc = get_opcode(PYTHON_VERSION, False)
for i in range(256):
    try:
        if op_has_argument(i, opc):
            effect = dis.stack_effect(i, 0)
            opargs_to_try = [
                -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 256, 1000, 0xffff, 0
            ]
            for operand in opargs_to_try:
                with_oparg = dis.stack_effect(i, operand)
                if effect != with_oparg:
                    effect = NOTFIXED
                    break
                pass
        else:
            effect = dis.stack_effect(i)
            pass