You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
On Python3.4 decompiling Python 3.4 instructions, use its
built-in disassembler routines. In contrast to what was here, they most likely work!
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
opcode module - potentially shared between dis and other modules which
|
opcode module - potentially shared between dis and other modules which
|
||||||
operate on bytecodes (e.g. peephole optimizers).
|
operate on bytecodes (e.g. peephole optimizers).
|
||||||
|
@@ -20,26 +20,33 @@ __all__ = ['Token', 'Scanner', 'Code']
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from uncompyle6 import PYTHON3
|
||||||
|
|
||||||
# FIXME: DRY
|
# FIXME: DRY
|
||||||
if (sys.version_info > (3, 0)):
|
if PYTHON3:
|
||||||
intern = sys.intern
|
intern = sys.intern
|
||||||
L65536 = 65536
|
L65536 = 65536
|
||||||
|
|
||||||
def cmp(a, b):
|
def cmp(a, b):
|
||||||
return (a > b) - (a < b)
|
return (a > b) - (a < b)
|
||||||
else:
|
else:
|
||||||
L65536 = long(65536)
|
L65536 = long(65536) # NOQA
|
||||||
|
|
||||||
from uncompyle6.opcodes import opcode_25, opcode_26, opcode_27, opcode_32, opcode_34
|
from uncompyle6.opcodes import opcode_25, opcode_26, opcode_27, opcode_32, opcode_34
|
||||||
|
|
||||||
|
|
||||||
class Token:
|
class Token:
|
||||||
'''
|
"""
|
||||||
Class representing a byte-code token.
|
Class representing a byte-code token.
|
||||||
|
|
||||||
A byte-code token is equivalent to the contents of one line
|
A byte-code token is equivalent to Python 3's dis.instruction or
|
||||||
as output by dis.dis().
|
the contents of one line as output by dis.dis().
|
||||||
'''
|
"""
|
||||||
|
# FIXME: match Python 3.4's terms:
|
||||||
|
# type_ should be opname
|
||||||
|
# linestart = starts_line
|
||||||
|
# attr = argval
|
||||||
|
# pattr = argrepr
|
||||||
def __init__(self, type_, attr=None, pattr=None, offset=-1, linestart=None):
|
def __init__(self, type_, attr=None, pattr=None, offset=-1, linestart=None):
|
||||||
self.type = intern(type_)
|
self.type = intern(type_)
|
||||||
self.attr = attr
|
self.attr = attr
|
||||||
@@ -98,7 +105,9 @@ class Scanner(object):
|
|||||||
elif version == 3.4:
|
elif version == 3.4:
|
||||||
self.opc = opcode_34
|
self.opc = opcode_34
|
||||||
|
|
||||||
return self.resetTokenClass()
|
# FIXME: This weird Python2 behavior is not Python3
|
||||||
|
if not PYTHON3:
|
||||||
|
return self.resetTokenClass()
|
||||||
|
|
||||||
def setShowAsm(self, showasm, out=None):
|
def setShowAsm(self, showasm, out=None):
|
||||||
self.showasm = showasm
|
self.showasm = showasm
|
||||||
@@ -318,3 +327,11 @@ class Scanner(object):
|
|||||||
if not (parent['start'] < target < parent['end']):
|
if not (parent['start'] < target < parent['end']):
|
||||||
target = parent['end']
|
target = parent['end']
|
||||||
return target
|
return target
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import inspect, uncompyle6
|
||||||
|
co = inspect.currentframe().f_code
|
||||||
|
tokens, customize = Scanner(uncompyle6.PYTHON_VERSION).disassemble(co)
|
||||||
|
for t in tokens:
|
||||||
|
print(t)
|
||||||
|
pass
|
||||||
|
@@ -911,3 +911,9 @@ class Scanner25(scan.Scanner):
|
|||||||
label = self.fixed_jumps[i]
|
label = self.fixed_jumps[i]
|
||||||
targets[label] = targets.get(label, []) + [i]
|
targets[label] = targets.get(label, []) + [i]
|
||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
co = inspect.currentframe().f_code
|
||||||
|
tokens, customize = Scanner25().disassemble(co)
|
||||||
|
for t in tokens:
|
||||||
|
print(t)
|
||||||
|
@@ -901,3 +901,9 @@ class Scanner26(scan.Scanner):
|
|||||||
label = self.fixed_jumps[i]
|
label = self.fixed_jumps[i]
|
||||||
targets[label] = targets.get(label, []) + [i]
|
targets[label] = targets.get(label, []) + [i]
|
||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
co = inspect.currentframe().f_code
|
||||||
|
tokens, customize = Scanner26().disassemble(co)
|
||||||
|
for t in tokens:
|
||||||
|
print(t)
|
||||||
|
@@ -633,3 +633,10 @@ class Scanner27(scan.Scanner):
|
|||||||
label = self.fixed_jumps[i]
|
label = self.fixed_jumps[i]
|
||||||
targets[label] = targets.get(label, []) + [i]
|
targets[label] = targets.get(label, []) + [i]
|
||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
co = inspect.currentframe().f_code
|
||||||
|
tokens, customize = Scanner27().disassemble(co)
|
||||||
|
for t in tokens:
|
||||||
|
print(t)
|
||||||
|
pass
|
||||||
|
@@ -7,7 +7,8 @@
|
|||||||
"""
|
"""
|
||||||
Python 3.4 bytecode scanner/deparser
|
Python 3.4 bytecode scanner/deparser
|
||||||
|
|
||||||
This overlaps Python's 3.4's dis module, but it can be run from
|
This overlaps Python's 3.4's dis module, and in fact in some cases
|
||||||
|
we just fall back to that. But the intent is that it can be run from
|
||||||
Python 2 and other versions of Python. Also, we save token information
|
Python 2 and other versions of Python. Also, we save token information
|
||||||
for later use in deparsing.
|
for later use in deparsing.
|
||||||
"""
|
"""
|
||||||
@@ -17,6 +18,7 @@ from __future__ import print_function
|
|||||||
import dis
|
import dis
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from uncompyle6 import PYTHON_VERSION
|
||||||
from uncompyle6.scanner import Token, L65536
|
from uncompyle6.scanner import Token, L65536
|
||||||
|
|
||||||
# Get all the opcodes into globals
|
# Get all the opcodes into globals
|
||||||
@@ -30,10 +32,31 @@ class Scanner34(scan.Scanner):
|
|||||||
self.Token = scan.Scanner.__init__(self, 3.4) # check
|
self.Token = scan.Scanner.__init__(self, 3.4) # check
|
||||||
|
|
||||||
def disassemble(self, co):
|
def disassemble(self, co):
|
||||||
"""
|
fn = self.disassemble_built_in if PYTHON_VERSION == 3.4 \
|
||||||
Convert code object <co> into a sequence of tokens.
|
else self.disassemble_cross_version
|
||||||
|
return fn(co)
|
||||||
|
|
||||||
Based on dis.disassemble() function.
|
def disassemble_built_in(self, co):
|
||||||
|
bytecode = dis.Bytecode(co)
|
||||||
|
tokens = []
|
||||||
|
for inst in bytecode:
|
||||||
|
tokens.append(
|
||||||
|
Token(
|
||||||
|
type_ = inst.opname,
|
||||||
|
attr = inst.argval,
|
||||||
|
pattr = inst.argrepr,
|
||||||
|
offset = inst.offset,
|
||||||
|
linestart = inst.starts_line,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
return tokens, {}
|
||||||
|
|
||||||
|
def disassemble_cross_version(self, co):
|
||||||
|
"""
|
||||||
|
Convert code object <co> into a sequence of tokens
|
||||||
|
FIXME: the below code faulty in many was is probably based on older Python2's dis.disassemble() function.
|
||||||
|
It needs to be rewritten and moduled off of Python 3.4's dis.disassemble_bytes().
|
||||||
"""
|
"""
|
||||||
# Container for tokens
|
# Container for tokens
|
||||||
tokens = []
|
tokens = []
|
||||||
@@ -488,3 +511,11 @@ class Scanner34(scan.Scanner):
|
|||||||
continue
|
continue
|
||||||
filtered.append(if_)
|
filtered.append(if_)
|
||||||
return filtered
|
return filtered
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import inspect
|
||||||
|
co = inspect.currentframe().f_code
|
||||||
|
tokens, customize = Scanner34().disassemble(co)
|
||||||
|
for t in tokens:
|
||||||
|
print(t)
|
||||||
|
pass
|
||||||
|
Reference in New Issue
Block a user