blob: 2b400dc88f9e784c3785982955b65c845dd0687f [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
Guido van Rossumbd307951997-01-17 20:05:04 +000013def dis(x=None):
Tim Peters88869f92001-01-14 23:36:06 +000014 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000015
Tim Peters88869f92001-01-14 23:36:06 +000016 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000017
Tim Peters88869f92001-01-14 23:36:06 +000018 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000019 if x is None:
Tim Peters88869f92001-01-14 23:36:06 +000020 distb()
21 return
Christian Heimesff737952007-11-27 10:40:20 +000022 if hasattr(x, '__func__'):
23 x = x.__func__
Neal Norwitz221085d2007-02-25 20:55:47 +000024 if hasattr(x, '__code__'):
25 x = x.__code__
Tim Peters88869f92001-01-14 23:36:06 +000026 if hasattr(x, '__dict__'):
Guido van Rossume7ba4952007-06-06 23:52:48 +000027 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000028 for name, x1 in items:
Guido van Rossume7ba4952007-06-06 23:52:48 +000029 if isinstance(x1, (types.MethodType, types.FunctionType,
Guido van Rossum13257902007-06-07 23:15:56 +000030 types.CodeType, type)):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000031 print("Disassembly of %s:" % name)
Tim Peters88869f92001-01-14 23:36:06 +000032 try:
33 dis(x1)
Guido van Rossumb940e112007-01-10 16:19:56 +000034 except TypeError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000035 print("Sorry:", msg)
36 print()
Guido van Rossumfc53c132001-01-19 02:41:41 +000037 elif hasattr(x, 'co_code'):
38 disassemble(x)
Alexandre Vassalotti267d4172008-06-04 20:26:54 +000039 elif isinstance(x, (bytes, bytearray)):
Skip Montanaro19c6ba32003-02-27 21:29:27 +000040 disassemble_string(x)
Tim Peters88869f92001-01-14 23:36:06 +000041 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000042 raise TypeError("don't know how to disassemble %s objects" %
43 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000044
Guido van Rossumbd307951997-01-17 20:05:04 +000045def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000046 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000047 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000048 try:
49 tb = sys.last_traceback
50 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000051 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000052 while tb.tb_next: tb = tb.tb_next
53 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000054
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000055# XXX This duplicates information from code.h, also duplicated in inspect.py.
56# XXX Maybe this ought to be put in a central location, like opcode.py?
57flag2name = {
58 1: "OPTIMIZED",
59 2: "NEWLOCALS",
60 4: "VARARGS",
61 8: "VARKEYWORDS",
62 16: "NESTED",
63 32: "GENERATOR",
64 64: "NOFREE",
65}
66
67def pretty_flags(flags):
68 """Return pretty representation of code flags."""
69 names = []
70 for i in range(32):
71 flag = 1<<i
72 if flags & flag:
73 names.append(flag2name.get(flag, hex(flag)))
74 flags ^= flag
75 if not flags:
76 break
77 else:
78 names.append(hex(flags))
79 return ", ".join(names)
80
81def show_code(co):
82 """Show details about a code object."""
83 print("Name: ", co.co_name)
84 print("Filename: ", co.co_filename)
85 print("Argument count: ", co.co_argcount)
86 print("Kw-only arguments:", co.co_kwonlyargcount)
87 print("Number of locals: ", co.co_nlocals)
88 print("Stack size: ", co.co_stacksize)
89 print("Flags: ", pretty_flags(co.co_flags))
90 if co.co_consts:
91 print("Constants:")
92 for i_c in enumerate(co.co_consts):
93 print("%4d: %r" % i_c)
94 if co.co_names:
95 print("Names:")
96 for i_n in enumerate(co.co_names):
97 print("%4d: %s" % i_n)
98 if co.co_varnames:
99 print("Variable names:")
100 for i_n in enumerate(co.co_varnames):
101 print("%4d: %s" % i_n)
102 if co.co_freevars:
103 print("Free variables:")
104 for i_n in enumerate(co.co_freevars):
105 print("%4d: %s" % i_n)
106 if co.co_cellvars:
107 print("Cell variables:")
108 for i_n in enumerate(co.co_cellvars):
109 print("%4d: %s" % i_n)
110
Guido van Rossumbd307951997-01-17 20:05:04 +0000111def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +0000112 """Disassemble a code object."""
113 code = co.co_code
114 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000115 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +0000116 n = len(code)
117 i = 0
118 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000119 free = None
Tim Peters88869f92001-01-14 23:36:06 +0000120 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000121 op = code[i]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000122 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000123 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000124 print()
125 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000126 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000127 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000128
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000129 if i == lasti: print('-->', end=' ')
130 else: print(' ', end=' ')
131 if i in labels: print('>>', end=' ')
132 else: print(' ', end=' ')
133 print(repr(i).rjust(4), end=' ')
134 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000135 i = i+1
136 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000137 oparg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000138 extended_arg = 0
139 i = i+2
140 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000141 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000142 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000143 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000144 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000145 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000146 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000147 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000148 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000149 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000150 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000151 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000152 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000153 elif op in hasfree:
154 if free is None:
155 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000156 print('(' + free[oparg] + ')', end=' ')
157 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000158
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000159def disassemble_string(code, lasti=-1, varnames=None, names=None,
160 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000161 labels = findlabels(code)
162 n = len(code)
163 i = 0
164 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000165 op = code[i]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000166 if i == lasti: print('-->', end=' ')
167 else: print(' ', end=' ')
168 if i in labels: print('>>', end=' ')
169 else: print(' ', end=' ')
170 print(repr(i).rjust(4), end=' ')
171 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000172 i = i+1
173 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000174 oparg = code[i] + code[i+1]*256
Tim Peters669454e2003-03-07 17:30:48 +0000175 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000176 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000177 if op in hasconst:
178 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000179 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000180 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000181 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000182 elif op in hasname:
183 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000184 print('(' + names[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 hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000188 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000189 elif op in haslocal:
190 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000191 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000192 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000193 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000194 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000195 print('(' + cmp_op[oparg] + ')', end=' ')
196 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000197
Tim Peters88869f92001-01-14 23:36:06 +0000198disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000199
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000200def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000201 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000202
Tim Peters88869f92001-01-14 23:36:06 +0000203 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000204
Tim Peters88869f92001-01-14 23:36:06 +0000205 """
206 labels = []
207 n = len(code)
208 i = 0
209 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000210 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000211 i = i+1
212 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000213 oparg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000214 i = i+2
215 label = -1
216 if op in hasjrel:
217 label = i+oparg
218 elif op in hasjabs:
219 label = oparg
220 if label >= 0:
221 if label not in labels:
222 labels.append(label)
223 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000224
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000225def findlinestarts(code):
226 """Find the offsets in a byte code which are start of lines in the source.
227
228 Generate pairs (offset, lineno) as described in Python/compile.c.
229
230 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000231 byte_increments = list(code.co_lnotab[0::2])
232 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000233
234 lastlineno = None
235 lineno = code.co_firstlineno
236 addr = 0
237 for byte_incr, line_incr in zip(byte_increments, line_increments):
238 if byte_incr:
239 if lineno != lastlineno:
240 yield (addr, lineno)
241 lastlineno = lineno
242 addr += byte_incr
243 lineno += line_incr
244 if lineno != lastlineno:
245 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000246
247def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000248 """Simple test program to disassemble a file."""
249 if sys.argv[1:]:
250 if sys.argv[2:]:
251 sys.stderr.write("usage: python dis.py [-|file]\n")
252 sys.exit(2)
253 fn = sys.argv[1]
254 if not fn or fn == "-":
255 fn = None
256 else:
257 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000258 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000259 f = sys.stdin
260 else:
261 f = open(fn)
262 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000263 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000264 f.close()
265 else:
266 fn = "<stdin>"
267 code = compile(source, fn, "exec")
268 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000269
270if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000271 _test()