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