mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2024-11-23 21:20:06 +00:00
marshal disassembly improvement
This commit is contained in:
parent
56aed3e560
commit
baaa7f81d0
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
import sys, types, os
|
import sys, types, os
|
||||||
import walker, verify, magics
|
import walker, verify, magics
|
||||||
|
import disas as dis
|
||||||
|
import marshal
|
||||||
|
|
||||||
sys.setrecursionlimit(5000)
|
sys.setrecursionlimit(5000)
|
||||||
__all__ = ['uncompyle_file', 'main']
|
__all__ = ['uncompyle_file', 'main']
|
||||||
@ -65,7 +67,6 @@ def _load_module(filename):
|
|||||||
code_object: code_object from this file
|
code_object: code_object from this file
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import magics, marshal
|
|
||||||
fp = open(filename, 'rb')
|
fp = open(filename, 'rb')
|
||||||
magic = fp.read(4)
|
magic = fp.read(4)
|
||||||
try:
|
try:
|
||||||
@ -76,7 +77,7 @@ def _load_module(filename):
|
|||||||
raise ImportError, "This is a Python %s file! Only Python 2.5 to 2.7 files are supported." % version
|
raise ImportError, "This is a Python %s file! Only Python 2.5 to 2.7 files are supported." % version
|
||||||
#print version
|
#print version
|
||||||
fp.read(4) # timestamp
|
fp.read(4) # timestamp
|
||||||
co = marshal.load(fp)
|
co = marshal.load(fp) #dis.marshalLoad(fp)
|
||||||
fp.close()
|
fp.close()
|
||||||
return version, co
|
return version, co
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ def uncompyle(version, co, out=None, showasm=0, showast=0):
|
|||||||
# store final output stream for case of error
|
# store final output stream for case of error
|
||||||
__real_out = out or sys.stdout
|
__real_out = out or sys.stdout
|
||||||
if co.co_filename:
|
if co.co_filename:
|
||||||
print >>__real_out, '#Embedded file name: %s' % co.co_filename
|
print >>__real_out, '# Embedded file name: %s' % co.co_filename
|
||||||
# diff scanner
|
# diff scanner
|
||||||
if version == 2.7:
|
if version == 2.7:
|
||||||
import scanner27 as scan
|
import scanner27 as scan
|
||||||
@ -101,11 +102,9 @@ def uncompyle(version, co, out=None, showasm=0, showast=0):
|
|||||||
elif version == 2.5:
|
elif version == 2.5:
|
||||||
import scanner25 as scan
|
import scanner25 as scan
|
||||||
scanner = scan.Scanner25()
|
scanner = scan.Scanner25()
|
||||||
|
|
||||||
scanner.setShowAsm(showasm, out)
|
scanner.setShowAsm(showasm, out)
|
||||||
tokens, customize = scanner.disassemble(co)
|
tokens, customize = scanner.disassemble(co)
|
||||||
|
|
||||||
#sys.exit(0)
|
|
||||||
# Build AST from disassembly.
|
# Build AST from disassembly.
|
||||||
walk = walker.Walker(out, scanner, showast=showast)
|
walk = walker.Walker(out, scanner, showast=showast)
|
||||||
try:
|
try:
|
||||||
@ -113,7 +112,6 @@ def uncompyle(version, co, out=None, showasm=0, showast=0):
|
|||||||
except walker.ParserError, e : # parser failed, dump disassembly
|
except walker.ParserError, e : # parser failed, dump disassembly
|
||||||
print >>__real_out, e
|
print >>__real_out, e
|
||||||
raise
|
raise
|
||||||
|
|
||||||
del tokens # save memory
|
del tokens # save memory
|
||||||
|
|
||||||
# convert leading '__doc__ = "..." into doc string
|
# convert leading '__doc__ = "..." into doc string
|
||||||
@ -185,11 +183,11 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
of = outfile
|
of = outfile
|
||||||
tot_files = okay_files = failed_files = verify_failed_files = 0
|
tot_files = okay_files = failed_files = verify_failed_files = 0
|
||||||
|
|
||||||
for code in codes:
|
#for code in codes:
|
||||||
version = sys.version[:3] # "2.5"
|
# version = sys.version[:3] # "2.5"
|
||||||
with open(code, "r") as f:
|
# with open(code, "r") as f:
|
||||||
co = compile(f.read(), "", "exec")
|
# co = compile(f.read(), "", "exec")
|
||||||
uncompyle(sys.version[:3], co, sys.stdout, showasm=showasm, showast=showast)
|
# uncompyle(sys.version[:3], co, sys.stdout, showasm=showasm, showast=showast)
|
||||||
|
|
||||||
for file in files:
|
for file in files:
|
||||||
infile = os.path.join(in_base, file)
|
infile = os.path.join(in_base, file)
|
||||||
@ -223,7 +221,6 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
sys.stderr.write("\n# Can't uncompyle %s\n" % infile)
|
sys.stderr.write("\n# Can't uncompyle %s\n" % infile)
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
#raise
|
|
||||||
else: # uncompyle successfull
|
else: # uncompyle successfull
|
||||||
if outfile:
|
if outfile:
|
||||||
outstream.close()
|
outstream.close()
|
||||||
|
@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
from struct import unpack
|
||||||
|
import marshal, pickle
|
||||||
|
|
||||||
_have_code = (types.MethodType, types.FunctionType, types.CodeType, types.ClassType, type)
|
_have_code = (types.MethodType, types.FunctionType, types.CodeType, types.ClassType, type)
|
||||||
|
internStrings = []
|
||||||
|
|
||||||
def dis(x=None):
|
def dis(x=None):
|
||||||
"""Disassemble classes, methods, functions, or code.
|
"""Disassemble classes, methods, functions, or code.
|
||||||
|
|
||||||
With no argument, disassemble the last traceback.
|
With no argument, disassemble the last traceback.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if x is None:
|
if x is None:
|
||||||
distb()
|
distb()
|
||||||
@ -144,9 +145,7 @@ disco = disassemble
|
|||||||
|
|
||||||
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.
|
||||||
|
|
||||||
Return the list of offsets.
|
Return the list of offsets.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
labels = []
|
labels = []
|
||||||
n = len(code)
|
n = len(code)
|
||||||
@ -170,9 +169,7 @@ def findlabels(code):
|
|||||||
|
|
||||||
def findlinestarts(code):
|
def findlinestarts(code):
|
||||||
"""Find the offsets in a byte code which are start of lines in the source.
|
"""Find the offsets in a byte code which are start of lines in the source.
|
||||||
|
|
||||||
Generate pairs (offset, lineno) as described in Python/compile.c.
|
Generate pairs (offset, lineno) as described in Python/compile.c.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
|
byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
|
||||||
line_increments = [ord(c) for c in code.co_lnotab[1::2]]
|
line_increments = [ord(c) for c in code.co_lnotab[1::2]]
|
||||||
@ -190,6 +187,117 @@ def findlinestarts(code):
|
|||||||
if lineno != lastlineno:
|
if lineno != lastlineno:
|
||||||
yield (addr, lineno)
|
yield (addr, lineno)
|
||||||
|
|
||||||
|
def marshalLoad(fp):
|
||||||
|
global internStrings
|
||||||
|
internStrings = []
|
||||||
|
return load(fp)
|
||||||
|
|
||||||
|
def load(fp):
|
||||||
|
"""
|
||||||
|
Load marshal
|
||||||
|
"""
|
||||||
|
global internStrings
|
||||||
|
|
||||||
|
marshalType = fp.read(1)
|
||||||
|
if marshalType == 'c':
|
||||||
|
Code = types.CodeType
|
||||||
|
|
||||||
|
co_argcount = unpack('l', fp.read(4))[0]
|
||||||
|
co_nlocals = unpack('l', fp.read(4))[0]
|
||||||
|
co_stacksize = unpack('l', fp.read(4))[0]
|
||||||
|
co_flags = unpack('l', fp.read(4))[0]
|
||||||
|
co_code = load(fp)
|
||||||
|
co_consts = load(fp)
|
||||||
|
co_names = load(fp)
|
||||||
|
co_varnames = load(fp)
|
||||||
|
co_freevars = load(fp)
|
||||||
|
co_cellvars = load(fp)
|
||||||
|
co_filename = load(fp)
|
||||||
|
co_name = load(fp)
|
||||||
|
co_firstlineno = unpack('l', fp.read(4))[0]
|
||||||
|
co_lnotab = load(fp)
|
||||||
|
return 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)
|
||||||
|
|
||||||
|
# const type
|
||||||
|
elif marshalType == '.':
|
||||||
|
return Ellipsis
|
||||||
|
elif marshalType == '0':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType == 'N':
|
||||||
|
return None
|
||||||
|
elif marshalType == 'T':
|
||||||
|
return True
|
||||||
|
elif marshalType == 'F':
|
||||||
|
return False
|
||||||
|
elif marshalType == 'S':
|
||||||
|
return StopIteration
|
||||||
|
# number type
|
||||||
|
elif marshalType == 'f':
|
||||||
|
n = fp.read(1)
|
||||||
|
return float(unpack('d', fp.read(n))[0])
|
||||||
|
elif marshalType == 'g':
|
||||||
|
return float(unpack('d', fp.read(8))[0])
|
||||||
|
elif marshalType == 'i':
|
||||||
|
return int(unpack('l', fp.read(4))[0])
|
||||||
|
elif marshalType == 'I':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType == 'x':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType == 'y':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType == 'l':
|
||||||
|
n = unpack('l', fp.read(4))[0]
|
||||||
|
if n == 0:
|
||||||
|
return long(0)
|
||||||
|
ratio = 2 #2 for 64bit 1 for 32bit
|
||||||
|
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
|
||||||
|
# strings type
|
||||||
|
elif marshalType == 'R':
|
||||||
|
refnum = unpack('l', fp.read(4))[0]
|
||||||
|
return internStrings[refnum]
|
||||||
|
elif marshalType == 's':
|
||||||
|
strsize = unpack('l', fp.read(4))[0]
|
||||||
|
return str(fp.read(strsize))
|
||||||
|
elif marshalType == 't':
|
||||||
|
strsize = unpack('l', fp.read(4))[0]
|
||||||
|
interned = str(fp.read(strsize))
|
||||||
|
internStrings.append(interned)
|
||||||
|
return interned
|
||||||
|
elif marshalType == 'u':
|
||||||
|
strsize = unpack('l', fp.read(4))[0]
|
||||||
|
return unicode(fp.read(strsize))
|
||||||
|
# collection type
|
||||||
|
elif marshalType == '(':
|
||||||
|
tuplesize = unpack('l', fp.read(4))[0]
|
||||||
|
ret = tuple()
|
||||||
|
while tuplesize > 0:
|
||||||
|
ret += load(fp),
|
||||||
|
tuplesize -= 1
|
||||||
|
return ret
|
||||||
|
elif marshalType == '[':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType == '{':
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
elif marshalType in ['<', '>']:
|
||||||
|
raise KeyError, marshalType
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Unkown type %i (hex %x)\n" % (ord(marshalType), ord(marshalType)))
|
||||||
|
|
||||||
def _test():
|
def _test():
|
||||||
"""Simple test program to disassemble a file."""
|
"""Simple test program to disassemble a file."""
|
||||||
if sys.argv[1:]:
|
if sys.argv[1:]:
|
||||||
|
@ -40,7 +40,27 @@ versions = {
|
|||||||
# introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
|
# introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
|
||||||
__build_magic(62191): '2.7', #2.7a0 (introduce SETUP_WITH)
|
__build_magic(62191): '2.7', #2.7a0 (introduce SETUP_WITH)
|
||||||
__build_magic(62201): '2.7', #2.7a0 (introduce BUILD_SET)
|
__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(62211): '2.7', #2.7a0 (introduce MAP_ADD and SET_ADD)
|
||||||
|
__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)
|
||||||
}
|
}
|
||||||
|
|
||||||
magics = __by_version(versions)
|
magics = __by_version(versions)
|
||||||
|
@ -17,7 +17,7 @@ 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.7) # check
|
||||||
|
|
||||||
def disassemble(self, co, classname=None):
|
def disassemble(self, co, classname=None):
|
||||||
'''
|
'''
|
||||||
|
@ -1247,7 +1247,7 @@ class Walker(GenericASTTraversal, object):
|
|||||||
#if node[1][0] not in ('unpack', 'unpack_list'):
|
#if node[1][0] not in ('unpack', 'unpack_list'):
|
||||||
return '(' + self.traverse(node[1]) + ')'
|
return '(' + self.traverse(node[1]) + ')'
|
||||||
#return self.traverse(node[1])
|
#return self.traverse(node[1])
|
||||||
raise "Can't find tuple parameter" % name
|
raise Exception("Can't find tuple parameter " + name)
|
||||||
|
|
||||||
|
|
||||||
def make_function(self, node, isLambda, nested=1):
|
def make_function(self, node, isLambda, nested=1):
|
||||||
|
Loading…
Reference in New Issue
Block a user