You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Patch for while loop + manifest + bug in test_pythonlib.py
This commit is contained in:
22
MANIFEST
Executable file
22
MANIFEST
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
README
|
||||||
|
compile_tests
|
||||||
|
setup.cfg
|
||||||
|
setup.py
|
||||||
|
test/*
|
||||||
|
uncompyle2/__init__.py
|
||||||
|
uncompyle2/disas.py
|
||||||
|
uncompyle2/magics.py
|
||||||
|
uncompyle2/parser.py
|
||||||
|
uncompyle2/scanner.py
|
||||||
|
uncompyle2/scanner25.py
|
||||||
|
uncompyle2/scanner26.py
|
||||||
|
uncompyle2/scanner27.py
|
||||||
|
uncompyle2/spark.py
|
||||||
|
uncompyle2/verify.py
|
||||||
|
uncompyle2/walker.py
|
||||||
|
uncompyle2/opcode/__init__.py
|
||||||
|
uncompyle2/opcode/opcode_23.py
|
||||||
|
uncompyle2/opcode/opcode_24.py
|
||||||
|
uncompyle2/opcode/opcode_25.py
|
||||||
|
uncompyle2/opcode/opcode_26.py
|
||||||
|
uncompyle2/opcode/opcode_27.py
|
11
MANIFEST.in
11
MANIFEST.in
@@ -1,11 +0,0 @@
|
|||||||
include MANIFEST
|
|
||||||
include MANIFEST.in
|
|
||||||
include README
|
|
||||||
include ANNOUNCE CHANGES TODO
|
|
||||||
include uncompyle
|
|
||||||
include test_pythonlib
|
|
||||||
include test_one
|
|
||||||
include compile_tests
|
|
||||||
graft test
|
|
||||||
graft scripts
|
|
||||||
global-exclude *~ .*~
|
|
85
README
85
README
@@ -1,59 +1,49 @@
|
|||||||
|
uncompyle2
|
||||||
|
==========
|
||||||
|
|
||||||
uncompyle2
|
A Python 2.5, 2.6, 2.7 byte-code decompiler, written in Python 2.7
|
||||||
A Python 2.5, 2.6, 2.7 byte-code decompiler, written in Python 2.7
|
|
||||||
0.13
|
|
||||||
2012-6-5
|
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
'uncompyle2' converts Python byte-code back into equivalent Python
|
'uncompyle2' converts Python byte-code back into equivalent Python
|
||||||
source. It accepts byte-code from Python version 2.5, 2.6 & 2.7. Additionally,
|
source code. It accepts byte-code from Python version 2.5 to 2.7.
|
||||||
it will only run on Python 2.7.
|
Additionally, it will only run on Python 2.7.
|
||||||
|
|
||||||
The generated source is very readable: docstrings, lists, tuples and
|
The generated source is very readable: docstrings, lists, tuples and
|
||||||
hashes get pretty-printed.
|
hashes get pretty-printed.
|
||||||
|
|
||||||
'uncompyle2' may also verify the equivalence of the generated source by
|
|
||||||
by compiling it and comparing both byte-codes.
|
|
||||||
|
|
||||||
'uncompyle2' is based on John Aycock's generic small languages compiler
|
'uncompyle2' is based on John Aycock's generic small languages compiler
|
||||||
'spark' (http://www.csr.uvic.ca/~aycock/python/) and his prior work on
|
'spark' (http://www.csr.uvic.ca/~aycock/python/) and his prior work on
|
||||||
'uncompyle'.
|
'uncompyle'.
|
||||||
|
|
||||||
Additional note (3 July 2004, Ben Burton):
|
### Additional note (3 July 2004, Ben Burton):
|
||||||
|
|
||||||
The original website from which this software was obtained is no longer
|
The original website from which this software was obtained is no longer
|
||||||
available. It has now become a commercial decompilation service, with
|
available. It has now become a commercial decompilation service, with
|
||||||
no software available for download.
|
no software available for download.
|
||||||
|
|
||||||
Any developers seeking to make alterations or enhancements to this code
|
Any developers seeking to make alterations or enhancements to this code
|
||||||
should therefore consider these debian packages an appropriate starting
|
should therefore consider these debian packages an appropriate starting
|
||||||
point.
|
point.
|
||||||
|
|
||||||
Additional note (5 June 2012):
|
### Additional note (5 June 2012):
|
||||||
|
|
||||||
The decompilation of python bytecode 2.5 & 2.6 is based on the work of
|
The decompilation of python bytecode 2.5 & 2.6 is based on the work of
|
||||||
Eloi Vanderbeken. bytecode is translated to a pseudo 2.7 python bytecode
|
Eloi Vanderbeken. bytecode is translated to a pseudo 2.7 python bytecode
|
||||||
and then decompiled.
|
and then decompiled.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* decompiles Python byte-code into equivalent Python source
|
- decompiles Python byte-code into equivalent Python source
|
||||||
|
- decompiles byte-code from Python version 2.5, 2.6, 2.7
|
||||||
|
- pretty-prints docstrings, hashes, lists and tuples
|
||||||
|
- reads directly from .pyc/.pyo files, bulk-decompile whole directories
|
||||||
|
- output may be written to file, a directory or to stdout
|
||||||
|
- option for including byte-code disassembly into generated source
|
||||||
|
|
||||||
* decompiles byte-code from Python version 2.5, 2.6, 2.7
|
For a list of changes please refer to the 'CHANGES' file.
|
||||||
|
|
||||||
* pretty-prints docstrings, hashes, lists and tuples
|
|
||||||
|
|
||||||
* reads directly from .pyc/.pyo files, bulk-decompile whole
|
|
||||||
directories
|
|
||||||
|
|
||||||
* output may be written to file, a directory or to stdout
|
|
||||||
|
|
||||||
* option for including byte-code disassembly into generated source
|
|
||||||
|
|
||||||
For a list of changes please refer to the 'CHANGES' file.
|
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
@@ -70,27 +60,26 @@ the source distribution.
|
|||||||
|
|
||||||
Creating RPMS:
|
Creating RPMS:
|
||||||
|
|
||||||
python setup.py bdist_rpm
|
python setup.py bdist_rpm
|
||||||
|
|
||||||
If you need to force the python interpreter to eg. pyton2:
|
If you need to force the python interpreter to eg. pyton2:
|
||||||
python2 setup.py bdist_rpm --python=python2
|
|
||||||
|
|
||||||
|
python2 setup.py bdist_rpm --python=python2
|
||||||
|
|
||||||
Installation from the source distribution:
|
### Installation from the source distribution:
|
||||||
|
|
||||||
python setup.py install
|
python setup.py install
|
||||||
|
|
||||||
To install to a user's home-dir:
|
To install to a user's home-dir:
|
||||||
python setup.py install --home=<dir>
|
|
||||||
|
|
||||||
To install to another prefix (eg. /usr/local)
|
python setup.py install --home=<dir>
|
||||||
python setup.py install --prefix=/usr/local
|
|
||||||
|
|
||||||
If you need to force the python interpreter to eg. pyton2:
|
To install to another prefix (eg. /usr/local)
|
||||||
python2 setup.py install
|
|
||||||
|
|
||||||
For more information on 'Installing Python Modules' please refer to
|
python setup.py install --prefix=/usr/local
|
||||||
http://www.python.org/doc/current/inst/inst.html
|
|
||||||
|
For more information on 'Installing Python Modules' please refer to
|
||||||
|
http://www.python.org/doc/current/inst/inst.html
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
@@ -103,4 +92,6 @@ uncompyle2 --help prints long usage
|
|||||||
Known Bugs/Restrictions
|
Known Bugs/Restrictions
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
I have some known bug in the 2.5 & 2.6 decompilation version but this will be fixed in a few.
|
No support for python 3.2
|
||||||
|
|
||||||
|
It currently reconstructs most of Python code but probably needs to be tested more thoroughly. All feedback welcome
|
||||||
|
@@ -13,10 +13,10 @@ Usage-Examples:
|
|||||||
Adding own test-trees:
|
Adding own test-trees:
|
||||||
|
|
||||||
Step 1) Edit this file and add a new entry to 'test_options', eg.
|
Step 1) Edit this file and add a new entry to 'test_options', eg.
|
||||||
test_options['mylib'] = ('/usr/lib/mylib', PYOC, 'mylib')
|
test_options['mylib'] = ('/usr/lib/mylib', PYOC, 'mylib')
|
||||||
Step 2: Run the test:
|
Step 2: Run the test:
|
||||||
test_pythonlib --mylib # decompile 'mylib'
|
test_pythonlib --mylib # decompile 'mylib'
|
||||||
test_pythonlib --mylib --verify # decompile verify 'mylib'
|
test_pythonlib --mylib --verify # decompile verify 'mylib'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from uncompyle2 import main, verify
|
from uncompyle2 import main, verify
|
||||||
@@ -105,7 +105,7 @@ if __name__ == '__main__':
|
|||||||
test_dirs.append(test_options[val])
|
test_dirs.append(test_options[val])
|
||||||
else:
|
else:
|
||||||
help()
|
help()
|
||||||
|
|
||||||
for src_dir, pattern, target_dir in test_dirs:
|
for src_dir, pattern, target_dir in test_dirs:
|
||||||
for libpath in lib_prefix:
|
for libpath in lib_prefix:
|
||||||
testpath = os.path.join(libpath, src_dir)
|
testpath = os.path.join(libpath, src_dir)
|
||||||
@@ -114,6 +114,7 @@ if __name__ == '__main__':
|
|||||||
if os.path.exists(testlibfile) or os.path.exists(testfile):
|
if os.path.exists(testlibfile) or os.path.exists(testfile):
|
||||||
src_dir = testpath
|
src_dir = testpath
|
||||||
checked_dirs.append([src_dir, pattern, target_dir])
|
checked_dirs.append([src_dir, pattern, target_dir])
|
||||||
|
break
|
||||||
|
|
||||||
for src_dir, pattern, target_dir in checked_dirs:
|
for src_dir, pattern, target_dir in checked_dirs:
|
||||||
target_dir = os.path.join(target_base, target_dir)
|
target_dir = os.path.join(target_base, target_dir)
|
||||||
|
@@ -139,7 +139,8 @@ def disassemble_string(code, lasti=-1, varnames=None, names=None,
|
|||||||
print '(' + cmp_op[oparg] + ')',
|
print '(' + cmp_op[oparg] + ')',
|
||||||
print
|
print
|
||||||
|
|
||||||
disco = disassemble # XXX For backwards compatibility
|
disco = disassemble
|
||||||
|
# XXX For backwards compatibility
|
||||||
|
|
||||||
def findlabels(code):
|
def findlabels(code):
|
||||||
"""Detect all offsets in a byte code which are jump targets.
|
"""Detect all offsets in a byte code which are jump targets.
|
||||||
|
@@ -505,7 +505,7 @@ class Scanner25(scan.Scanner):
|
|||||||
last_stmt = s
|
last_stmt = s
|
||||||
slist += [s] * (s-i)
|
slist += [s] * (s-i)
|
||||||
i = s
|
i = s
|
||||||
slist += [len(code)] * (len(code)-len(slist))
|
slist += [end] * (end-len(slist))
|
||||||
|
|
||||||
def next_except_jump(self, start):
|
def next_except_jump(self, start):
|
||||||
'''
|
'''
|
||||||
@@ -610,7 +610,7 @@ class Scanner25(scan.Scanner):
|
|||||||
test = self.prev[next_line_byte]
|
test = self.prev[next_line_byte]
|
||||||
if test == pos:
|
if test == pos:
|
||||||
loop_type = 'while 1'
|
loop_type = 'while 1'
|
||||||
else:
|
elif self.code[test] in hasjabs+hasjrel:
|
||||||
self.ignore_if.add(test)
|
self.ignore_if.add(test)
|
||||||
test_target = self.get_target(test)
|
test_target = self.get_target(test)
|
||||||
if test_target > (jump_back+3):
|
if test_target > (jump_back+3):
|
||||||
|
@@ -502,7 +502,7 @@ class Scanner26(scan.Scanner):
|
|||||||
last_stmt = s
|
last_stmt = s
|
||||||
slist += [s] * (s-i)
|
slist += [s] * (s-i)
|
||||||
i = s
|
i = s
|
||||||
slist += [len(code)] * (len(code)-len(slist))
|
slist += [end] * (end-len(slist))
|
||||||
|
|
||||||
def next_except_jump(self, start):
|
def next_except_jump(self, start):
|
||||||
'''
|
'''
|
||||||
@@ -607,7 +607,7 @@ class Scanner26(scan.Scanner):
|
|||||||
test = self.prev[next_line_byte]
|
test = self.prev[next_line_byte]
|
||||||
if test == pos:
|
if test == pos:
|
||||||
loop_type = 'while 1'
|
loop_type = 'while 1'
|
||||||
else:
|
elif self.code[test] in hasjabs+hasjrel:
|
||||||
self.ignore_if.add(test)
|
self.ignore_if.add(test)
|
||||||
test_target = self.get_target(test)
|
test_target = self.get_target(test)
|
||||||
if test_target > (jump_back+3):
|
if test_target > (jump_back+3):
|
||||||
|
@@ -18,11 +18,10 @@ import scanner as scan
|
|||||||
class Scanner27(scan.Scanner):
|
class Scanner27(scan.Scanner):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.Token = scan.Scanner.__init__(self, 2.6)
|
self.Token = scan.Scanner.__init__(self, 2.6)
|
||||||
|
|
||||||
def disassemble(self, co, classname=None):
|
def disassemble(self, co, classname=None):
|
||||||
'''
|
'''
|
||||||
Disassemble a code object, returning a list of 'Token'.
|
Disassemble a code object, returning a list of 'Token'.
|
||||||
|
|
||||||
The main part of this procedure is modelled after
|
The main part of this procedure is modelled after
|
||||||
dis.disassemble().
|
dis.disassemble().
|
||||||
'''
|
'''
|
||||||
@@ -98,14 +97,13 @@ class Scanner27(scan.Scanner):
|
|||||||
|
|
||||||
extended_arg = 0
|
extended_arg = 0
|
||||||
for offset in self.op_range(0, n):
|
for offset in self.op_range(0, n):
|
||||||
|
|
||||||
if offset in cf:
|
if offset in cf:
|
||||||
k = 0
|
k = 0
|
||||||
for j in cf[offset]:
|
for j in cf[offset]:
|
||||||
rv.append(Token('COME_FROM', None, repr(j),
|
rv.append(Token('COME_FROM', None, repr(j),
|
||||||
offset="%s_%d" % (offset, k) ))
|
offset="%s_%d" % (offset, k)))
|
||||||
k += 1
|
k += 1
|
||||||
|
|
||||||
op = code[offset]
|
op = code[offset]
|
||||||
op_name = opname[op]
|
op_name = opname[op]
|
||||||
oparg = None; pattr = None
|
oparg = None; pattr = None
|
||||||
@@ -274,7 +272,7 @@ class Scanner27(scan.Scanner):
|
|||||||
last_stmt = s
|
last_stmt = s
|
||||||
slist += [s] * (s-i)
|
slist += [s] * (s-i)
|
||||||
i = s
|
i = s
|
||||||
slist += [len(code)] * (len(code)-len(slist))
|
slist += [end] * (end-len(slist))
|
||||||
|
|
||||||
def remove_mid_line_ifs(self, ifs):
|
def remove_mid_line_ifs(self, ifs):
|
||||||
filtered = []
|
filtered = []
|
||||||
@@ -341,13 +339,13 @@ class Scanner27(scan.Scanner):
|
|||||||
start = pos+3
|
start = pos+3
|
||||||
target = self.get_target(pos, op)
|
target = self.get_target(pos, op)
|
||||||
end = self.restrict_to_parent(target, parent)
|
end = self.restrict_to_parent(target, parent)
|
||||||
|
|
||||||
if target != end:
|
if target != end:
|
||||||
self.fixed_jumps[pos] = end
|
self.fixed_jumps[pos] = end
|
||||||
|
|
||||||
(line_no, next_line_byte) = self.lines[pos]
|
(line_no, next_line_byte) = self.lines[pos]
|
||||||
jump_back = self.last_instr(start, end, JA,
|
jump_back = self.last_instr(start, end, JA,
|
||||||
next_line_byte, False)
|
next_line_byte, False)
|
||||||
|
|
||||||
if jump_back and jump_back != self.prev[end] and code[jump_back+3] in (JA, JF):
|
if jump_back and jump_back != self.prev[end] and code[jump_back+3] in (JA, JF):
|
||||||
if code[self.prev[end]] == RETURN_VALUE or \
|
if code[self.prev[end]] == RETURN_VALUE or \
|
||||||
(code[self.prev[end]] == POP_BLOCK and code[self.prev[self.prev[end]]] == RETURN_VALUE):
|
(code[self.prev[end]] == POP_BLOCK and code[self.prev[self.prev[end]]] == RETURN_VALUE):
|
||||||
@@ -365,8 +363,7 @@ class Scanner27(scan.Scanner):
|
|||||||
end = jump_back + 3
|
end = jump_back + 3
|
||||||
else:
|
else:
|
||||||
if self.get_target(jump_back) >= next_line_byte:
|
if self.get_target(jump_back) >= next_line_byte:
|
||||||
jump_back = self.last_instr(start, end, JA,
|
jump_back = self.last_instr(start, end, JA, start, False)
|
||||||
start, False)
|
|
||||||
if end > jump_back+4 and code[end] in (JF, JA):
|
if end > jump_back+4 and code[end] in (JF, JA):
|
||||||
if code[jump_back+4] in (JA, JF):
|
if code[jump_back+4] in (JA, JF):
|
||||||
if self.get_target(jump_back+4) == self.get_target(end):
|
if self.get_target(jump_back+4) == self.get_target(end):
|
||||||
@@ -375,9 +372,8 @@ class Scanner27(scan.Scanner):
|
|||||||
elif target < pos:
|
elif target < pos:
|
||||||
self.fixed_jumps[pos] = jump_back+4
|
self.fixed_jumps[pos] = jump_back+4
|
||||||
end = jump_back+4
|
end = jump_back+4
|
||||||
|
|
||||||
target = self.get_target(jump_back, JA)
|
target = self.get_target(jump_back, JA)
|
||||||
|
|
||||||
if code[target] in (FOR_ITER, GET_ITER):
|
if code[target] in (FOR_ITER, GET_ITER):
|
||||||
loop_type = 'for'
|
loop_type = 'for'
|
||||||
else:
|
else:
|
||||||
@@ -385,7 +381,7 @@ class Scanner27(scan.Scanner):
|
|||||||
test = self.prev[next_line_byte]
|
test = self.prev[next_line_byte]
|
||||||
if test == pos:
|
if test == pos:
|
||||||
loop_type = 'while 1'
|
loop_type = 'while 1'
|
||||||
else:
|
elif self.code[test] in hasjabs+hasjrel:
|
||||||
self.ignore_if.add(test)
|
self.ignore_if.add(test)
|
||||||
test_target = self.get_target(test)
|
test_target = self.get_target(test)
|
||||||
if test_target > (jump_back+3):
|
if test_target > (jump_back+3):
|
||||||
@@ -455,7 +451,7 @@ class Scanner27(scan.Scanner):
|
|||||||
#does this jump to right after another cond jump?
|
#does this jump to right after another cond jump?
|
||||||
# if so, it's part of a larger conditional
|
# if so, it's part of a larger conditional
|
||||||
if (code[pre[target]] in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP,
|
if (code[pre[target]] in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP,
|
||||||
PJIF, PJIT)) and (target > pos):
|
PJIF, PJIT)) and (target > pos):
|
||||||
self.fixed_jumps[pos] = pre[target]
|
self.fixed_jumps[pos] = pre[target]
|
||||||
self.structs.append({'type': 'and/or',
|
self.structs.append({'type': 'and/or',
|
||||||
'start': start,
|
'start': start,
|
||||||
|
Reference in New Issue
Block a user