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()