blob: f274606075b34d813bfec8b487c34450ec285219 [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
Neal Norwitz221085d2007-02-25 20:55:47 +000023 if hasattr(x, '__code__'):
24 x = x.__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 Rossum3e1b85e2007-05-30 02:07:00 +000058# XXX This duplicates information from code.h, also duplicated in inspect.py.
59# XXX Maybe this ought to be put in a central location, like opcode.py?
60flag2name = {
61 1: "OPTIMIZED",
62 2: "NEWLOCALS",
63 4: "VARARGS",
64 8: "VARKEYWORDS",
65 16: "NESTED",
66 32: "GENERATOR",
67 64: "NOFREE",
68}
69
70def pretty_flags(flags):
71 """Return pretty representation of code flags."""
72 names = []
73 for i in range(32):
74 flag = 1<<i
75 if flags & flag:
76 names.append(flag2name.get(flag, hex(flag)))
77 flags ^= flag
78 if not flags:
79 break
80 else:
81 names.append(hex(flags))
82 return ", ".join(names)
83
84def show_code(co):
85 """Show details about a code object."""
86 print("Name: ", co.co_name)
87 print("Filename: ", co.co_filename)
88 print("Argument count: ", co.co_argcount)
89 print("Kw-only arguments:", co.co_kwonlyargcount)
90 print("Number of locals: ", co.co_nlocals)
91 print("Stack size: ", co.co_stacksize)
92 print("Flags: ", pretty_flags(co.co_flags))
93 if co.co_consts:
94 print("Constants:")
95 for i_c in enumerate(co.co_consts):
96 print("%4d: %r" % i_c)
97 if co.co_names:
98 print("Names:")
99 for i_n in enumerate(co.co_names):
100 print("%4d: %s" % i_n)
101 if co.co_varnames:
102 print("Variable names:")
103 for i_n in enumerate(co.co_varnames):
104 print("%4d: %s" % i_n)
105 if co.co_freevars:
106 print("Free variables:")
107 for i_n in enumerate(co.co_freevars):
108 print("%4d: %s" % i_n)
109 if co.co_cellvars:
110 print("Cell variables:")
111 for i_n in enumerate(co.co_cellvars):
112 print("%4d: %s" % i_n)
113
Guido van Rossumbd307951997-01-17 20:05:04 +0000114def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +0000115 """Disassemble a code object."""
116 code = co.co_code
117 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000118 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +0000119 n = len(code)
120 i = 0
121 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000122 free = None
Tim Peters88869f92001-01-14 23:36:06 +0000123 while i < n:
124 c = code[i]
125 op = ord(c)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000126 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000127 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000128 print()
129 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000130 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000131 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000132
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000133 if i == lasti: print('-->', end=' ')
134 else: print(' ', end=' ')
135 if i in labels: print('>>', end=' ')
136 else: print(' ', end=' ')
137 print(repr(i).rjust(4), end=' ')
138 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000139 i = i+1
140 if op >= HAVE_ARGUMENT:
141 oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
142 extended_arg = 0
143 i = i+2
144 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000145 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000146 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000147 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000148 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000149 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000150 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000151 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000152 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000153 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000154 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000155 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000156 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000157 elif op in hasfree:
158 if free is None:
159 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000160 print('(' + free[oparg] + ')', end=' ')
161 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000162
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000163def disassemble_string(code, lasti=-1, varnames=None, names=None,
164 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000165 labels = findlabels(code)
166 n = len(code)
167 i = 0
168 while i < n:
169 c = code[i]
170 op = ord(c)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000171 if i == lasti: print('-->', end=' ')
172 else: print(' ', end=' ')
173 if i in labels: print('>>', end=' ')
174 else: print(' ', end=' ')
175 print(repr(i).rjust(4), end=' ')
176 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000177 i = i+1
178 if op >= HAVE_ARGUMENT:
179 oparg = ord(code[i]) + ord(code[i+1])*256
180 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000181 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000182 if op in hasconst:
183 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000184 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000185 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000186 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000187 elif op in hasname:
188 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000189 print('(' + names[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000190 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000191 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000192 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000193 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000194 elif op in haslocal:
195 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000196 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000197 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000198 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000199 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000200 print('(' + cmp_op[oparg] + ')', end=' ')
201 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000202
Tim Peters88869f92001-01-14 23:36:06 +0000203disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000204
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000205def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000206 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000207
Tim Peters88869f92001-01-14 23:36:06 +0000208 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000209
Tim Peters88869f92001-01-14 23:36:06 +0000210 """
211 labels = []
212 n = len(code)
213 i = 0
214 while i < n:
215 c = code[i]
216 op = ord(c)
217 i = i+1
218 if op >= HAVE_ARGUMENT:
219 oparg = ord(code[i]) + ord(code[i+1])*256
220 i = i+2
221 label = -1
222 if op in hasjrel:
223 label = i+oparg
224 elif op in hasjabs:
225 label = oparg
226 if label >= 0:
227 if label not in labels:
228 labels.append(label)
229 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000230
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000231def findlinestarts(code):
232 """Find the offsets in a byte code which are start of lines in the source.
233
234 Generate pairs (offset, lineno) as described in Python/compile.c.
235
236 """
237 byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
238 line_increments = [ord(c) for c in code.co_lnotab[1::2]]
239
240 lastlineno = None
241 lineno = code.co_firstlineno
242 addr = 0
243 for byte_incr, line_incr in zip(byte_increments, line_increments):
244 if byte_incr:
245 if lineno != lastlineno:
246 yield (addr, lineno)
247 lastlineno = lineno
248 addr += byte_incr
249 lineno += line_incr
250 if lineno != lastlineno:
251 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000252
253def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000254 """Simple test program to disassemble a file."""
255 if sys.argv[1:]:
256 if sys.argv[2:]:
257 sys.stderr.write("usage: python dis.py [-|file]\n")
258 sys.exit(2)
259 fn = sys.argv[1]
260 if not fn or fn == "-":
261 fn = None
262 else:
263 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000264 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000265 f = sys.stdin
266 else:
267 f = open(fn)
268 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000269 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000270 f.close()
271 else:
272 fn = "<stdin>"
273 code = compile(source, fn, "exec")
274 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000275
276if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000277 _test()