blob: 1f560142534cde9178f22e245c9d1d4923d8df46 [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
Nick Coghlan7646f7e2010-09-10 12:24:24 +00009__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
Nick Coghlanc02adca2010-09-10 12:32:58 +000010 "findlinestarts", "findlabels"] + _opcodes_all
Skip Montanaro19c6ba32003-02-27 21:29:27 +000011del _opcodes_all
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000012
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000013_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
14
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000015def _try_compile(source, name):
16 """Attempts to compile the given source, first as an expression and
17 then as a statement if the first approach fails.
18
19 Utility function to accept strings in functions that otherwise
20 expect code objects
21 """
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000022 try:
23 c = compile(source, name, 'eval')
24 except SyntaxError:
25 c = compile(source, name, 'exec')
26 return c
27
Guido van Rossumbd307951997-01-17 20:05:04 +000028def dis(x=None):
Tim Peters88869f92001-01-14 23:36:06 +000029 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000030
Tim Peters88869f92001-01-14 23:36:06 +000031 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000032
Tim Peters88869f92001-01-14 23:36:06 +000033 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000034 if x is None:
Tim Peters88869f92001-01-14 23:36:06 +000035 distb()
36 return
Nick Coghlaneae2da12010-08-17 08:03:36 +000037 if hasattr(x, '__func__'): # Method
Christian Heimesff737952007-11-27 10:40:20 +000038 x = x.__func__
Nick Coghlaneae2da12010-08-17 08:03:36 +000039 if hasattr(x, '__code__'): # Function
Neal Norwitz221085d2007-02-25 20:55:47 +000040 x = x.__code__
Nick Coghlaneae2da12010-08-17 08:03:36 +000041 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000042 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000043 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000044 if isinstance(x1, _have_code):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000045 print("Disassembly of %s:" % name)
Tim Peters88869f92001-01-14 23:36:06 +000046 try:
47 dis(x1)
Guido van Rossumb940e112007-01-10 16:19:56 +000048 except TypeError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000049 print("Sorry:", msg)
50 print()
Nick Coghlaneae2da12010-08-17 08:03:36 +000051 elif hasattr(x, 'co_code'): # Code object
Guido van Rossumfc53c132001-01-19 02:41:41 +000052 disassemble(x)
Nick Coghlaneae2da12010-08-17 08:03:36 +000053 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000054 _disassemble_bytes(x)
Nick Coghlaneae2da12010-08-17 08:03:36 +000055 elif isinstance(x, str): # Source code
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000056 _disassemble_str(x)
Tim Peters88869f92001-01-14 23:36:06 +000057 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000058 raise TypeError("don't know how to disassemble %s objects" %
59 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000060
Guido van Rossumbd307951997-01-17 20:05:04 +000061def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000062 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000063 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000064 try:
65 tb = sys.last_traceback
66 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000067 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000068 while tb.tb_next: tb = tb.tb_next
69 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000070
Nick Coghlan09c81232010-08-17 10:18:16 +000071# The inspect module interrogates this dictionary to build its
72# list of CO_* constants. It is also used by pretty_flags to
73# turn the co_flags field into a human readable list.
74COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000075 1: "OPTIMIZED",
76 2: "NEWLOCALS",
77 4: "VARARGS",
78 8: "VARKEYWORDS",
79 16: "NESTED",
80 32: "GENERATOR",
81 64: "NOFREE",
82}
83
84def pretty_flags(flags):
85 """Return pretty representation of code flags."""
86 names = []
87 for i in range(32):
88 flag = 1<<i
89 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000090 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000091 flags ^= flag
92 if not flags:
93 break
94 else:
95 names.append(hex(flags))
96 return ", ".join(names)
97
Nick Coghlaneae2da12010-08-17 08:03:36 +000098def code_info(x):
99 """Formatted details of methods, functions, or code."""
100 if hasattr(x, '__func__'): # Method
101 x = x.__func__
102 if hasattr(x, '__code__'): # Function
103 x = x.__code__
104 if isinstance(x, str): # Source code
105 x = _try_compile(x, "<code_info>")
106 if hasattr(x, 'co_code'): # Code object
107 return _format_code_info(x)
108 else:
109 raise TypeError("don't know how to disassemble %s objects" %
110 type(x).__name__)
111
112def _format_code_info(co):
113 lines = []
114 lines.append("Name: %s" % co.co_name)
115 lines.append("Filename: %s" % co.co_filename)
116 lines.append("Argument count: %s" % co.co_argcount)
117 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
118 lines.append("Number of locals: %s" % co.co_nlocals)
119 lines.append("Stack size: %s" % co.co_stacksize)
120 lines.append("Flags: %s" % pretty_flags(co.co_flags))
121 if co.co_consts:
122 lines.append("Constants:")
123 for i_c in enumerate(co.co_consts):
124 lines.append("%4d: %r" % i_c)
125 if co.co_names:
126 lines.append("Names:")
127 for i_n in enumerate(co.co_names):
128 lines.append("%4d: %s" % i_n)
129 if co.co_varnames:
130 lines.append("Variable names:")
131 for i_n in enumerate(co.co_varnames):
132 lines.append("%4d: %s" % i_n)
133 if co.co_freevars:
134 lines.append("Free variables:")
135 for i_n in enumerate(co.co_freevars):
136 lines.append("%4d: %s" % i_n)
137 if co.co_cellvars:
138 lines.append("Cell variables:")
139 for i_n in enumerate(co.co_cellvars):
140 lines.append("%4d: %s" % i_n)
141 return "\n".join(lines)
142
Nick Coghlanc02adca2010-09-10 12:32:58 +0000143# show_code is deliberately undocumented and left out of __all__,
144# since it doesn't offer any real benefit over code_info() above
145# It is only retained because it already existed and was not
146# marked as private in previous versions of Python
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000147def show_code(co):
148 """Show details about a code object."""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000149 print(code_info(co))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000150
Guido van Rossumbd307951997-01-17 20:05:04 +0000151def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +0000152 """Disassemble a code object."""
153 code = co.co_code
154 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000155 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +0000156 n = len(code)
157 i = 0
158 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000159 free = None
Tim Peters88869f92001-01-14 23:36:06 +0000160 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000161 op = code[i]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000162 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000163 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000164 print()
165 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000166 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000167 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000168
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000169 if i == lasti: print('-->', end=' ')
170 else: print(' ', end=' ')
171 if i in labels: print('>>', end=' ')
172 else: print(' ', end=' ')
173 print(repr(i).rjust(4), end=' ')
174 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000175 i = i+1
176 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000177 oparg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000178 extended_arg = 0
179 i = i+2
180 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000181 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000182 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000183 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000184 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000185 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000186 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000187 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000188 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000189 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000190 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000191 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000192 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000193 elif op in hasfree:
194 if free is None:
195 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000196 print('(' + free[oparg] + ')', end=' ')
197 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000198
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000199def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000200 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000201 labels = findlabels(code)
202 n = len(code)
203 i = 0
204 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000205 op = code[i]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000206 if i == lasti: print('-->', end=' ')
207 else: print(' ', end=' ')
208 if i in labels: print('>>', end=' ')
209 else: print(' ', end=' ')
210 print(repr(i).rjust(4), end=' ')
211 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000212 i = i+1
213 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000214 oparg = code[i] + code[i+1]*256
Tim Peters669454e2003-03-07 17:30:48 +0000215 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000216 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000217 if op in hasconst:
218 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000219 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000220 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000221 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000222 elif op in hasname:
223 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000224 print('(' + names[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000225 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000226 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000227 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000228 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000229 elif op in haslocal:
230 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000231 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000232 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000233 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000234 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000235 print('(' + cmp_op[oparg] + ')', end=' ')
236 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000237
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000238def _disassemble_str(source):
239 """Compile the source string, then disassemble the code object."""
240 disassemble(_try_compile(source, '<dis>'))
241
Tim Peters88869f92001-01-14 23:36:06 +0000242disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000243
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000244def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000245 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000246
Tim Peters88869f92001-01-14 23:36:06 +0000247 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000248
Tim Peters88869f92001-01-14 23:36:06 +0000249 """
250 labels = []
251 n = len(code)
252 i = 0
253 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000254 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000255 i = i+1
256 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000257 oparg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000258 i = i+2
259 label = -1
260 if op in hasjrel:
261 label = i+oparg
262 elif op in hasjabs:
263 label = oparg
264 if label >= 0:
265 if label not in labels:
266 labels.append(label)
267 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000268
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000269def findlinestarts(code):
270 """Find the offsets in a byte code which are start of lines in the source.
271
272 Generate pairs (offset, lineno) as described in Python/compile.c.
273
274 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000275 byte_increments = list(code.co_lnotab[0::2])
276 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000277
278 lastlineno = None
279 lineno = code.co_firstlineno
280 addr = 0
281 for byte_incr, line_incr in zip(byte_increments, line_increments):
282 if byte_incr:
283 if lineno != lastlineno:
284 yield (addr, lineno)
285 lastlineno = lineno
286 addr += byte_incr
287 lineno += line_incr
288 if lineno != lastlineno:
289 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000290
291def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000292 """Simple test program to disassemble a file."""
293 if sys.argv[1:]:
294 if sys.argv[2:]:
295 sys.stderr.write("usage: python dis.py [-|file]\n")
296 sys.exit(2)
297 fn = sys.argv[1]
298 if not fn or fn == "-":
299 fn = None
300 else:
301 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000302 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000303 f = sys.stdin
304 else:
305 f = open(fn)
306 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000307 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000308 f.close()
309 else:
310 fn = "<stdin>"
311 code = compile(source, fn, "exec")
312 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000313
314if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000315 _test()