You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +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
|
||||
operate on bytecodes (e.g. peephole optimizers).
|
||||
|
@@ -20,26 +20,33 @@ __all__ = ['Token', 'Scanner', 'Code']
|
||||
|
||||
import sys
|
||||
|
||||
from uncompyle6 import PYTHON3
|
||||
|
||||
# FIXME: DRY
|
||||
if (sys.version_info > (3, 0)):
|
||||
if PYTHON3:
|
||||
intern = sys.intern
|
||||
L65536 = 65536
|
||||
|
||||
def cmp(a, b):
|
||||
return (a > b) - (a < b)
|
||||
else:
|
||||
L65536 = long(65536)
|
||||
L65536 = long(65536) # NOQA
|
||||
|
||||
from uncompyle6.opcodes import opcode_25, opcode_26, opcode_27, opcode_32, opcode_34
|
||||
|
||||
|
||||
class Token:
|
||||
'''
|
||||
"""
|
||||
Class representing a byte-code token.
|
||||
|
||||
A byte-code token is equivalent to the contents of one line
|
||||
as output by dis.dis().
|
||||
'''
|
||||
A byte-code token is equivalent to Python 3's dis.instruction or
|
||||
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):
|
||||
self.type = intern(type_)
|
||||
self.attr = attr
|
||||
@@ -98,7 +105,9 @@ class Scanner(object):
|
||||
elif version == 3.4:
|
||||
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):
|
||||
self.showasm = showasm
|
||||
@@ -318,3 +327,11 @@ class Scanner(object):
|
||||
if not (parent['start'] < target < parent['end']):
|
||||
target = parent['end']
|
||||
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]
|
||||
targets[label] = targets.get(label, []) + [i]
|
||||
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]
|
||||
targets[label] = targets.get(label, []) + [i]
|
||||
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]
|
||||
targets[label] = targets.get(label, []) + [i]
|
||||
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
|
||||
|
||||
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
|
||||
for later use in deparsing.
|
||||
"""
|
||||
@@ -17,6 +18,7 @@ from __future__ import print_function
|
||||
import dis
|
||||
from collections import namedtuple
|
||||
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
from uncompyle6.scanner import Token, L65536
|
||||
|
||||
# Get all the opcodes into globals
|
||||
@@ -30,10 +32,31 @@ class Scanner34(scan.Scanner):
|
||||
self.Token = scan.Scanner.__init__(self, 3.4) # check
|
||||
|
||||
def disassemble(self, co):
|
||||
"""
|
||||
Convert code object <co> into a sequence of tokens.
|
||||
fn = self.disassemble_built_in if PYTHON_VERSION == 3.4 \
|
||||
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
|
||||
tokens = []
|
||||
@@ -488,3 +511,11 @@ class Scanner34(scan.Scanner):
|
||||
continue
|
||||
filtered.append(if_)
|
||||
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