Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Oct 15, 2011
1 parent 50825bc commit c9dd4f0
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 42 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
This module provides a universal disassembler that is able to disassemble *.pyc files from both Python 2 and Python 3. Example usage:

import unwind
print(unwind.dis('example.pyc'))
print(unwind.disassemble('example.pyc'))

The disassembler allows one version of Python to unmarshal code compiled by all other versions of Python. This is made possible by scraping information from the official Python repository at http://hg.python.org/cpython. In the example below, the code `print('Hello, World')` is compiled and disassembled from both Python 2.5 and Python 3.1. Notice how Python 2.5 uses the `PRINT_ITEM` opcode but Python 3.1 uses the `CALL_FUNCTION` opcode, since the print statement was removed in Python 3.

$ cat > example.py
print('Hello, World')
$ python2.5 -m py_compile example.py
$ python -c 'import unwind; print unwind.dis("example.pyc")'
$ python -c 'import unwind; print unwind.disassemble("example.pyc")'
Module(
magic = 168686259,
timestamp = 1318574250,
Expand All @@ -31,7 +31,7 @@ The disassembler allows one version of Python to unmarshal code compiled by all
Opcode(offset = 5, opcode = 'LOAD_CONST', argument = None),
Opcode(offset = 8, opcode = 'RETURN_VALUE', argument = None)])))
$ python3.1 -m py_compile example.py
$ python -c 'import unwind; print unwind.dis("example.pyc")'
$ python -c 'import unwind; print unwind.disassemble("example.pyc")'
Module(
magic = 168627279,
timestamp = 1318574250,
Expand Down
2 changes: 1 addition & 1 deletion runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
def test_file(path, versions):
for version in versions:
os.system('%s -m py_compile "%s"' % (version, path))
print(unwind.dis(path + 'c'))
print(unwind.disassemble(path + 'c'))

versions = ['python2.6', 'python3.1']
test_file('tests/datatypes.py', versions)
Expand Down
3 changes: 2 additions & 1 deletion unwind/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from unwind.disasm import *
from unwind.disasm import disassemble
from unwind.decomp import decompile
14 changes: 6 additions & 8 deletions unwind/decomp.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import unwind.disasm as disasm
from unwind.passes import *
from unwind.disasm import disassemble
import unwind.passes as _passes

def decompile(path):
passes = [
CodeObjectsToNodes(),
ComputeBasicBlocks(),
DecompileControlStructures(),
_passes.CodeObjectsToNodes(),
_passes.ComputeBasicBlocks(),
_passes.DecompileControlStructures(),
]
result = disasm.dis(path)
result = disassemble(path)
for p in passes:
result = p.run(result)
return result

print decompile('temp.pyc')
35 changes: 6 additions & 29 deletions unwind/disasm.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
'''
disasm.disassemble(file_object)
Disassemble a python module from file_object, an open file object
containing a *.pyc file. Returns a disasm.Module with the disassembly
or raises a disasm.DisassemblerException if there was an error.
disasm.dis(path)
Shortcut for disasm.disassemble(open(path, 'rb')).
disasm.disassemble(path)
Disassemble a python module from a *.pyc file. Returns a disasm.Module with
the disassembly or raises a disasm.DisassemblerException if there was an
error.
disasm.Module, disasm.CodeObject, disasm.Opcode
Used to represent the disassembled module. Constant values are
Expand All @@ -22,19 +19,13 @@
import time
import struct

def dis(path):
'''
Shortcut for disasm.disassemble(open(path, 'rb')).
'''
return disassemble(open(path, 'rb'))

def disassemble(file_object):
def disassemble(path):
'''
Disassemble a python module from file_object, an open file object
containing a *.pyc file. Returns a disasm.Module with the disassembly
or raises a disasm.DisassemblerException if there was an error.
'''
return _Disassembler().disassemble(file_object)
return _Disassembler().disassemble(open(path, 'rb'))

class DisassemblerException(Exception):
'''
Expand Down Expand Up @@ -334,17 +325,3 @@ def unmarshal_node(self):

else:
raise DisassemblerException('Cannot unmarshal unknown type 0x%02X' % type)

# Provide a command-line disassembly tool
if __name__ == '__main__':
if len(sys.argv) == 1:
sys.exit('usage: python disasm.py *.pyc')

dis = _Disassembler()
for pyc in sys.argv[1:]:
print('\n# disassembling: ' + pyc)
try:
module = dis.disassemble(open(pyc, 'rb'))
print(module)
except DisassemblerException:
print('# error: ' + str(sys.exc_info()[1]))

0 comments on commit c9dd4f0

Please sign in to comment.