blob: f3c18a5fde483db53cdc4cd8df63246f5c467a4c [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
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100034def dis(x=None, *, file=None):
Nick Coghlanefd5df92014-07-25 23:02:56 +100035 """Disassemble classes, methods, functions, generators, or code.
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
Tim Peters88869f92001-01-14 23:36:06 +000039 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000040 if x is None:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100041 distb(file=file)
Tim Peters88869f92001-01-14 23:36:06 +000042 return
Nick Coghlaneae2da12010-08-17 08:03:36 +000043 if hasattr(x, '__func__'): # Method
Christian Heimesff737952007-11-27 10:40:20 +000044 x = x.__func__
Nick Coghlaneae2da12010-08-17 08:03:36 +000045 if hasattr(x, '__code__'): # Function
Neal Norwitz221085d2007-02-25 20:55:47 +000046 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +100047 if hasattr(x, 'gi_code'): # Generator
48 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +000049 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000050 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000051 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000052 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100053 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000054 try:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100055 dis(x1, file=file)
Guido van Rossumb940e112007-01-10 16:19:56 +000056 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100057 print("Sorry:", msg, file=file)
58 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000059 elif hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100060 disassemble(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000061 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100062 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000063 elif isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100064 _disassemble_str(x, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000065 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000066 raise TypeError("don't know how to disassemble %s objects" %
67 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000068
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100069def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000070 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000071 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000072 try:
73 tb = sys.last_traceback
74 except AttributeError:
Serhiy Storchaka5affd232017-04-05 09:37:24 +030075 raise RuntimeError("no last traceback to disassemble") from None
Tim Peters88869f92001-01-14 23:36:06 +000076 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100077 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000078
Nick Coghlan09c81232010-08-17 10:18:16 +000079# The inspect module interrogates this dictionary to build its
80# list of CO_* constants. It is also used by pretty_flags to
81# turn the co_flags field into a human readable list.
82COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000083 1: "OPTIMIZED",
84 2: "NEWLOCALS",
85 4: "VARARGS",
86 8: "VARKEYWORDS",
87 16: "NESTED",
88 32: "GENERATOR",
89 64: "NOFREE",
Yury Selivanov75445082015-05-11 22:57:16 -040090 128: "COROUTINE",
91 256: "ITERABLE_COROUTINE",
Yury Selivanoveb636452016-09-08 22:01:51 -070092 512: "ASYNC_GENERATOR",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000093}
94
95def pretty_flags(flags):
96 """Return pretty representation of code flags."""
97 names = []
98 for i in range(32):
99 flag = 1<<i
100 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +0000101 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000102 flags ^= flag
103 if not flags:
104 break
105 else:
106 names.append(hex(flags))
107 return ", ".join(names)
108
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000109def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000110 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000111 if hasattr(x, '__func__'): # Method
112 x = x.__func__
113 if hasattr(x, '__code__'): # Function
114 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000115 if hasattr(x, 'gi_code'): # Generator
116 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000117 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000118 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000119 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000120 return x
121 raise TypeError("don't know how to disassemble %s objects" %
122 type(x).__name__)
123
124def code_info(x):
125 """Formatted details of methods, functions, or code."""
126 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000127
128def _format_code_info(co):
129 lines = []
130 lines.append("Name: %s" % co.co_name)
131 lines.append("Filename: %s" % co.co_filename)
132 lines.append("Argument count: %s" % co.co_argcount)
133 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
134 lines.append("Number of locals: %s" % co.co_nlocals)
135 lines.append("Stack size: %s" % co.co_stacksize)
136 lines.append("Flags: %s" % pretty_flags(co.co_flags))
137 if co.co_consts:
138 lines.append("Constants:")
139 for i_c in enumerate(co.co_consts):
140 lines.append("%4d: %r" % i_c)
141 if co.co_names:
142 lines.append("Names:")
143 for i_n in enumerate(co.co_names):
144 lines.append("%4d: %s" % i_n)
145 if co.co_varnames:
146 lines.append("Variable names:")
147 for i_n in enumerate(co.co_varnames):
148 lines.append("%4d: %s" % i_n)
149 if co.co_freevars:
150 lines.append("Free variables:")
151 for i_n in enumerate(co.co_freevars):
152 lines.append("%4d: %s" % i_n)
153 if co.co_cellvars:
154 lines.append("Cell variables:")
155 for i_n in enumerate(co.co_cellvars):
156 lines.append("%4d: %s" % i_n)
157 return "\n".join(lines)
158
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000159def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300160 """Print details of methods, functions, or code to *file*.
161
162 If *file* is not provided, the output is printed on stdout.
163 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000164 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000165
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000166_Instruction = collections.namedtuple("_Instruction",
167 "opname opcode arg argval argrepr offset starts_line is_jump_target")
168
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700169_Instruction.opname.__doc__ = "Human readable name for operation"
170_Instruction.opcode.__doc__ = "Numeric code for operation"
171_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
172_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
173_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
174_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
175_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
176_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
177
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300178_OPNAME_WIDTH = 20
179_OPARG_WIDTH = 5
180
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000181class Instruction(_Instruction):
182 """Details for a bytecode operation
183
184 Defined fields:
185 opname - human readable name for operation
186 opcode - numeric code for operation
187 arg - numeric argument to operation (if any), otherwise None
188 argval - resolved arg value (if known), otherwise same as arg
189 argrepr - human readable description of operation argument
190 offset - start index of operation within bytecode sequence
191 starts_line - line started by this opcode (if any), otherwise None
192 is_jump_target - True if other code jumps to here, otherwise False
193 """
194
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300195 def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000196 """Format instruction details for inclusion in disassembly output
197
198 *lineno_width* sets the width of the line number field (0 omits it)
199 *mark_as_current* inserts a '-->' marker arrow as part of the line
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300200 *offset_width* sets the width of the instruction offset field
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000201 """
202 fields = []
203 # Column: Source code line number
204 if lineno_width:
205 if self.starts_line is not None:
206 lineno_fmt = "%%%dd" % lineno_width
207 fields.append(lineno_fmt % self.starts_line)
208 else:
209 fields.append(' ' * lineno_width)
210 # Column: Current instruction indicator
211 if mark_as_current:
212 fields.append('-->')
213 else:
214 fields.append(' ')
215 # Column: Jump target marker
216 if self.is_jump_target:
217 fields.append('>>')
218 else:
219 fields.append(' ')
220 # Column: Instruction offset from start of code sequence
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300221 fields.append(repr(self.offset).rjust(offset_width))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000222 # Column: Opcode name
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300223 fields.append(self.opname.ljust(_OPNAME_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000224 # Column: Opcode argument
225 if self.arg is not None:
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300226 fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000227 # Column: Opcode argument details
228 if self.argrepr:
229 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000230 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000231
232
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000233def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000234 """Iterator for the opcodes in methods, functions or code
235
236 Generates a series of Instruction named tuples giving the details of
237 each operations in the supplied code.
238
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000239 If *first_line* is not None, it indicates the line number that should
240 be reported for the first source line in the disassembled code.
241 Otherwise, the source line information (if any) is taken directly from
242 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000243 """
244 co = _get_code_object(x)
245 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000246 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000247 if first_line is not None:
248 line_offset = first_line - co.co_firstlineno
249 else:
250 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000251 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
252 co.co_consts, cell_names, linestarts,
253 line_offset)
254
255def _get_const_info(const_index, const_list):
256 """Helper to get optional details about const references
257
258 Returns the dereferenced constant and its repr if the constant
259 list is defined.
260 Otherwise returns the constant index and its repr().
261 """
262 argval = const_index
263 if const_list is not None:
264 argval = const_list[const_index]
265 return argval, repr(argval)
266
267def _get_name_info(name_index, name_list):
268 """Helper to get optional details about named references
269
270 Returns the dereferenced name as both value and repr if the name
271 list is defined.
272 Otherwise returns the name index and its repr().
273 """
274 argval = name_index
275 if name_list is not None:
276 argval = name_list[name_index]
277 argrepr = argval
278 else:
279 argrepr = repr(argval)
280 return argval, argrepr
281
282
283def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
284 cells=None, linestarts=None, line_offset=0):
285 """Iterate over the instructions in a bytecode string.
286
287 Generates a sequence of Instruction namedtuples giving the details of each
288 opcode. Additional information about the code's runtime environment
289 (e.g. variable names, constants) can be specified using optional
290 arguments.
291
292 """
293 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000294 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300295 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000296 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300297 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000298 if starts_line is not None:
299 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300300 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000301 argval = None
302 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300303 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000304 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300305 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 # _disassemble_bytes needs the string repr of the
307 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
308 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000309 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000311 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000312 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000313 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300314 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000315 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000316 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000317 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000318 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000319 argval = cmp_op[arg]
320 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000321 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000322 argval, argrepr = _get_name_info(arg, cells)
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300323 elif op == FORMAT_VALUE:
324 argval = ((None, str, repr, ascii)[arg & 0x3], bool(arg & 0x4))
325 argrepr = ('', 'str', 'repr', 'ascii')[arg & 0x3]
326 if argval[1]:
327 if argrepr:
328 argrepr += ', '
329 argrepr += 'with format'
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000330 yield Instruction(opname[op], op,
331 arg, argval, argrepr,
332 offset, starts_line, is_jump_target)
333
334def disassemble(co, lasti=-1, *, file=None):
335 """Disassemble a code object."""
336 cell_names = co.co_cellvars + co.co_freevars
337 linestarts = dict(findlinestarts(co))
338 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
339 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000340
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000341def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000342 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000343 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000344 # Omit the line number column entirely if we have no line number info
345 show_lineno = linestarts is not None
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300346 if show_lineno:
347 maxlineno = max(linestarts.values()) + line_offset
348 if maxlineno >= 1000:
349 lineno_width = len(str(maxlineno))
350 else:
351 lineno_width = 3
352 else:
353 lineno_width = 0
354 maxoffset = len(code) - 2
355 if maxoffset >= 10000:
356 offset_width = len(str(maxoffset))
357 else:
358 offset_width = 4
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000359 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000360 constants, cells, linestarts,
361 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000362 new_source_line = (show_lineno and
363 instr.starts_line is not None and
364 instr.offset > 0)
365 if new_source_line:
366 print(file=file)
367 is_current_instr = instr.offset == lasti
Serhiy Storchakad90045f2017-04-19 20:36:31 +0300368 print(instr._disassemble(lineno_width, is_current_instr, offset_width),
369 file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000370
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000371def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000372 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000373 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000374
Tim Peters88869f92001-01-14 23:36:06 +0000375disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000376
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300377def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300378 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300379 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300380 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300381 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300382 arg = code[i+1] | extended_arg
383 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
384 else:
385 arg = None
386 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300387
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000388def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000389 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000390
Tim Peters88869f92001-01-14 23:36:06 +0000391 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000392
Tim Peters88869f92001-01-14 23:36:06 +0000393 """
394 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300395 for offset, op, arg in _unpack_opargs(code):
396 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000397 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300398 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000399 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000400 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300401 else:
402 continue
403 if label not in labels:
404 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000405 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000406
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000407def findlinestarts(code):
408 """Find the offsets in a byte code which are start of lines in the source.
409
410 Generate pairs (offset, lineno) as described in Python/compile.c.
411
412 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100413 byte_increments = code.co_lnotab[0::2]
414 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000415
416 lastlineno = None
417 lineno = code.co_firstlineno
418 addr = 0
419 for byte_incr, line_incr in zip(byte_increments, line_increments):
420 if byte_incr:
421 if lineno != lastlineno:
422 yield (addr, lineno)
423 lastlineno = lineno
424 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100425 if line_incr >= 0x80:
426 # line_increments is an array of 8-bit signed integers
427 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000428 lineno += line_incr
429 if lineno != lastlineno:
430 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000431
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000432class Bytecode:
433 """The bytecode operations of a piece of code
434
435 Instantiate this with a function, method, string of code, or a code object
436 (as returned by compile()).
437
438 Iterating over this yields the bytecode operations as Instruction instances.
439 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000440 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000441 self.codeobj = co = _get_code_object(x)
442 if first_line is None:
443 self.first_line = co.co_firstlineno
444 self._line_offset = 0
445 else:
446 self.first_line = first_line
447 self._line_offset = first_line - co.co_firstlineno
448 self._cell_names = co.co_cellvars + co.co_freevars
449 self._linestarts = dict(findlinestarts(co))
450 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000451 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000452
453 def __iter__(self):
454 co = self.codeobj
455 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000456 co.co_consts, self._cell_names,
457 self._linestarts,
458 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000459
460 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000461 return "{}({!r})".format(self.__class__.__name__,
462 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000463
Nick Coghlan50c48b82013-11-23 00:57:00 +1000464 @classmethod
465 def from_traceback(cls, tb):
466 """ Construct a Bytecode from the given traceback """
467 while tb.tb_next:
468 tb = tb.tb_next
469 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
470
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000471 def info(self):
472 """Return formatted information about the code object."""
473 return _format_code_info(self.codeobj)
474
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000475 def dis(self):
476 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000477 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000478 if self.current_offset is not None:
479 offset = self.current_offset
480 else:
481 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000482 with io.StringIO() as output:
483 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
484 names=co.co_names, constants=co.co_consts,
485 cells=self._cell_names,
486 linestarts=self._linestarts,
487 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000488 file=output,
489 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000490 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000491
492
Guido van Rossum1fdae122000-02-04 17:47:55 +0000493def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000494 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000495 import argparse
496
497 parser = argparse.ArgumentParser()
498 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
499 args = parser.parse_args()
500 with args.infile as infile:
501 source = infile.read()
502 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000503 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000504
505if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000506 _test()