Ejemplo n.º 1
0
def main(asm, show_bytes, header, files):
    """Disassembles a Python bytecode file.

    We handle bytecode for virtually every release of Python and some releases of PyPy.
    The version of Python in the bytecode doesn't have to be the same version as
    the Python interpreter used to run this program. For example, you can disassemble Python 3.6.9
    bytecode from Python 2.7.15 and vice versa.
    """
    if not (2.7 <= PYTHON_VERSION <= 3.9):
        if 2.4 <= PYTHON_VERSION <= 2.6:
            sys.stderr.write(
                "This code works on 2.7..3.8. code that works for %s can be found in the python-2.4 branch\n"
                % PYTHON_VERSION)
            sys.exit(1)
        sys.stderr.write("This works on Python version 2.7..3.8; have %s.\n" %
                         PYTHON_VERSION)
        sys.exit(2)

    for path in files:
        # Some sanity checks
        if not osp.exists(path):
            sys.stderr.write("File name: '%s' doesn't exist\n" % path)
            continue
        elif not osp.isfile(path):
            sys.stderr.write("File name: '%s' isn't a file\n" % path)
            continue
        elif osp.getsize(path) < 50 and not path.endswith(".py"):
            sys.stderr.write(
                "File name: '%s (%d bytes)' is too short to be a valid pyc file\n"
                % (path, osp.getsize(path)))
            continue

        disassemble_file(path, sys.stdout, asm, header, show_bytes)
    return
Ejemplo n.º 2
0
def main(format, files):
    """Disassembles a Python bytecode file.

    We handle bytecode for virtually every release of Python and some releases of PyPy.
    The version of Python in the bytecode doesn't have to be the same version as
    the Python interpreter used to run this program. For example, you can disassemble Python 3.6.9
    bytecode from Python 2.7.15 and vice versa.
    """
    if not ((2, 7) <= PYTHON_VERSION_TRIPLE < (3, 12)):
        mess = "This code works on 3.6 to 3.12."
        if (2, 4) <= PYTHON_VERSION_TRIPLE <= (2, 7):
            mess += " Code that works for %s can be found in the python-2.4 branch\n"
        elif (3, 1) <= PYTHON_VERSION_TRIPLE <= (3, 2):
            mess += " Code that works for %s can be found in the python-3.1 branch\n"
        elif (3, 3) <= PYTHON_VERSION_TRIPLE <= (3, 5):
            mess += " Code that works for %s can be found in the python-3.3 branch\n"
        sys.stderr.write(mess % PYTHON_VERSION_STR)
        sys.exit(2)

    for path in files:
        # Some sanity checks
        if not osp.exists(path):
            sys.stderr.write("File name: '%s' doesn't exist\n" % path)
            continue
        elif not osp.isfile(path):
            sys.stderr.write("File name: '%s' isn't a file\n" % path)
            continue
        elif osp.getsize(path) < 50 and not path.endswith(".py"):
            sys.stderr.write(
                "File name: '%s (%d bytes)' is too short to be a valid pyc file\n"
                % (path, osp.getsize(path)))
            continue

        disassemble_file(path, sys.stdout, format)
    return
Ejemplo n.º 3
0
def main(conversion_type, input_pyc, output_pyc):
    """Convert Python bytecode from one version to another.

    INPUT_PYC contains the input bytecode path name
    OUTPUT_PYC  contians the output bytecode path name if supplied
    The --conversion type option specifies what conversion to do.

    Note: there are a very limited set of conversions currently supported.
    Help out and write more!"""

    shortname = osp.basename(input_pyc)
    if shortname.endswith(".pyc"):
        shortname = shortname[:-4]
    src_version = conversion_to_version(conversion_type, is_dest=False)
    dest_version = conversion_to_version(conversion_type, is_dest=True)
    if output_pyc is None:
        output_pyc = "%s-%s.pyc" % (shortname, dest_version)

    if conversion_type in UPWARD_COMPATABLE:
        copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version)
        return
    temp_asm = NamedTemporaryFile("w",
                                  suffix=".pyasm",
                                  prefix=shortname,
                                  delete=False)
    (filename, co, version, timestamp,
     magic_int) = disassemble_file(input_pyc, temp_asm, asm_format=True)
    temp_asm.close()
    assert version == float(
        src_version
    ), "Need Python %s bytecode; got bytecode for version %s" % (src_version,
                                                                 version)
    asm = asm_file(temp_asm.name)
    new_asm = transform_asm(asm, conversion_type, src_version, dest_version)
    os.unlink(temp_asm.name)
    write_pycfile(output_pyc, new_asm)
Ejemplo n.º 4
0
def findlabels():
    my_dir = osp.dirname(osp.abspath(__file__))

    # Python 2.7 code
    code = bug708901.__code__

    # FIXME: Consider loading from a file like below to remove
    # dependence on running interpreter
    if PYTHON_VERSION_TRIPLE[:2] == (2, 7):
        # 19:           0 SETUP_LOOP               23 (to 26)
        #               3 LOAD_GLOBAL               0 (range)
        #               6 LOAD_CONST                1 (1)
        #
        # 20:           9 LOAD_CONST                2 (10)
        #              12 CALL_FUNCTION             2 (2 positional, 0 keyword pair)
        #              15 GET_ITER
        #         >>   16 FOR_ITER                  6 (to 25)
        #              19 STORE_FAST                0 (res)
        #
        # 21:          22 JUMP_ABSOLUTE            16 (to 16)
        #         >>   25 POP_BLOCK
        #         >>   26 LOAD_CONST                0 (None)
        #              29 RETURN_VALUE
        offset_map = opcode_27.get_jump_target_maps(code, opcode_27)

        expected = {
            3: [0],
            6: [3],
            9: [6],
            12: [9],
            15: [12],
            16: [15, 22],
            19: [16],
            22: [19],
            25: [16],
            26: [0, 25],
            29: [26]
        }
        assert expected == offset_map

        offsets = opcode_27.get_jump_targets(code, opcode_27)
        assert offsets == [26, 25, 16]

    test_pyc = my_dir + '/../test/bytecode_2.7/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy, source_size,
     _) = load_module(test_pyc)
    code = co.co_consts[0]
    offsets = opcode_27.get_jump_targets(code, opcode_27)
    assert [10] == offsets

    # from xdis import disassemble_file
    # print('\n')
    # disassemble_file(test_pyc)

    #  2:           0 LOAD_FAST                 0 (a)
    #               3 POP_JUMP_IF_FALSE        10 (to 10)
    #
    #  3:           6 LOAD_CONST                1 (5)
    #               9 RETURN_VALUE
    #
    #  5:     >>   10 LOAD_CONST                2 (6)
    #              13 RETURN_VALUE
    #              14 LOAD_CONST                0 (None)
    #              17 RETURN_VALUE
    offset_map = opcode_27.get_jump_target_maps(code, opcode_27)
    # print(offset_map)
    expect = {3: [0], 6: [3], 9: [6], 10: [3], 13: [10], 17: [14]}
    assert expect == offset_map

    # Python 3.6 code wordcode
    # ------------------------
    test_pyc = my_dir + '/../test/bytecode_3.6/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy, source_size,
     _) = load_module(test_pyc)
    code = co.co_consts[0]

    #  2:           0 LOAD_FAST                 0 (a)
    #               2 POP_JUMP_IF_FALSE         8 (to 8)
    #
    #  3:           4 LOAD_CONST                1 (5)
    #               6 RETURN_VALUE
    #
    #  5:           8 LOAD_CONST                2 (6)
    #              10 RETURN_VALUE
    #              12 LOAD_CONST                0 (None)
    #              14 RETURN_VALUE

    offsets = opcode_36.get_jump_targets(code, opcode_36)
    assert offsets == [8]

    from xdis import disassemble_file
    print('\n')
    disassemble_file(test_pyc)

    offset_map = opcode_36.get_jump_target_maps(code, opcode_36)
    expect = {2: [0], 4: [2], 6: [4], 8: [2], 10: [8], 14: [12]}
    assert expect == offset_map
Ejemplo n.º 5
0
def do_tests(src_dir, obj_patterns, target_dir, opts):
    def file_matches(files, root, basenames, patterns):
        files.extend([
            os.path.normpath(os.path.join(root, n)) for n in basenames
            for pat in patterns if fnmatch(n, pat)
        ])

    files = []
    # Change directories so use relative rather than
    # absolute paths. This speeds up things, and allows
    # main() to write to a relative-path destination.
    cwd = os.getcwd()
    os.chdir(src_dir)

    if opts['do_compile']:
        compiled_version = opts['compiled_version']
        if compiled_version and PYTHON_VERSION != compiled_version:
            sys.stderr.write("Not compiling: desired Python version is %s "
                             "but we are running %s\n" %
                             (compiled_version, PYTHON_VERSION))
        else:
            for root, dirs, basenames in os.walk(src_dir):
                file_matches(files, root, basenames, PY)
                for sfile in files:
                    py_compile.compile(sfile)
                    pass
                pass
            files = []
            pass
        pass

    for root, dirs, basenames in os.walk('.'):
        # Turn root into a relative path
        dirname = root[2:]  # 2 = len('.') + 1
        file_matches(files, dirname, basenames, obj_patterns)

    if not files:
        sys.stderr.write(
            "Didn't come up with any files to test! Try with --compile?\n")
        exit(1)

    os.chdir(cwd)
    files.sort()

    if opts['start_with']:
        try:
            start_with = files.index(opts['start_with'])
            files = files[start_with:]
            print('>>> starting with file', files[0])
        except ValueError:
            pass

    output = open(os.devnull, "w")
    # output = sys.stdout
    print(time.ctime())
    print('Source directory: ', src_dir)
    cwd = os.getcwd()
    os.chdir(src_dir)
    try:
        for infile in files:
            disassemble_file(infile, output)
            if opts['do_verify']:
                pass
            # print("Need to do something here to verify %s" % infile)
            # msg = verify.verify_file(infile, outfile)

        # if failed_files != 0:
        #     exit(2)
        # elif failed_verify != 0:
        #     exit(3)

    except (KeyboardInterrupt, OSError):
        print()
        exit(1)
    os.chdir(cwd)
Ejemplo n.º 6
0
def do_tests(
    src_dir,
    patterns,
    target_dir,
    start_with=None,
    do_verify=False,
    max_files=800,
    do_compile=False,
    verbose=False,
):
    def visitor(files, dirname, names):
        files.extend([
            os.path.normpath(os.path.join(dirname, n)) for n in names
            for pat in patterns if fnmatch(n, pat)
        ])

    def file_matches(files, root, basenames, patterns):
        files.extend([
            os.path.normpath(os.path.join(root, n)) for n in basenames
            for pat in patterns if fnmatch(n, pat)
        ])

    files = []
    if do_compile:
        for root, dirs, basenames in os.walk(src_dir):
            file_matches(files, root, basenames, PY)
            for sfile in files:
                py_compile.compile(sfile)
                pass
            pass
        files = []
        pass

    cwd = os.getcwd()
    os.chdir(src_dir)
    if PYTHON3:
        for root, dirname, names in os.walk(os.curdir):
            files.extend([
                os.path.normpath(os.path.join(root, n)) for n in names
                for pat in patterns if fnmatch(n, pat)
            ])
            pass
        pass
    else:
        os.path.walk(os.curdir, visitor, files)
    files.sort()

    if start_with:
        try:
            start_with = files.index(start_with)
            files = files[start_with:]
            print(">>> starting with file", files[0])
        except ValueError:
            pass

    if len(files) > max_files:
        files = [file for file in files if not "site-packages" in file]
        files = [file for file in files if not "test" in file]
        if len(files) > max_files:
            files = files[:max_files]
            pass
    elif len(files) == 0:
        print("No files found\n")
        os.chdir(cwd)
        return

    output = open(os.devnull, "w")
    # output = sys.stdout
    start_time = time.time()
    print(time.ctime())
    for i, bc_file in enumerate(files):
        if verbose:
            print(os.path.join(src_dir, bc_file))
        if src_dir.find("simple_source") >= 0:
            continue
        if sys.version_info >= (3, 4, 0) and bc_file.endswith(".py"):
            check_bc_file = check_object_path(bc_file)
            if not osp.exists(check_bc_file):
                basename = osp.basename(bc_file)[0:-3]
                new_bc_file = tempfile.mkstemp(prefix=basename + "-",
                                               suffix=".pyc",
                                               text=False)[1]
                py_compile.compile(bc_file, cfile=new_bc_file, doraise=True)
                bc_file = new_bc_file

        bc_filename, co, version, ts, magic, _, _, _ = disassemble_file(
            bc_file, output)
        if do_verify:
            file = co.co_filename
            verify_file(file, bc_filename)
        if i % 100 == 0 and i > 0:
            print("Processed %d files" % (i))
    print("Processed %d files, total" % (i + 1))
    print(time.ctime())
    elapsed_time = time.time() - start_time
    print("%g seconds" % elapsed_time)
    os.chdir(cwd)