Very crude inter-python version opcode translator. Raises SyntaxError when
    the opcode doesn't exist in the destination opmap. Used to transcribe
    python code objects between python versions.

    Arguments:
        code_obj(pwnypack.bytecode.CodeObject): The code object representation
            to translate.
        target(dict): The py_internals structure for the target
            python version.

def translate_opcodes(code_obj, target):
    """
    Very crude inter-python version opcode translator. Raises SyntaxError when
    the opcode doesn't exist in the destination opmap. Used to transcribe
    python code objects between python versions.

    Arguments:
        code_obj(pwnypack.bytecode.CodeObject): The code object representation
            to translate.
        target(dict): The py_internals structure for the target
            python version.
    """

    target = get_py_internals(target)
    src_ops = code_obj.disassemble()

    dst_opmap = target['opmap']
    dst_ops = []

    op_iter = enumerate(src_ops)
    for i, op in op_iter:
        if isinstance(op, pwnypack.bytecode.Label):
            dst_ops.append(op)
            continue

        if op.name not in dst_opmap:
            if op.name == 'POP_JUMP_IF_FALSE' and 'JUMP_IF_TRUE' in dst_opmap:
                lbl = pwnypack.bytecode.Label()
                dst_ops.extend([
                    pwnypack.bytecode.Op('JUMP_IF_TRUE', lbl),
                    pwnypack.bytecode.Op('POP_TOP', None),
                    pwnypack.bytecode.Op('JUMP_ABSOLUTE', op.arg),
                    lbl,
                    pwnypack.bytecode.Op('POP_TOP', None),
                ])
            elif op.name == 'POP_JUMP_IF_TRUE' and 'JUMP_IF_FALSE' in dst_opmap:
                lbl = pwnypack.bytecode.Label()
                dst_ops.extend([
                    pwnypack.bytecode.Op('JUMP_IF_FALSE', lbl),
                    pwnypack.bytecode.Op('POP_TOP', None),
                    pwnypack.bytecode.Op('JUMP_ABSOLUTE', op.arg),
                    lbl,
                    pwnypack.bytecode.Op('POP_TOP', None),
                ])
            elif op.name == 'JUMP_IF_FALSE' and 'JUMP_IF_FALSE_OR_POP' in dst_opmap and \
                    src_ops[i + 1].name == 'POP_TOP':
                next(op_iter)
                dst_ops.append(pwnypack.bytecode.Op('JUMP_IF_FALSE_OR_POP', op.arg))
            elif op.name == 'JUMP_IF_TRUE' and 'JUMP_IF_TRUE_OR_POP' in dst_opmap and \
                    src_ops[i + 1].name == 'POP_TOP':
                next(op_iter)
                dst_ops.append(pwnypack.bytecode.Op('JUMP_IF_TRUE_OR_POP', op.arg))
            else:
                raise SyntaxError('Opcode %s not supported on target.' % op.name)
        else:
            dst_ops.append(op)

    code_obj.assemble(dst_ops, target)