You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Use xdis for code, magics, and marshal
This commit is contained in:
@@ -36,7 +36,8 @@ entry_points={
|
|||||||
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
'pydisassemble=uncompyle6.bin.pydisassemble:main',
|
||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.2.1']
|
install_requires = ['spark-parser >= 1.2.1',
|
||||||
|
'xdis >= 1.0.1']
|
||||||
license = 'MIT'
|
license = 'MIT'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
modname = 'uncompyle6'
|
modname = 'uncompyle6'
|
||||||
|
@@ -18,7 +18,6 @@ def test_if_in_for():
|
|||||||
scan.build_prev_op(n)
|
scan.build_prev_op(n)
|
||||||
fjt = scan.find_jump_targets()
|
fjt = scan.find_jump_targets()
|
||||||
assert {15: [3], 69: [66], 63: [18]} == fjt
|
assert {15: [3], 69: [66], 63: [18]} == fjt
|
||||||
print(scan.structs)
|
|
||||||
assert scan.structs == \
|
assert scan.structs == \
|
||||||
[{'start': 0, 'end': 72, 'type': 'root'},
|
[{'start': 0, 'end': 72, 'type': 'root'},
|
||||||
{'start': 18, 'end': 66, 'type': 'if-then'},
|
{'start': 18, 'end': 66, 'type': 'if-then'},
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
import os, sys
|
|
||||||
from uncompyle6.load import load_file, check_object_path, load_module
|
|
||||||
|
|
||||||
def test_load():
|
|
||||||
"""Basic test of load_file, check_object_path and load_module"""
|
|
||||||
co = load_file(__file__)
|
|
||||||
obj_path = check_object_path(__file__)
|
|
||||||
if os.path.exists(obj_path):
|
|
||||||
version, timestamp, magic_int, co2 = load_module(obj_path)
|
|
||||||
assert sys.version[0:3] == str(version)
|
|
||||||
assert co == co2
|
|
||||||
else:
|
|
||||||
assert True, "Skipped because we can't find %s" % obj_path
|
|
@@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
from uncompyle6.load import load_module
|
|
||||||
|
|
||||||
def get_srcdir():
|
|
||||||
filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
return os.path.realpath(filename)
|
|
||||||
|
|
||||||
srcdir = get_srcdir()
|
|
||||||
|
|
||||||
def test_load_module():
|
|
||||||
"""Tests uncompile6.load.load_module"""
|
|
||||||
# We deliberately pick a bytecode that we aren't likely to be running against
|
|
||||||
mod_file = os.path.join(get_srcdir(), '..', 'test', 'bytecode_2.5',
|
|
||||||
'02_complex.pyc')
|
|
||||||
|
|
||||||
version, timestamp, magic_int, co = load_module(mod_file)
|
|
||||||
assert version == 2.5, "Should have picked up Python version properly"
|
|
||||||
assert co.co_consts == (5j, None), "Code should have a complex constant"
|
|
||||||
|
|
||||||
mod_file = os.path.join(get_srcdir(), '..', 'test', 'bytecode_3.3',
|
|
||||||
'06_frozenset.pyc')
|
|
||||||
version, timestamp, magic_int, co = load_module(mod_file)
|
|
||||||
print(co.co_consts)
|
|
||||||
expect = (0, None, 'attlist', 'linktype', 'link', 'element', 'Yep',
|
|
||||||
frozenset({'linktype', 'attlist', 'element', 'link'}))
|
|
||||||
assert co.co_consts == expect, "Should handle frozenset"
|
|
@@ -45,10 +45,8 @@ sys.setrecursionlimit(5000)
|
|||||||
|
|
||||||
import uncompyle6.semantics.pysource
|
import uncompyle6.semantics.pysource
|
||||||
import uncompyle6.semantics.fragments
|
import uncompyle6.semantics.fragments
|
||||||
import uncompyle6.load
|
|
||||||
|
|
||||||
# Export some functions
|
# Export some functions
|
||||||
from uncompyle6.load import load_module, load_file
|
|
||||||
from uncompyle6.main import uncompyle_file
|
from uncompyle6.main import uncompyle_file
|
||||||
|
|
||||||
# Conventience functions so you can say:
|
# Conventience functions so you can say:
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, os, getopt
|
import sys, os, getopt
|
||||||
|
|
||||||
from uncompyle6 import check_python_version
|
|
||||||
from uncompyle6.disas import disassemble_file
|
from uncompyle6.disas import disassemble_file
|
||||||
from uncompyle6.version import VERSION
|
from uncompyle6.version import VERSION
|
||||||
|
|
||||||
@@ -35,8 +34,6 @@ def main():
|
|||||||
Usage_short = """usage: %s FILE...
|
Usage_short = """usage: %s FILE...
|
||||||
Type -h for for full help.""" % program
|
Type -h for for full help.""" % program
|
||||||
|
|
||||||
check_python_version(program)
|
|
||||||
|
|
||||||
use_uncompyle6_format = False
|
use_uncompyle6_format = False
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
import inspect
|
|
||||||
class Code3:
|
|
||||||
"""Class for a Python3 code object used when a Python interpreter less than 3 is
|
|
||||||
working on Python3 bytecode
|
|
||||||
"""
|
|
||||||
def __init__(self, co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags, co_code,
|
|
||||||
co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, co_lnotab, co_freevars, co_cellvars):
|
|
||||||
self.co_argcount = co_argcount
|
|
||||||
self.co_kwonlyargcount = co_kwonlyargcount
|
|
||||||
self.co_nlocals = co_nlocals
|
|
||||||
self.co_stacksize = co_stacksize
|
|
||||||
self.co_flags = co_flags
|
|
||||||
self.co_code = co_code
|
|
||||||
self.co_consts = co_consts
|
|
||||||
self.co_names = co_names
|
|
||||||
self.co_varnames = co_varnames
|
|
||||||
self.co_filename = co_filename
|
|
||||||
self.co_name = co_name
|
|
||||||
self.co_firstlineno = co_firstlineno
|
|
||||||
self.co_lnotab = co_lnotab
|
|
||||||
self.co_freevars = co_freevars
|
|
||||||
self.co_cellvars = co_cellvars
|
|
||||||
|
|
||||||
class Code2:
|
|
||||||
"""Class for a Python2 code object used when a Python interpreter less than 3 is
|
|
||||||
working on Python3 bytecode
|
|
||||||
"""
|
|
||||||
def __init__(self, co_argcount, co_kwonlyargcount,co_nlocals, co_stacksize, co_flags, co_code,
|
|
||||||
co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, co_lnotab, co_freevars, co_cellvars):
|
|
||||||
self.co_argcount = co_argcount
|
|
||||||
self.co_kwonlyargcount = co_kwonlyargcount
|
|
||||||
self.co_nlocals = co_nlocals
|
|
||||||
self.co_stacksize = co_stacksize
|
|
||||||
self.co_flags = co_flags
|
|
||||||
self.co_code = co_code
|
|
||||||
self.co_consts = co_consts
|
|
||||||
self.co_names = co_names
|
|
||||||
self.co_varnames = co_varnames
|
|
||||||
self.co_filename = co_filename
|
|
||||||
self.co_name = co_name
|
|
||||||
self.co_firstlineno = co_firstlineno
|
|
||||||
self.co_lnotab = co_lnotab
|
|
||||||
self.co_freevars = co_freevars
|
|
||||||
self.co_cellvars = co_cellvars
|
|
||||||
|
|
||||||
def iscode(obj):
|
|
||||||
"""A replacement for inspect.iscode() which we can't used because we may be
|
|
||||||
using a different version of Python than the version of Python used
|
|
||||||
in creating the byte-compiled objects. Here, he code types may mismatch.
|
|
||||||
"""
|
|
||||||
return inspect.iscode(obj) or isinstance(obj, Code3)
|
|
@@ -22,8 +22,8 @@ import os, sys
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
import uncompyle6
|
import uncompyle6
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.load import check_object_path, load_module
|
from xdis.load import check_object_path, load_module
|
||||||
from uncompyle6.scanner import get_scanner
|
from uncompyle6.scanner import get_scanner
|
||||||
|
|
||||||
def disco(version, co, out=None, use_uncompyle6_format=False):
|
def disco(version, co, out=None, use_uncompyle6_format=False):
|
||||||
@@ -57,7 +57,7 @@ def disco_loop(disasm, queue, real_out, use_uncompyle6_format):
|
|||||||
print('\n# %s line %d of %s' %
|
print('\n# %s line %d of %s' %
|
||||||
(co.co_name, co.co_firstlineno, co.co_filename),
|
(co.co_name, co.co_firstlineno, co.co_filename),
|
||||||
file=real_out)
|
file=real_out)
|
||||||
tokens, customize = disasm(co, use_uncompyle6_format)
|
tokens, customize = disasm(co)
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
if iscode(t.pattr):
|
if iscode(t.pattr):
|
||||||
queue.append(t.pattr)
|
queue.append(t.pattr)
|
||||||
|
@@ -1,117 +0,0 @@
|
|||||||
# Copyright (c) 2015 by Rocky Bernstein
|
|
||||||
# Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import imp, marshal, os, py_compile, sys, tempfile
|
|
||||||
from struct import unpack
|
|
||||||
|
|
||||||
import uncompyle6.marsh
|
|
||||||
from uncompyle6 import PYTHON3
|
|
||||||
from uncompyle6 import magics
|
|
||||||
|
|
||||||
def check_object_path(path):
|
|
||||||
if path.endswith(".py"):
|
|
||||||
try:
|
|
||||||
import importlib
|
|
||||||
return importlib.util.cache_from_source(path,
|
|
||||||
optimization='')
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
import imp
|
|
||||||
imp.cache_from_source(path, debug_override=False)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
basename = os.path.basename(path)[0:-3]
|
|
||||||
spath = path if PYTHON3 else path.decode('utf-8')
|
|
||||||
path = tempfile.mkstemp(prefix=basename + '-',
|
|
||||||
suffix='.pyc', text=False)[1]
|
|
||||||
py_compile.compile(spath, cfile=path, doraise=True)
|
|
||||||
|
|
||||||
if not path.endswith(".pyc") and not path.endswith(".pyo"):
|
|
||||||
raise ValueError("path %s must point to a .py or .pyc file\n" %
|
|
||||||
path)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def load_file(filename):
|
|
||||||
"""
|
|
||||||
load a Python source file and compile it to byte-code
|
|
||||||
_load_file(filename: string): code_object
|
|
||||||
filename: name of file containing Python source code
|
|
||||||
(normally a .py)
|
|
||||||
code_object: code_object compiled from this source code
|
|
||||||
This function does NOT write any file!
|
|
||||||
"""
|
|
||||||
with open(filename, 'rb') as fp:
|
|
||||||
source = fp.read().decode('utf-8') + '\n'
|
|
||||||
try:
|
|
||||||
co = compile(source, filename, 'exec', dont_inherit=True)
|
|
||||||
except SyntaxError:
|
|
||||||
print('>>Syntax error in %s\n' % filename, file= sys.stderr)
|
|
||||||
raise
|
|
||||||
pass
|
|
||||||
return co
|
|
||||||
|
|
||||||
def load_module(filename, code_objects={}):
|
|
||||||
"""
|
|
||||||
load a module without importing it.
|
|
||||||
load_module(filename: string): version, magic_int, code_object
|
|
||||||
|
|
||||||
filename: name of file containing Python byte-code object
|
|
||||||
(normally a .pyc)
|
|
||||||
|
|
||||||
code_object: code_object from this file
|
|
||||||
version: Python major/minor value e.g. 2.7. or 3.4
|
|
||||||
magic_int: more specific than version. The actual byte code version of the
|
|
||||||
code object
|
|
||||||
"""
|
|
||||||
|
|
||||||
with open(filename, 'rb') as fp:
|
|
||||||
magic = fp.read(4)
|
|
||||||
try:
|
|
||||||
version = float(magics.versions[magic])
|
|
||||||
except KeyError:
|
|
||||||
if len(magic) >= 2:
|
|
||||||
raise ImportError("Unknown magic number %s in %s" %
|
|
||||||
(ord(magic[0])+256*ord(magic[1]), filename))
|
|
||||||
else:
|
|
||||||
raise ImportError("Bad magic number: '%s'" % magic)
|
|
||||||
|
|
||||||
if not (2.5 <= version <= 2.7) and not (3.2 <= version <= 3.5):
|
|
||||||
raise ImportError("This is a Python %s file! Only "
|
|
||||||
"Python 2.5 to 2.7 and 3.2 to 3.5 files are supported."
|
|
||||||
% version)
|
|
||||||
|
|
||||||
# print version
|
|
||||||
ts = fp.read(4)
|
|
||||||
timestamp = unpack("I", ts)[0]
|
|
||||||
magic_int = magics.magic2int(magic)
|
|
||||||
my_magic_int = magics.magic2int(imp.get_magic())
|
|
||||||
|
|
||||||
# Note: a higher magic number doesn't necessarily mean a later
|
|
||||||
# release. At Python 3.0 the magic number decreased
|
|
||||||
# significantly. Hence the range below. Also note inclusion of
|
|
||||||
# the size info, occurred within a Python major/minor
|
|
||||||
# release. Hence the test on the magic value rather than
|
|
||||||
# PYTHON_VERSION, although PYTHON_VERSION would probably work.
|
|
||||||
if 3200 <= magic_int < 20121:
|
|
||||||
fp.read(4) # size mod 2**32
|
|
||||||
|
|
||||||
if my_magic_int == magic_int:
|
|
||||||
bytecode = fp.read()
|
|
||||||
co = marshal.loads(bytecode)
|
|
||||||
else:
|
|
||||||
co = uncompyle6.marsh.load_code(fp, magic_int, code_objects)
|
|
||||||
pass
|
|
||||||
|
|
||||||
return version, timestamp, magic_int, co
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
co = load_file(__file__)
|
|
||||||
obj_path = check_object_path(__file__)
|
|
||||||
version, timestamp, magic_int, co2 = load_module(obj_path)
|
|
||||||
print("version", version, "magic int", magic_int)
|
|
||||||
import datetime
|
|
||||||
print(datetime.datetime.fromtimestamp(timestamp))
|
|
||||||
if version < 3.5:
|
|
||||||
assert co == co2
|
|
@@ -1,110 +0,0 @@
|
|||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import imp, struct, sys
|
|
||||||
|
|
||||||
def __build_magic(magic):
|
|
||||||
if (sys.version_info >= (3, 0)):
|
|
||||||
return struct.pack('Hcc', magic, bytes('\r', 'utf-8'), bytes('\n', 'utf-8'))
|
|
||||||
else:
|
|
||||||
return struct.pack('Hcc', magic, '\r', '\n')
|
|
||||||
|
|
||||||
def magic2int(magic):
|
|
||||||
return struct.unpack('Hcc', magic)[0]
|
|
||||||
|
|
||||||
PYTHON_MAGIC_INT = magic2int(imp.get_magic())
|
|
||||||
|
|
||||||
by_magic = {}
|
|
||||||
by_version = {}
|
|
||||||
|
|
||||||
def __by_version(magics):
|
|
||||||
for m, v in list(magics.items()):
|
|
||||||
by_magic[m] = v
|
|
||||||
by_version[v] = m
|
|
||||||
return by_version
|
|
||||||
|
|
||||||
versions = {
|
|
||||||
# taken from from Python/import.c
|
|
||||||
# or importlib/_bootstrap.py
|
|
||||||
# magic, version
|
|
||||||
__build_magic(20121): '1.5', # 1.5, 1.5.1, 1.5.2
|
|
||||||
__build_magic(50428): '1.6', # 1.6
|
|
||||||
__build_magic(50823): '2.0', # 2.0, 2.0.1
|
|
||||||
__build_magic(60202): '2.1', # 2.1, 2.1.1, 2.1.2
|
|
||||||
__build_magic(60717): '2.2', # 2.2
|
|
||||||
__build_magic(62011): '2.3', # 2.3a0
|
|
||||||
__build_magic(62021): '2.3', # 2.3a0
|
|
||||||
__build_magic(62041): '2.4', # 2.4a0
|
|
||||||
__build_magic(62051): '2.4', # 2.4a3
|
|
||||||
__build_magic(62061): '2.4', # 2.4b1
|
|
||||||
__build_magic(62071): '2.5', # 2.5a0
|
|
||||||
__build_magic(62081): '2.5', # 2.5a0 (ast-branch)
|
|
||||||
__build_magic(62091): '2.5', # 2.5a0 (with)
|
|
||||||
__build_magic(62092): '2.5', # 2.5a0 (changed WITH_CLEANUP opcode)
|
|
||||||
__build_magic(62101): '2.5', # 2.5b3 (fix wrong code: for x, in ...)
|
|
||||||
__build_magic(62111): '2.5', # 2.5b3 (fix wrong code: x += yield)
|
|
||||||
__build_magic(62121): '2.5', # 2.5c1 (fix wrong lnotab with for loops and
|
|
||||||
# storing constants that should have been removed
|
|
||||||
__build_magic(62131): '2.5', # 2.5c2 (fix wrong code: for x, in ... in listcomp/genexp)
|
|
||||||
__build_magic(62151): '2.6', # 2.6a0 (peephole optimizations & STORE_MAP)
|
|
||||||
__build_magic(62161): '2.6', # 2.6a1 (WITH_CLEANUP optimization)
|
|
||||||
__build_magic(62171): '2.7', # 2.7a0 (optimize list comprehensions/change LIST_APPEND)
|
|
||||||
__build_magic(62181): '2.7', # 2.7a0 (optimize conditional branches:
|
|
||||||
# introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
|
|
||||||
__build_magic(62191): '2.7', # 2.7a0 (introduce SETUP_WITH)
|
|
||||||
__build_magic(62201): '2.7', # 2.7a0 (introduce BUILD_SET)
|
|
||||||
__build_magic(62211): '2.7', # 2.7a0 (introduce MAP_ADD and SET_ADD)
|
|
||||||
__build_magic(62218): '2.7', # 2.7 pypy?
|
|
||||||
__build_magic(3000): '3.0', # 3.000
|
|
||||||
__build_magic(3010): '3.0', # 3.000 (removed UNARY_CONVERT)
|
|
||||||
__build_magic(3020): '3.0', # 3.000 (added BUILD_SET)
|
|
||||||
__build_magic(3030): '3.0', # 3.000 (added keyword-only parameters)
|
|
||||||
__build_magic(3040): '3.0', # 3.000 (added signature annotations)
|
|
||||||
__build_magic(3050): '3.0', # 3.000 (print becomes a function)
|
|
||||||
__build_magic(3060): '3.0', # 3.000 (PEP 3115 metaclass syntax)
|
|
||||||
__build_magic(3061): '3.0', # 3.000 (string literals become unicode)
|
|
||||||
__build_magic(3071): '3.0', # 3.000 (PEP 3109 raise changes)
|
|
||||||
__build_magic(3081): '3.0', # 3.000 (PEP 3137 make __file__ and __name__ unicode)
|
|
||||||
__build_magic(3091): '3.0', # 3.000 (kill str8 interning)
|
|
||||||
__build_magic(3101): '3.0', # 3.000 (merge from 2.6a0, see 62151)
|
|
||||||
__build_magic(3103): '3.0', # 3.000 (__file__ points to source file)
|
|
||||||
__build_magic(3111): '3.0', # 3.0a4 (WITH_CLEANUP optimization).
|
|
||||||
__build_magic(3131): '3.0', # 3.0a5 (lexical exception stacking, including POP_EXCEPT)
|
|
||||||
__build_magic(3141): '3.1', # 3.1a0 (optimize list, set and dict comprehensions)
|
|
||||||
__build_magic(3151): '3.1', # 3.1a0 (optimize conditional branches)
|
|
||||||
__build_magic(3160): '3.2', # 3.2a0 (add SETUP_WITH)
|
|
||||||
__build_magic(3170): '3.2', # 3.2a1 (add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR)
|
|
||||||
__build_magic(3180): '3.2', # 3.2a2 (add DELETE_DEREF)
|
|
||||||
__build_magic(3190): '3.3', # 3.3a0 3190 __class__ super closure changed
|
|
||||||
__build_magic(3100): '3.3', # 3.3a0 3200 (__qualname__ added)
|
|
||||||
__build_magic(3210): '3.3', # 3210 (added size modulo 2**32 to the pyc header)
|
|
||||||
__build_magic(3220): '3.3', # 3.3a1 3220 (changed PEP 380 implementation)
|
|
||||||
__build_magic(3230): '3.3', # 3.3a4 3230 (revert changes to implicit __class__ closure)
|
|
||||||
__build_magic(3250): '3.4', # 3.4a1 3250 (evaluate positional default arg
|
|
||||||
# keyword-only defaults)
|
|
||||||
__build_magic(3260): '3.4', # 3.4a1 3260 (add LOAD_CLASSDEREF;
|
|
||||||
# allow locals of class to override free vars)
|
|
||||||
__build_magic(3270): '3.4', # 3.4a1 3270 (various tweaks to the __class__ closure)
|
|
||||||
__build_magic(3280): '3.4', # 3.4a1 3280 (remove implicit class argument)
|
|
||||||
__build_magic(3290): '3.4', # 3.4a4 3290 (changes to __qualname__ computation)
|
|
||||||
__build_magic(3300): '3.4', # 3.4a4 3300 (more changes to __qualname__ computation)
|
|
||||||
__build_magic(3310): '3.4', # 3.4rc2 3310 (alter __qualname__ computation)
|
|
||||||
__build_magic(3350): '3.5', # 3.5.0
|
|
||||||
}
|
|
||||||
|
|
||||||
magics = __by_version(versions)
|
|
||||||
|
|
||||||
def __show(text, magic):
|
|
||||||
print(text, struct.unpack('BBBB', magic), struct.unpack('HBB', magic))
|
|
||||||
|
|
||||||
def test():
|
|
||||||
magic_20 = magics['2.0']
|
|
||||||
current = imp.get_magic()
|
|
||||||
magic_current = by_magic[ current ]
|
|
||||||
print(type(magic_20), len(magic_20), repr(magic_20))
|
|
||||||
print()
|
|
||||||
print('This Python interpreter has version', magic_current)
|
|
||||||
print('Magic code: ', PYTHON_MAGIC_INT)
|
|
||||||
print(type(magic_20), len(magic_20), repr(magic_20))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test()
|
|
@@ -2,12 +2,12 @@ from __future__ import print_function
|
|||||||
import datetime, os, sys
|
import datetime, os, sys
|
||||||
|
|
||||||
from uncompyle6 import verify, PYTHON_VERSION
|
from uncompyle6 import verify, PYTHON_VERSION
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.disas import check_object_path
|
from uncompyle6.disas import check_object_path
|
||||||
from uncompyle6.semantics import pysource
|
from uncompyle6.semantics import pysource
|
||||||
from uncompyle6.parser import ParserError
|
from uncompyle6.parser import ParserError
|
||||||
|
|
||||||
from uncompyle6.load import load_module
|
from xdis.load import load_module
|
||||||
|
|
||||||
def uncompyle(version, co, out=None, showasm=False, showast=False,
|
def uncompyle(version, co, out=None, showasm=False, showast=False,
|
||||||
timestamp=None, showgrammar=False, code_objects={}):
|
timestamp=None, showgrammar=False, code_objects={}):
|
||||||
|
@@ -1,306 +0,0 @@
|
|||||||
"""
|
|
||||||
CPython magic- and version- independent marshal routines
|
|
||||||
|
|
||||||
This is needed when the bytecode extracted is from
|
|
||||||
a different version than the currently-running Python.
|
|
||||||
|
|
||||||
When the two are the same, you can simply use Python's built-in marshal.loads()
|
|
||||||
to produce a code object
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Copyright (c) 1999 John Aycock
|
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
|
||||||
# Copyright (c) 2015 by Rocky Bernstein
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys, types
|
|
||||||
from struct import unpack
|
|
||||||
|
|
||||||
from uncompyle6.magics import PYTHON_MAGIC_INT
|
|
||||||
from uncompyle6.code import Code3
|
|
||||||
|
|
||||||
internStrings = []
|
|
||||||
internObjects = []
|
|
||||||
|
|
||||||
PYTHON3 = (sys.version_info >= (3, 0))
|
|
||||||
|
|
||||||
if PYTHON3:
|
|
||||||
def long(n): return n
|
|
||||||
|
|
||||||
def compat_str(s):
|
|
||||||
return s.decode('utf-8', errors='ignore') if PYTHON3 else str(s)
|
|
||||||
|
|
||||||
def load_code(fp, magic_int, code_objects={}):
|
|
||||||
"""
|
|
||||||
marshal.load() written in Python. When the Python bytecode magic loaded is the
|
|
||||||
same magic for the running Python interpreter, we can simply use the
|
|
||||||
Python-supplied mashal.load().
|
|
||||||
|
|
||||||
However we need to use this when versions are different since the internal
|
|
||||||
code structures are different. Sigh.
|
|
||||||
"""
|
|
||||||
global internStrings, internObjects
|
|
||||||
internStrings = []
|
|
||||||
internObjects = []
|
|
||||||
seek_pos = fp.tell()
|
|
||||||
# Do a sanity check. Is this a code type?
|
|
||||||
b = ord(fp.read(1))
|
|
||||||
|
|
||||||
if (b & 0x80):
|
|
||||||
b = b & 0x7f
|
|
||||||
|
|
||||||
c = chr(b)
|
|
||||||
if c != 'c':
|
|
||||||
raise TypeError("File %s doesn't smell like Python bytecode" % fp.name)
|
|
||||||
|
|
||||||
fp.seek(seek_pos)
|
|
||||||
return load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
|
|
||||||
def load_code_type(fp, magic_int, bytes_for_s=False, code_objects={}):
|
|
||||||
# Python [1.3 .. 2.3)
|
|
||||||
# FIXME: find out what magics were for 1.3
|
|
||||||
v13_to_23 = magic_int in (20121, 50428, 50823, 60202, 60717)
|
|
||||||
|
|
||||||
# Python [1.5 .. 2.3)
|
|
||||||
v15_to_23 = magic_int in (20121, 50428, 50823, 60202, 60717)
|
|
||||||
|
|
||||||
if v13_to_23:
|
|
||||||
co_argcount = unpack('h', fp.read(2))[0]
|
|
||||||
else:
|
|
||||||
co_argcount = unpack('i', fp.read(4))[0]
|
|
||||||
|
|
||||||
if 3020 < magic_int < 20121:
|
|
||||||
kwonlyargcount = unpack('i', fp.read(4))[0]
|
|
||||||
else:
|
|
||||||
kwonlyargcount = 0
|
|
||||||
|
|
||||||
if v13_to_23:
|
|
||||||
co_nlocals = unpack('h', fp.read(2))[0]
|
|
||||||
else:
|
|
||||||
co_nlocals = unpack('i', fp.read(4))[0]
|
|
||||||
|
|
||||||
if v15_to_23:
|
|
||||||
co_stacksize = unpack('h', fp.read(2))[0]
|
|
||||||
else:
|
|
||||||
co_stacksize = unpack('i', fp.read(4))[0]
|
|
||||||
|
|
||||||
if v13_to_23:
|
|
||||||
co_flags = unpack('h', fp.read(2))[0]
|
|
||||||
else:
|
|
||||||
co_flags = unpack('i', fp.read(4))[0]
|
|
||||||
|
|
||||||
co_code = load_code_internal(fp, magic_int, bytes_for_s=True,
|
|
||||||
code_objects=code_objects)
|
|
||||||
|
|
||||||
co_consts = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_names = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_varnames = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_freevars = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_cellvars = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_filename = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
co_name = load_code_internal(fp, magic_int)
|
|
||||||
co_firstlineno = unpack('i', fp.read(4))[0]
|
|
||||||
co_lnotab = load_code_internal(fp, magic_int, code_objects=code_objects)
|
|
||||||
|
|
||||||
# The Python3 code object is different than Python2's which
|
|
||||||
# we are reading if we get here.
|
|
||||||
# Also various parameters which were strings are now
|
|
||||||
# bytes (which is probably more logical).
|
|
||||||
if PYTHON3:
|
|
||||||
Code = types.CodeType
|
|
||||||
if PYTHON_MAGIC_INT > 3020:
|
|
||||||
# In later Python3 magic_ints, there is a
|
|
||||||
# kwonlyargcount parameter which we set to 0.
|
|
||||||
code = Code(co_argcount, kwonlyargcount, co_nlocals, co_stacksize, co_flags,
|
|
||||||
co_code, co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, bytes(co_lnotab, encoding='utf-8'),
|
|
||||||
co_freevars, co_cellvars)
|
|
||||||
else:
|
|
||||||
code = Code(co_argcount, kwonlyargcount, co_nlocals, co_stacksize, co_flags,
|
|
||||||
co_code, co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, bytes(co_lnotab, encoding='utf-8'),
|
|
||||||
co_freevars, co_cellvars)
|
|
||||||
else:
|
|
||||||
if (3000 <= magic_int < 20121):
|
|
||||||
# Python 3 encodes some fields as Unicode while Python2
|
|
||||||
# requires the corresponding field to have string values
|
|
||||||
co_consts = tuple([str(s) if isinstance(s, unicode) else s for s in co_consts])
|
|
||||||
co_names = tuple([str(s) if isinstance(s, unicode) else s for s in co_names])
|
|
||||||
co_varnames = tuple([str(s) if isinstance(s, unicode) else s for s in co_varnames])
|
|
||||||
co_filename = str(co_filename)
|
|
||||||
co_name = str(co_name)
|
|
||||||
if 3020 < magic_int <= 20121:
|
|
||||||
code = Code3(co_argcount, kwonlyargcount,
|
|
||||||
co_nlocals, co_stacksize, co_flags, co_code,
|
|
||||||
co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, co_lnotab, co_freevars, co_cellvars)
|
|
||||||
else:
|
|
||||||
Code = types.CodeType
|
|
||||||
code = Code(co_argcount, co_nlocals, co_stacksize, co_flags, co_code,
|
|
||||||
co_consts, co_names, co_varnames, co_filename, co_name,
|
|
||||||
co_firstlineno, co_lnotab, co_freevars, co_cellvars)
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
code_objects[str(code)] = code
|
|
||||||
return code
|
|
||||||
|
|
||||||
def load_code_internal(fp, magic_int, bytes_for_s=False,
|
|
||||||
code_objects={}, marshalType=None):
|
|
||||||
global internStrings, internObjects
|
|
||||||
|
|
||||||
if marshalType is None:
|
|
||||||
b1 = ord(fp.read(1))
|
|
||||||
if b1 & 0x80:
|
|
||||||
b1 = b1 &0x7f
|
|
||||||
code = load_code_internal(fp, magic_int, bytes_for_s=False,
|
|
||||||
code_objects=code_objects,
|
|
||||||
marshalType=chr(b1))
|
|
||||||
internObjects.append(code)
|
|
||||||
return code
|
|
||||||
marshalType = chr(b1)
|
|
||||||
|
|
||||||
# print(marshalType) # debug
|
|
||||||
if marshalType == '0':
|
|
||||||
# Null
|
|
||||||
return None
|
|
||||||
elif marshalType == 'N':
|
|
||||||
return None
|
|
||||||
elif marshalType == 'F':
|
|
||||||
return False
|
|
||||||
elif marshalType == 'T':
|
|
||||||
return True
|
|
||||||
elif marshalType == 'S':
|
|
||||||
return StopIteration
|
|
||||||
elif marshalType == '.':
|
|
||||||
return Ellipsis
|
|
||||||
elif marshalType == 'i':
|
|
||||||
# int
|
|
||||||
return int(unpack('i', fp.read(4))[0])
|
|
||||||
elif marshalType == 'I':
|
|
||||||
# int64
|
|
||||||
return unpack('q', fp.read(8))[0]
|
|
||||||
elif marshalType == 'f':
|
|
||||||
# float
|
|
||||||
n = fp.read(1)
|
|
||||||
return float(unpack('d', fp.read(n))[0])
|
|
||||||
elif marshalType == 'g':
|
|
||||||
# binary float
|
|
||||||
return float(unpack('d', fp.read(8))[0])
|
|
||||||
elif marshalType == 'x':
|
|
||||||
# complex
|
|
||||||
raise KeyError(marshalType)
|
|
||||||
elif marshalType == 'y':
|
|
||||||
# binary complex
|
|
||||||
real = unpack('d', fp.read(8))[0]
|
|
||||||
imag = unpack('d', fp.read(8))[0]
|
|
||||||
return complex(real, imag)
|
|
||||||
elif marshalType == 'l':
|
|
||||||
# long
|
|
||||||
n = unpack('i', fp.read(4))[0]
|
|
||||||
if n == 0:
|
|
||||||
return long(0)
|
|
||||||
size = abs(n)
|
|
||||||
d = long(0)
|
|
||||||
for j in range(0, size):
|
|
||||||
md = int(unpack('h', fp.read(2))[0])
|
|
||||||
d += md << j*15
|
|
||||||
if n < 0:
|
|
||||||
return long(d*-1)
|
|
||||||
return d
|
|
||||||
elif marshalType == 's':
|
|
||||||
# string
|
|
||||||
# Note: could mean bytes in Python3 processing Python2 bytecode
|
|
||||||
strsize = unpack('i', fp.read(4))[0]
|
|
||||||
s = fp.read(strsize)
|
|
||||||
if not bytes_for_s:
|
|
||||||
s = compat_str(s)
|
|
||||||
return s
|
|
||||||
elif marshalType == 't':
|
|
||||||
# interned
|
|
||||||
strsize = unpack('i', fp.read(4))[0]
|
|
||||||
interned = compat_str(fp.read(strsize))
|
|
||||||
internStrings.append(interned)
|
|
||||||
return interned
|
|
||||||
elif marshalType == 'R':
|
|
||||||
# string reference
|
|
||||||
refnum = unpack('i', fp.read(4))[0]
|
|
||||||
return internStrings[refnum]
|
|
||||||
elif marshalType == 'r':
|
|
||||||
# object reference - new in Python3
|
|
||||||
refnum = unpack('i', fp.read(4))[0]
|
|
||||||
return internObjects[refnum-1]
|
|
||||||
elif marshalType == '(':
|
|
||||||
tuplesize = unpack('i', fp.read(4))[0]
|
|
||||||
ret = tuple()
|
|
||||||
while tuplesize > 0:
|
|
||||||
ret += load_code_internal(fp, magic_int, code_objects=code_objects),
|
|
||||||
tuplesize -= 1
|
|
||||||
return ret
|
|
||||||
elif marshalType == '[':
|
|
||||||
raise KeyError(marshalType)
|
|
||||||
elif marshalType == '{':
|
|
||||||
# dictionary
|
|
||||||
raise KeyError(marshalType)
|
|
||||||
elif marshalType == 'c':
|
|
||||||
return load_code_type(fp, magic_int, bytes_for_s=False,
|
|
||||||
code_objects=code_objects)
|
|
||||||
elif marshalType == 'C':
|
|
||||||
# code type used in Python 1.0 - 1.2
|
|
||||||
raise KeyError("C code is Python 1.0 - 1.2; can't handle yet")
|
|
||||||
elif marshalType == 'u':
|
|
||||||
strsize = unpack('i', fp.read(4))[0]
|
|
||||||
unicodestring = fp.read(strsize)
|
|
||||||
return unicodestring.decode('utf-8')
|
|
||||||
elif marshalType == '?':
|
|
||||||
# unknown
|
|
||||||
raise KeyError(marshalType)
|
|
||||||
elif marshalType in ['<', '>']:
|
|
||||||
# set and frozenset
|
|
||||||
setsize = unpack('i', fp.read(4))[0]
|
|
||||||
ret = tuple()
|
|
||||||
while setsize > 0:
|
|
||||||
ret += load_code_internal(fp, magic_int, code_objects=code_objects),
|
|
||||||
setsize -= 1
|
|
||||||
if marshalType == '>':
|
|
||||||
return frozenset(ret)
|
|
||||||
else:
|
|
||||||
return set(ret)
|
|
||||||
elif marshalType == 'a':
|
|
||||||
# ascii
|
|
||||||
# FIXME check
|
|
||||||
strsize = unpack('i', fp.read(4))[0]
|
|
||||||
s = fp.read(strsize)
|
|
||||||
s = compat_str(s)
|
|
||||||
return s
|
|
||||||
elif marshalType == 'A':
|
|
||||||
# ascii interned - since Python3
|
|
||||||
# FIXME: check
|
|
||||||
strsize = unpack('i', fp.read(4))[0]
|
|
||||||
interned = compat_str(fp.read(strsize))
|
|
||||||
internStrings.append(interned)
|
|
||||||
return interned
|
|
||||||
elif marshalType == ')':
|
|
||||||
# small tuple - since Python3
|
|
||||||
tuplesize = unpack('B', fp.read(1))[0]
|
|
||||||
ret = tuple()
|
|
||||||
while tuplesize > 0:
|
|
||||||
ret += load_code_internal(fp, magic_int, code_objects=code_objects),
|
|
||||||
tuplesize -= 1
|
|
||||||
return ret
|
|
||||||
elif marshalType == 'z':
|
|
||||||
# short ascii - since Python3
|
|
||||||
strsize = unpack('B', fp.read(1))[0]
|
|
||||||
return compat_str(fp.read(strsize))
|
|
||||||
elif marshalType == 'Z':
|
|
||||||
# short ascii interned - since Python3
|
|
||||||
# FIXME: check
|
|
||||||
strsize = unpack('B', fp.read(1))[0]
|
|
||||||
interned = compat_str(fp.read(strsize))
|
|
||||||
internStrings.append(interned)
|
|
||||||
return interned
|
|
||||||
else:
|
|
||||||
sys.stderr.write("Unknown type %i (hex %x) %c\n" %
|
|
||||||
(ord(marshalType), ord(marshalType), ord(marshalType)))
|
|
||||||
return
|
|
@@ -10,7 +10,7 @@ from __future__ import print_function
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||||
|
|
||||||
class ParserError(Exception):
|
class ParserError(Exception):
|
||||||
|
@@ -316,7 +316,7 @@ def get_scanner(version):
|
|||||||
import uncompyle6.scanners.scanner35 as scan
|
import uncompyle6.scanners.scanner35 as scan
|
||||||
scanner = scan.Scanner35()
|
scanner = scan.Scanner35()
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported Python version %d" % version)
|
raise RuntimeError("Unsupported Python version %s" % version)
|
||||||
return scanner
|
return scanner
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@@ -17,7 +17,7 @@ import dis, inspect
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.opcodes.opcode_27 import * # NOQA
|
from uncompyle6.opcodes.opcode_27 import * # NOQA
|
||||||
import uncompyle6.scanner as scan
|
import uncompyle6.scanner as scan
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ import uncompyle6.scanners.dis3 as dis3
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.scanner import Token
|
from uncompyle6.scanner import Token
|
||||||
from uncompyle6 import PYTHON3
|
from uncompyle6 import PYTHON3
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ from __future__ import print_function
|
|||||||
import re, sys
|
import re, sys
|
||||||
|
|
||||||
from uncompyle6 import PYTHON3
|
from uncompyle6 import PYTHON3
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.semantics import pysource
|
from uncompyle6.semantics import pysource
|
||||||
from uncompyle6.parser import get_python_parser
|
from uncompyle6.parser import get_python_parser
|
||||||
from uncompyle6 import parser
|
from uncompyle6 import parser
|
||||||
|
@@ -70,7 +70,7 @@ from __future__ import print_function
|
|||||||
import sys, re
|
import sys, re
|
||||||
|
|
||||||
from uncompyle6 import PYTHON3
|
from uncompyle6 import PYTHON3
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.parser import get_python_parser
|
from uncompyle6.parser import get_python_parser
|
||||||
from uncompyle6.parsers.astnode import AST
|
from uncompyle6.parsers.astnode import AST
|
||||||
from spark_parser import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
from spark_parser import GenericASTTraversal, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
||||||
|
@@ -13,9 +13,9 @@ import dis, operator
|
|||||||
import uncompyle6
|
import uncompyle6
|
||||||
import uncompyle6.scanner as scanner
|
import uncompyle6.scanner as scanner
|
||||||
from uncompyle6 import PYTHON3
|
from uncompyle6 import PYTHON3
|
||||||
from uncompyle6.code import iscode
|
from xdis.code import iscode
|
||||||
from uncompyle6.magics import PYTHON_MAGIC_INT
|
from xdis.magics import PYTHON_MAGIC_INT
|
||||||
from uncompyle6.load import load_file, load_module
|
from xdis.load import load_file, load_module
|
||||||
|
|
||||||
# FIXME: DRY
|
# FIXME: DRY
|
||||||
if PYTHON3:
|
if PYTHON3:
|
||||||
|
Reference in New Issue
Block a user