blob: f7e3c7f8d7c98d93db6310659e20ea9ba3f0728c [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",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000090}
91
92def pretty_flags(flags):
93 """Return pretty representation of code flags."""
94 names = []
95 for i in range(32):
96 flag = 1<<i
97 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000098 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000099 flags ^= flag
100 if not flags:
101 break
102 else:
103 names.append(hex(flags))
104 return ", ".join(names)
105
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000106def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000107 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000108 if hasattr(x, '__func__'): # Method
109 x = x.__func__
110 if hasattr(x, '__code__'): # Function
111 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000112 if hasattr(x, 'gi_code'): # Generator
113 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000114 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000115 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000116 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000117 return x
118 raise TypeError("don't know how to disassemble %s objects" %
119 type(x).__name__)
120
121def code_info(x):
122 """Formatted details of methods, functions, or code."""
123 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000124
125def _format_code_info(co):
126 lines = []
127 lines.append("Name: %s" % co.co_name)
128 lines.append("Filename: %s" % co.co_filename)
129 lines.append("Argument count: %s" % co.co_argcount)
130 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
131 lines.append("Number of locals: %s" % co.co_nlocals)
132 lines.append("Stack size: %s" % co.co_stacksize)
133 lines.append("Flags: %s" % pretty_flags(co.co_flags))
134 if co.co_consts:
135 lines.append("Constants:")
136 for i_c in enumerate(co.co_consts):
137 lines.append("%4d: %r" % i_c)
138 if co.co_names:
139 lines.append("Names:")
140 for i_n in enumerate(co.co_names):
141 lines.append("%4d: %s" % i_n)
142 if co.co_varnames:
143 lines.append("Variable names:")
144 for i_n in enumerate(co.co_varnames):
145 lines.append("%4d: %s" % i_n)
146 if co.co_freevars:
147 lines.append("Free variables:")
148 for i_n in enumerate(co.co_freevars):
149 lines.append("%4d: %s" % i_n)
150 if co.co_cellvars:
151 lines.append("Cell variables:")
152 for i_n in enumerate(co.co_cellvars):
153 lines.append("%4d: %s" % i_n)
154 return "\n".join(lines)
155
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000156def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300157 """Print details of methods, functions, or code to *file*.
158
159 If *file* is not provided, the output is printed on stdout.
160 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000161 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000162
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000163_Instruction = collections.namedtuple("_Instruction",
164 "opname opcode arg argval argrepr offset starts_line is_jump_target")
165
166class Instruction(_Instruction):
167 """Details for a bytecode operation
168
169 Defined fields:
170 opname - human readable name for operation
171 opcode - numeric code for operation
172 arg - numeric argument to operation (if any), otherwise None
173 argval - resolved arg value (if known), otherwise same as arg
174 argrepr - human readable description of operation argument
175 offset - start index of operation within bytecode sequence
176 starts_line - line started by this opcode (if any), otherwise None
177 is_jump_target - True if other code jumps to here, otherwise False
178 """
179
180 def _disassemble(self, lineno_width=3, mark_as_current=False):
181 """Format instruction details for inclusion in disassembly output
182
183 *lineno_width* sets the width of the line number field (0 omits it)
184 *mark_as_current* inserts a '-->' marker arrow as part of the line
185 """
186 fields = []
187 # Column: Source code line number
188 if lineno_width:
189 if self.starts_line is not None:
190 lineno_fmt = "%%%dd" % lineno_width
191 fields.append(lineno_fmt % self.starts_line)
192 else:
193 fields.append(' ' * lineno_width)
194 # Column: Current instruction indicator
195 if mark_as_current:
196 fields.append('-->')
197 else:
198 fields.append(' ')
199 # Column: Jump target marker
200 if self.is_jump_target:
201 fields.append('>>')
202 else:
203 fields.append(' ')
204 # Column: Instruction offset from start of code sequence
205 fields.append(repr(self.offset).rjust(4))
206 # Column: Opcode name
207 fields.append(self.opname.ljust(20))
208 # Column: Opcode argument
209 if self.arg is not None:
210 fields.append(repr(self.arg).rjust(5))
211 # Column: Opcode argument details
212 if self.argrepr:
213 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000214 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000215
216
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000217def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000218 """Iterator for the opcodes in methods, functions or code
219
220 Generates a series of Instruction named tuples giving the details of
221 each operations in the supplied code.
222
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000223 If *first_line* is not None, it indicates the line number that should
224 be reported for the first source line in the disassembled code.
225 Otherwise, the source line information (if any) is taken directly from
226 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000227 """
228 co = _get_code_object(x)
229 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000230 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000231 if first_line is not None:
232 line_offset = first_line - co.co_firstlineno
233 else:
234 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000235 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
236 co.co_consts, cell_names, linestarts,
237 line_offset)
238
239def _get_const_info(const_index, const_list):
240 """Helper to get optional details about const references
241
242 Returns the dereferenced constant and its repr if the constant
243 list is defined.
244 Otherwise returns the constant index and its repr().
245 """
246 argval = const_index
247 if const_list is not None:
248 argval = const_list[const_index]
249 return argval, repr(argval)
250
251def _get_name_info(name_index, name_list):
252 """Helper to get optional details about named references
253
254 Returns the dereferenced name as both value and repr if the name
255 list is defined.
256 Otherwise returns the name index and its repr().
257 """
258 argval = name_index
259 if name_list is not None:
260 argval = name_list[name_index]
261 argrepr = argval
262 else:
263 argrepr = repr(argval)
264 return argval, argrepr
265
266
267def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
268 cells=None, linestarts=None, line_offset=0):
269 """Iterate over the instructions in a bytecode string.
270
271 Generates a sequence of Instruction namedtuples giving the details of each
272 opcode. Additional information about the code's runtime environment
273 (e.g. variable names, constants) can be specified using optional
274 arguments.
275
276 """
277 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000278 starts_line = None
279 free = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300280 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000281 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300282 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000283 if starts_line is not None:
284 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300285 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000286 argval = None
287 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300288 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000289 # Set argval to the dereferenced value of the argument when
Martin Panter46f50722016-05-26 05:35:26 +0000290 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000291 # _disassemble_bytes needs the string repr of the
292 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
293 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000294 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000296 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000297 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000298 elif op in hasjrel:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300299 argval = offset + 3 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000300 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000301 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000302 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000303 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000304 argval = cmp_op[arg]
305 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000306 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000307 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400308 elif op in hasnargs:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300309 argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 yield Instruction(opname[op], op,
311 arg, argval, argrepr,
312 offset, starts_line, is_jump_target)
313
314def disassemble(co, lasti=-1, *, file=None):
315 """Disassemble a code object."""
316 cell_names = co.co_cellvars + co.co_freevars
317 linestarts = dict(findlinestarts(co))
318 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
319 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000320
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000321def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000322 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000323 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000324 # Omit the line number column entirely if we have no line number info
325 show_lineno = linestarts is not None
326 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
327 lineno_width = 3 if show_lineno else 0
328 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000329 constants, cells, linestarts,
330 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000331 new_source_line = (show_lineno and
332 instr.starts_line is not None and
333 instr.offset > 0)
334 if new_source_line:
335 print(file=file)
336 is_current_instr = instr.offset == lasti
337 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000338
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000339def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000340 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000341 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000342
Tim Peters88869f92001-01-14 23:36:06 +0000343disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000344
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300345def _unpack_opargs(code):
346 # enumerate() is not an option, since we sometimes process
347 # multiple elements on a single pass through the loop
348 extended_arg = 0
349 n = len(code)
350 i = 0
351 while i < n:
352 op = code[i]
353 offset = i
354 i = i+1
355 arg = None
356 if op >= HAVE_ARGUMENT:
357 arg = code[i] + code[i+1]*256 + extended_arg
358 extended_arg = 0
359 i = i+2
360 if op == EXTENDED_ARG:
361 extended_arg = arg*65536
362 yield (offset, op, arg)
363
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000364def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000365 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000366
Tim Peters88869f92001-01-14 23:36:06 +0000367 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000368
Tim Peters88869f92001-01-14 23:36:06 +0000369 """
370 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300371 for offset, op, arg in _unpack_opargs(code):
372 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000373 label = -1
374 if op in hasjrel:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300375 label = offset + 3 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000376 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000377 label = arg
Tim Peters88869f92001-01-14 23:36:06 +0000378 if label >= 0:
379 if label not in labels:
380 labels.append(label)
381 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000382
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000383def findlinestarts(code):
384 """Find the offsets in a byte code which are start of lines in the source.
385
386 Generate pairs (offset, lineno) as described in Python/compile.c.
387
388 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000389 byte_increments = list(code.co_lnotab[0::2])
390 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000391
392 lastlineno = None
393 lineno = code.co_firstlineno
394 addr = 0
395 for byte_incr, line_incr in zip(byte_increments, line_increments):
396 if byte_incr:
397 if lineno != lastlineno:
398 yield (addr, lineno)
399 lastlineno = lineno
400 addr += byte_incr
401 lineno += line_incr
402 if lineno != lastlineno:
403 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000404
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000405class Bytecode:
406 """The bytecode operations of a piece of code
407
408 Instantiate this with a function, method, string of code, or a code object
409 (as returned by compile()).
410
411 Iterating over this yields the bytecode operations as Instruction instances.
412 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000413 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000414 self.codeobj = co = _get_code_object(x)
415 if first_line is None:
416 self.first_line = co.co_firstlineno
417 self._line_offset = 0
418 else:
419 self.first_line = first_line
420 self._line_offset = first_line - co.co_firstlineno
421 self._cell_names = co.co_cellvars + co.co_freevars
422 self._linestarts = dict(findlinestarts(co))
423 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000424 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000425
426 def __iter__(self):
427 co = self.codeobj
428 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000429 co.co_consts, self._cell_names,
430 self._linestarts,
431 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000432
433 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000434 return "{}({!r})".format(self.__class__.__name__,
435 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000436
Nick Coghlan50c48b82013-11-23 00:57:00 +1000437 @classmethod
438 def from_traceback(cls, tb):
439 """ Construct a Bytecode from the given traceback """
440 while tb.tb_next:
441 tb = tb.tb_next
442 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
443
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000444 def info(self):
445 """Return formatted information about the code object."""
446 return _format_code_info(self.codeobj)
447
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000448 def dis(self):
449 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000450 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000451 if self.current_offset is not None:
452 offset = self.current_offset
453 else:
454 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000455 with io.StringIO() as output:
456 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
457 names=co.co_names, constants=co.co_consts,
458 cells=self._cell_names,
459 linestarts=self._linestarts,
460 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000461 file=output,
462 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000463 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000464
465
Guido van Rossum1fdae122000-02-04 17:47:55 +0000466def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000467 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000468 import argparse
469
470 parser = argparse.ArgumentParser()
471 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
472 args = parser.parse_args()
473 with args.infile as infile:
474 source = infile.read()
475 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000476 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000477
478if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000479 _test()