blob: 385c19d64c936060c05d6b4c6439e96328127540 [file] [log] [blame]
Guido van Rossum421c2241997-11-18 15:47:55 +00001"""Disassembler of Python byte code into mnemonics."""
Guido van Rossum217a5fa1990-12-26 15:40:07 +00002
3import sys
Guido van Rossum18aef3c1997-03-14 04:15:43 +00004import types
Guido van Rossum217a5fa1990-12-26 15:40:07 +00005
Skip Montanaro19c6ba32003-02-27 21:29:27 +00006from opcode import *
7from opcode import __all__ as _opcodes_all
8
9__all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
10del _opcodes_all
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000011
Guido van Rossumbd307951997-01-17 20:05:04 +000012def dis(x=None):
Tim Peters88869f92001-01-14 23:36:06 +000013 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000014
Tim Peters88869f92001-01-14 23:36:06 +000015 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000016
Tim Peters88869f92001-01-14 23:36:06 +000017 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000018 if x is None:
Tim Peters88869f92001-01-14 23:36:06 +000019 distb()
20 return
Guido van Rossumfc53c132001-01-19 02:41:41 +000021 if hasattr(x, 'im_func'):
22 x = x.im_func
23 if hasattr(x, 'func_code'):
24 x = x.func_code
Tim Peters88869f92001-01-14 23:36:06 +000025 if hasattr(x, '__dict__'):
26 items = x.__dict__.items()
27 items.sort()
28 for name, x1 in items:
29 if type(x1) in (types.MethodType,
30 types.FunctionType,
Skip Montanaro19c6ba32003-02-27 21:29:27 +000031 types.CodeType,
32 types.ClassType):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000033 print("Disassembly of %s:" % name)
Tim Peters88869f92001-01-14 23:36:06 +000034 try:
35 dis(x1)
Guido van Rossumb940e112007-01-10 16:19:56 +000036 except TypeError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000037 print("Sorry:", msg)
38 print()
Guido van Rossumfc53c132001-01-19 02:41:41 +000039 elif hasattr(x, 'co_code'):
40 disassemble(x)
Skip Montanaro19c6ba32003-02-27 21:29:27 +000041 elif isinstance(x, str):
42 disassemble_string(x)
Tim Peters88869f92001-01-14 23:36:06 +000043 else:
Guido van Rossumfc53c132001-01-19 02:41:41 +000044 raise TypeError, \
45 "don't know how to disassemble %s objects" % \
46 type(x).__name__
Guido van Rossum217a5fa1990-12-26 15:40:07 +000047
Guido van Rossumbd307951997-01-17 20:05:04 +000048def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000049 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000050 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000051 try:
52 tb = sys.last_traceback
53 except AttributeError:
54 raise RuntimeError, "no last traceback to disassemble"
55 while tb.tb_next: tb = tb.tb_next
56 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000057
Guido van Rossumbd307951997-01-17 20:05:04 +000058def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +000059 """Disassemble a code object."""
60 code = co.co_code
61 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +000062 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +000063 n = len(code)
64 i = 0
65 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +000066 free = None
Tim Peters88869f92001-01-14 23:36:06 +000067 while i < n:
68 c = code[i]
69 op = ord(c)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +000070 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +000071 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000072 print()
73 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +000074 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000075 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +000076
Guido van Rossumbe19ed72007-02-09 05:37:30 +000077 if i == lasti: print('-->', end=' ')
78 else: print(' ', end=' ')
79 if i in labels: print('>>', end=' ')
80 else: print(' ', end=' ')
81 print(repr(i).rjust(4), end=' ')
82 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000083 i = i+1
84 if op >= HAVE_ARGUMENT:
85 oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
86 extended_arg = 0
87 i = i+2
88 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +000089 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +000090 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000091 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000092 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000093 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000094 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000095 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000096 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000097 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000098 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +000099 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000100 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000101 elif op in hasfree:
102 if free is None:
103 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000104 print('(' + free[oparg] + ')', end=' ')
105 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000106
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000107def disassemble_string(code, lasti=-1, varnames=None, names=None,
108 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000109 labels = findlabels(code)
110 n = len(code)
111 i = 0
112 while i < n:
113 c = code[i]
114 op = ord(c)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000115 if i == lasti: print('-->', end=' ')
116 else: print(' ', end=' ')
117 if i in labels: print('>>', end=' ')
118 else: print(' ', end=' ')
119 print(repr(i).rjust(4), end=' ')
120 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000121 i = i+1
122 if op >= HAVE_ARGUMENT:
123 oparg = ord(code[i]) + ord(code[i+1])*256
124 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000125 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000126 if op in hasconst:
127 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000128 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000129 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000130 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000131 elif op in hasname:
132 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000133 print('(' + names[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000134 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000135 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000136 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000137 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000138 elif op in haslocal:
139 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000140 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000141 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000142 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000143 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000144 print('(' + cmp_op[oparg] + ')', end=' ')
145 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000146
Tim Peters88869f92001-01-14 23:36:06 +0000147disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000148
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000149def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000150 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000151
Tim Peters88869f92001-01-14 23:36:06 +0000152 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000153
Tim Peters88869f92001-01-14 23:36:06 +0000154 """
155 labels = []
156 n = len(code)
157 i = 0
158 while i < n:
159 c = code[i]
160 op = ord(c)
161 i = i+1
162 if op >= HAVE_ARGUMENT:
163 oparg = ord(code[i]) + ord(code[i+1])*256
164 i = i+2
165 label = -1
166 if op in hasjrel:
167 label = i+oparg
168 elif op in hasjabs:
169 label = oparg
170 if label >= 0:
171 if label not in labels:
172 labels.append(label)
173 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000174
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000175def findlinestarts(code):
176 """Find the offsets in a byte code which are start of lines in the source.
177
178 Generate pairs (offset, lineno) as described in Python/compile.c.
179
180 """
181 byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
182 line_increments = [ord(c) for c in code.co_lnotab[1::2]]
183
184 lastlineno = None
185 lineno = code.co_firstlineno
186 addr = 0
187 for byte_incr, line_incr in zip(byte_increments, line_increments):
188 if byte_incr:
189 if lineno != lastlineno:
190 yield (addr, lineno)
191 lastlineno = lineno
192 addr += byte_incr
193 lineno += line_incr
194 if lineno != lastlineno:
195 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000196
197def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000198 """Simple test program to disassemble a file."""
199 if sys.argv[1:]:
200 if sys.argv[2:]:
201 sys.stderr.write("usage: python dis.py [-|file]\n")
202 sys.exit(2)
203 fn = sys.argv[1]
204 if not fn or fn == "-":
205 fn = None
206 else:
207 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000208 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000209 f = sys.stdin
210 else:
211 f = open(fn)
212 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000213 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000214 f.close()
215 else:
216 fn = "<stdin>"
217 code = compile(source, fn, "exec")
218 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000219
220if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000221 _test()