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:
rocky
2015-12-16 09:13:14 -05:00
parent 9fecb48744
commit 06653a6163
6 changed files with 78 additions and 12 deletions

View File

@@ -1,4 +1,3 @@
"""
opcode module - potentially shared between dis and other modules which
operate on bytecodes (e.g. peephole optimizers).

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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