blob: 2f467744d3d371a8cff98e7a767dc44622bdeb4a [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
Benjamin Peterson75edad02009-01-01 15:05:06 +00009__all__ = ["dis", "disassemble", "distb", "disco",
10 "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 """
22 # ncoghlan: currently only used by dis(), but plan to add an
23 # equivalent for show_code() as well (but one that returns a
24 # string rather than printing directly to the console)
25 try:
26 c = compile(source, name, 'eval')
27 except SyntaxError:
28 c = compile(source, name, 'exec')
29 return c
30
Guido van Rossumbd307951997-01-17 20:05:04 +000031def dis(x=None):
Tim Peters88869f92001-01-14 23:36:06 +000032 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000033
Tim Peters88869f92001-01-14 23:36:06 +000034 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000035
Tim Peters88869f92001-01-14 23:36:06 +000036 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000037 if x is None:
Tim Peters88869f92001-01-14 23:36:06 +000038 distb()
39 return
Christian Heimesff737952007-11-27 10:40:20 +000040 if hasattr(x, '__func__'):
41 x = x.__func__
Neal Norwitz221085d2007-02-25 20:55:47 +000042 if hasattr(x, '__code__'):
43 x = x.__code__
Tim Peters88869f92001-01-14 23:36:06 +000044 if hasattr(x, '__dict__'):
Guido van Rossume7ba4952007-06-06 23:52:48 +000045 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000046 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000047 if isinstance(x1, _have_code):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000048 print("Disassembly of %s:" % name)
Tim Peters88869f92001-01-14 23:36:06 +000049 try:
50 dis(x1)
Guido van Rossumb940e112007-01-10 16:19:56 +000051 except TypeError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000052 print("Sorry:", msg)
53 print()
Guido van Rossumfc53c132001-01-19 02:41:41 +000054 elif hasattr(x, 'co_code'):
55 disassemble(x)
Alexandre Vassalotti267d4172008-06-04 20:26:54 +000056 elif isinstance(x, (bytes, bytearray)):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000057 _disassemble_bytes(x)
58 elif isinstance(x, str):
59 _disassemble_str(x)
Tim Peters88869f92001-01-14 23:36:06 +000060 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000061 raise TypeError("don't know how to disassemble %s objects" %
62 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000063
Guido van Rossumbd307951997-01-17 20:05:04 +000064def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000065 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000066 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000067 try:
68 tb = sys.last_traceback
69 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000070 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000071 while tb.tb_next: tb = tb.tb_next
72 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000073
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000074# XXX This duplicates information from code.h, also duplicated in inspect.py.
75# XXX Maybe this ought to be put in a central location, like opcode.py?
76flag2name = {
77 1: "OPTIMIZED",
78 2: "NEWLOCALS",
79 4: "VARARGS",
80 8: "VARKEYWORDS",
81 16: "NESTED",
82 32: "GENERATOR",
83 64: "NOFREE",
84}
85
86def pretty_flags(flags):
87 """Return pretty representation of code flags."""
88 names = []
89 for i in range(32):
90 flag = 1<<i
91 if flags & flag:
92 names.append(flag2name.get(flag, hex(flag)))
93 flags ^= flag
94 if not flags:
95 break
96 else:
97 names.append(hex(flags))
98 return ", ".join(names)
99
100def show_code(co):
101 """Show details about a code object."""
102 print("Name: ", co.co_name)
103 print("Filename: ", co.co_filename)
104 print("Argument count: ", co.co_argcount)
105 print("Kw-only arguments:", co.co_kwonlyargcount)
106 print("Number of locals: ", co.co_nlocals)
107 print("Stack size: ", co.co_stacksize)
108 print("Flags: ", pretty_flags(co.co_flags))
109 if co.co_consts:
110 print("Constants:")
111 for i_c in enumerate(co.co_consts):
112 print("%4d: %r" % i_c)
113 if co.co_names:
114 print("Names:")
115 for i_n in enumerate(co.co_names):
116 print("%4d: %s" % i_n)
117 if co.co_varnames:
118 print("Variable names:")
119 for i_n in enumerate(co.co_varnames):
120 print("%4d: %s" % i_n)
121 if co.co_freevars:
122 print("Free variables:")
123 for i_n in enumerate(co.co_freevars):
124 print("%4d: %s" % i_n)
125 if co.co_cellvars:
126 print("Cell variables:")
127 for i_n in enumerate(co.co_cellvars):
128 print("%4d: %s" % i_n)
129
Guido van Rossumbd307951997-01-17 20:05:04 +0000130def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +0000131 """Disassemble a code object."""
132 code = co.co_code
133 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000134 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +0000135 n = len(code)
136 i = 0
137 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000138 free = None
Tim Peters88869f92001-01-14 23:36:06 +0000139 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000140 op = code[i]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000141 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000142 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000143 print()
144 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000145 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000146 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000147
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000148 if i == lasti: print('-->', end=' ')
149 else: print(' ', end=' ')
150 if i in labels: print('>>', end=' ')
151 else: print(' ', end=' ')
152 print(repr(i).rjust(4), end=' ')
153 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000154 i = i+1
155 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000156 oparg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000157 extended_arg = 0
158 i = i+2
159 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000160 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000161 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000162 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000163 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000164 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000165 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000166 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000167 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000168 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000169 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000170 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000171 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000172 elif op in hasfree:
173 if free is None:
174 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000175 print('(' + free[oparg] + ')', end=' ')
176 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000177
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000178def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000179 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000180 labels = findlabels(code)
181 n = len(code)
182 i = 0
183 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000184 op = code[i]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000185 if i == lasti: print('-->', end=' ')
186 else: print(' ', end=' ')
187 if i in labels: print('>>', end=' ')
188 else: print(' ', end=' ')
189 print(repr(i).rjust(4), end=' ')
190 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000191 i = i+1
192 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000193 oparg = code[i] + code[i+1]*256
Tim Peters669454e2003-03-07 17:30:48 +0000194 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000195 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000196 if op in hasconst:
197 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000198 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000199 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000200 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000201 elif op in hasname:
202 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000203 print('(' + names[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000204 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000205 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000206 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000207 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000208 elif op in haslocal:
209 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000210 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000211 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000212 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000213 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000214 print('(' + cmp_op[oparg] + ')', end=' ')
215 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000216
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000217def _disassemble_str(source):
218 """Compile the source string, then disassemble the code object."""
219 disassemble(_try_compile(source, '<dis>'))
220
Tim Peters88869f92001-01-14 23:36:06 +0000221disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000222
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000223def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000224 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000225
Tim Peters88869f92001-01-14 23:36:06 +0000226 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000227
Tim Peters88869f92001-01-14 23:36:06 +0000228 """
229 labels = []
230 n = len(code)
231 i = 0
232 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000233 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000234 i = i+1
235 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000236 oparg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000237 i = i+2
238 label = -1
239 if op in hasjrel:
240 label = i+oparg
241 elif op in hasjabs:
242 label = oparg
243 if label >= 0:
244 if label not in labels:
245 labels.append(label)
246 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000247
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000248def findlinestarts(code):
249 """Find the offsets in a byte code which are start of lines in the source.
250
251 Generate pairs (offset, lineno) as described in Python/compile.c.
252
253 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000254 byte_increments = list(code.co_lnotab[0::2])
255 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000256
257 lastlineno = None
258 lineno = code.co_firstlineno
259 addr = 0
260 for byte_incr, line_incr in zip(byte_increments, line_increments):
261 if byte_incr:
262 if lineno != lastlineno:
263 yield (addr, lineno)
264 lastlineno = lineno
265 addr += byte_incr
266 lineno += line_incr
267 if lineno != lastlineno:
268 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000269
270def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000271 """Simple test program to disassemble a file."""
272 if sys.argv[1:]:
273 if sys.argv[2:]:
274 sys.stderr.write("usage: python dis.py [-|file]\n")
275 sys.exit(2)
276 fn = sys.argv[1]
277 if not fn or fn == "-":
278 fn = None
279 else:
280 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000281 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000282 f = sys.stdin
283 else:
284 f = open(fn)
285 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000286 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000287 f.close()
288 else:
289 fn = "<stdin>"
290 code = compile(source, fn, "exec")
291 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000292
293if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000294 _test()