You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +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
|
||||
0.13
|
||||
2012-6-5
|
||||
A Python 2.5, 2.6, 2.7 byte-code decompiler, written in Python 2.7
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
'uncompyle2' converts Python byte-code back into equivalent Python
|
||||
source. It accepts byte-code from Python version 2.5, 2.6 & 2.7. Additionally,
|
||||
it will only run on Python 2.7.
|
||||
source code. It accepts byte-code from Python version 2.5 to 2.7.
|
||||
Additionally, it will only run on Python 2.7.
|
||||
|
||||
The generated source is very readable: docstrings, lists, tuples and
|
||||
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
|
||||
'spark' (http://www.csr.uvic.ca/~aycock/python/) and his prior work on
|
||||
'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
|
||||
available. It has now become a commercial decompilation service, with
|
||||
no software available for download.
|
||||
The original website from which this software was obtained is no longer
|
||||
available. It has now become a commercial decompilation service, with
|
||||
no software available for download.
|
||||
|
||||
Any developers seeking to make alterations or enhancements to this code
|
||||
should therefore consider these debian packages an appropriate starting
|
||||
point.
|
||||
Any developers seeking to make alterations or enhancements to this code
|
||||
should therefore consider these debian packages an appropriate starting
|
||||
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
|
||||
Eloi Vanderbeken. bytecode is translated to a pseudo 2.7 python bytecode
|
||||
and then decompiled.
|
||||
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
|
||||
and then decompiled.
|
||||
|
||||
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
|
||||
|
||||
* 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.
|
||||
For a list of changes please refer to the 'CHANGES' file.
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -70,27 +60,26 @@ the source distribution.
|
||||
|
||||
Creating RPMS:
|
||||
|
||||
python setup.py bdist_rpm
|
||||
python setup.py bdist_rpm
|
||||
|
||||
If you need to force the python interpreter to eg. pyton2:
|
||||
python2 setup.py bdist_rpm --python=python2
|
||||
If you need to force the python interpreter to eg. pyton2:
|
||||
|
||||
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:
|
||||
python setup.py install --home=<dir>
|
||||
To install to a user's home-dir:
|
||||
|
||||
To install to another prefix (eg. /usr/local)
|
||||
python setup.py install --prefix=/usr/local
|
||||
python setup.py install --home=<dir>
|
||||
|
||||
If you need to force the python interpreter to eg. pyton2:
|
||||
python2 setup.py install
|
||||
To install to another prefix (eg. /usr/local)
|
||||
|
||||
For more information on 'Installing Python Modules' please refer to
|
||||
http://www.python.org/doc/current/inst/inst.html
|
||||
python setup.py install --prefix=/usr/local
|
||||
|
||||
For more information on 'Installing Python Modules' please refer to
|
||||
http://www.python.org/doc/current/inst/inst.html
|
||||
|
||||
|
||||
Usage
|
||||
@@ -103,4 +92,6 @@ uncompyle2 --help prints long usage
|
||||
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:
|
||||
|
||||
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:
|
||||
test_pythonlib --mylib # decompile 'mylib'
|
||||
test_pythonlib --mylib --verify # decompile verify 'mylib'
|
||||
test_pythonlib --mylib # decompile 'mylib'
|
||||
test_pythonlib --mylib --verify # decompile verify 'mylib'
|
||||
'''
|
||||
|
||||
from uncompyle2 import main, verify
|
||||
@@ -105,7 +105,7 @@ if __name__ == '__main__':
|
||||
test_dirs.append(test_options[val])
|
||||
else:
|
||||
help()
|
||||
|
||||
|
||||
for src_dir, pattern, target_dir in test_dirs:
|
||||
for libpath in lib_prefix:
|
||||
testpath = os.path.join(libpath, src_dir)
|
||||
@@ -114,6 +114,7 @@ if __name__ == '__main__':
|
||||
if os.path.exists(testlibfile) or os.path.exists(testfile):
|
||||
src_dir = testpath
|
||||
checked_dirs.append([src_dir, pattern, target_dir])
|
||||
break
|
||||
|
||||
for src_dir, pattern, target_dir in checked_dirs:
|
||||
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
|
||||
|
||||
disco = disassemble # XXX For backwards compatibility
|
||||
disco = disassemble
|
||||
# XXX For backwards compatibility
|
||||
|
||||
def findlabels(code):
|
||||
"""Detect all offsets in a byte code which are jump targets.
|
||||
|
@@ -505,7 +505,7 @@ class Scanner25(scan.Scanner):
|
||||
last_stmt = s
|
||||
slist += [s] * (s-i)
|
||||
i = s
|
||||
slist += [len(code)] * (len(code)-len(slist))
|
||||
slist += [end] * (end-len(slist))
|
||||
|
||||
def next_except_jump(self, start):
|
||||
'''
|
||||
@@ -610,7 +610,7 @@ class Scanner25(scan.Scanner):
|
||||
test = self.prev[next_line_byte]
|
||||
if test == pos:
|
||||
loop_type = 'while 1'
|
||||
else:
|
||||
elif self.code[test] in hasjabs+hasjrel:
|
||||
self.ignore_if.add(test)
|
||||
test_target = self.get_target(test)
|
||||
if test_target > (jump_back+3):
|
||||
|
@@ -502,7 +502,7 @@ class Scanner26(scan.Scanner):
|
||||
last_stmt = s
|
||||
slist += [s] * (s-i)
|
||||
i = s
|
||||
slist += [len(code)] * (len(code)-len(slist))
|
||||
slist += [end] * (end-len(slist))
|
||||
|
||||
def next_except_jump(self, start):
|
||||
'''
|
||||
@@ -607,7 +607,7 @@ class Scanner26(scan.Scanner):
|
||||
test = self.prev[next_line_byte]
|
||||
if test == pos:
|
||||
loop_type = 'while 1'
|
||||
else:
|
||||
elif self.code[test] in hasjabs+hasjrel:
|
||||
self.ignore_if.add(test)
|
||||
test_target = self.get_target(test)
|
||||
if test_target > (jump_back+3):
|
||||
|
@@ -18,11 +18,10 @@ import scanner as scan
|
||||
class Scanner27(scan.Scanner):
|
||||
def __init__(self):
|
||||
self.Token = scan.Scanner.__init__(self, 2.6)
|
||||
|
||||
|
||||
def disassemble(self, co, classname=None):
|
||||
'''
|
||||
Disassemble a code object, returning a list of 'Token'.
|
||||
|
||||
The main part of this procedure is modelled after
|
||||
dis.disassemble().
|
||||
'''
|
||||
@@ -98,14 +97,13 @@ class Scanner27(scan.Scanner):
|
||||
|
||||
extended_arg = 0
|
||||
for offset in self.op_range(0, n):
|
||||
|
||||
if offset in cf:
|
||||
k = 0
|
||||
for j in cf[offset]:
|
||||
rv.append(Token('COME_FROM', None, repr(j),
|
||||
offset="%s_%d" % (offset, k) ))
|
||||
offset="%s_%d" % (offset, k)))
|
||||
k += 1
|
||||
|
||||
|
||||
op = code[offset]
|
||||
op_name = opname[op]
|
||||
oparg = None; pattr = None
|
||||
@@ -274,7 +272,7 @@ class Scanner27(scan.Scanner):
|
||||
last_stmt = s
|
||||
slist += [s] * (s-i)
|
||||
i = s
|
||||
slist += [len(code)] * (len(code)-len(slist))
|
||||
slist += [end] * (end-len(slist))
|
||||
|
||||
def remove_mid_line_ifs(self, ifs):
|
||||
filtered = []
|
||||
@@ -341,13 +339,13 @@ class Scanner27(scan.Scanner):
|
||||
start = pos+3
|
||||
target = self.get_target(pos, op)
|
||||
end = self.restrict_to_parent(target, parent)
|
||||
|
||||
|
||||
if target != end:
|
||||
self.fixed_jumps[pos] = end
|
||||
|
||||
(line_no, next_line_byte) = self.lines[pos]
|
||||
jump_back = self.last_instr(start, end, JA,
|
||||
next_line_byte, False)
|
||||
|
||||
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 \
|
||||
(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
|
||||
else:
|
||||
if self.get_target(jump_back) >= next_line_byte:
|
||||
jump_back = self.last_instr(start, end, JA,
|
||||
start, False)
|
||||
jump_back = self.last_instr(start, end, JA, start, False)
|
||||
if end > jump_back+4 and code[end] in (JF, JA):
|
||||
if code[jump_back+4] in (JA, JF):
|
||||
if self.get_target(jump_back+4) == self.get_target(end):
|
||||
@@ -375,9 +372,8 @@ class Scanner27(scan.Scanner):
|
||||
elif target < pos:
|
||||
self.fixed_jumps[pos] = jump_back+4
|
||||
end = jump_back+4
|
||||
|
||||
target = self.get_target(jump_back, JA)
|
||||
|
||||
|
||||
if code[target] in (FOR_ITER, GET_ITER):
|
||||
loop_type = 'for'
|
||||
else:
|
||||
@@ -385,7 +381,7 @@ class Scanner27(scan.Scanner):
|
||||
test = self.prev[next_line_byte]
|
||||
if test == pos:
|
||||
loop_type = 'while 1'
|
||||
else:
|
||||
elif self.code[test] in hasjabs+hasjrel:
|
||||
self.ignore_if.add(test)
|
||||
test_target = self.get_target(test)
|
||||
if test_target > (jump_back+3):
|
||||
@@ -455,7 +451,7 @@ class Scanner27(scan.Scanner):
|
||||
#does this jump to right after another cond jump?
|
||||
# if so, it's part of a larger conditional
|
||||
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.structs.append({'type': 'and/or',
|
||||
'start': start,
|
||||
|
Reference in New Issue
Block a user