blob: ccbd65be73255a29f29ecf2f5518aa29560b3cb9 [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)
Pablo Galindo8c77b8c2019-04-29 13:36:57 +0100160 lines.append("Positional-only arguments: %s" % co.co_posonlyargcount)
Nick Coghlaneae2da12010-08-17 08:03:36 +0000161 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
162 lines.append("Number of locals: %s" % co.co_nlocals)
163 lines.append("Stack size: %s" % co.co_stacksize)
164 lines.append("Flags: %s" % pretty_flags(co.co_flags))
165 if co.co_consts:
166 lines.append("Constants:")
167 for i_c in enumerate(co.co_consts):
168 lines.append("%4d: %r" % i_c)
169 if co.co_names:
170 lines.append("Names:")
171 for i_n in enumerate(co.co_names):
172 lines.append("%4d: %s" % i_n)
173 if co.co_varnames:
174 lines.append("Variable names:")
175 for i_n in enumerate(co.co_varnames):
176 lines.append("%4d: %s" % i_n)
177 if co.co_freevars:
178 lines.append("Free variables:")
179 for i_n in enumerate(co.co_freevars):
180 lines.append("%4d: %s" % i_n)
181 if co.co_cellvars:
182 lines.append("Cell variables:")
183 for i_n in enumerate(co.co_cellvars):
184 lines.append("%4d: %s" % i_n)
185 return "\n".join(lines)
186
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000187def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300188 """Print details of methods, functions, or code to *file*.
189
190 If *file* is not provided, the output is printed on stdout.
191 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000192 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000193
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000194_Instruction = collections.namedtuple("_Instruction",
195 "opname opcode arg argval argrepr offset starts_line is_jump_target")
196
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700197_Instruction.opname.__doc__ = "Human readable name for operation"
198_Instruction.opcode.__doc__ = "Numeric code for operation"
199_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
200_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
201_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
202_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
203_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
204_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
205
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300206_OPNAME_WIDTH = 20
207_OPARG_WIDTH = 5
208
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000209class Instruction(_Instruction):
210 """Details for a bytecode operation
211
212 Defined fields:
213 opname - human readable name for operation
214 opcode - numeric code for operation
215 arg - numeric argument to operation (if any), otherwise None
216 argval - resolved arg value (if known), otherwise same as arg
217 argrepr - human readable description of operation argument
218 offset - start index of operation within bytecode sequence
219 starts_line - line started by this opcode (if any), otherwise None
220 is_jump_target - True if other code jumps to here, otherwise False
221 """
222
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300223 def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000224 """Format instruction details for inclusion in disassembly output
225
226 *lineno_width* sets the width of the line number field (0 omits it)
227 *mark_as_current* inserts a '-->' marker arrow as part of the line
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300228 *offset_width* sets the width of the instruction offset field
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000229 """
230 fields = []
231 # Column: Source code line number
232 if lineno_width:
233 if self.starts_line is not None:
234 lineno_fmt = "%%%dd" % lineno_width
235 fields.append(lineno_fmt % self.starts_line)
236 else:
237 fields.append(' ' * lineno_width)
238 # Column: Current instruction indicator
239 if mark_as_current:
240 fields.append('-->')
241 else:
242 fields.append(' ')
243 # Column: Jump target marker
244 if self.is_jump_target:
245 fields.append('>>')
246 else:
247 fields.append(' ')
248 # Column: Instruction offset from start of code sequence
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300249 fields.append(repr(self.offset).rjust(offset_width))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000250 # Column: Opcode name
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300251 fields.append(self.opname.ljust(_OPNAME_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000252 # Column: Opcode argument
253 if self.arg is not None:
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300254 fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000255 # Column: Opcode argument details
256 if self.argrepr:
257 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000258 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000259
260
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000261def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000262 """Iterator for the opcodes in methods, functions or code
263
264 Generates a series of Instruction named tuples giving the details of
265 each operations in the supplied code.
266
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000267 If *first_line* is not None, it indicates the line number that should
268 be reported for the first source line in the disassembled code.
269 Otherwise, the source line information (if any) is taken directly from
270 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000271 """
272 co = _get_code_object(x)
273 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000274 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000275 if first_line is not None:
276 line_offset = first_line - co.co_firstlineno
277 else:
278 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000279 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
280 co.co_consts, cell_names, linestarts,
281 line_offset)
282
283def _get_const_info(const_index, const_list):
284 """Helper to get optional details about const references
285
286 Returns the dereferenced constant and its repr if the constant
287 list is defined.
288 Otherwise returns the constant index and its repr().
289 """
290 argval = const_index
291 if const_list is not None:
292 argval = const_list[const_index]
293 return argval, repr(argval)
294
295def _get_name_info(name_index, name_list):
296 """Helper to get optional details about named references
297
298 Returns the dereferenced name as both value and repr if the name
299 list is defined.
300 Otherwise returns the name index and its repr().
301 """
302 argval = name_index
303 if name_list is not None:
304 argval = name_list[name_index]
305 argrepr = argval
306 else:
307 argrepr = repr(argval)
308 return argval, argrepr
309
310
311def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
312 cells=None, linestarts=None, line_offset=0):
313 """Iterate over the instructions in a bytecode string.
314
315 Generates a sequence of Instruction namedtuples giving the details of each
316 opcode. Additional information about the code's runtime environment
317 (e.g. variable names, constants) can be specified using optional
318 arguments.
319
320 """
321 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000322 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300323 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000324 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300325 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000326 if starts_line is not None:
327 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300328 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000329 argval = None
330 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300331 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000332 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300333 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000334 # _disassemble_bytes needs the string repr of the
335 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
336 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000337 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000338 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000339 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000340 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000341 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300342 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000343 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000344 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000345 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000346 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000347 argval = cmp_op[arg]
348 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000349 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000350 argval, argrepr = _get_name_info(arg, cells)
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300351 elif op == FORMAT_VALUE:
Serhiy Storchakae2732d32018-03-11 11:07:06 +0200352 argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
353 argval = (argval, bool(arg & 0x4))
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300354 if argval[1]:
355 if argrepr:
356 argrepr += ', '
357 argrepr += 'with format'
Serhiy Storchakae2732d32018-03-11 11:07:06 +0200358 elif op == MAKE_FUNCTION:
359 argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)
360 if arg & (1<<i))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000361 yield Instruction(opname[op], op,
362 arg, argval, argrepr,
363 offset, starts_line, is_jump_target)
364
365def disassemble(co, lasti=-1, *, file=None):
366 """Disassemble a code object."""
367 cell_names = co.co_cellvars + co.co_freevars
368 linestarts = dict(findlinestarts(co))
369 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
370 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000371
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300372def _disassemble_recursive(co, *, file=None, depth=None):
373 disassemble(co, file=file)
374 if depth is None or depth > 0:
375 if depth is not None:
376 depth = depth - 1
377 for x in co.co_consts:
378 if hasattr(x, 'co_code'):
379 print(file=file)
380 print("Disassembly of %r:" % (x,), file=file)
381 _disassemble_recursive(x, file=file, depth=depth)
382
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000383def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000384 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000385 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000386 # Omit the line number column entirely if we have no line number info
Yurii Karabasf24b8102020-12-04 17:20:53 +0200387 show_lineno = bool(linestarts)
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300388 if show_lineno:
389 maxlineno = max(linestarts.values()) + line_offset
390 if maxlineno >= 1000:
391 lineno_width = len(str(maxlineno))
392 else:
393 lineno_width = 3
394 else:
395 lineno_width = 0
396 maxoffset = len(code) - 2
397 if maxoffset >= 10000:
398 offset_width = len(str(maxoffset))
399 else:
400 offset_width = 4
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000401 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000402 constants, cells, linestarts,
403 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000404 new_source_line = (show_lineno and
405 instr.starts_line is not None and
406 instr.offset > 0)
407 if new_source_line:
408 print(file=file)
409 is_current_instr = instr.offset == lasti
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300410 print(instr._disassemble(lineno_width, is_current_instr, offset_width),
411 file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000412
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300413def _disassemble_str(source, **kwargs):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000414 """Compile the source string, then disassemble the code object."""
Serhiy Storchaka1efbf922017-06-11 14:09:39 +0300415 _disassemble_recursive(_try_compile(source, '<dis>'), **kwargs)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000416
Tim Peters88869f92001-01-14 23:36:06 +0000417disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000418
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300419def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300420 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300421 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300422 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300423 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300424 arg = code[i+1] | extended_arg
425 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
426 else:
427 arg = None
428 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300429
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000430def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000431 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000432
Tim Peters88869f92001-01-14 23:36:06 +0000433 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000434
Tim Peters88869f92001-01-14 23:36:06 +0000435 """
436 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300437 for offset, op, arg in _unpack_opargs(code):
438 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000439 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300440 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000441 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000442 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300443 else:
444 continue
445 if label not in labels:
446 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000447 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000448
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000449def findlinestarts(code):
450 """Find the offsets in a byte code which are start of lines in the source.
451
Mark Shannon877df852020-11-12 09:43:29 +0000452 Generate pairs (offset, lineno)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000453 """
Mark Shannon877df852020-11-12 09:43:29 +0000454 lastline = None
455 for start, end, line in code.co_lines():
456 if line is not None and line != lastline:
457 lastline = line
458 yield start, line
459 return
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000460
Guido van Rossum1fdae122000-02-04 17:47:55 +0000461
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000462class Bytecode:
463 """The bytecode operations of a piece of code
464
syncosmicfe2b56a2017-08-17 19:29:21 -0700465 Instantiate this with a function, method, other compiled object, string of
466 code, or a code object (as returned by compile()).
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000467
468 Iterating over this yields the bytecode operations as Instruction instances.
469 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000470 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000471 self.codeobj = co = _get_code_object(x)
472 if first_line is None:
473 self.first_line = co.co_firstlineno
474 self._line_offset = 0
475 else:
476 self.first_line = first_line
477 self._line_offset = first_line - co.co_firstlineno
478 self._cell_names = co.co_cellvars + co.co_freevars
479 self._linestarts = dict(findlinestarts(co))
480 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000481 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000482
483 def __iter__(self):
484 co = self.codeobj
485 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000486 co.co_consts, self._cell_names,
487 self._linestarts,
488 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000489
490 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000491 return "{}({!r})".format(self.__class__.__name__,
492 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000493
Nick Coghlan50c48b82013-11-23 00:57:00 +1000494 @classmethod
495 def from_traceback(cls, tb):
496 """ Construct a Bytecode from the given traceback """
497 while tb.tb_next:
498 tb = tb.tb_next
499 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
500
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000501 def info(self):
502 """Return formatted information about the code object."""
503 return _format_code_info(self.codeobj)
504
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000505 def dis(self):
506 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000507 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000508 if self.current_offset is not None:
509 offset = self.current_offset
510 else:
511 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000512 with io.StringIO() as output:
513 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
514 names=co.co_names, constants=co.co_consts,
515 cells=self._cell_names,
516 linestarts=self._linestarts,
517 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000518 file=output,
519 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000520 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000521
522
Guido van Rossum1fdae122000-02-04 17:47:55 +0000523def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000524 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000525 import argparse
526
527 parser = argparse.ArgumentParser()
Kongea4084b92020-08-08 11:03:09 +0800528 parser.add_argument('infile', type=argparse.FileType('rb'), nargs='?', default='-')
Nick Coghlan09566892013-08-25 00:48:17 +1000529 args = parser.parse_args()
530 with args.infile as infile:
531 source = infile.read()
532 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000533 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000534
535if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000536 _test()