You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
DRY scanner code. Allow 2.4 decompile from 3.x
This commit is contained in:
@@ -51,7 +51,7 @@ check-bytecode-3:
|
|||||||
|
|
||||||
#: Check deparsing bytecode that works running Python 2 and Python 3
|
#: Check deparsing bytecode that works running Python 2 and Python 3
|
||||||
check-bytecode: check-bytecode-3
|
check-bytecode: check-bytecode-3
|
||||||
$(PYTHON) test_pythonlib.py --bytecode-2.5 --bytecode-2.6 --bytecode-2.7
|
$(PYTHON) test_pythonlib.py --bytecode-2.4 --bytecode-2.5 --bytecode-2.6 --bytecode-2.7
|
||||||
|
|
||||||
#: Check deparsing Python 2.3
|
#: Check deparsing Python 2.3
|
||||||
check-bytecode-2.3:
|
check-bytecode-2.3:
|
||||||
|
@@ -24,7 +24,7 @@ from uncompyle6.scanners.tok import Token
|
|||||||
# The byte code versions we support
|
# The byte code versions we support
|
||||||
if PYTHON3:
|
if PYTHON3:
|
||||||
# Need to work out Python 2.3. ord's in PYTHON3
|
# Need to work out Python 2.3. ord's in PYTHON3
|
||||||
PYTHON_VERSIONS = (2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
|
PYTHON_VERSIONS = (2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
|
||||||
else:
|
else:
|
||||||
PYTHON_VERSIONS = (2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
|
PYTHON_VERSIONS = (2.3, 2.4, 2.5, 2.6, 2.7, 3.2, 3.3, 3.4, 3.5)
|
||||||
|
|
||||||
|
@@ -8,62 +8,20 @@ information for later use in deparsing.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import uncompyle6.scanners.scanner25 as scan
|
import uncompyle6.scanners.scanner25 as scan
|
||||||
import uncompyle6.scanners.scanner2 as scan2
|
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||||
from xdis.opcodes import opcode_24
|
from xdis.opcodes import opcode_24
|
||||||
JUMP_OPs = opcode_24.JUMP_OPs
|
JUMP_OPs = opcode_24.JUMP_OPs
|
||||||
|
|
||||||
# We base this off of 2.6 instead of the other way around
|
# We base this off of 2.5 instead of the other way around
|
||||||
# because we cleaned things up this way.
|
# because we cleaned things up this way.
|
||||||
# The history is that 2.7 support is the cleanest,
|
# The history is that 2.7 support is the cleanest,
|
||||||
# then from that we got 2.6 and so on.
|
# then from that we got 2.6 and so on.
|
||||||
class Scanner24(scan.Scanner25):
|
class Scanner24(scan.Scanner25):
|
||||||
def __init__(self, show_asm):
|
def __init__(self, show_asm):
|
||||||
scan2.Scanner2.__init__(self, 2.4, show_asm)
|
scan.Scanner25.__init__(self, show_asm)
|
||||||
self.stmt_opcodes = frozenset([
|
# These are the only differences in initialization between
|
||||||
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
|
# 2.4, 2.5 and 2.6
|
||||||
self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
|
self.version = 2.4
|
||||||
self.opc.SETUP_EXCEPT, self.opc.POP_BLOCK,
|
|
||||||
self.opc.STORE_FAST, self.opc.DELETE_FAST,
|
|
||||||
self.opc.STORE_DEREF, self.opc.STORE_GLOBAL,
|
|
||||||
self.opc.DELETE_GLOBAL, self.opc.STORE_NAME,
|
|
||||||
self.opc.DELETE_NAME, self.opc.STORE_ATTR,
|
|
||||||
self.opc.DELETE_ATTR, self.opc.STORE_SUBSCR,
|
|
||||||
self.opc.DELETE_SUBSCR, self.opc.RETURN_VALUE,
|
|
||||||
self.opc.RAISE_VARARGS, self.opc.POP_TOP,
|
|
||||||
self.opc.PRINT_EXPR, self.opc.PRINT_ITEM,
|
|
||||||
self.opc.PRINT_NEWLINE, self.opc.PRINT_ITEM_TO,
|
|
||||||
self.opc.PRINT_NEWLINE_TO, self.opc.CONTINUE_LOOP,
|
|
||||||
self.opc.JUMP_ABSOLUTE, self.opc.EXEC_STMT,
|
|
||||||
])
|
|
||||||
|
|
||||||
# "setup" opcodes
|
|
||||||
self.setup_ops = frozenset([
|
|
||||||
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
|
|
||||||
])
|
|
||||||
|
|
||||||
# opcodes with expect a variable number pushed values whose
|
|
||||||
# count is in the opcode. For parsing we generally change the
|
|
||||||
# opcode name to include that number.
|
|
||||||
self.varargs_ops = frozenset([
|
|
||||||
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
|
||||||
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
|
|
||||||
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
|
|
||||||
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
|
|
||||||
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
|
|
||||||
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS])
|
|
||||||
|
|
||||||
# opcodes that store values into a variable
|
|
||||||
self.designator_ops = frozenset([
|
|
||||||
self.opc.STORE_FAST, self.opc.STORE_NAME,
|
|
||||||
self.opc.STORE_GLOBAL, self.opc.STORE_DEREF, self.opc.STORE_ATTR,
|
|
||||||
self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, self.opc.STORE_SLICE_2,
|
|
||||||
self.opc.STORE_SLICE_3, self.opc.STORE_SUBSCR, self.opc.UNPACK_SEQUENCE,
|
|
||||||
self.opc.JA
|
|
||||||
])
|
|
||||||
# Python 2.7 has POP_JUMP_IF_{TRUE,FALSE}_OR_POP but < 2.7 doesn't
|
|
||||||
# Add an empty set make processing more uniform.
|
|
||||||
self.pop_jump_if_or_pop = frozenset([])
|
|
||||||
self.genexpr_name = '<generator expression>';
|
self.genexpr_name = '<generator expression>';
|
||||||
return
|
return
|
||||||
|
@@ -8,7 +8,6 @@ information for later use in deparsing.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import uncompyle6.scanners.scanner26 as scan
|
import uncompyle6.scanners.scanner26 as scan
|
||||||
import uncompyle6.scanners.scanner2 as scan2
|
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||||
from xdis.opcodes import opcode_25
|
from xdis.opcodes import opcode_25
|
||||||
@@ -20,49 +19,8 @@ JUMP_OPs = opcode_25.JUMP_OPs
|
|||||||
# then from that we got 2.6 and so on.
|
# then from that we got 2.6 and so on.
|
||||||
class Scanner25(scan.Scanner26):
|
class Scanner25(scan.Scanner26):
|
||||||
def __init__(self, show_asm):
|
def __init__(self, show_asm):
|
||||||
scan2.Scanner2.__init__(self, 2.5, show_asm)
|
# There are no differences in initialization between
|
||||||
self.stmt_opcodes = frozenset([
|
# 2.5 and 2.6
|
||||||
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
|
scan.Scanner26.__init__(self, show_asm)
|
||||||
self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
|
self.version = 2.5
|
||||||
self.opc.SETUP_EXCEPT, self.opc.POP_BLOCK,
|
|
||||||
self.opc.STORE_FAST, self.opc.DELETE_FAST,
|
|
||||||
self.opc.STORE_DEREF, self.opc.STORE_GLOBAL,
|
|
||||||
self.opc.DELETE_GLOBAL, self.opc.STORE_NAME,
|
|
||||||
self.opc.DELETE_NAME, self.opc.STORE_ATTR,
|
|
||||||
self.opc.DELETE_ATTR, self.opc.STORE_SUBSCR,
|
|
||||||
self.opc.DELETE_SUBSCR, self.opc.RETURN_VALUE,
|
|
||||||
self.opc.RAISE_VARARGS, self.opc.POP_TOP,
|
|
||||||
self.opc.PRINT_EXPR, self.opc.PRINT_ITEM,
|
|
||||||
self.opc.PRINT_NEWLINE, self.opc.PRINT_ITEM_TO,
|
|
||||||
self.opc.PRINT_NEWLINE_TO, self.opc.CONTINUE_LOOP,
|
|
||||||
self.opc.JUMP_ABSOLUTE, self.opc.EXEC_STMT,
|
|
||||||
])
|
|
||||||
|
|
||||||
# "setup" opcodes
|
|
||||||
self.setup_ops = frozenset([
|
|
||||||
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
|
|
||||||
])
|
|
||||||
|
|
||||||
# opcodes with expect a variable number pushed values whose
|
|
||||||
# count is in the opcode. For parsing we generally change the
|
|
||||||
# opcode name to include that number.
|
|
||||||
self.varargs_ops = frozenset([
|
|
||||||
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
|
||||||
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
|
|
||||||
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
|
|
||||||
self.opc.MAKE_CLOSURE, self.opc.CALL_FUNCTION_VAR,
|
|
||||||
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
|
|
||||||
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS])
|
|
||||||
|
|
||||||
# opcodes that store values into a variable
|
|
||||||
self.designator_ops = frozenset([
|
|
||||||
self.opc.STORE_FAST, self.opc.STORE_NAME,
|
|
||||||
self.opc.STORE_GLOBAL, self.opc.STORE_DEREF, self.opc.STORE_ATTR,
|
|
||||||
self.opc.STORE_SLICE_0, self.opc.STORE_SLICE_1, self.opc.STORE_SLICE_2,
|
|
||||||
self.opc.STORE_SLICE_3, self.opc.STORE_SUBSCR, self.opc.UNPACK_SEQUENCE,
|
|
||||||
self.opc.JA
|
|
||||||
])
|
|
||||||
# Python 2.7 has POP_JUMP_IF_{TRUE,FALSE}_OR_POP but < 2.7 doesn't
|
|
||||||
# Add an empty set make processing more uniform.
|
|
||||||
self.pop_jump_if_or_pop = frozenset([])
|
|
||||||
return
|
return
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
# Copyright (c) 2015, 2016 by Rocky Bernstein
|
# Copyright (c) 2015, 2016 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
# Copyright (c) 1999 John Aycock
|
|
||||||
"""
|
"""
|
||||||
Python 2.6 bytecode scanner
|
Python 2.6 bytecode scanner
|
||||||
|
|
||||||
@@ -100,7 +99,8 @@ class Scanner26(scan.Scanner2):
|
|||||||
|
|
||||||
n = self.setup_code(co)
|
n = self.setup_code(co)
|
||||||
|
|
||||||
self.build_lines_data(co, n-1)
|
self.build_lines_data(co, n)
|
||||||
|
self.build_prev_op(n)
|
||||||
|
|
||||||
# linestarts contains block code adresses (addr,block)
|
# linestarts contains block code adresses (addr,block)
|
||||||
self.linestarts = list(findlinestarts(co))
|
self.linestarts = list(findlinestarts(co))
|
||||||
@@ -123,17 +123,10 @@ class Scanner26(scan.Scanner2):
|
|||||||
varnames = co.co_varnames
|
varnames = co.co_varnames
|
||||||
self.names = names
|
self.names = names
|
||||||
|
|
||||||
# list of instruction to remove/add or change to match with bytecode 2.7
|
|
||||||
self.toChange = []
|
|
||||||
# Rocky: the restructure code isn't adjusting linestarts
|
|
||||||
# and this causes problems
|
|
||||||
# self.restructBytecode()
|
|
||||||
codelen = len(self.code)
|
codelen = len(self.code)
|
||||||
|
|
||||||
self.build_prev_op(codelen)
|
|
||||||
|
|
||||||
self.load_asserts = set()
|
self.load_asserts = set()
|
||||||
for i in self.op_range(0, codelen):
|
for i in self.op_range(0, n):
|
||||||
if (self.code[i] == self.opc.JUMP_IF_TRUE and
|
if (self.code[i] == self.opc.JUMP_IF_TRUE and
|
||||||
i + 4 < codelen and
|
i + 4 < codelen and
|
||||||
self.code[i+3] == self.opc.POP_TOP and
|
self.code[i+3] == self.opc.POP_TOP and
|
||||||
@@ -233,11 +226,6 @@ class Scanner26(scan.Scanner2):
|
|||||||
pattr = self.opc.cmp_op[oparg]
|
pattr = self.opc.cmp_op[oparg]
|
||||||
elif op in self.opc.hasfree:
|
elif op in self.opc.hasfree:
|
||||||
pattr = free[oparg]
|
pattr = free[oparg]
|
||||||
if offset in self.toChange:
|
|
||||||
if (self.code[offset] == self.opc.JA and
|
|
||||||
self.code[oparg] == self.opc.WITH_CLEANUP):
|
|
||||||
op_name = 'SETUP_WITH'
|
|
||||||
cf[oparg] = cf.get(oparg, []) + [offset]
|
|
||||||
if op in self.varargs_ops:
|
if op in self.varargs_ops:
|
||||||
# CE - Hack for >= 2.5
|
# CE - Hack for >= 2.5
|
||||||
# Now all values loaded via LOAD_CLOSURE are packed into
|
# Now all values loaded via LOAD_CLOSURE are packed into
|
||||||
|
Reference in New Issue
Block a user