blob: 0794b7f743b01de50c1575aceff7cab17918395b [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:
Collin Winterce36ad82007-08-30 01:19:48 +000075 raise RuntimeError("no last traceback to disassemble")
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
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000178class Instruction(_Instruction):
179 """Details for a bytecode operation
180
181 Defined fields:
182 opname - human readable name for operation
183 opcode - numeric code for operation
184 arg - numeric argument to operation (if any), otherwise None
185 argval - resolved arg value (if known), otherwise same as arg
186 argrepr - human readable description of operation argument
187 offset - start index of operation within bytecode sequence
188 starts_line - line started by this opcode (if any), otherwise None
189 is_jump_target - True if other code jumps to here, otherwise False
190 """
191
192 def _disassemble(self, lineno_width=3, mark_as_current=False):
193 """Format instruction details for inclusion in disassembly output
194
195 *lineno_width* sets the width of the line number field (0 omits it)
196 *mark_as_current* inserts a '-->' marker arrow as part of the line
197 """
198 fields = []
199 # Column: Source code line number
200 if lineno_width:
201 if self.starts_line is not None:
202 lineno_fmt = "%%%dd" % lineno_width
203 fields.append(lineno_fmt % self.starts_line)
204 else:
205 fields.append(' ' * lineno_width)
206 # Column: Current instruction indicator
207 if mark_as_current:
208 fields.append('-->')
209 else:
210 fields.append(' ')
211 # Column: Jump target marker
212 if self.is_jump_target:
213 fields.append('>>')
214 else:
215 fields.append(' ')
216 # Column: Instruction offset from start of code sequence
217 fields.append(repr(self.offset).rjust(4))
218 # Column: Opcode name
219 fields.append(self.opname.ljust(20))
220 # Column: Opcode argument
221 if self.arg is not None:
222 fields.append(repr(self.arg).rjust(5))
223 # Column: Opcode argument details
224 if self.argrepr:
225 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000226 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000227
228
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000229def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000230 """Iterator for the opcodes in methods, functions or code
231
232 Generates a series of Instruction named tuples giving the details of
233 each operations in the supplied code.
234
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000235 If *first_line* is not None, it indicates the line number that should
236 be reported for the first source line in the disassembled code.
237 Otherwise, the source line information (if any) is taken directly from
238 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000239 """
240 co = _get_code_object(x)
241 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000242 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000243 if first_line is not None:
244 line_offset = first_line - co.co_firstlineno
245 else:
246 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000247 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
248 co.co_consts, cell_names, linestarts,
249 line_offset)
250
251def _get_const_info(const_index, const_list):
252 """Helper to get optional details about const references
253
254 Returns the dereferenced constant and its repr if the constant
255 list is defined.
256 Otherwise returns the constant index and its repr().
257 """
258 argval = const_index
259 if const_list is not None:
260 argval = const_list[const_index]
261 return argval, repr(argval)
262
263def _get_name_info(name_index, name_list):
264 """Helper to get optional details about named references
265
266 Returns the dereferenced name as both value and repr if the name
267 list is defined.
268 Otherwise returns the name index and its repr().
269 """
270 argval = name_index
271 if name_list is not None:
272 argval = name_list[name_index]
273 argrepr = argval
274 else:
275 argrepr = repr(argval)
276 return argval, argrepr
277
278
279def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
280 cells=None, linestarts=None, line_offset=0):
281 """Iterate over the instructions in a bytecode string.
282
283 Generates a sequence of Instruction namedtuples giving the details of each
284 opcode. Additional information about the code's runtime environment
285 (e.g. variable names, constants) can be specified using optional
286 arguments.
287
288 """
289 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000290 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300291 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000292 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300293 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000294 if starts_line is not None:
295 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300296 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000297 argval = None
298 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300299 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000300 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300301 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000302 # _disassemble_bytes needs the string repr of the
303 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
304 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000305 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000307 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000308 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000309 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300310 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000311 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000312 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000313 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000314 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000315 argval = cmp_op[arg]
316 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000317 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000318 argval, argrepr = _get_name_info(arg, cells)
Serhiy Storchakadd102f72016-10-08 12:34:25 +0300319 elif op == FORMAT_VALUE:
320 argval = ((None, str, repr, ascii)[arg & 0x3], bool(arg & 0x4))
321 argrepr = ('', 'str', 'repr', 'ascii')[arg & 0x3]
322 if argval[1]:
323 if argrepr:
324 argrepr += ', '
325 argrepr += 'with format'
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000326 yield Instruction(opname[op], op,
327 arg, argval, argrepr,
328 offset, starts_line, is_jump_target)
329
330def disassemble(co, lasti=-1, *, file=None):
331 """Disassemble a code object."""
332 cell_names = co.co_cellvars + co.co_freevars
333 linestarts = dict(findlinestarts(co))
334 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
335 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000336
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000337def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000338 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000339 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000340 # Omit the line number column entirely if we have no line number info
341 show_lineno = linestarts is not None
342 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
343 lineno_width = 3 if show_lineno else 0
344 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000345 constants, cells, linestarts,
346 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000347 new_source_line = (show_lineno and
348 instr.starts_line is not None and
349 instr.offset > 0)
350 if new_source_line:
351 print(file=file)
352 is_current_instr = instr.offset == lasti
353 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000354
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000355def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000356 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000357 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000358
Tim Peters88869f92001-01-14 23:36:06 +0000359disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000360
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300361def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300362 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300363 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300364 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300365 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300366 arg = code[i+1] | extended_arg
367 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
368 else:
369 arg = None
370 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300371
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000372def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000373 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000374
Tim Peters88869f92001-01-14 23:36:06 +0000375 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000376
Tim Peters88869f92001-01-14 23:36:06 +0000377 """
378 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300379 for offset, op, arg in _unpack_opargs(code):
380 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000381 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300382 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000383 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000384 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300385 else:
386 continue
387 if label not in labels:
388 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000389 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000390
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000391def findlinestarts(code):
392 """Find the offsets in a byte code which are start of lines in the source.
393
394 Generate pairs (offset, lineno) as described in Python/compile.c.
395
396 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100397 byte_increments = code.co_lnotab[0::2]
398 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000399
400 lastlineno = None
401 lineno = code.co_firstlineno
402 addr = 0
403 for byte_incr, line_incr in zip(byte_increments, line_increments):
404 if byte_incr:
405 if lineno != lastlineno:
406 yield (addr, lineno)
407 lastlineno = lineno
408 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100409 if line_incr >= 0x80:
410 # line_increments is an array of 8-bit signed integers
411 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000412 lineno += line_incr
413 if lineno != lastlineno:
414 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000415
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000416class Bytecode:
417 """The bytecode operations of a piece of code
418
419 Instantiate this with a function, method, string of code, or a code object
420 (as returned by compile()).
421
422 Iterating over this yields the bytecode operations as Instruction instances.
423 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000424 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000425 self.codeobj = co = _get_code_object(x)
426 if first_line is None:
427 self.first_line = co.co_firstlineno
428 self._line_offset = 0
429 else:
430 self.first_line = first_line
431 self._line_offset = first_line - co.co_firstlineno
432 self._cell_names = co.co_cellvars + co.co_freevars
433 self._linestarts = dict(findlinestarts(co))
434 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000435 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000436
437 def __iter__(self):
438 co = self.codeobj
439 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000440 co.co_consts, self._cell_names,
441 self._linestarts,
442 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000443
444 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000445 return "{}({!r})".format(self.__class__.__name__,
446 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000447
Nick Coghlan50c48b82013-11-23 00:57:00 +1000448 @classmethod
449 def from_traceback(cls, tb):
450 """ Construct a Bytecode from the given traceback """
451 while tb.tb_next:
452 tb = tb.tb_next
453 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
454
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000455 def info(self):
456 """Return formatted information about the code object."""
457 return _format_code_info(self.codeobj)
458
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000459 def dis(self):
460 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000461 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000462 if self.current_offset is not None:
463 offset = self.current_offset
464 else:
465 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000466 with io.StringIO() as output:
467 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
468 names=co.co_names, constants=co.co_consts,
469 cells=self._cell_names,
470 linestarts=self._linestarts,
471 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000472 file=output,
473 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000474 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000475
476
Guido van Rossum1fdae122000-02-04 17:47:55 +0000477def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000478 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000479 import argparse
480
481 parser = argparse.ArgumentParser()
482 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
483 args = parser.parse_args()
484 with args.infile as infile:
485 source = infile.read()
486 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000487 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000488
489if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000490 _test()