home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / DIS.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  7.5 KB  |  304 lines

  1. """Disassembler of Python byte code into mnemonics."""
  2.  
  3. import sys
  4. import string
  5. import types
  6.  
  7. def dis(x=None):
  8.     """Disassemble classes, methods, functions, or code.
  9.  
  10.     With no argument, disassemble the last traceback.
  11.  
  12.     """
  13.     if not x:
  14.         distb()
  15.         return
  16.     if type(x) is types.InstanceType:
  17.         x = x.__class__
  18.     if hasattr(x, '__dict__'):
  19.         items = x.__dict__.items()
  20.         items.sort()
  21.         for name, x1 in items:
  22.             if type(x1) in (types.MethodType,
  23.                     types.FunctionType,
  24.                     types.CodeType):
  25.                 print "Disassembly of %s:" % name
  26.                 try:
  27.                     dis(x1)
  28.                 except TypeError, msg:
  29.                     print "Sorry:", msg
  30.                 print
  31.     else:
  32.         if hasattr(x, 'im_func'):
  33.             x = x.im_func
  34.         if hasattr(x, 'func_code'):
  35.             x = x.func_code
  36.         if hasattr(x, 'co_code'):
  37.             disassemble(x)
  38.         else:
  39.             raise TypeError, \
  40.                   "don't know how to disassemble %s objects" % \
  41.                   type(x).__name__
  42.  
  43. def distb(tb=None):
  44.     """Disassemble a traceback (default: last traceback)."""
  45.     if not tb:
  46.         try:
  47.             tb = sys.last_traceback
  48.         except AttributeError:
  49.             raise RuntimeError, "no last traceback to disassemble"
  50.         while tb.tb_next: tb = tb.tb_next
  51.     disassemble(tb.tb_frame.f_code, tb.tb_lasti)
  52.  
  53. def disassemble(co, lasti=-1):
  54.     """Disassemble a code object."""
  55.     code = co.co_code
  56.     labels = findlabels(code)
  57.     n = len(code)
  58.     i = 0
  59.     extended_arg = 0
  60.     while i < n:
  61.         c = code[i]
  62.         op = ord(c)
  63.         if op == SET_LINENO and i > 0: print # Extra blank line
  64.         if i == lasti: print '-->',
  65.         else: print '   ',
  66.         if i in labels: print '>>',
  67.         else: print '  ',
  68.         print string.rjust(`i`, 4),
  69.         print string.ljust(opname[op], 20),
  70.         i = i+1
  71.         if op >= HAVE_ARGUMENT:
  72.             oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
  73.             extended_arg = 0
  74.             i = i+2
  75.             if op == EXTENDED_ARG:
  76.                 extended_arg = oparg*65536L
  77.             print string.rjust(`oparg`, 5),
  78.             if op in hasconst:
  79.                 print '(' + `co.co_consts[oparg]` + ')',
  80.             elif op in hasname:
  81.                 print '(' + co.co_names[oparg] + ')',
  82.             elif op in hasjrel:
  83.                 print '(to ' + `i + oparg` + ')',
  84.             elif op in haslocal:
  85.                 print '(' + co.co_varnames[oparg] + ')',
  86.             elif op in hascompare:
  87.                 print '(' + cmp_op[oparg] + ')',
  88.         print
  89.  
  90. disco = disassemble            # XXX For backwards compatibility
  91.  
  92. def findlabels(code):
  93.     """Detect all offsets in a byte code which are jump targets.
  94.  
  95.     Return the list of offsets.
  96.  
  97.     """
  98.     labels = []
  99.     n = len(code)
  100.     i = 0
  101.     while i < n:
  102.         c = code[i]
  103.         op = ord(c)
  104.         i = i+1
  105.         if op >= HAVE_ARGUMENT:
  106.             oparg = ord(code[i]) + ord(code[i+1])*256
  107.             i = i+2
  108.             label = -1
  109.             if op in hasjrel:
  110.                 label = i+oparg
  111.             elif op in hasjabs:
  112.                 label = oparg
  113.             if label >= 0:
  114.                 if label not in labels:
  115.                     labels.append(label)
  116.     return labels
  117.  
  118. cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
  119.         'is not', 'exception match', 'BAD')
  120.  
  121. hasconst = []
  122. hasname = []
  123. hasjrel = []
  124. hasjabs = []
  125. haslocal = []
  126. hascompare = []
  127.  
  128. opname = [''] * 256
  129. for op in range(256): opname[op] = '<' + `op` + '>'
  130.  
  131. def def_op(name, op):
  132.     opname[op] = name
  133.  
  134. def name_op(name, op):
  135.     opname[op] = name
  136.     hasname.append(op)
  137.  
  138. def jrel_op(name, op):
  139.     opname[op] = name
  140.     hasjrel.append(op)
  141.  
  142. def jabs_op(name, op):
  143.     opname[op] = name
  144.     hasjabs.append(op)
  145.  
  146. # Instruction opcodes for compiled code
  147.  
  148. def_op('STOP_CODE', 0)
  149. def_op('POP_TOP', 1)
  150. def_op('ROT_TWO', 2)
  151. def_op('ROT_THREE', 3)
  152. def_op('DUP_TOP', 4)
  153. def_op('ROT_FOUR', 5)
  154.  
  155. def_op('UNARY_POSITIVE', 10)
  156. def_op('UNARY_NEGATIVE', 11)
  157. def_op('UNARY_NOT', 12)
  158. def_op('UNARY_CONVERT', 13)
  159.  
  160. def_op('UNARY_INVERT', 15)
  161.  
  162. def_op('BINARY_POWER', 19)
  163.  
  164. def_op('BINARY_MULTIPLY', 20)
  165. def_op('BINARY_DIVIDE', 21)
  166. def_op('BINARY_MODULO', 22)
  167. def_op('BINARY_ADD', 23)
  168. def_op('BINARY_SUBTRACT', 24)
  169. def_op('BINARY_SUBSCR', 25)
  170.  
  171. def_op('SLICE+0', 30)
  172. def_op('SLICE+1', 31)
  173. def_op('SLICE+2', 32)
  174. def_op('SLICE+3', 33)
  175.  
  176. def_op('STORE_SLICE+0', 40)
  177. def_op('STORE_SLICE+1', 41)
  178. def_op('STORE_SLICE+2', 42)
  179. def_op('STORE_SLICE+3', 43)
  180.  
  181. def_op('DELETE_SLICE+0', 50)
  182. def_op('DELETE_SLICE+1', 51)
  183. def_op('DELETE_SLICE+2', 52)
  184. def_op('DELETE_SLICE+3', 53)
  185.  
  186. def_op('INPLACE_ADD', 55)
  187. def_op('INPLACE_SUBTRACT', 56)
  188. def_op('INPLACE_MULTIPLY', 57)
  189. def_op('INPLACE_DIVIDE', 58)
  190. def_op('INPLACE_MODULO', 59)
  191. def_op('STORE_SUBSCR', 60)
  192. def_op('DELETE_SUBSCR', 61)
  193.  
  194. def_op('BINARY_LSHIFT', 62)
  195. def_op('BINARY_RSHIFT', 63)
  196. def_op('BINARY_AND', 64)
  197. def_op('BINARY_XOR', 65)
  198. def_op('BINARY_OR', 66)
  199. def_op('INPLACE_POWER', 67)
  200.  
  201. def_op('PRINT_EXPR', 70)
  202. def_op('PRINT_ITEM', 71)
  203. def_op('PRINT_NEWLINE', 72)
  204. def_op('PRINT_ITEM_TO', 73)
  205. def_op('PRINT_NEWLINE_TO', 74)
  206. def_op('INPLACE_LSHIFT', 75)
  207. def_op('INPLACE_RSHIFT', 76)
  208. def_op('INPLACE_AND', 77)
  209. def_op('INPLACE_XOR', 78)
  210. def_op('INPLACE_OR', 79)
  211. def_op('BREAK_LOOP', 80)
  212.  
  213. def_op('LOAD_LOCALS', 82)
  214. def_op('RETURN_VALUE', 83)
  215. def_op('IMPORT_STAR', 84)
  216. def_op('EXEC_STMT', 85)
  217.  
  218. def_op('POP_BLOCK', 87)
  219. def_op('END_FINALLY', 88)
  220. def_op('BUILD_CLASS', 89)
  221.  
  222. HAVE_ARGUMENT = 90        # Opcodes from here have an argument: 
  223.  
  224. name_op('STORE_NAME', 90)    # Index in name list 
  225. name_op('DELETE_NAME', 91)    # "" 
  226. def_op('UNPACK_SEQUENCE', 92)    # Number of tuple items 
  227.  
  228. name_op('STORE_ATTR', 95)    # Index in name list 
  229. name_op('DELETE_ATTR', 96)    # ""
  230. name_op('STORE_GLOBAL', 97)    # ""
  231. name_op('DELETE_GLOBAL', 98)    # ""
  232. def_op('DUP_TOPX', 99)        # number of items to duplicate
  233. def_op('LOAD_CONST', 100)    # Index in const list 
  234. hasconst.append(100)
  235. name_op('LOAD_NAME', 101)    # Index in name list 
  236. def_op('BUILD_TUPLE', 102)    # Number of tuple items 
  237. def_op('BUILD_LIST', 103)    # Number of list items 
  238. def_op('BUILD_MAP', 104)    # Always zero for now 
  239. name_op('LOAD_ATTR', 105)    # Index in name list 
  240. def_op('COMPARE_OP', 106)    # Comparison operator 
  241. hascompare.append(106)
  242. name_op('IMPORT_NAME', 107)    # Index in name list 
  243. name_op('IMPORT_FROM', 108)    # Index in name list 
  244.  
  245. jrel_op('JUMP_FORWARD', 110)    # Number of bytes to skip 
  246. jrel_op('JUMP_IF_FALSE', 111)    # "" 
  247. jrel_op('JUMP_IF_TRUE', 112)    # "" 
  248. jabs_op('JUMP_ABSOLUTE', 113)    # Target byte offset from beginning of code 
  249. jrel_op('FOR_LOOP', 114)    # Number of bytes to skip 
  250.  
  251. name_op('LOAD_GLOBAL', 116)    # Index in name list
  252.  
  253. jrel_op('SETUP_LOOP', 120)    # Distance to target address
  254. jrel_op('SETUP_EXCEPT', 121)    # ""
  255. jrel_op('SETUP_FINALLY', 122)    # ""
  256.  
  257. def_op('LOAD_FAST', 124)    # Local variable number
  258. haslocal.append(124)
  259. def_op('STORE_FAST', 125)    # Local variable number
  260. haslocal.append(125)
  261. def_op('DELETE_FAST', 126)    # Local variable number
  262. haslocal.append(126)
  263.  
  264. def_op('SET_LINENO', 127)    # Current line number
  265. SET_LINENO = 127
  266.  
  267. def_op('RAISE_VARARGS', 130)    # Number of raise arguments (1, 2, or 3)
  268. def_op('CALL_FUNCTION', 131)    # #args + (#kwargs << 8)
  269. def_op('MAKE_FUNCTION', 132)    # Number of args with default values
  270. def_op('BUILD_SLICE', 133)      # Number of items
  271.  
  272. def_op('CALL_FUNCTION_VAR', 140)     # #args + (#kwargs << 8)
  273. def_op('CALL_FUNCTION_KW', 141)      # #args + (#kwargs << 8)
  274. def_op('CALL_FUNCTION_VAR_KW', 142)  # #args + (#kwargs << 8)
  275.  
  276. def_op('EXTENDED_ARG', 143) 
  277. EXTENDED_ARG = 143
  278.  
  279. def _test():
  280.     """Simple test program to disassemble a file."""
  281.     if sys.argv[1:]:
  282.         if sys.argv[2:]:
  283.             sys.stderr.write("usage: python dis.py [-|file]\n")
  284.             sys.exit(2)
  285.         fn = sys.argv[1]
  286.         if not fn or fn == "-":
  287.             fn = None
  288.     else:
  289.         fn = None
  290.     if not fn:
  291.         f = sys.stdin
  292.     else:
  293.         f = open(fn)
  294.     source = f.read()
  295.     if fn:
  296.         f.close()
  297.     else:
  298.         fn = "<stdin>"
  299.     code = compile(source, fn, "exec")
  300.     dis(code)
  301.  
  302. if __name__ == "__main__":
  303.     _test()
  304.