Exemplo n.º 1
0
def next_offset(op, opc, offset):
    return offset + instruction_size(op, opc)
Exemplo n.º 2
0
def get_instructions_bytes(
    bytecode,
    opc,
    varnames=None,
    names=None,
    constants=None,
    cells=None,
    linestarts=None,
    line_offset=0,
):
    """Iterate over the instructions in a bytecode string.

    Generates a sequence of Instruction namedtuples giving the details of each
    opcode.  Additional information about the code's runtime environment
    (e.g. variable names, constants) can be specified using optional
    arguments.

    """
    labels = opc.findlabels(bytecode, opc)
    # label_maps = get_jump_target_maps(bytecode, opc)
    extended_arg = 0

    # FIXME: We really need to distinguish 3.6.0a1 from 3.6.a3.
    # See below FIXME
    python_36 = True if opc.python_version >= 3.6 else False

    starts_line = None
    # enumerate() is not an option, since we sometimes process
    # multiple elements on a single pass through the loop
    n = len(bytecode)
    i = 0
    extended_arg_count = 0
    extended_arg = 0
    extended_arg_size = instruction_size(opc.EXTENDED_ARG, opc)
    while i < n:
        op = code2num(bytecode, i)

        offset = i
        if linestarts is not None:
            starts_line = linestarts.get(i, None)
            if starts_line is not None:
                starts_line += line_offset
        if i in labels:
            #  come_from = label_maps[i]
            if False:  # come_from[0] > i:
                is_jump_target = "loop"
                # print("XXX %s at %d" % (opc.opname[op], i))
                # from trepan.api import debug; debug()
            else:
                is_jump_target = True
        else:
            is_jump_target = False

        i += 1
        arg = None
        argval = None
        argrepr = ""
        has_arg = op_has_argument(op, opc)
        optype = None
        if has_arg:
            if python_36:
                arg = code2num(bytecode, i) | extended_arg
                extended_arg = (arg << 8) if op == opc.EXTENDED_ARG else 0
                # FIXME: Python 3.6.0a1 is 2, for 3.6.a3 we have 1
                i += 1
            else:
                arg = (code2num(bytecode, i) +
                       code2num(bytecode, i + 1) * 256 + extended_arg)
                i += 2
                extended_arg = arg * 65536 if op == opc.EXTENDED_ARG else 0

            #  Set argval to the dereferenced value of the argument when
            #  availabe, and argrepr to the string representation of argval.
            #    disassemble_bytes needs the string repr of the
            #    raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
            argval = arg
            if op in opc.CONST_OPS:
                argval, argrepr = _get_const_info(arg, constants)
                optype = "const"
            elif op in opc.NAME_OPS:
                argval, argrepr = _get_name_info(arg, names)
                optype = "name"
            elif op in opc.JREL_OPS:
                argval = i + arg
                argrepr = "to " + repr(argval)
                optype = "jrel"
            elif op in opc.JABS_OPS:
                argval = arg
                argrepr = "to " + repr(argval)
                optype = "jabs"
            elif op in opc.LOCAL_OPS:
                argval, argrepr = _get_name_info(arg, varnames)
                optype = "local"
            elif op in opc.COMPARE_OPS:
                argval = opc.cmp_op[arg]
                argrepr = argval
                optype = "compare"
            elif op in opc.FREE_OPS:
                argval, argrepr = _get_name_info(arg, cells)
                optype = "free"
            elif op in opc.NARGS_OPS:
                optype = "nargs"
                if not (python_36 or opc.opname[op]
                        in ("RAISE_VARARGS", "DUP_TOPX", "MAKE_FUNCTION")):
                    argrepr = "%d positional, %d named" % (
                        code2num(bytecode, i - 2),
                        code2num(bytecode, i - 1),
                    )
            # This has to come after hasnargs. Some are in both?
            elif op in opc.VARGS_OPS:
                optype = "vargs"
            if hasattr(
                    opc,
                    "opcode_arg_fmt") and opc.opname[op] in opc.opcode_arg_fmt:
                argrepr = opc.opcode_arg_fmt[opc.opname[op]](arg)
        elif python_36:
            i += 1

        opname = opc.opname[op]
        inst_size = instruction_size(
            op, opc) + (extended_arg_count * extended_arg_size)
        fallthrough = op not in opc.nofollow
        yield Instruction(
            opname,
            op,
            optype,
            inst_size,
            arg,
            argval,
            argrepr,
            has_arg,
            offset,
            starts_line,
            is_jump_target,
            extended_arg_count != 0,
        )
        # fallthrough)
        extended_arg_count = extended_arg_count + 1 if op == opc.EXTENDED_ARG else 0