source file: /System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/dis.py
file stats: 179 lines, 15 executed: 8.4% covered
   1. """Disassembler of Python byte code into mnemonics."""
   2. 
   3. import sys
   4. import types
   5. 
   6. from opcode import *
   7. from opcode import __all__ as _opcodes_all
   8. 
   9. __all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
  10. del _opcodes_all
  11. 
  12. def dis(x=None):
  13.     """Disassemble classes, methods, functions, or code.
  14. 
  15.     With no argument, disassemble the last traceback.
  16. 
  17.     """
  18.     if x is None:
  19.         distb()
  20.         return
  21.     if type(x) is types.InstanceType:
  22.         x = x.__class__
  23.     if hasattr(x, 'im_func'):
  24.         x = x.im_func
  25.     if hasattr(x, 'func_code'):
  26.         x = x.func_code
  27.     if hasattr(x, '__dict__'):
  28.         items = x.__dict__.items()
  29.         items.sort()
  30.         for name, x1 in items:
  31.             if type(x1) in (types.MethodType,
  32.                             types.FunctionType,
  33.                             types.CodeType,
  34.                             types.ClassType):
  35.                 print "Disassembly of %s:" % name
  36.                 try:
  37.                     dis(x1)
  38.                 except TypeError, msg:
  39.                     print "Sorry:", msg
  40.                 print
  41.     elif hasattr(x, 'co_code'):
  42.         disassemble(x)
  43.     elif isinstance(x, str):
  44.         disassemble_string(x)
  45.     else:
  46.         raise TypeError, \
  47.               "don't know how to disassemble %s objects" % \
  48.               type(x).__name__
  49. 
  50. def distb(tb=None):
  51.     """Disassemble a traceback (default: last traceback)."""
  52.     if tb is None:
  53.         try:
  54.             tb = sys.last_traceback
  55.         except AttributeError:
  56.             raise RuntimeError, "no last traceback to disassemble"
  57.         while tb.tb_next: tb = tb.tb_next
  58.     disassemble(tb.tb_frame.f_code, tb.tb_lasti)
  59. 
  60. def disassemble(co, lasti=-1):
  61.     """Disassemble a code object."""
  62.     code = co.co_code
  63. 
  64.     byte_increments = [ord(c) for c in co.co_lnotab[0::2]]
  65.     line_increments = [ord(c) for c in co.co_lnotab[1::2]]
  66.     table_length = len(byte_increments) # == len(line_increments)
  67. 
  68.     lineno = co.co_firstlineno
  69.     table_index = 0
  70.     while (table_index < table_length
  71.            and byte_increments[table_index] == 0):
  72.         lineno += line_increments[table_index]
  73.         table_index += 1
  74.     addr = 0
  75.     line_incr = 0
  76. 
  77.     labels = findlabels(code)
  78.     n = len(code)
  79.     i = 0
  80.     extended_arg = 0
  81.     free = None
  82.     while i < n:
  83.         c = code[i]
  84.         op = ord(c)
  85. 
  86.         if i >= addr:
  87.             lineno += line_incr
  88.             while table_index < table_length:
  89.                 addr += byte_increments[table_index]
  90.                 line_incr = line_increments[table_index]
  91.                 table_index += 1
  92.                 if line_incr:
  93.                     break
  94.             else:
  95.                 addr = sys.maxint
  96.             if i > 0:
  97.                 print
  98.             print "%3d"%lineno,
  99.         else:
 100.             print '   ',
 101. 
 102.         if i == lasti: print '-->',
 103.         else: print '   ',
 104.         if i in labels: print '>>',
 105.         else: print '  ',
 106.         print `i`.rjust(4),
 107.         print opname[op].ljust(20),
 108.         i = i+1
 109.         if op >= HAVE_ARGUMENT:
 110.             oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
 111.             extended_arg = 0
 112.             i = i+2
 113.             if op == EXTENDED_ARG:
 114.                 extended_arg = oparg*65536L
 115.             print `oparg`.rjust(5),
 116.             if op in hasconst:
 117.                 print '(' + `co.co_consts[oparg]` + ')',
 118.             elif op in hasname:
 119.                 print '(' + co.co_names[oparg] + ')',
 120.             elif op in hasjrel:
 121.                 print '(to ' + `i + oparg` + ')',
 122.             elif op in haslocal:
 123.                 print '(' + co.co_varnames[oparg] + ')',
 124.             elif op in hascompare:
 125.                 print '(' + cmp_op[oparg] + ')',
 126.             elif op in hasfree:
 127.                 if free is None:
 128.                     free = co.co_cellvars + co.co_freevars
 129.                 print '(' + free[oparg] + ')',
 130.         print
 131. 
 132. def disassemble_string(code, lasti=-1, varnames=None, names=None,
 133.                        constants=None):
 134.     labels = findlabels(code)
 135.     n = len(code)
 136.     i = 0
 137.     while i < n:
 138.         c = code[i]
 139.         op = ord(c)
 140.         if i == lasti: print '-->',
 141.         else: print '   ',
 142.         if i in labels: print '>>',
 143.         else: print '  ',
 144.         print `i`.rjust(4),
 145.         print opname[op].ljust(15),
 146.         i = i+1
 147.         if op >= HAVE_ARGUMENT:
 148.             oparg = ord(code[i]) + ord(code[i+1])*256
 149.             i = i+2
 150.             print `oparg`.rjust(5),
 151.             if op in hasconst:
 152.                 if constants:
 153.                     print '(' + `constants[oparg]` + ')',
 154.                 else:
 155.                     print '(%d)'%oparg,
 156.             elif op in hasname:
 157.                 if names is not None:
 158.                     print '(' + names[oparg] + ')',
 159.                 else:
 160.                     print '(%d)'%oparg,
 161.             elif op in hasjrel:
 162.                 print '(to ' + `i + oparg` + ')',
 163.             elif op in haslocal:
 164.                 if varnames:
 165.                     print '(' + varnames[oparg] + ')',
 166.                 else:
 167.                     print '(%d)' % oparg,
 168.             elif op in hascompare:
 169.                 print '(' + cmp_op[oparg] + ')',
 170.         print
 171. 
 172. disco = disassemble                     # XXX For backwards compatibility
 173. 
 174. def findlabels(code):
 175.     """Detect all offsets in a byte code which are jump targets.
 176. 
 177.     Return the list of offsets.
 178. 
 179.     """
 180.     labels = []
 181.     n = len(code)
 182.     i = 0
 183.     while i < n:
 184.         c = code[i]
 185.         op = ord(c)
 186.         i = i+1
 187.         if op >= HAVE_ARGUMENT:
 188.             oparg = ord(code[i]) + ord(code[i+1])*256
 189.             i = i+2
 190.             label = -1
 191.             if op in hasjrel:
 192.                 label = i+oparg
 193.             elif op in hasjabs:
 194.                 label = oparg
 195.             if label >= 0:
 196.                 if label not in labels:
 197.                     labels.append(label)
 198.     return labels
 199. 
 200. 
 201. def _test():
 202.     """Simple test program to disassemble a file."""
 203.     if sys.argv[1:]:
 204.         if sys.argv[2:]:
 205.             sys.stderr.write("usage: python dis.py [-|file]\n")
 206.             sys.exit(2)
 207.         fn = sys.argv[1]
 208.         if not fn or fn == "-":
 209.             fn = None
 210.     else:
 211.         fn = None
 212.     if fn is None:
 213.         f = sys.stdin
 214.     else:
 215.         f = open(fn)
 216.     source = f.read()
 217.     if fn is not None:
 218.         f.close()
 219.     else:
 220.         fn = "<stdin>"
 221.     code = compile(source, fn, "exec")
 222.     dis(code)
 223. 
 224. if __name__ == "__main__":
 225.     _test()