blob: 3a706be3c8914dbfc27a1d4fc0bb43465156d447 [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
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000019def _try_compile(source, name):
20 """Attempts to compile the given source, first as an expression and
21 then as a statement if the first approach fails.
22
23 Utility function to accept strings in functions that otherwise
24 expect code objects
25 """
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000026 try:
27 c = compile(source, name, 'eval')
28 except SyntaxError:
29 c = compile(source, name, 'exec')
30 return c
31
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100032def dis(x=None, *, file=None):
Nick Coghlanefd5df92014-07-25 23:02:56 +100033 """Disassemble classes, methods, functions, generators, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000034
Tim Peters88869f92001-01-14 23:36:06 +000035 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000036
Tim Peters88869f92001-01-14 23:36:06 +000037 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000038 if x is None:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100039 distb(file=file)
Tim Peters88869f92001-01-14 23:36:06 +000040 return
Nick Coghlaneae2da12010-08-17 08:03:36 +000041 if hasattr(x, '__func__'): # Method
Christian Heimesff737952007-11-27 10:40:20 +000042 x = x.__func__
Nick Coghlaneae2da12010-08-17 08:03:36 +000043 if hasattr(x, '__code__'): # Function
Neal Norwitz221085d2007-02-25 20:55:47 +000044 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +100045 if hasattr(x, 'gi_code'): # Generator
46 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +000047 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000048 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000049 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000050 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100051 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000052 try:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100053 dis(x1, file=file)
Guido van Rossumb940e112007-01-10 16:19:56 +000054 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100055 print("Sorry:", msg, file=file)
56 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000057 elif hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100058 disassemble(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000059 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100060 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000061 elif isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100062 _disassemble_str(x, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000063 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000064 raise TypeError("don't know how to disassemble %s objects" %
65 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000066
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100067def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000068 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000069 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000070 try:
71 tb = sys.last_traceback
72 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000073 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000074 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100075 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000076
Nick Coghlan09c81232010-08-17 10:18:16 +000077# The inspect module interrogates this dictionary to build its
78# list of CO_* constants. It is also used by pretty_flags to
79# turn the co_flags field into a human readable list.
80COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000081 1: "OPTIMIZED",
82 2: "NEWLOCALS",
83 4: "VARARGS",
84 8: "VARKEYWORDS",
85 16: "NESTED",
86 32: "GENERATOR",
87 64: "NOFREE",
Yury Selivanov75445082015-05-11 22:57:16 -040088 128: "COROUTINE",
89 256: "ITERABLE_COROUTINE",
Yury Selivanoveb636452016-09-08 22:01:51 -070090 512: "ASYNC_GENERATOR",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000091}
92
93def pretty_flags(flags):
94 """Return pretty representation of code flags."""
95 names = []
96 for i in range(32):
97 flag = 1<<i
98 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000099 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000100 flags ^= flag
101 if not flags:
102 break
103 else:
104 names.append(hex(flags))
105 return ", ".join(names)
106
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000107def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000108 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000109 if hasattr(x, '__func__'): # Method
110 x = x.__func__
111 if hasattr(x, '__code__'): # Function
112 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000113 if hasattr(x, 'gi_code'): # Generator
114 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000115 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000116 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000117 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000118 return x
119 raise TypeError("don't know how to disassemble %s objects" %
120 type(x).__name__)
121
122def code_info(x):
123 """Formatted details of methods, functions, or code."""
124 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000125
126def _format_code_info(co):
127 lines = []
128 lines.append("Name: %s" % co.co_name)
129 lines.append("Filename: %s" % co.co_filename)
130 lines.append("Argument count: %s" % co.co_argcount)
131 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
132 lines.append("Number of locals: %s" % co.co_nlocals)
133 lines.append("Stack size: %s" % co.co_stacksize)
134 lines.append("Flags: %s" % pretty_flags(co.co_flags))
135 if co.co_consts:
136 lines.append("Constants:")
137 for i_c in enumerate(co.co_consts):
138 lines.append("%4d: %r" % i_c)
139 if co.co_names:
140 lines.append("Names:")
141 for i_n in enumerate(co.co_names):
142 lines.append("%4d: %s" % i_n)
143 if co.co_varnames:
144 lines.append("Variable names:")
145 for i_n in enumerate(co.co_varnames):
146 lines.append("%4d: %s" % i_n)
147 if co.co_freevars:
148 lines.append("Free variables:")
149 for i_n in enumerate(co.co_freevars):
150 lines.append("%4d: %s" % i_n)
151 if co.co_cellvars:
152 lines.append("Cell variables:")
153 for i_n in enumerate(co.co_cellvars):
154 lines.append("%4d: %s" % i_n)
155 return "\n".join(lines)
156
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000157def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300158 """Print details of methods, functions, or code to *file*.
159
160 If *file* is not provided, the output is printed on stdout.
161 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000162 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000163
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000164_Instruction = collections.namedtuple("_Instruction",
165 "opname opcode arg argval argrepr offset starts_line is_jump_target")
166
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700167_Instruction.opname.__doc__ = "Human readable name for operation"
168_Instruction.opcode.__doc__ = "Numeric code for operation"
169_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
170_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
171_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
172_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
173_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
174_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
175
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000176class Instruction(_Instruction):
177 """Details for a bytecode operation
178
179 Defined fields:
180 opname - human readable name for operation
181 opcode - numeric code for operation
182 arg - numeric argument to operation (if any), otherwise None
183 argval - resolved arg value (if known), otherwise same as arg
184 argrepr - human readable description of operation argument
185 offset - start index of operation within bytecode sequence
186 starts_line - line started by this opcode (if any), otherwise None
187 is_jump_target - True if other code jumps to here, otherwise False
188 """
189
190 def _disassemble(self, lineno_width=3, mark_as_current=False):
191 """Format instruction details for inclusion in disassembly output
192
193 *lineno_width* sets the width of the line number field (0 omits it)
194 *mark_as_current* inserts a '-->' marker arrow as part of the line
195 """
196 fields = []
197 # Column: Source code line number
198 if lineno_width:
199 if self.starts_line is not None:
200 lineno_fmt = "%%%dd" % lineno_width
201 fields.append(lineno_fmt % self.starts_line)
202 else:
203 fields.append(' ' * lineno_width)
204 # Column: Current instruction indicator
205 if mark_as_current:
206 fields.append('-->')
207 else:
208 fields.append(' ')
209 # Column: Jump target marker
210 if self.is_jump_target:
211 fields.append('>>')
212 else:
213 fields.append(' ')
214 # Column: Instruction offset from start of code sequence
215 fields.append(repr(self.offset).rjust(4))
216 # Column: Opcode name
217 fields.append(self.opname.ljust(20))
218 # Column: Opcode argument
219 if self.arg is not None:
220 fields.append(repr(self.arg).rjust(5))
221 # Column: Opcode argument details
222 if self.argrepr:
223 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000224 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000225
226
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000227def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000228 """Iterator for the opcodes in methods, functions or code
229
230 Generates a series of Instruction named tuples giving the details of
231 each operations in the supplied code.
232
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000233 If *first_line* is not None, it indicates the line number that should
234 be reported for the first source line in the disassembled code.
235 Otherwise, the source line information (if any) is taken directly from
236 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000237 """
238 co = _get_code_object(x)
239 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000240 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000241 if first_line is not None:
242 line_offset = first_line - co.co_firstlineno
243 else:
244 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000245 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
246 co.co_consts, cell_names, linestarts,
247 line_offset)
248
249def _get_const_info(const_index, const_list):
250 """Helper to get optional details about const references
251
252 Returns the dereferenced constant and its repr if the constant
253 list is defined.
254 Otherwise returns the constant index and its repr().
255 """
256 argval = const_index
257 if const_list is not None:
258 argval = const_list[const_index]
259 return argval, repr(argval)
260
261def _get_name_info(name_index, name_list):
262 """Helper to get optional details about named references
263
264 Returns the dereferenced name as both value and repr if the name
265 list is defined.
266 Otherwise returns the name index and its repr().
267 """
268 argval = name_index
269 if name_list is not None:
270 argval = name_list[name_index]
271 argrepr = argval
272 else:
273 argrepr = repr(argval)
274 return argval, argrepr
275
276
277def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
278 cells=None, linestarts=None, line_offset=0):
279 """Iterate over the instructions in a bytecode string.
280
281 Generates a sequence of Instruction namedtuples giving the details of each
282 opcode. Additional information about the code's runtime environment
283 (e.g. variable names, constants) can be specified using optional
284 arguments.
285
286 """
287 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000288 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300289 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000290 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300291 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000292 if starts_line is not None:
293 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300294 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 argval = None
296 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300297 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000298 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300299 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000300 # _disassemble_bytes needs the string repr of the
301 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
302 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000303 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000304 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000305 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000307 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300308 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000309 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000310 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000311 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000312 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000313 argval = cmp_op[arg]
314 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000315 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000316 argval, argrepr = _get_name_info(arg, cells)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000317 yield Instruction(opname[op], op,
318 arg, argval, argrepr,
319 offset, starts_line, is_jump_target)
320
321def disassemble(co, lasti=-1, *, file=None):
322 """Disassemble a code object."""
323 cell_names = co.co_cellvars + co.co_freevars
324 linestarts = dict(findlinestarts(co))
325 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
326 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000327
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000328def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000329 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000330 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000331 # Omit the line number column entirely if we have no line number info
332 show_lineno = linestarts is not None
333 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
334 lineno_width = 3 if show_lineno else 0
335 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000336 constants, cells, linestarts,
337 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000338 new_source_line = (show_lineno and
339 instr.starts_line is not None and
340 instr.offset > 0)
341 if new_source_line:
342 print(file=file)
343 is_current_instr = instr.offset == lasti
344 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000345
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000346def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000347 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000348 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000349
Tim Peters88869f92001-01-14 23:36:06 +0000350disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000351
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300352def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300353 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300354 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300355 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300356 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300357 arg = code[i+1] | extended_arg
358 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
359 else:
360 arg = None
361 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300362
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000363def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000364 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000365
Tim Peters88869f92001-01-14 23:36:06 +0000366 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000367
Tim Peters88869f92001-01-14 23:36:06 +0000368 """
369 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300370 for offset, op, arg in _unpack_opargs(code):
371 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000372 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300373 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000374 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000375 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300376 else:
377 continue
378 if label not in labels:
379 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000380 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000381
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000382def findlinestarts(code):
383 """Find the offsets in a byte code which are start of lines in the source.
384
385 Generate pairs (offset, lineno) as described in Python/compile.c.
386
387 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100388 byte_increments = code.co_lnotab[0::2]
389 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000390
391 lastlineno = None
392 lineno = code.co_firstlineno
393 addr = 0
394 for byte_incr, line_incr in zip(byte_increments, line_increments):
395 if byte_incr:
396 if lineno != lastlineno:
397 yield (addr, lineno)
398 lastlineno = lineno
399 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100400 if line_incr >= 0x80:
401 # line_increments is an array of 8-bit signed integers
402 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000403 lineno += line_incr
404 if lineno != lastlineno:
405 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000406
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000407class Bytecode:
408 """The bytecode operations of a piece of code
409
410 Instantiate this with a function, method, string of code, or a code object
411 (as returned by compile()).
412
413 Iterating over this yields the bytecode operations as Instruction instances.
414 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000415 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000416 self.codeobj = co = _get_code_object(x)
417 if first_line is None:
418 self.first_line = co.co_firstlineno
419 self._line_offset = 0
420 else:
421 self.first_line = first_line
422 self._line_offset = first_line - co.co_firstlineno
423 self._cell_names = co.co_cellvars + co.co_freevars
424 self._linestarts = dict(findlinestarts(co))
425 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000426 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000427
428 def __iter__(self):
429 co = self.codeobj
430 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000431 co.co_consts, self._cell_names,
432 self._linestarts,
433 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000434
435 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000436 return "{}({!r})".format(self.__class__.__name__,
437 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000438
Nick Coghlan50c48b82013-11-23 00:57:00 +1000439 @classmethod
440 def from_traceback(cls, tb):
441 """ Construct a Bytecode from the given traceback """
442 while tb.tb_next:
443 tb = tb.tb_next
444 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
445
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000446 def info(self):
447 """Return formatted information about the code object."""
448 return _format_code_info(self.codeobj)
449
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000450 def dis(self):
451 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000452 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000453 if self.current_offset is not None:
454 offset = self.current_offset
455 else:
456 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000457 with io.StringIO() as output:
458 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
459 names=co.co_names, constants=co.co_consts,
460 cells=self._cell_names,
461 linestarts=self._linestarts,
462 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000463 file=output,
464 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000465 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000466
467
Guido van Rossum1fdae122000-02-04 17:47:55 +0000468def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000469 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000470 import argparse
471
472 parser = argparse.ArgumentParser()
473 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
474 args = parser.parse_args()
475 with args.infile as infile:
476 source = infile.read()
477 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000478 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000479
480if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000481 _test()