blob: b2b0003203a44f386836e41c2b5e053917981056 [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']
Serhiy Storchakae2732d32018-03-11 11:07:06 +020020FORMAT_VALUE_CONVERTERS = (
21 (None, ''),
22 (str, 'str'),
23 (repr, 'repr'),
24 (ascii, 'ascii'),
25)
26MAKE_FUNCTION = opmap['MAKE_FUNCTION']
27MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')
28
Serhiy Storchakadd102f72016-10-08 12:34:25 +030029
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000030def _try_compile(source, name):
31 """Attempts to compile the given source, first as an expression and
32 then as a statement if the first approach fails.
33
34 Utility function to accept strings in functions that otherwise
35 expect code objects
36 """
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000037 try:
38 c = compile(source, name, 'eval')
39 except SyntaxError:
40 c = compile(source, name, 'exec')
41 return c
42
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030043def dis(x=None, *, file=None, depth=None):
syncosmicfe2b56a2017-08-17 19:29:21 -070044 """Disassemble classes, methods, functions, and other compiled objects.
Guido van Rossum421c2241997-11-18 15:47:55 +000045
Tim Peters88869f92001-01-14 23:36:06 +000046 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000047
syncosmicfe2b56a2017-08-17 19:29:21 -070048 Compiled objects currently include generator objects, async generator
49 objects, and coroutine objects, all of which store their code object
50 in a special attribute.
Tim Peters88869f92001-01-14 23:36:06 +000051 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000052 if x is None:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100053 distb(file=file)
Tim Peters88869f92001-01-14 23:36:06 +000054 return
syncosmicfe2b56a2017-08-17 19:29:21 -070055 # Extract functions from methods.
56 if hasattr(x, '__func__'):
Christian Heimesff737952007-11-27 10:40:20 +000057 x = x.__func__
syncosmicfe2b56a2017-08-17 19:29:21 -070058 # Extract compiled code objects from...
59 if hasattr(x, '__code__'): # ...a function, or
Neal Norwitz221085d2007-02-25 20:55:47 +000060 x = x.__code__
syncosmicfe2b56a2017-08-17 19:29:21 -070061 elif hasattr(x, 'gi_code'): #...a generator object, or
Nick Coghlanefd5df92014-07-25 23:02:56 +100062 x = x.gi_code
syncosmicfe2b56a2017-08-17 19:29:21 -070063 elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
64 x = x.ag_code
65 elif hasattr(x, 'cr_code'): #...a coroutine.
66 x = x.cr_code
67 # Perform the disassembly.
Nick Coghlaneae2da12010-08-17 08:03:36 +000068 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000069 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000070 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000071 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100072 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000073 try:
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030074 dis(x1, file=file, depth=depth)
Guido van Rossumb940e112007-01-10 16:19:56 +000075 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100076 print("Sorry:", msg, file=file)
77 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000078 elif hasattr(x, 'co_code'): # Code object
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030079 _disassemble_recursive(x, file=file, depth=depth)
Nick Coghlaneae2da12010-08-17 08:03:36 +000080 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100081 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000082 elif isinstance(x, str): # Source code
Serhiy Storchaka1efbf922017-06-11 14:09:39 +030083 _disassemble_str(x, file=file, depth=depth)
Tim Peters88869f92001-01-14 23:36:06 +000084 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000085 raise TypeError("don't know how to disassemble %s objects" %
86 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000087
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100088def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000089 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000090 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000091 try:
92 tb = sys.last_traceback
93 except AttributeError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +030094 raise RuntimeError("no last traceback to disassemble") from None
Tim Peters88869f92001-01-14 23:36:06 +000095 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100096 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000097
Nick Coghlan09c81232010-08-17 10:18:16 +000098# The inspect module interrogates this dictionary to build its
99# list of CO_* constants. It is also used by pretty_flags to
100# turn the co_flags field into a human readable list.
101COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000102 1: "OPTIMIZED",
103 2: "NEWLOCALS",
104 4: "VARARGS",
105 8: "VARKEYWORDS",
106 16: "NESTED",
107 32: "GENERATOR",
108 64: "NOFREE",
Yury Selivanov75445082015-05-11 22:57:16 -0400109 128: "COROUTINE",
110 256: "ITERABLE_COROUTINE",
Yury Selivanoveb636452016-09-08 22:01:51 -0700111 512: "ASYNC_GENERATOR",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000112}
113
114def pretty_flags(flags):
115 """Return pretty representation of code flags."""
116 names = []
117 for i in range(32):
118 flag = 1<<i
119 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +0000120 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000121 flags ^= flag
122 if not flags:
123 break
124 else:
125 names.append(hex(flags))
126 return ", ".join(names)
127
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000128def _get_code_object(x):
syncosmicfe2b56a2017-08-17 19:29:21 -0700129 """Helper to handle methods, compiled or raw code objects, and strings."""
130 # Extract functions from methods.
131 if hasattr(x, '__func__'):
Nick Coghlaneae2da12010-08-17 08:03:36 +0000132 x = x.__func__
syncosmicfe2b56a2017-08-17 19:29:21 -0700133 # Extract compiled code objects from...
134 if hasattr(x, '__code__'): # ...a function, or
Nick Coghlaneae2da12010-08-17 08:03:36 +0000135 x = x.__code__
syncosmicfe2b56a2017-08-17 19:29:21 -0700136 elif hasattr(x, 'gi_code'): #...a generator object, or
Nick Coghlanefd5df92014-07-25 23:02:56 +1000137 x = x.gi_code
syncosmicfe2b56a2017-08-17 19:29:21 -0700138 elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
139 x = x.ag_code
140 elif hasattr(x, 'cr_code'): #...a coroutine.
141 x = x.cr_code
142 # Handle source code.
143 if isinstance(x, str):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000144 x = _try_compile(x, "<disassembly>")
syncosmicfe2b56a2017-08-17 19:29:21 -0700145 # By now, if we don't have a code object, we can't disassemble x.
146 if hasattr(x, 'co_code'):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000147 return x
148 raise TypeError("don't know how to disassemble %s objects" %
149 type(x).__name__)
150
151def code_info(x):
152 """Formatted details of methods, functions, or code."""
153 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000154
155def _format_code_info(co):
156 lines = []
157 lines.append("Name: %s" % co.co_name)
158 lines.append("Filename: %s" % co.co_filename)
159 lines.append("Argument count: %s" % co.co_argcount)
160 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
161 lines.append("Number of locals: %s" % co.co_nlocals)
162 lines.append("Stack size: %s" % co.co_stacksize)
163 lines.append("Flags: %s" % pretty_flags(co.co_flags))
164 if co.co_consts:
165 lines.append("Constants:")
166 for i_c in enumerate(co.co_consts):
167 lines.append("%4d: %r" % i_c)
168 if co.co_names:
169 lines.append("Names:")
170 for i_n in enumerate(co.co_names):
171 lines.append("%4d: %s" % i_n)
172 if co.co_varnames:
173 lines.append("Variable names:")
174 for i_n in enumerate(co.co_varnames):
175 lines.append("%4d: %s" % i_n)
176 if co.co_freevars:
177 lines.append("Free variables:")
178 for i_n in enumerate(co.co_freevars):
179 lines.append("%4d: %s" % i_n)
180 if co.co_cellvars:
181 lines.append("Cell variables:")
182 for i_n in enumerate(co.co_cellvars):
183 lines.append("%4d: %s" % i_n)
184 return "\n".join(lines)
185
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000186def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300187 """Print details of methods, functions, or code to *file*.
188
189 If *file* is not provided, the output is printed on stdout.
190 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000191 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000192
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000193_Instruction = collections.namedtuple("_Instruction",
194 "opname opcode arg argval argrepr offset starts_line is_jump_target")
195
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700196_Instruction.opname.__doc__ = "Human readable name for operation"
197_Instruction.opcode.__doc__ = "Numeric code for operation"
198_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
199_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
200_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
201_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
202_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
203_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
204
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300205_OPNAME_WIDTH = 20
206_OPARG_WIDTH = 5
207
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000208class Instruction(_Instruction):
209 """Details for a bytecode operation
210
211 Defined fields:
212 opname - human readable name for operation
213 opcode - numeric code for operation
214 arg - numeric argument to operation (if any), otherwise None
215 argval - resolved arg value (if known), otherwise same as arg
216 argrepr - human readable description of operation argument
217 offset - start index of operation within bytecode sequence
218 starts_line - line started by this opcode (if any), otherwise None
219 is_jump_target - True if other code jumps to here, otherwise False
220 """
221
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300222 def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000223 """Format instruction details for inclusion in disassembly output
224
225 *lineno_width* sets the width of the line number field (0 omits it)
226 *mark_as_current* inserts a '-->' marker arrow as part of the line
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300227 *offset_width* sets the width of the instruction offset field
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000228 """
229 fields = []
230 # Column: Source code line number
231 if lineno_width:
232 if self.starts_line is not None:
233 lineno_fmt = "%%%dd" % lineno_width
234 fields.append(lineno_fmt % self.starts_line)
235 else:
236 fields.append(' ' * lineno_width)
237 # Column: Current instruction indicator
238 if mark_as_current:
239 fields.append('-->')
240 else:
241 fields.append(' ')
242 # Column: Jump target marker
243 if self.is_jump_target:
244 fields.append('>>')
245 else:
246 fields.append(' ')
247 # Column: Instruction offset from start of code sequence
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300248 fields.append(repr(self.offset).rjust(offset_width))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000249 # Column: Opcode name
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300250 fields.append(self.opname.ljust(_OPNAME_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000251 # Column: Opcode argument
252 if self.arg is not None:
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300253 fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000254 # Column: Opcode argument details
255 if self.argrepr:
256 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000257 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000258
259
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000260def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000261 """Iterator for the opcodes in methods, functions or code
262
263 Generates a series of Instruction named tuples giving the details of
264 each operations in the supplied code.
265
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000266 If *first_line* is not None, it indicates the line number that should
267 be reported for the first source line in the disassembled code.
268 Otherwise, the source line information (if any) is taken directly from
269 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000270 """
271 co = _get_code_object(x)
272 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000273 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000274 if first_line is not None:
275 line_offset = first_line - co.co_firstlineno
276 else:
277 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000278 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
279 co.co_consts, cell_names, linestarts,
280 line_offset)
281
282def _get_const_info(const_index, const_list):
283 """Helper to get optional details about const references
284
285 Returns the dereferenced constant and its repr if the constant
286 list is defined.
287 Otherwise returns the constant index and its repr().
288 """
289 argval = const_index
290 if const_list is not None:
291 argval = const_list[const_index]
292 return argval, repr(argval)
293
294def _get_name_info(name_index, name_list):
295 """Helper to get optional details about named references
296
297 Returns the dereferenced name as both value and repr if the name
298 list is defined.
299 Otherwise returns the name index and its repr().
300 """
301 argval = name_index
302 if name_list is not None:
303 argval = name_list[name_index]
304 argrepr = argval
305 else:
306 argrepr = repr(argval)
307 return argval, argrepr
308
309
310def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
311 cells=None, linestarts=None, line_offset=0):
312 """Iterate over the instructions in a bytecode string.
313
314 Generates a sequence of Instruction namedtuples giving the details of each
315 opcode. Additional information about the code's runtime environment
316 (e.g. variable names, constants) can be specified using optional
317 arguments.
318
319 """
320 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000321 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300322 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000323 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300324 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000325 if starts_line is not None:
326 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300327 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000328 argval = None
329 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300330 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000331 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300332 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000333 # _disassemble_bytes needs the string repr of the
334 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
335 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000336 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000337 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000338 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000339 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000340 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300341 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000342 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000343 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000344 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000345 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000346 argval = cmp_op[arg]
347 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000348 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000349 argval, argrepr = _get_name_info(arg, cells)
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300350 elif op == FORMAT_VALUE:
Serhiy Storchakae2732d32018-03-11 11:07:06 +0200351 argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
352 argval = (argval, bool(arg & 0x4))
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300353 if argval[1]:
354 if argrepr:
355 argrepr += ', '
356 argrepr += 'with format'
Serhiy Storchakae2732d32018-03-11 11:07:06 +0200357 elif op == MAKE_FUNCTION:
358 argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)
359 if arg & (1<<i))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000360 yield Instruction(opname[op], op,
361 arg, argval, argrepr,
362 offset, starts_line, is_jump_target)
363
364def disassemble(co, lasti=-1, *, file=None):
365 """Disassemble a code object."""
366 cell_names = co.co_cellvars + co.co_freevars
367 linestarts = dict(findlinestarts(co))
368 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
369 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000370
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300371def _disassemble_recursive(co, *, file=None, depth=None):
372 disassemble(co, file=file)
373 if depth is None or depth > 0:
374 if depth is not None:
375 depth = depth - 1
376 for x in co.co_consts:
377 if hasattr(x, 'co_code'):
378 print(file=file)
379 print("Disassembly of %r:" % (x,), file=file)
380 _disassemble_recursive(x, file=file, depth=depth)
381
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000382def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000383 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000384 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000385 # Omit the line number column entirely if we have no line number info
386 show_lineno = linestarts is not None
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300387 if show_lineno:
388 maxlineno = max(linestarts.values()) + line_offset
389 if maxlineno >= 1000:
390 lineno_width = len(str(maxlineno))
391 else:
392 lineno_width = 3
393 else:
394 lineno_width = 0
395 maxoffset = len(code) - 2
396 if maxoffset >= 10000:
397 offset_width = len(str(maxoffset))
398 else:
399 offset_width = 4
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000400 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000401 constants, cells, linestarts,
402 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000403 new_source_line = (show_lineno and
404 instr.starts_line is not None and
405 instr.offset > 0)
406 if new_source_line:
407 print(file=file)
408 is_current_instr = instr.offset == lasti
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300409 print(instr._disassemble(lineno_width, is_current_instr, offset_width),
410 file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000411
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300412def _disassemble_str(source, **kwargs):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000413 """Compile the source string, then disassemble the code object."""
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300414 _disassemble_recursive(_try_compile(source, '<dis>'), **kwargs)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000415
Tim Peters88869f92001-01-14 23:36:06 +0000416disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000417
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300418def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300419 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300420 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300421 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300422 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300423 arg = code[i+1] | extended_arg
424 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
425 else:
426 arg = None
427 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300428
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000429def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000430 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000431
Tim Peters88869f92001-01-14 23:36:06 +0000432 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000433
Tim Peters88869f92001-01-14 23:36:06 +0000434 """
435 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300436 for offset, op, arg in _unpack_opargs(code):
437 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000438 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300439 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000440 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000441 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300442 else:
443 continue
444 if label not in labels:
445 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000446 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000447
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000448def findlinestarts(code):
449 """Find the offsets in a byte code which are start of lines in the source.
450
451 Generate pairs (offset, lineno) as described in Python/compile.c.
452
453 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100454 byte_increments = code.co_lnotab[0::2]
455 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000456
457 lastlineno = None
458 lineno = code.co_firstlineno
459 addr = 0
460 for byte_incr, line_incr in zip(byte_increments, line_increments):
461 if byte_incr:
462 if lineno != lastlineno:
463 yield (addr, lineno)
464 lastlineno = lineno
465 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100466 if line_incr >= 0x80:
467 # line_increments is an array of 8-bit signed integers
468 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000469 lineno += line_incr
470 if lineno != lastlineno:
471 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000472
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000473class Bytecode:
474 """The bytecode operations of a piece of code
475
syncosmicfe2b56a2017-08-17 19:29:21 -0700476 Instantiate this with a function, method, other compiled object, string of
477 code, or a code object (as returned by compile()).
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000478
479 Iterating over this yields the bytecode operations as Instruction instances.
480 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000481 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000482 self.codeobj = co = _get_code_object(x)
483 if first_line is None:
484 self.first_line = co.co_firstlineno
485 self._line_offset = 0
486 else:
487 self.first_line = first_line
488 self._line_offset = first_line - co.co_firstlineno
489 self._cell_names = co.co_cellvars + co.co_freevars
490 self._linestarts = dict(findlinestarts(co))
491 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000492 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000493
494 def __iter__(self):
495 co = self.codeobj
496 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000497 co.co_consts, self._cell_names,
498 self._linestarts,
499 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000500
501 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000502 return "{}({!r})".format(self.__class__.__name__,
503 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000504
Nick Coghlan50c48b82013-11-23 00:57:00 +1000505 @classmethod
506 def from_traceback(cls, tb):
507 """ Construct a Bytecode from the given traceback """
508 while tb.tb_next:
509 tb = tb.tb_next
510 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
511
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000512 def info(self):
513 """Return formatted information about the code object."""
514 return _format_code_info(self.codeobj)
515
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000516 def dis(self):
517 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000518 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000519 if self.current_offset is not None:
520 offset = self.current_offset
521 else:
522 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000523 with io.StringIO() as output:
524 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
525 names=co.co_names, constants=co.co_consts,
526 cells=self._cell_names,
527 linestarts=self._linestarts,
528 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000529 file=output,
530 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000531 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000532
533
Guido van Rossum1fdae122000-02-04 17:47:55 +0000534def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000535 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000536 import argparse
537
538 parser = argparse.ArgumentParser()
539 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
540 args = parser.parse_args()
541 with args.infile as infile:
542 source = infile.read()
543 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000544 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000545
546if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000547 _test()