dismantle.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
00004 #
00005 # This file is part of the Python-on-a-Chip program.
00006 # Python-on-a-Chip is free software: you can redistribute it and/or modify
00007 # it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
00008 # 
00009 # Python-on-a-Chip is distributed in the hope that it will be useful,
00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00012 # A copy of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
00013 # is seen in the file COPYING in this directory.
00014 
00015 """
00016 Dismantles a .py file by compiling it
00017 into a code object and recursively dismantling
00018 and disassembling the code object.
00019 """
00020 
00021 __usage__ = """Usage:
00022     dismantle.py sourcefilename.py
00023 """
00024 
00025 ## @file
00026 #  @copybrief dismantle
00027 
00028 ## @package dismantle
00029 #  @brief Dismantles a .py file by compiling it
00030 #  into a code object and recursively dismantling
00031 #  and disassembling the code object.
00032 
00033 
00034 STRINGTOOLONG = 32
00035 
00036 
00037 import dis, sys, types, py_compile, time
00038 
00039 
00040 def dismantle_file(fn):
00041     """Dismantles the .py file, fn. Returns the root code object.
00042     """
00043 
00044     #create a code object
00045     f = open(fn)
00046     source = f.read()
00047     f.close()
00048     return dismantle(source, fn)
00049 
00050 
00051 def dismantle(source, fn=""):
00052 
00053     # If no filename given, just dismantle source, skip magic and ignore
00054     if fn == "":
00055         magic = 0
00056         ignore = 0
00057         fn = "fn"
00058         pyc = ""
00059 
00060     else:
00061         # Compile to .pyc and open
00062         py_compile.compile(fn)
00063         f = open(fn + 'c','rb')
00064         pyc = f.read()
00065         f.close()
00066 
00067         # Check for magic number
00068         magic = int((ord(pyc[0])      ) | (ord(pyc[1]) <<  8) |
00069                     (ord(pyc[2]) << 16) | (ord(pyc[3]) << 24))
00070 
00071         # Grab the next 4 bytes (don't know what they do)
00072         ignore = int((ord(pyc[4])      ) | (ord(pyc[5]) <<  8) |
00073                      (ord(pyc[6]) << 16) | (ord(pyc[7]) << 24))
00074 
00075     code = compile(source, fn, "exec")
00076 
00077     # Print header
00078     print "BEGIN DISMANTLE"
00079     print "date:           \t", time.ctime(time.time())
00080     print "src file:       \t", fn
00081     print "src file size:  \t", len(source), "bytes"
00082     print "pyc file size:  \t", len(pyc), "bytes"
00083     print
00084     print "magic:          \t0x%08x" % magic
00085     print "ignore:         \t0x%08x" % ignore
00086     print
00087 
00088     # Recurse into the code object
00089     rdismantle(code)
00090 
00091     print "END DISMANTLE"
00092     return code
00093 
00094 
00095 def rdismantle(co, parent = None):
00096     """Dismantles the code object, co.  Prints the co_* field values and
00097     the co_code disassembly for each code object in the file and recurses
00098     into any code objects in the constant pool.
00099     """
00100 
00101     # Create full name
00102     if parent:
00103         fullname = parent + "." + co.co_name
00104     else:
00105         fullname = co.co_name
00106 
00107     # Print object fields and values
00108     print "fullname:       \t", fullname
00109     print " co_name:       \t", co.co_name
00110     print " co_filename:   \t", co.co_filename
00111     print " co_firstlineno:\t", co.co_firstlineno
00112     print " co_flags:      \t0x%04x"  % co.co_flags
00113     print " co_stacksize:  \t", co.co_stacksize
00114     print " co_lnotab[%3d]:\t%s" % \
00115           (len(co.co_lnotab), repr(co.co_lnotab[:8]))
00116     print " co_argcount:   \t", co.co_argcount
00117     print " co_nlocals:    \t", co.co_nlocals
00118     print " co_freevars:   \t", co.co_freevars
00119     print " co_cellvars:   \t", co.co_cellvars
00120 
00121     # Print vital compound components
00122     tabspacing = "\t\t"
00123 
00124     print " co_varnames:"
00125     i = 0
00126     for item in co.co_varnames:
00127         print tabspacing, i, ":\t", item
00128         i += 1
00129 
00130     print " co_names:       "
00131     i = 0
00132     for item in co.co_names:
00133         print tabspacing, i, ":\t", item
00134         i += 1
00135 
00136     print " co_consts:      "
00137     i = 0
00138     for item in co.co_consts:
00139         if type(item) == types.StringType and \
00140            len(item) > STRINGTOOLONG:
00141                 print tabspacing, i, ":\t", repr(item[:STRINGTOOLONG]), "..."
00142         else:
00143             print tabspacing, i, ":\t", repr(item)
00144         i += 1
00145 
00146     # Print disassembly
00147     print " co_code:"
00148     dis.dis(co)
00149     print "\n"
00150 
00151     # Dismantle code objects in constant pool
00152     for obj in co.co_consts:
00153         if type(obj) == types.CodeType:
00154             rdismantle(obj, fullname)
00155     return
00156 
00157 
00158 def main():
00159     """Dismantles the source file given as an arg.
00160     """
00161 
00162     if len(sys.argv) == 2:
00163         return dismantle_file(sys.argv[1])
00164     else:
00165         print __usage__
00166 
00167 
00168 if __name__ == "__main__":
00169     main()
00170 

Generated on Mon Oct 18 07:40:47 2010 for Python-on-a-chip by  doxygen 1.5.9