blob: af37cdf0c67e4e45c6c68c02ef31149ff3ef65cd [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):
Nick Coghlanefd5df92014-07-25 23:02:56 +100032 """Disassemble classes, methods, functions, generators, 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 Coghlanefd5df92014-07-25 23:02:56 +100044 if hasattr(x, 'gi_code'): # Generator
45 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +000046 if hasattr(x, '__dict__'): # Class or module
Guido van Rossume7ba4952007-06-06 23:52:48 +000047 items = sorted(x.__dict__.items())
Tim Peters88869f92001-01-14 23:36:06 +000048 for name, x1 in items:
Benjamin Peterson6ef9a842010-04-04 23:26:50 +000049 if isinstance(x1, _have_code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100050 print("Disassembly of %s:" % name, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000051 try:
Nick Coghlan90b8e7d2013-11-06 22:08:36 +100052 dis(x1, file=file)
Guido van Rossumb940e112007-01-10 16:19:56 +000053 except TypeError as msg:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100054 print("Sorry:", msg, file=file)
55 print(file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000056 elif hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100057 disassemble(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000058 elif isinstance(x, (bytes, bytearray)): # Raw bytecode
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100059 _disassemble_bytes(x, file=file)
Nick Coghlaneae2da12010-08-17 08:03:36 +000060 elif isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100061 _disassemble_str(x, file=file)
Tim Peters88869f92001-01-14 23:36:06 +000062 else:
Guido van Rossume7ba4952007-06-06 23:52:48 +000063 raise TypeError("don't know how to disassemble %s objects" %
64 type(x).__name__)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000065
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100066def distb(tb=None, *, file=None):
Tim Peters88869f92001-01-14 23:36:06 +000067 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000068 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000069 try:
70 tb = sys.last_traceback
71 except AttributeError:
Collin Winterce36ad82007-08-30 01:19:48 +000072 raise RuntimeError("no last traceback to disassemble")
Tim Peters88869f92001-01-14 23:36:06 +000073 while tb.tb_next: tb = tb.tb_next
Nick Coghlanb39fd0c2013-05-06 23:59:20 +100074 disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000075
Nick Coghlan09c81232010-08-17 10:18:16 +000076# The inspect module interrogates this dictionary to build its
77# list of CO_* constants. It is also used by pretty_flags to
78# turn the co_flags field into a human readable list.
79COMPILER_FLAG_NAMES = {
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000080 1: "OPTIMIZED",
81 2: "NEWLOCALS",
82 4: "VARARGS",
83 8: "VARKEYWORDS",
84 16: "NESTED",
85 32: "GENERATOR",
86 64: "NOFREE",
Yury Selivanov75445082015-05-11 22:57:16 -040087 128: "COROUTINE",
88 256: "ITERABLE_COROUTINE",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000089}
90
91def pretty_flags(flags):
92 """Return pretty representation of code flags."""
93 names = []
94 for i in range(32):
95 flag = 1<<i
96 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000097 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000098 flags ^= flag
99 if not flags:
100 break
101 else:
102 names.append(hex(flags))
103 return ", ".join(names)
104
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000105def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000106 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000107 if hasattr(x, '__func__'): # Method
108 x = x.__func__
109 if hasattr(x, '__code__'): # Function
110 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000111 if hasattr(x, 'gi_code'): # Generator
112 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000113 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000114 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000115 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000116 return x
117 raise TypeError("don't know how to disassemble %s objects" %
118 type(x).__name__)
119
120def code_info(x):
121 """Formatted details of methods, functions, or code."""
122 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000123
124def _format_code_info(co):
125 lines = []
126 lines.append("Name: %s" % co.co_name)
127 lines.append("Filename: %s" % co.co_filename)
128 lines.append("Argument count: %s" % co.co_argcount)
129 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
130 lines.append("Number of locals: %s" % co.co_nlocals)
131 lines.append("Stack size: %s" % co.co_stacksize)
132 lines.append("Flags: %s" % pretty_flags(co.co_flags))
133 if co.co_consts:
134 lines.append("Constants:")
135 for i_c in enumerate(co.co_consts):
136 lines.append("%4d: %r" % i_c)
137 if co.co_names:
138 lines.append("Names:")
139 for i_n in enumerate(co.co_names):
140 lines.append("%4d: %s" % i_n)
141 if co.co_varnames:
142 lines.append("Variable names:")
143 for i_n in enumerate(co.co_varnames):
144 lines.append("%4d: %s" % i_n)
145 if co.co_freevars:
146 lines.append("Free variables:")
147 for i_n in enumerate(co.co_freevars):
148 lines.append("%4d: %s" % i_n)
149 if co.co_cellvars:
150 lines.append("Cell variables:")
151 for i_n in enumerate(co.co_cellvars):
152 lines.append("%4d: %s" % i_n)
153 return "\n".join(lines)
154
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000155def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300156 """Print details of methods, functions, or code to *file*.
157
158 If *file* is not provided, the output is printed on stdout.
159 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000160 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000161
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000162_Instruction = collections.namedtuple("_Instruction",
163 "opname opcode arg argval argrepr offset starts_line is_jump_target")
164
165class Instruction(_Instruction):
166 """Details for a bytecode operation
167
168 Defined fields:
169 opname - human readable name for operation
170 opcode - numeric code for operation
171 arg - numeric argument to operation (if any), otherwise None
172 argval - resolved arg value (if known), otherwise same as arg
173 argrepr - human readable description of operation argument
174 offset - start index of operation within bytecode sequence
175 starts_line - line started by this opcode (if any), otherwise None
176 is_jump_target - True if other code jumps to here, otherwise False
177 """
178
179 def _disassemble(self, lineno_width=3, mark_as_current=False):
180 """Format instruction details for inclusion in disassembly output
181
182 *lineno_width* sets the width of the line number field (0 omits it)
183 *mark_as_current* inserts a '-->' marker arrow as part of the line
184 """
185 fields = []
186 # Column: Source code line number
187 if lineno_width:
188 if self.starts_line is not None:
189 lineno_fmt = "%%%dd" % lineno_width
190 fields.append(lineno_fmt % self.starts_line)
191 else:
192 fields.append(' ' * lineno_width)
193 # Column: Current instruction indicator
194 if mark_as_current:
195 fields.append('-->')
196 else:
197 fields.append(' ')
198 # Column: Jump target marker
199 if self.is_jump_target:
200 fields.append('>>')
201 else:
202 fields.append(' ')
203 # Column: Instruction offset from start of code sequence
204 fields.append(repr(self.offset).rjust(4))
205 # Column: Opcode name
206 fields.append(self.opname.ljust(20))
207 # Column: Opcode argument
208 if self.arg is not None:
209 fields.append(repr(self.arg).rjust(5))
210 # Column: Opcode argument details
211 if self.argrepr:
212 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000213 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000214
215
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000216def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000217 """Iterator for the opcodes in methods, functions or code
218
219 Generates a series of Instruction named tuples giving the details of
220 each operations in the supplied code.
221
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000222 If *first_line* is not None, it indicates the line number that should
223 be reported for the first source line in the disassembled code.
224 Otherwise, the source line information (if any) is taken directly from
225 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000226 """
227 co = _get_code_object(x)
228 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000229 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000230 if first_line is not None:
231 line_offset = first_line - co.co_firstlineno
232 else:
233 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000234 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
235 co.co_consts, cell_names, linestarts,
236 line_offset)
237
238def _get_const_info(const_index, const_list):
239 """Helper to get optional details about const references
240
241 Returns the dereferenced constant and its repr if the constant
242 list is defined.
243 Otherwise returns the constant index and its repr().
244 """
245 argval = const_index
246 if const_list is not None:
247 argval = const_list[const_index]
248 return argval, repr(argval)
249
250def _get_name_info(name_index, name_list):
251 """Helper to get optional details about named references
252
253 Returns the dereferenced name as both value and repr if the name
254 list is defined.
255 Otherwise returns the name index and its repr().
256 """
257 argval = name_index
258 if name_list is not None:
259 argval = name_list[name_index]
260 argrepr = argval
261 else:
262 argrepr = repr(argval)
263 return argval, argrepr
264
265
266def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
267 cells=None, linestarts=None, line_offset=0):
268 """Iterate over the instructions in a bytecode string.
269
270 Generates a sequence of Instruction namedtuples giving the details of each
271 opcode. Additional information about the code's runtime environment
272 (e.g. variable names, constants) can be specified using optional
273 arguments.
274
275 """
276 labels = findlabels(code)
277 extended_arg = 0
278 starts_line = None
279 free = None
280 # enumerate() is not an option, since we sometimes process
281 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000282 n = len(code)
283 i = 0
Tim Peters88869f92001-01-14 23:36:06 +0000284 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000285 op = code[i]
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000286 offset = i
287 if linestarts is not None:
288 starts_line = linestarts.get(i, None)
289 if starts_line is not None:
290 starts_line += line_offset
291 is_jump_target = i in labels
Tim Peters88869f92001-01-14 23:36:06 +0000292 i = i+1
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000293 arg = None
294 argval = None
295 argrepr = ''
Tim Peters88869f92001-01-14 23:36:06 +0000296 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000297 arg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000298 extended_arg = 0
299 i = i+2
300 if op == EXTENDED_ARG:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000301 extended_arg = arg*65536
302 # Set argval to the dereferenced value of the argument when
303 # availabe, and argrepr to the string representation of argval.
304 # _disassemble_bytes needs the string repr of the
305 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
306 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000307 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000308 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000309 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000311 elif op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000312 argval = i + arg
313 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000314 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000315 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000316 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000317 argval = cmp_op[arg]
318 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000319 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000320 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400321 elif op in hasnargs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000322 argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
323 yield Instruction(opname[op], op,
324 arg, argval, argrepr,
325 offset, starts_line, is_jump_target)
326
327def disassemble(co, lasti=-1, *, file=None):
328 """Disassemble a code object."""
329 cell_names = co.co_cellvars + co.co_freevars
330 linestarts = dict(findlinestarts(co))
331 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
332 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000333
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000334def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000335 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000336 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000337 # Omit the line number column entirely if we have no line number info
338 show_lineno = linestarts is not None
339 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
340 lineno_width = 3 if show_lineno else 0
341 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000342 constants, cells, linestarts,
343 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000344 new_source_line = (show_lineno and
345 instr.starts_line is not None and
346 instr.offset > 0)
347 if new_source_line:
348 print(file=file)
349 is_current_instr = instr.offset == lasti
350 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000351
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000352def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000353 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000354 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000355
Tim Peters88869f92001-01-14 23:36:06 +0000356disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000357
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000358def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000359 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000360
Tim Peters88869f92001-01-14 23:36:06 +0000361 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000362
Tim Peters88869f92001-01-14 23:36:06 +0000363 """
364 labels = []
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000365 # enumerate() is not an option, since we sometimes process
366 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000367 n = len(code)
368 i = 0
369 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000370 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000371 i = i+1
372 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000373 arg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000374 i = i+2
375 label = -1
376 if op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000377 label = i+arg
Tim Peters88869f92001-01-14 23:36:06 +0000378 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000379 label = arg
Tim Peters88869f92001-01-14 23:36:06 +0000380 if label >= 0:
381 if label not in labels:
382 labels.append(label)
383 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000384
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000385def findlinestarts(code):
386 """Find the offsets in a byte code which are start of lines in the source.
387
388 Generate pairs (offset, lineno) as described in Python/compile.c.
389
390 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000391 byte_increments = list(code.co_lnotab[0::2])
392 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000393
394 lastlineno = None
395 lineno = code.co_firstlineno
396 addr = 0
397 for byte_incr, line_incr in zip(byte_increments, line_increments):
398 if byte_incr:
399 if lineno != lastlineno:
400 yield (addr, lineno)
401 lastlineno = lineno
402 addr += byte_incr
403 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()