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-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-bytecode-2.3:
|
||||
|
@@ -24,7 +24,7 @@ from uncompyle6.scanners.tok import Token
|
||||
# The byte code versions we support
|
||||
if 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:
|
||||
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.scanner2 as scan2
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
from xdis.opcodes import opcode_24
|
||||
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.
|
||||
# The history is that 2.7 support is the cleanest,
|
||||
# then from that we got 2.6 and so on.
|
||||
class Scanner24(scan.Scanner25):
|
||||
def __init__(self, show_asm):
|
||||
scan2.Scanner2.__init__(self, 2.4, show_asm)
|
||||
self.stmt_opcodes = frozenset([
|
||||
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
|
||||
self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
|
||||
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([])
|
||||
scan.Scanner25.__init__(self, show_asm)
|
||||
# These are the only differences in initialization between
|
||||
# 2.4, 2.5 and 2.6
|
||||
self.version = 2.4
|
||||
self.genexpr_name = '<generator expression>';
|
||||
return
|
||||
|
@@ -8,7 +8,6 @@ information for later use in deparsing.
|
||||
"""
|
||||
|
||||
import uncompyle6.scanners.scanner26 as scan
|
||||
import uncompyle6.scanners.scanner2 as scan2
|
||||
|
||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||
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.
|
||||
class Scanner25(scan.Scanner26):
|
||||
def __init__(self, show_asm):
|
||||
scan2.Scanner2.__init__(self, 2.5, show_asm)
|
||||
self.stmt_opcodes = frozenset([
|
||||
self.opc.SETUP_LOOP, self.opc.BREAK_LOOP,
|
||||
self.opc.SETUP_FINALLY, self.opc.END_FINALLY,
|
||||
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([])
|
||||
# There are no differences in initialization between
|
||||
# 2.5 and 2.6
|
||||
scan.Scanner26.__init__(self, show_asm)
|
||||
self.version = 2.5
|
||||
return
|
||||
|
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) 2015, 2016 by Rocky Bernstein
|
||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Copyright (c) 1999 John Aycock
|
||||
"""
|
||||
Python 2.6 bytecode scanner
|
||||
|
||||
@@ -100,7 +99,8 @@ class Scanner26(scan.Scanner2):
|
||||
|
||||
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)
|
||||
self.linestarts = list(findlinestarts(co))
|
||||
@@ -123,17 +123,10 @@ class Scanner26(scan.Scanner2):
|
||||
varnames = co.co_varnames
|
||||
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)
|
||||
|
||||
self.build_prev_op(codelen)
|
||||
|
||||
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
|
||||
i + 4 < codelen and
|
||||
self.code[i+3] == self.opc.POP_TOP and
|
||||
@@ -233,11 +226,6 @@ class Scanner26(scan.Scanner2):
|
||||
pattr = self.opc.cmp_op[oparg]
|
||||
elif op in self.opc.hasfree:
|
||||
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:
|
||||
# CE - Hack for >= 2.5
|
||||
# Now all values loaded via LOAD_CLOSURE are packed into
|
||||
|
Reference in New Issue
Block a user