# Copyright (c) 2015-2016 by Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock """ CPython magic- and version- independent disassembly routines There are two reasons we can't use Python's built-in routines from dis. First, the bytecode we are extracting may be from a different version of Python (different magic number) than the version of Python that is doing the extraction. Second, we need structured instruction information for the (de)-parsing step. Python 3.4 and up provides this, but we still do want to run on Python 2.7. """ from __future__ import print_function import os, sys from collections import deque import uncompyle6 from xdis.main import disassemble_file as xdisassemble_file from xdis.code import iscode from xdis.load import check_object_path, load_module from uncompyle6.scanner import get_scanner def disco(version, co, out=None, is_pypy=False): """ diassembles and deparses a given code block 'co' """ assert iscode(co) # store final output stream for case of error real_out = out or sys.stdout print('# Python %s' % version, file=real_out) if co.co_filename: print('# Embedded file name: %s' % co.co_filename, file=real_out) scanner = get_scanner(version, is_pypy=is_pypy) queue = deque([co]) disco_loop(scanner.disassemble, queue, real_out) def disco_loop(disasm, queue, real_out): while len(queue) > 0: co = queue.popleft() if co.co_name != '': print('\n# %s line %d of %s' % (co.co_name, co.co_firstlineno, co.co_filename), file=real_out) tokens, customize = disasm(co) for t in tokens: if iscode(t.pattr): queue.append(t.pattr) elif iscode(t.attr): queue.append(t.attr) print(t, file=real_out) pass pass def disassemble_file(filename, outstream=None, native=False): """ disassemble Python byte-code file (.pyc) If given a Python source file (".py") file, we'll try to find the corresponding compiled object. """ if native: xdisassemble_file(filename, outstream) return filename = check_object_path(filename) version, timestamp, magic_int, co, is_pypy = load_module(filename) if type(co) == list: for con in co: disco(version, con, outstream) else: disco(version, co, outstream, is_pypy=is_pypy) co = None def _test(): """Simple test program to disassemble a file.""" argc = len(sys.argv) if argc != 2: if argc == 1 and uncompyle6.PYTHON3: fn = __file__ else: sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__) sys.exit(2) else: fn = sys.argv[1] disassemble_file(fn, native=True) if __name__ == "__main__": _test()