blob: 90ddf4f3360324ce7ccc2c153aa8cad015cbcacd [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
Nick Coghlanb39fd0c2013-05-06 23:59:20 +10005import collections
Nick Coghlan90b8e7d2013-11-06 22:08:36 +10006import io
Guido van Rossum217a5fa1990-12-26 15:40:07 +00007
Skip Montanaro19c6ba32003-02-27 21:29:27 +00008from opcode import *
9from opcode import __all__ as _opcodes_all
10
Nick Coghlan7646f7e2010-09-10 12:24:24 +000011__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100012 "findlinestarts", "findlabels", "show_code",
13 "get_instructions", "Instruction", "Bytecode"] + _opcodes_all
Skip Montanaro19c6ba32003-02-27 21:29:27 +000014del _opcodes_all
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000015
Serhiy Storchaka585c93d2016-04-23 09:23:52 +030016_have_code = (types.MethodType, types.FunctionType, types.CodeType,
17 classmethod, staticmethod, type)
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000018
Serhiy Storchakadd102f72016-10-08 12:34:25 +030019FORMAT_VALUE = opmap['FORMAT_VALUE']
20
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000021def _try_compile(source, name):
22 """Attempts to compile the given source, first as an expression and
23 then as a statement if the first approach fails.
24
25 Utility function to accept strings in functions that otherwise
26 expect code objects
27 """
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000028 try:
29 c = compile(source, name, 'eval')
30 except SyntaxError:
31 c = compile(source, name, 'exec')
32 return c
33
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030034def dis(x=None, *, file=None, depth=None):
syncosmicfe2b56a2017-08-17 19:29:21 -070035 """Disassemble classes, methods, functions, and other compiled objects.
Guido van Rossum421c2241997-11-18 15:47:55 +000036
Tim Peters88869f92001-01-14 23:36:06 +000037 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000038
syncosmicfe2b56a2017-08-17 19:29:21 -070039 Compiled objects currently include generator objects, async generator
40 objects, and coroutine objects, all of which store their code object
41 in a special attribute.
Tim Peters88869f92001-01-14 23:36:06 +000042 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000043 if x is None:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100044 distb(file=file)
Tim Peters88869f92001-01-14 23:36:06 +000045 return
syncosmicfe2b56a2017-08-17 19:29:21 -070046 # Extract functions from methods.
47 if hasattr(x, '__func__'):
Christian Heimesff737952007-11-27 10:40:20 +000048 x = x.__func__
syncosmicfe2b56a2017-08-17 19:29:21 -070049 # Extract compiled code objects from...
50 if hasattr(x, '__code__'): # ...a function, or
Neal Norwitz221085d2007-02-25 20:55:47 +000051 x = x.__code__
syncosmicfe2b56a2017-08-17 19:29:21 -070052 elif hasattr(x, 'gi_code'): #...a generator object, or
Nick Coghlanefd5df92014-07-25 23:02:56 +100053 x = x.gi_code
syncosmicfe2b56a2017-08-17 19:29:21 -070054 elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
55 x = x.ag_code
56 elif hasattr(x, 'cr_code'): #...a coroutine.
57 x = x.cr_code
58 # Perform the disassembly.
Nick Coghlaneae2da12010-08-17 08:03:36 +000059 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000060 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000061 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000062 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100063 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000064 try:
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030065 dis(x1, file=file, depth=depth)
Guido van Rossumb940e112007-01-10 16:19:56 +000066 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100067 print("Sorry:", msg, file=file)
68 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000069 elif hasattr(x, 'co_code'): # Code object
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030070 _disassemble_recursive(x, file=file, depth=depth)
Nick Coghlaneae2da12010-08-17 08:03:36 +000071 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100072 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000073 elif isinstance(x, str): # Source code
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030074 _disassemble_str(x, file=file, depth=depth)
Tim Peters88869f92001-01-14 23:36:06 +000075 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000076 raise TypeError("don't know how to disassemble %s objects" %
77 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000078
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100079def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000080 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000081 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000082 try:
83 tb = sys.last_traceback
84 except AttributeError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +030085 raise RuntimeError("no last traceback to disassemble") from None
Tim Peters88869f92001-01-14 23:36:06 +000086 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100087 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000088
Nick Coghlan09c81232010-08-17 10:18:16 +000089# The inspect module interrogates this dictionary to build its
90# list of CO_* constants. It is also used by pretty_flags to
91# turn the co_flags field into a human readable list.
92COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000093 1: "OPTIMIZED",
94 2: "NEWLOCALS",
95 4: "VARARGS",
96 8: "VARKEYWORDS",
97 16: "NESTED",
98 32: "GENERATOR",
99 64: "NOFREE",
Yury Selivanov75445082015-05-11 22:57:16 -0400100 128: "COROUTINE",
101 256: "ITERABLE_COROUTINE",
Yury Selivanoveb636452016-09-08 22:01:51 -0700102 512: "ASYNC_GENERATOR",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000103}
104
105def pretty_flags(flags):
106 """Return pretty representation of code flags."""
107 names = []
108 for i in range(32):
109 flag = 1<<i
110 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +0000111 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000112 flags ^= flag
113 if not flags:
114 break
115 else:
116 names.append(hex(flags))
117 return ", ".join(names)
118
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000119def _get_code_object(x):
syncosmicfe2b56a2017-08-17 19:29:21 -0700120 """Helper to handle methods, compiled or raw code objects, and strings."""
121 # Extract functions from methods.
122 if hasattr(x, '__func__'):
Nick Coghlaneae2da12010-08-17 08:03:36 +0000123 x = x.__func__
syncosmicfe2b56a2017-08-17 19:29:21 -0700124 # Extract compiled code objects from...
125 if hasattr(x, '__code__'): # ...a function, or
Nick Coghlaneae2da12010-08-17 08:03:36 +0000126 x = x.__code__
syncosmicfe2b56a2017-08-17 19:29:21 -0700127 elif hasattr(x, 'gi_code'): #...a generator object, or
Nick Coghlanefd5df92014-07-25 23:02:56 +1000128 x = x.gi_code
syncosmicfe2b56a2017-08-17 19:29:21 -0700129 elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
130 x = x.ag_code
131 elif hasattr(x, 'cr_code'): #...a coroutine.
132 x = x.cr_code
133 # Handle source code.
134 if isinstance(x, str):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000135 x = _try_compile(x, "<disassembly>")
syncosmicfe2b56a2017-08-17 19:29:21 -0700136 # By now, if we don't have a code object, we can't disassemble x.
137 if hasattr(x, 'co_code'):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000138 return x
139 raise TypeError("don't know how to disassemble %s objects" %
140 type(x).__name__)
141
142def code_info(x):
143 """Formatted details of methods, functions, or code."""
144 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000145
146def _format_code_info(co):
147 lines = []
148 lines.append("Name: %s" % co.co_name)
149 lines.append("Filename: %s" % co.co_filename)
150 lines.append("Argument count: %s" % co.co_argcount)
151 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
152 lines.append("Number of locals: %s" % co.co_nlocals)
153 lines.append("Stack size: %s" % co.co_stacksize)
154 lines.append("Flags: %s" % pretty_flags(co.co_flags))
155 if co.co_consts:
156 lines.append("Constants:")
157 for i_c in enumerate(co.co_consts):
158 lines.append("%4d: %r" % i_c)
159 if co.co_names:
160 lines.append("Names:")
161 for i_n in enumerate(co.co_names):
162 lines.append("%4d: %s" % i_n)
163 if co.co_varnames:
164 lines.append("Variable names:")
165 for i_n in enumerate(co.co_varnames):
166 lines.append("%4d: %s" % i_n)
167 if co.co_freevars:
168 lines.append("Free variables:")
169 for i_n in enumerate(co.co_freevars):
170 lines.append("%4d: %s" % i_n)
171 if co.co_cellvars:
172 lines.append("Cell variables:")
173 for i_n in enumerate(co.co_cellvars):
174 lines.append("%4d: %s" % i_n)
175 return "\n".join(lines)
176
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000177def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300178 """Print details of methods, functions, or code to *file*.
179
180 If *file* is not provided, the output is printed on stdout.
181 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000182 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000183
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000184_Instruction = collections.namedtuple("_Instruction",
185 "opname opcode arg argval argrepr offset starts_line is_jump_target")
186
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700187_Instruction.opname.__doc__ = "Human readable name for operation"
188_Instruction.opcode.__doc__ = "Numeric code for operation"
189_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
190_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
191_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
192_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
193_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
194_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
195
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300196_OPNAME_WIDTH = 20
197_OPARG_WIDTH = 5
198
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000199class Instruction(_Instruction):
200 """Details for a bytecode operation
201
202 Defined fields:
203 opname - human readable name for operation
204 opcode - numeric code for operation
205 arg - numeric argument to operation (if any), otherwise None
206 argval - resolved arg value (if known), otherwise same as arg
207 argrepr - human readable description of operation argument
208 offset - start index of operation within bytecode sequence
209 starts_line - line started by this opcode (if any), otherwise None
210 is_jump_target - True if other code jumps to here, otherwise False
211 """
212
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300213 def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000214 """Format instruction details for inclusion in disassembly output
215
216 *lineno_width* sets the width of the line number field (0 omits it)
217 *mark_as_current* inserts a '-->' marker arrow as part of the line
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300218 *offset_width* sets the width of the instruction offset field
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000219 """
220 fields = []
221 # Column: Source code line number
222 if lineno_width:
223 if self.starts_line is not None:
224 lineno_fmt = "%%%dd" % lineno_width
225 fields.append(lineno_fmt % self.starts_line)
226 else:
227 fields.append(' ' * lineno_width)
228 # Column: Current instruction indicator
229 if mark_as_current:
230 fields.append('-->')
231 else:
232 fields.append(' ')
233 # Column: Jump target marker
234 if self.is_jump_target:
235 fields.append('>>')
236 else:
237 fields.append(' ')
238 # Column: Instruction offset from start of code sequence
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300239 fields.append(repr(self.offset).rjust(offset_width))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000240 # Column: Opcode name
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300241 fields.append(self.opname.ljust(_OPNAME_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000242 # Column: Opcode argument
243 if self.arg is not None:
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300244 fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000245 # Column: Opcode argument details
246 if self.argrepr:
247 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000248 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000249
250
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000251def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000252 """Iterator for the opcodes in methods, functions or code
253
254 Generates a series of Instruction named tuples giving the details of
255 each operations in the supplied code.
256
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000257 If *first_line* is not None, it indicates the line number that should
258 be reported for the first source line in the disassembled code.
259 Otherwise, the source line information (if any) is taken directly from
260 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000261 """
262 co = _get_code_object(x)
263 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000264 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000265 if first_line is not None:
266 line_offset = first_line - co.co_firstlineno
267 else:
268 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000269 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
270 co.co_consts, cell_names, linestarts,
271 line_offset)
272
273def _get_const_info(const_index, const_list):
274 """Helper to get optional details about const references
275
276 Returns the dereferenced constant and its repr if the constant
277 list is defined.
278 Otherwise returns the constant index and its repr().
279 """
280 argval = const_index
281 if const_list is not None:
282 argval = const_list[const_index]
283 return argval, repr(argval)
284
285def _get_name_info(name_index, name_list):
286 """Helper to get optional details about named references
287
288 Returns the dereferenced name as both value and repr if the name
289 list is defined.
290 Otherwise returns the name index and its repr().
291 """
292 argval = name_index
293 if name_list is not None:
294 argval = name_list[name_index]
295 argrepr = argval
296 else:
297 argrepr = repr(argval)
298 return argval, argrepr
299
300
301def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
302 cells=None, linestarts=None, line_offset=0):
303 """Iterate over the instructions in a bytecode string.
304
305 Generates a sequence of Instruction namedtuples giving the details of each
306 opcode. Additional information about the code's runtime environment
307 (e.g. variable names, constants) can be specified using optional
308 arguments.
309
310 """
311 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000312 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300313 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000314 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300315 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000316 if starts_line is not None:
317 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300318 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000319 argval = None
320 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300321 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000322 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300323 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000324 # _disassemble_bytes needs the string repr of the
325 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
326 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000327 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000328 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000329 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000330 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000331 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300332 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000333 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000334 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000335 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000336 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000337 argval = cmp_op[arg]
338 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000339 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000340 argval, argrepr = _get_name_info(arg, cells)
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300341 elif op == FORMAT_VALUE:
342 argval = ((None, str, repr, ascii)[arg & 0x3], bool(arg & 0x4))
343 argrepr = ('', 'str', 'repr', 'ascii')[arg & 0x3]
344 if argval[1]:
345 if argrepr:
346 argrepr += ', '
347 argrepr += 'with format'
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000348 yield Instruction(opname[op], op,
349 arg, argval, argrepr,
350 offset, starts_line, is_jump_target)
351
352def disassemble(co, lasti=-1, *, file=None):
353 """Disassemble a code object."""
354 cell_names = co.co_cellvars + co.co_freevars
355 linestarts = dict(findlinestarts(co))
356 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
357 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000358
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300359def _disassemble_recursive(co, *, file=None, depth=None):
360 disassemble(co, file=file)
361 if depth is None or depth > 0:
362 if depth is not None:
363 depth = depth - 1
364 for x in co.co_consts:
365 if hasattr(x, 'co_code'):
366 print(file=file)
367 print("Disassembly of %r:" % (x,), file=file)
368 _disassemble_recursive(x, file=file, depth=depth)
369
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000370def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000371 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000372 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000373 # Omit the line number column entirely if we have no line number info
374 show_lineno = linestarts is not None
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300375 if show_lineno:
376 maxlineno = max(linestarts.values()) + line_offset
377 if maxlineno >= 1000:
378 lineno_width = len(str(maxlineno))
379 else:
380 lineno_width = 3
381 else:
382 lineno_width = 0
383 maxoffset = len(code) - 2
384 if maxoffset >= 10000:
385 offset_width = len(str(maxoffset))
386 else:
387 offset_width = 4
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000388 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000389 constants, cells, linestarts,
390 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000391 new_source_line = (show_lineno and
392 instr.starts_line is not None and
393 instr.offset > 0)
394 if new_source_line:
395 print(file=file)
396 is_current_instr = instr.offset == lasti
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300397 print(instr._disassemble(lineno_width, is_current_instr, offset_width),
398 file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000399
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300400def _disassemble_str(source, **kwargs):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000401 """Compile the source string, then disassemble the code object."""
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300402 _disassemble_recursive(_try_compile(source, '<dis>'), **kwargs)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000403
Tim Peters88869f92001-01-14 23:36:06 +0000404disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000405
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300406def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300407 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300408 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300409 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300410 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300411 arg = code[i+1] | extended_arg
412 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
413 else:
414 arg = None
415 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300416
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000417def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000418 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000419
Tim Peters88869f92001-01-14 23:36:06 +0000420 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000421
Tim Peters88869f92001-01-14 23:36:06 +0000422 """
423 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300424 for offset, op, arg in _unpack_opargs(code):
425 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000426 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300427 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000428 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000429 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300430 else:
431 continue
432 if label not in labels:
433 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000434 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000435
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000436def findlinestarts(code):
437 """Find the offsets in a byte code which are start of lines in the source.
438
439 Generate pairs (offset, lineno) as described in Python/compile.c.
440
441 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100442 byte_increments = code.co_lnotab[0::2]
443 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000444
445 lastlineno = None
446 lineno = code.co_firstlineno
447 addr = 0
448 for byte_incr, line_incr in zip(byte_increments, line_increments):
449 if byte_incr:
450 if lineno != lastlineno:
451 yield (addr, lineno)
452 lastlineno = lineno
453 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100454 if line_incr >= 0x80:
455 # line_increments is an array of 8-bit signed integers
456 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000457 lineno += line_incr
458 if lineno != lastlineno:
459 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000460
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000461class Bytecode:
462 """The bytecode operations of a piece of code
463
syncosmicfe2b56a2017-08-17 19:29:21 -0700464 Instantiate this with a function, method, other compiled object, string of
465 code, or a code object (as returned by compile()).
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000466
467 Iterating over this yields the bytecode operations as Instruction instances.
468 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000469 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000470 self.codeobj = co = _get_code_object(x)
471 if first_line is None:
472 self.first_line = co.co_firstlineno
473 self._line_offset = 0
474 else:
475 self.first_line = first_line
476 self._line_offset = first_line - co.co_firstlineno
477 self._cell_names = co.co_cellvars + co.co_freevars
478 self._linestarts = dict(findlinestarts(co))
479 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000480 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000481
482 def __iter__(self):
483 co = self.codeobj
484 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000485 co.co_consts, self._cell_names,
486 self._linestarts,
487 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000488
489 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000490 return "{}({!r})".format(self.__class__.__name__,
491 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000492
Nick Coghlan50c48b82013-11-23 00:57:00 +1000493 @classmethod
494 def from_traceback(cls, tb):
495 """ Construct a Bytecode from the given traceback """
496 while tb.tb_next:
497 tb = tb.tb_next
498 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
499
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000500 def info(self):
501 """Return formatted information about the code object."""
502 return _format_code_info(self.codeobj)
503
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000504 def dis(self):
505 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000506 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000507 if self.current_offset is not None:
508 offset = self.current_offset
509 else:
510 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000511 with io.StringIO() as output:
512 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
513 names=co.co_names, constants=co.co_consts,
514 cells=self._cell_names,
515 linestarts=self._linestarts,
516 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000517 file=output,
518 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000519 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000520
521
Guido van Rossum1fdae122000-02-04 17:47:55 +0000522def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000523 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000524 import argparse
525
526 parser = argparse.ArgumentParser()
527 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
528 args = parser.parse_args()
529 with args.infile as infile:
530 source = infile.read()
531 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000532 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000533
534if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000535 _test()