blob: 4cf452a097ab9d1577e9d5cbe2caca1247efeb29 [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__'):
Guido van Rossume7ba4952007-06-06 23:52:48 +000026 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000027 for name, x1 in items:
Guido van Rossume7ba4952007-06-06 23:52:48 +000028 if isinstance(x1, (types.MethodType, types.FunctionType,
Guido van Rossum13257902007-06-07 23:15:56 +000029 types.CodeType, type)):
Guido van Rossumbe19ed72007-02-09 05:37:30 +000030 print("Disassembly of %s:" % name)
Tim Peters88869f92001-01-14 23:36:06 +000031 try:
32 dis(x1)
Guido van Rossumb940e112007-01-10 16:19:56 +000033 except TypeError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +000034 print("Sorry:", msg)
35 print()
Guido van Rossumfc53c132001-01-19 02:41:41 +000036 elif hasattr(x, 'co_code'):
37 disassemble(x)
Skip Montanaro19c6ba32003-02-27 21:29:27 +000038 elif isinstance(x, str):
39 disassemble_string(x)
Tim Peters88869f92001-01-14 23:36:06 +000040 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000041 raise TypeError("don't know how to disassemble %s objects" %
42 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000043
Guido van Rossumbd307951997-01-17 20:05:04 +000044def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000045 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000046 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000047 try:
48 tb = sys.last_traceback
49 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000050 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000051 while tb.tb_next: tb = tb.tb_next
52 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000053
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000054# XXX This duplicates information from code.h, also duplicated in inspect.py.
55# XXX Maybe this ought to be put in a central location, like opcode.py?
56flag2name = {
57 1: "OPTIMIZED",
58 2: "NEWLOCALS",
59 4: "VARARGS",
60 8: "VARKEYWORDS",
61 16: "NESTED",
62 32: "GENERATOR",
63 64: "NOFREE",
64}
65
66def pretty_flags(flags):
67 """Return pretty representation of code flags."""
68 names = []
69 for i in range(32):
70 flag = 1<<i
71 if flags & flag:
72 names.append(flag2name.get(flag, hex(flag)))
73 flags ^= flag
74 if not flags:
75 break
76 else:
77 names.append(hex(flags))
78 return ", ".join(names)
79
80def show_code(co):
81 """Show details about a code object."""
82 print("Name: ", co.co_name)
83 print("Filename: ", co.co_filename)
84 print("Argument count: ", co.co_argcount)
85 print("Kw-only arguments:", co.co_kwonlyargcount)
86 print("Number of locals: ", co.co_nlocals)
87 print("Stack size: ", co.co_stacksize)
88 print("Flags: ", pretty_flags(co.co_flags))
89 if co.co_consts:
90 print("Constants:")
91 for i_c in enumerate(co.co_consts):
92 print("%4d: %r" % i_c)
93 if co.co_names:
94 print("Names:")
95 for i_n in enumerate(co.co_names):
96 print("%4d: %s" % i_n)
97 if co.co_varnames:
98 print("Variable names:")
99 for i_n in enumerate(co.co_varnames):
100 print("%4d: %s" % i_n)
101 if co.co_freevars:
102 print("Free variables:")
103 for i_n in enumerate(co.co_freevars):
104 print("%4d: %s" % i_n)
105 if co.co_cellvars:
106 print("Cell variables:")
107 for i_n in enumerate(co.co_cellvars):
108 print("%4d: %s" % i_n)
109
Guido van Rossumbd307951997-01-17 20:05:04 +0000110def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +0000111 """Disassemble a code object."""
112 code = co.co_code
113 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000114 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +0000115 n = len(code)
116 i = 0
117 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000118 free = None
Tim Peters88869f92001-01-14 23:36:06 +0000119 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000120 op = code[i]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000121 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000122 if i > 0:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000123 print()
124 print("%3d" % linestarts[i], end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000125 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000126 print(' ', end=' ')
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000127
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000128 if i == lasti: print('-->', end=' ')
129 else: print(' ', end=' ')
130 if i in labels: print('>>', end=' ')
131 else: print(' ', end=' ')
132 print(repr(i).rjust(4), end=' ')
133 print(opname[op].ljust(20), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000134 i = i+1
135 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000136 oparg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000137 extended_arg = 0
138 i = i+2
139 if op == EXTENDED_ARG:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000140 extended_arg = oparg*65536
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000141 print(repr(oparg).rjust(5), end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000142 if op in hasconst:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000143 print('(' + repr(co.co_consts[oparg]) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000144 elif op in hasname:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000145 print('(' + co.co_names[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000146 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000147 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000148 elif op in haslocal:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000149 print('(' + co.co_varnames[oparg] + ')', end=' ')
Tim Peters88869f92001-01-14 23:36:06 +0000150 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000151 print('(' + cmp_op[oparg] + ')', end=' ')
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000152 elif op in hasfree:
153 if free is None:
154 free = co.co_cellvars + co.co_freevars
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000155 print('(' + free[oparg] + ')', end=' ')
156 print()
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000157
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000158def disassemble_string(code, lasti=-1, varnames=None, names=None,
159 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000160 labels = findlabels(code)
161 n = len(code)
162 i = 0
163 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000164 op = code[i]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000165 if i == lasti: print('-->', end=' ')
166 else: print(' ', end=' ')
167 if i in labels: print('>>', end=' ')
168 else: print(' ', end=' ')
169 print(repr(i).rjust(4), end=' ')
170 print(opname[op].ljust(15), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000171 i = i+1
172 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000173 oparg = code[i] + code[i+1]*256
Tim Peters669454e2003-03-07 17:30:48 +0000174 i = i+2
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000175 print(repr(oparg).rjust(5), end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000176 if op in hasconst:
177 if constants:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000178 print('(' + repr(constants[oparg]) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000179 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000180 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000181 elif op in hasname:
182 if names is not None:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000183 print('(' + names[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000184 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000185 print('(%d)'%oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000186 elif op in hasjrel:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000187 print('(to ' + repr(i + oparg) + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000188 elif op in haslocal:
189 if varnames:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000190 print('(' + varnames[oparg] + ')', end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000191 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000192 print('(%d)' % oparg, end=' ')
Tim Peters669454e2003-03-07 17:30:48 +0000193 elif op in hascompare:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000194 print('(' + cmp_op[oparg] + ')', end=' ')
195 print()
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000196
Tim Peters88869f92001-01-14 23:36:06 +0000197disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000198
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000199def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000200 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000201
Tim Peters88869f92001-01-14 23:36:06 +0000202 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000203
Tim Peters88869f92001-01-14 23:36:06 +0000204 """
205 labels = []
206 n = len(code)
207 i = 0
208 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000209 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000210 i = i+1
211 if op >= HAVE_ARGUMENT:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000212 oparg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000213 i = i+2
214 label = -1
215 if op in hasjrel:
216 label = i+oparg
217 elif op in hasjabs:
218 label = oparg
219 if label >= 0:
220 if label not in labels:
221 labels.append(label)
222 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000223
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000224def findlinestarts(code):
225 """Find the offsets in a byte code which are start of lines in the source.
226
227 Generate pairs (offset, lineno) as described in Python/compile.c.
228
229 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000230 byte_increments = list(code.co_lnotab[0::2])
231 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000232
233 lastlineno = None
234 lineno = code.co_firstlineno
235 addr = 0
236 for byte_incr, line_incr in zip(byte_increments, line_increments):
237 if byte_incr:
238 if lineno != lastlineno:
239 yield (addr, lineno)
240 lastlineno = lineno
241 addr += byte_incr
242 lineno += line_incr
243 if lineno != lastlineno:
244 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000245
246def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000247 """Simple test program to disassemble a file."""
248 if sys.argv[1:]:
249 if sys.argv[2:]:
250 sys.stderr.write("usage: python dis.py [-|file]\n")
251 sys.exit(2)
252 fn = sys.argv[1]
253 if not fn or fn == "-":
254 fn = None
255 else:
256 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000257 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000258 f = sys.stdin
259 else:
260 f = open(fn)
261 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000262 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000263 f.close()
264 else:
265 fn = "<stdin>"
266 code = compile(source, fn, "exec")
267 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000268
269if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000270 _test()