0001 """Disassembler of Python byte code into mnemonics.""" 0002 0003 import sys 0004 import types 0005 0006 from opcode import * 0007 from opcode import __all__ as _opcodes_all 0008 0009 __all__ = ["dis","disassemble","distb","disco"] + _opcodes_all 0010 del _opcodes_all 0011 0012 def dis(x=None): 0013 """Disassemble classes, methods, functions, or code. 0014 0015 With no argument, disassemble the last traceback. 0016 0017 """ 0018 if x is None: 0019 distb() 0020 return 0021 if type(x) is types.InstanceType: 0022 x = x.__class__ 0023 if hasattr(x, 'im_func'): 0024 x = x.im_func 0025 if hasattr(x, 'func_code'): 0026 x = x.func_code 0027 if hasattr(x, '__dict__'): 0028 items = x.__dict__.items() 0029 items.sort() 0030 for name, x1 in items: 0031 if type(x1) in (types.MethodType, 0032 types.FunctionType, 0033 types.CodeType, 0034 types.ClassType): 0035 print "Disassembly of %s:" % name 0036 try: 0037 dis(x1) 0038 except TypeError, msg: 0039 print "Sorry:", msg 0040 print 0041 elif hasattr(x, 'co_code'): 0042 disassemble(x) 0043 elif isinstance(x, str): 0044 disassemble_string(x) 0045 else: 0046 raise TypeError, \ 0047 "don't know how to disassemble %s objects" % \ 0048 type(x).__name__ 0049 0050 def distb(tb=None): 0051 """Disassemble a traceback (default: last traceback).""" 0052 if tb is None: 0053 try: 0054 tb = sys.last_traceback 0055 except AttributeError: 0056 raise RuntimeError, "no last traceback to disassemble" 0057 while tb.tb_next: tb = tb.tb_next 0058 disassemble(tb.tb_frame.f_code, tb.tb_lasti) 0059 0060 def disassemble(co, lasti=-1): 0061 """Disassemble a code object.""" 0062 code = co.co_code 0063 labels = findlabels(code) 0064 linestarts = dict(findlinestarts(co)) 0065 n = len(code) 0066 i = 0 0067 extended_arg = 0 0068 free = None 0069 while i < n: 0070 c = code[i] 0071 op = ord(c) 0072 if i in linestarts: 0073 if i > 0: 0074 print 0075 print "%3d" % linestarts[i], 0076 else: 0077 print ' ', 0078 0079 if i == lasti: print '-->', 0080 else: print ' ', 0081 if i in labels: print '>>', 0082 else: print ' ', 0083 print repr(i).rjust(4), 0084 print opname[op].ljust(20), 0085 i = i+1 0086 if op >= HAVE_ARGUMENT: 0087 oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg 0088 extended_arg = 0 0089 i = i+2 0090 if op == EXTENDED_ARG: 0091 extended_arg = oparg*65536L 0092 print repr(oparg).rjust(5), 0093 if op in hasconst: 0094 print '(' + repr(co.co_consts[oparg]) + ')', 0095 elif op in hasname: 0096 print '(' + co.co_names[oparg] + ')', 0097 elif op in hasjrel: 0098 print '(to ' + repr(i + oparg) + ')', 0099 elif op in haslocal: 0100 print '(' + co.co_varnames[oparg] + ')', 0101 elif op in hascompare: 0102 print '(' + cmp_op[oparg] + ')', 0103 elif op in hasfree: 0104 if free is None: 0105 free = co.co_cellvars + co.co_freevars 0106 print '(' + free[oparg] + ')', 0107 print 0108 0109 def disassemble_string(code, lasti=-1, varnames=None, names=None, 0110 constants=None): 0111 labels = findlabels(code) 0112 n = len(code) 0113 i = 0 0114 while i < n: 0115 c = code[i] 0116 op = ord(c) 0117 if i == lasti: print '-->', 0118 else: print ' ', 0119 if i in labels: print '>>', 0120 else: print ' ', 0121 print repr(i).rjust(4), 0122 print opname[op].ljust(15), 0123 i = i+1 0124 if op >= HAVE_ARGUMENT: 0125 oparg = ord(code[i]) + ord(code[i+1])*256 0126 i = i+2 0127 print repr(oparg).rjust(5), 0128 if op in hasconst: 0129 if constants: 0130 print '(' + repr(constants[oparg]) + ')', 0131 else: 0132 print '(%d)'%oparg, 0133 elif op in hasname: 0134 if names is not None: 0135 print '(' + names[oparg] + ')', 0136 else: 0137 print '(%d)'%oparg, 0138 elif op in hasjrel: 0139 print '(to ' + repr(i + oparg) + ')', 0140 elif op in haslocal: 0141 if varnames: 0142 print '(' + varnames[oparg] + ')', 0143 else: 0144 print '(%d)' % oparg, 0145 elif op in hascompare: 0146 print '(' + cmp_op[oparg] + ')', 0147 print 0148 0149 disco = disassemble # XXX For backwards compatibility 0150 0151 def findlabels(code): 0152 """Detect all offsets in a byte code which are jump targets. 0153 0154 Return the list of offsets. 0155 0156 """ 0157 labels = [] 0158 n = len(code) 0159 i = 0 0160 while i < n: 0161 c = code[i] 0162 op = ord(c) 0163 i = i+1 0164 if op >= HAVE_ARGUMENT: 0165 oparg = ord(code[i]) + ord(code[i+1])*256 0166 i = i+2 0167 label = -1 0168 if op in hasjrel: 0169 label = i+oparg 0170 elif op in hasjabs: 0171 label = oparg 0172 if label >= 0: 0173 if label not in labels: 0174 labels.append(label) 0175 return labels 0176 0177 def findlinestarts(code): 0178 """Find the offsets in a byte code which are start of lines in the source. 0179 0180 Generate pairs (offset, lineno) as described in Python/compile.c. 0181 0182 """ 0183 byte_increments = [ord(c) for c in code.co_lnotab[0::2]] 0184 line_increments = [ord(c) for c in code.co_lnotab[1::2]] 0185 0186 lastlineno = None 0187 lineno = code.co_firstlineno 0188 addr = 0 0189 for byte_incr, line_incr in zip(byte_increments, line_increments): 0190 if byte_incr: 0191 if lineno != lastlineno: 0192 yield (addr, lineno) 0193 lastlineno = lineno 0194 addr += byte_incr 0195 lineno += line_incr 0196 if lineno != lastlineno: 0197 yield (addr, lineno) 0198 0199 def _test(): 0200 """Simple test program to disassemble a file.""" 0201 if sys.argv[1:]: 0202 if sys.argv[2:]: 0203 sys.stderr.write("usage: python dis.py [-|file]\n") 0204 sys.exit(2) 0205 fn = sys.argv[1] 0206 if not fn or fn == "-": 0207 fn = None 0208 else: 0209 fn = None 0210 if fn is None: 0211 f = sys.stdin 0212 else: 0213 f = open(fn) 0214 source = f.read() 0215 if fn is not None: 0216 f.close() 0217 else: 0218 fn = "<stdin>" 0219 code = compile(source, fn, "exec") 0220 dis(code) 0221 0222 if __name__ == "__main__": 0223 _test() 0224
Generated by PyXR 0.9.4