From 06653a616368e88a817e2e977b95ca90632e1369 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 16 Dec 2015 09:13:14 -0500 Subject: [PATCH] On Python3.4 decompiling Python 3.4 instructions, use its built-in disassembler routines. In contrast to what was here, they most likely work! --- uncompyle6/opcodes/opcode_34.py | 1 - uncompyle6/scanner.py | 31 +++++++++++++++++++------ uncompyle6/scanners/scanner25.py | 6 +++++ uncompyle6/scanners/scanner26.py | 6 +++++ uncompyle6/scanners/scanner27.py | 7 ++++++ uncompyle6/scanners/scanner34.py | 39 ++++++++++++++++++++++++++++---- 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/uncompyle6/opcodes/opcode_34.py b/uncompyle6/opcodes/opcode_34.py index 8e15d13e..266d24d8 100644 --- a/uncompyle6/opcodes/opcode_34.py +++ b/uncompyle6/opcodes/opcode_34.py @@ -1,4 +1,3 @@ - """ opcode module - potentially shared between dis and other modules which operate on bytecodes (e.g. peephole optimizers). diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 1b82bcae..543be669 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -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 diff --git a/uncompyle6/scanners/scanner25.py b/uncompyle6/scanners/scanner25.py index 0d632912..de79fe89 100644 --- a/uncompyle6/scanners/scanner25.py +++ b/uncompyle6/scanners/scanner25.py @@ -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) diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 5ad44951..48cee6cb 100644 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -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) diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 63199e98..4f971656 100644 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -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 diff --git a/uncompyle6/scanners/scanner34.py b/uncompyle6/scanners/scanner34.py index 463c978a..b415f6c0 100644 --- a/uncompyle6/scanners/scanner34.py +++ b/uncompyle6/scanners/scanner34.py @@ -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 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 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