home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / Texte / scribus / scribus-1.3.3.9-win32-install.exe / lib / dis.py < prev    next >
Text File  |  2004-06-01  |  7KB  |  224 lines

  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.     labels = findlabels(code)
  64.     linestarts = dict(findlinestarts(co))
  65.     n = len(code)
  66.     i = 0
  67.     extended_arg = 0
  68.     free = None
  69.     while i < n:
  70.         c = code[i]
  71.         op = ord(c)
  72.         if i in linestarts:
  73.             if i > 0:
  74.                 print
  75.             print "%3d" % linestarts[i],
  76.         else:
  77.             print '   ',
  78.  
  79.         if i == lasti: print '-->',
  80.         else: print '   ',
  81.         if i in labels: print '>>',
  82.         else: print '  ',
  83.         print repr(i).rjust(4),
  84.         print opname[op].ljust(20),
  85.         i = i+1
  86.         if op >= HAVE_ARGUMENT:
  87.             oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
  88.             extended_arg = 0
  89.             i = i+2
  90.             if op == EXTENDED_ARG:
  91.                 extended_arg = oparg*65536L
  92.             print repr(oparg).rjust(5),
  93.             if op in hasconst:
  94.                 print '(' + repr(co.co_consts[oparg]) + ')',
  95.             elif op in hasname:
  96.                 print '(' + co.co_names[oparg] + ')',
  97.             elif op in hasjrel:
  98.                 print '(to ' + repr(i + oparg) + ')',
  99.             elif op in haslocal:
  100.                 print '(' + co.co_varnames[oparg] + ')',
  101.             elif op in hascompare:
  102.                 print '(' + cmp_op[oparg] + ')',
  103.             elif op in hasfree:
  104.                 if free is None:
  105.                     free = co.co_cellvars + co.co_freevars
  106.                 print '(' + free[oparg] + ')',
  107.         print
  108.  
  109. def disassemble_string(code, lasti=-1, varnames=None, names=None,
  110.                        constants=None):
  111.     labels = findlabels(code)
  112.     n = len(code)
  113.     i = 0
  114.     while i < n:
  115.         c = code[i]
  116.         op = ord(c)
  117.         if i == lasti: print '-->',
  118.         else: print '   ',
  119.         if i in labels: print '>>',
  120.         else: print '  ',
  121.         print repr(i).rjust(4),
  122.         print opname[op].ljust(15),
  123.         i = i+1
  124.         if op >= HAVE_ARGUMENT:
  125.             oparg = ord(code[i]) + ord(code[i+1])*256
  126.             i = i+2
  127.             print repr(oparg).rjust(5),
  128.             if op in hasconst:
  129.                 if constants:
  130.                     print '(' + repr(constants[oparg]) + ')',
  131.                 else:
  132.                     print '(%d)'%oparg,
  133.             elif op in hasname:
  134.                 if names is not None:
  135.                     print '(' + names[oparg] + ')',
  136.                 else:
  137.                     print '(%d)'%oparg,
  138.             elif op in hasjrel:
  139.                 print '(to ' + repr(i + oparg) + ')',
  140.             elif op in haslocal:
  141.                 if varnames:
  142.                     print '(' + varnames[oparg] + ')',
  143.                 else:
  144.                     print '(%d)' % oparg,
  145.             elif op in hascompare:
  146.                 print '(' + cmp_op[oparg] + ')',
  147.         print
  148.  
  149. disco = disassemble                     # XXX For backwards compatibility
  150.  
  151. def findlabels(code):
  152.     """Detect all offsets in a byte code which are jump targets.
  153.  
  154.     Return the list of offsets.
  155.  
  156.     """
  157.     labels = []
  158.     n = len(code)
  159.     i = 0
  160.     while i < n:
  161.         c = code[i]
  162.         op = ord(c)
  163.         i = i+1
  164.         if op >= HAVE_ARGUMENT:
  165.             oparg = ord(code[i]) + ord(code[i+1])*256
  166.             i = i+2
  167.             label = -1
  168.             if op in hasjrel:
  169.                 label = i+oparg
  170.             elif op in hasjabs:
  171.                 label = oparg
  172.             if label >= 0:
  173.                 if label not in labels:
  174.                     labels.append(label)
  175.     return labels
  176.  
  177. def findlinestarts(code):
  178.     """Find the offsets in a byte code which are start of lines in the source.
  179.  
  180.     Generate pairs (offset, lineno) as described in Python/compile.c.
  181.  
  182.     """
  183.     byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
  184.     line_increments = [ord(c) for c in code.co_lnotab[1::2]]
  185.  
  186.     lastlineno = None
  187.     lineno = code.co_firstlineno
  188.     addr = 0
  189.     for byte_incr, line_incr in zip(byte_increments, line_increments):
  190.         if byte_incr:
  191.             if lineno != lastlineno:
  192.                 yield (addr, lineno)
  193.                 lastlineno = lineno
  194.             addr += byte_incr
  195.         lineno += line_incr
  196.     if lineno != lastlineno:
  197.         yield (addr, lineno)
  198.  
  199. def _test():
  200.     """Simple test program to disassemble a file."""
  201.     if sys.argv[1:]:
  202.         if sys.argv[2:]:
  203.             sys.stderr.write("usage: python dis.py [-|file]\n")
  204.             sys.exit(2)
  205.         fn = sys.argv[1]
  206.         if not fn or fn == "-":
  207.             fn = None
  208.     else:
  209.         fn = None
  210.     if fn is None:
  211.         f = sys.stdin
  212.     else:
  213.         f = open(fn)
  214.     source = f.read()
  215.     if fn is not None:
  216.         f.close()
  217.     else:
  218.         fn = "<stdin>"
  219.     code = compile(source, fn, "exec")
  220.     dis(code)
  221.  
  222. if __name__ == "__main__":
  223.     _test()
  224.