blob: 1fafcc5346f50f64dae21df9a13694c80842f490 [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
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000016_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
17
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000018def _try_compile(source, name):
19 """Attempts to compile the given source, first as an expression and
20 then as a statement if the first approach fails.
21
22 Utility function to accept strings in functions that otherwise
23 expect code objects
24 """
Nick Coghlan5c8b54e2010-07-03 07:36:51 +000025 try:
26 c = compile(source, name, 'eval')
27 except SyntaxError:
28 c = compile(source, name, 'exec')
29 return c
30
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100031def dis(x=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000032 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000033
Tim Peters88869f92001-01-14 23:36:06 +000034 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000035
Tim Peters88869f92001-01-14 23:36:06 +000036 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000037 if x is None:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100038 distb(file=file)
Tim Peters88869f92001-01-14 23:36:06 +000039 return
Nick Coghlaneae2da12010-08-17 08:03:36 +000040 if hasattr(x, '__func__'): # Method
Christian Heimesff737952007-11-27 10:40:20 +000041 x = x.__func__
Nick Coghlaneae2da12010-08-17 08:03:36 +000042 if hasattr(x, '__code__'): # Function
Neal Norwitz221085d2007-02-25 20:55:47 +000043 x = x.__code__
Nick Coghlaneae2da12010-08-17 08:03:36 +000044 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000045 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000046 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000047 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100048 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000049 try:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100050 dis(x1, file=file)
Guido van Rossumb940e112007-01-10 16:19:56 +000051 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100052 print("Sorry:", msg, file=file)
53 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000054 elif hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100055 disassemble(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000056 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100057 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000058 elif isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100059 _disassemble_str(x, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000060 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000061 raise TypeError("don't know how to disassemble %s objects" %
62 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000063
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100064def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000065 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000066 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000067 try:
68 tb = sys.last_traceback
69 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000070 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000071 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100072 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000073
Nick Coghlan09c81232010-08-17 10:18:16 +000074# The inspect module interrogates this dictionary to build its
75# list of CO_* constants. It is also used by pretty_flags to
76# turn the co_flags field into a human readable list.
77COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000078 1: "OPTIMIZED",
79 2: "NEWLOCALS",
80 4: "VARARGS",
81 8: "VARKEYWORDS",
82 16: "NESTED",
83 32: "GENERATOR",
84 64: "NOFREE",
85}
86
87def pretty_flags(flags):
88 """Return pretty representation of code flags."""
89 names = []
90 for i in range(32):
91 flag = 1<<i
92 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000093 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000094 flags ^= flag
95 if not flags:
96 break
97 else:
98 names.append(hex(flags))
99 return ", ".join(names)
100
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000101def _get_code_object(x):
102 """Helper to handle methods, functions, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000103 if hasattr(x, '__func__'): # Method
104 x = x.__func__
105 if hasattr(x, '__code__'): # Function
106 x = x.__code__
107 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000108 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000109 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000110 return x
111 raise TypeError("don't know how to disassemble %s objects" %
112 type(x).__name__)
113
114def code_info(x):
115 """Formatted details of methods, functions, or code."""
116 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000117
118def _format_code_info(co):
119 lines = []
120 lines.append("Name: %s" % co.co_name)
121 lines.append("Filename: %s" % co.co_filename)
122 lines.append("Argument count: %s" % co.co_argcount)
123 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
124 lines.append("Number of locals: %s" % co.co_nlocals)
125 lines.append("Stack size: %s" % co.co_stacksize)
126 lines.append("Flags: %s" % pretty_flags(co.co_flags))
127 if co.co_consts:
128 lines.append("Constants:")
129 for i_c in enumerate(co.co_consts):
130 lines.append("%4d: %r" % i_c)
131 if co.co_names:
132 lines.append("Names:")
133 for i_n in enumerate(co.co_names):
134 lines.append("%4d: %s" % i_n)
135 if co.co_varnames:
136 lines.append("Variable names:")
137 for i_n in enumerate(co.co_varnames):
138 lines.append("%4d: %s" % i_n)
139 if co.co_freevars:
140 lines.append("Free variables:")
141 for i_n in enumerate(co.co_freevars):
142 lines.append("%4d: %s" % i_n)
143 if co.co_cellvars:
144 lines.append("Cell variables:")
145 for i_n in enumerate(co.co_cellvars):
146 lines.append("%4d: %s" % i_n)
147 return "\n".join(lines)
148
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000149def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300150 """Print details of methods, functions, or code to *file*.
151
152 If *file* is not provided, the output is printed on stdout.
153 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000154 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000155
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000156_Instruction = collections.namedtuple("_Instruction",
157 "opname opcode arg argval argrepr offset starts_line is_jump_target")
158
159class Instruction(_Instruction):
160 """Details for a bytecode operation
161
162 Defined fields:
163 opname - human readable name for operation
164 opcode - numeric code for operation
165 arg - numeric argument to operation (if any), otherwise None
166 argval - resolved arg value (if known), otherwise same as arg
167 argrepr - human readable description of operation argument
168 offset - start index of operation within bytecode sequence
169 starts_line - line started by this opcode (if any), otherwise None
170 is_jump_target - True if other code jumps to here, otherwise False
171 """
172
173 def _disassemble(self, lineno_width=3, mark_as_current=False):
174 """Format instruction details for inclusion in disassembly output
175
176 *lineno_width* sets the width of the line number field (0 omits it)
177 *mark_as_current* inserts a '-->' marker arrow as part of the line
178 """
179 fields = []
180 # Column: Source code line number
181 if lineno_width:
182 if self.starts_line is not None:
183 lineno_fmt = "%%%dd" % lineno_width
184 fields.append(lineno_fmt % self.starts_line)
185 else:
186 fields.append(' ' * lineno_width)
187 # Column: Current instruction indicator
188 if mark_as_current:
189 fields.append('-->')
190 else:
191 fields.append(' ')
192 # Column: Jump target marker
193 if self.is_jump_target:
194 fields.append('>>')
195 else:
196 fields.append(' ')
197 # Column: Instruction offset from start of code sequence
198 fields.append(repr(self.offset).rjust(4))
199 # Column: Opcode name
200 fields.append(self.opname.ljust(20))
201 # Column: Opcode argument
202 if self.arg is not None:
203 fields.append(repr(self.arg).rjust(5))
204 # Column: Opcode argument details
205 if self.argrepr:
206 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000207 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000208
209
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000210def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000211 """Iterator for the opcodes in methods, functions or code
212
213 Generates a series of Instruction named tuples giving the details of
214 each operations in the supplied code.
215
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000216 If *first_line* is not None, it indicates the line number that should
217 be reported for the first source line in the disassembled code.
218 Otherwise, the source line information (if any) is taken directly from
219 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000220 """
221 co = _get_code_object(x)
222 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000223 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000224 if first_line is not None:
225 line_offset = first_line - co.co_firstlineno
226 else:
227 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000228 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
229 co.co_consts, cell_names, linestarts,
230 line_offset)
231
232def _get_const_info(const_index, const_list):
233 """Helper to get optional details about const references
234
235 Returns the dereferenced constant and its repr if the constant
236 list is defined.
237 Otherwise returns the constant index and its repr().
238 """
239 argval = const_index
240 if const_list is not None:
241 argval = const_list[const_index]
242 return argval, repr(argval)
243
244def _get_name_info(name_index, name_list):
245 """Helper to get optional details about named references
246
247 Returns the dereferenced name as both value and repr if the name
248 list is defined.
249 Otherwise returns the name index and its repr().
250 """
251 argval = name_index
252 if name_list is not None:
253 argval = name_list[name_index]
254 argrepr = argval
255 else:
256 argrepr = repr(argval)
257 return argval, argrepr
258
259
260def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
261 cells=None, linestarts=None, line_offset=0):
262 """Iterate over the instructions in a bytecode string.
263
264 Generates a sequence of Instruction namedtuples giving the details of each
265 opcode. Additional information about the code's runtime environment
266 (e.g. variable names, constants) can be specified using optional
267 arguments.
268
269 """
270 labels = findlabels(code)
271 extended_arg = 0
272 starts_line = None
273 free = None
274 # enumerate() is not an option, since we sometimes process
275 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000276 n = len(code)
277 i = 0
Tim Peters88869f92001-01-14 23:36:06 +0000278 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000279 op = code[i]
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000280 offset = i
281 if linestarts is not None:
282 starts_line = linestarts.get(i, None)
283 if starts_line is not None:
284 starts_line += line_offset
285 is_jump_target = i in labels
Tim Peters88869f92001-01-14 23:36:06 +0000286 i = i+1
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000287 arg = None
288 argval = None
289 argrepr = ''
Tim Peters88869f92001-01-14 23:36:06 +0000290 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000291 arg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000292 extended_arg = 0
293 i = i+2
294 if op == EXTENDED_ARG:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 extended_arg = arg*65536
296 # Set argval to the dereferenced value of the argument when
297 # availabe, and argrepr to the string representation of argval.
298 # _disassemble_bytes needs the string repr of the
299 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
300 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000301 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000302 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000303 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000304 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000305 elif op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 argval = i + arg
307 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000308 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000309 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000310 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000311 argval = cmp_op[arg]
312 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000313 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000314 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400315 elif op in hasnargs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000316 argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
317 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
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000352def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000353 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000354
Tim Peters88869f92001-01-14 23:36:06 +0000355 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000356
Tim Peters88869f92001-01-14 23:36:06 +0000357 """
358 labels = []
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000359 # enumerate() is not an option, since we sometimes process
360 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000361 n = len(code)
362 i = 0
363 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000364 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000365 i = i+1
366 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000367 arg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000368 i = i+2
369 label = -1
370 if op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000371 label = i+arg
Tim Peters88869f92001-01-14 23:36:06 +0000372 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000373 label = arg
Tim Peters88869f92001-01-14 23:36:06 +0000374 if label >= 0:
375 if label not in labels:
376 labels.append(label)
377 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000378
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000379def findlinestarts(code):
380 """Find the offsets in a byte code which are start of lines in the source.
381
382 Generate pairs (offset, lineno) as described in Python/compile.c.
383
384 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000385 byte_increments = list(code.co_lnotab[0::2])
386 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000387
388 lastlineno = None
389 lineno = code.co_firstlineno
390 addr = 0
391 for byte_incr, line_incr in zip(byte_increments, line_increments):
392 if byte_incr:
393 if lineno != lastlineno:
394 yield (addr, lineno)
395 lastlineno = lineno
396 addr += byte_incr
397 lineno += line_incr
398 if lineno != lastlineno:
399 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000400
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000401class Bytecode:
402 """The bytecode operations of a piece of code
403
404 Instantiate this with a function, method, string of code, or a code object
405 (as returned by compile()).
406
407 Iterating over this yields the bytecode operations as Instruction instances.
408 """
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000409 def __init__(self, x, *, first_line=None):
410 self.codeobj = co = _get_code_object(x)
411 if first_line is None:
412 self.first_line = co.co_firstlineno
413 self._line_offset = 0
414 else:
415 self.first_line = first_line
416 self._line_offset = first_line - co.co_firstlineno
417 self._cell_names = co.co_cellvars + co.co_freevars
418 self._linestarts = dict(findlinestarts(co))
419 self._original_object = x
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000420
421 def __iter__(self):
422 co = self.codeobj
423 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000424 co.co_consts, self._cell_names,
425 self._linestarts,
426 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000427
428 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000429 return "{}({!r})".format(self.__class__.__name__,
430 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000431
432 def info(self):
433 """Return formatted information about the code object."""
434 return _format_code_info(self.codeobj)
435
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000436 def dis(self):
437 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000438 co = self.codeobj
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000439 with io.StringIO() as output:
440 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
441 names=co.co_names, constants=co.co_consts,
442 cells=self._cell_names,
443 linestarts=self._linestarts,
444 line_offset=self._line_offset,
445 file=output)
446 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000447
448
Guido van Rossum1fdae122000-02-04 17:47:55 +0000449def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000450 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000451 import argparse
452
453 parser = argparse.ArgumentParser()
454 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
455 args = parser.parse_args()
456 with args.infile as infile:
457 source = infile.read()
458 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000459 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000460
461if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000462 _test()