blob: d215bc59e4a833d6e91945ba805ce427926aaaf8 [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",
87}
88
89def pretty_flags(flags):
90 """Return pretty representation of code flags."""
91 names = []
92 for i in range(32):
93 flag = 1<<i
94 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000095 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000096 flags ^= flag
97 if not flags:
98 break
99 else:
100 names.append(hex(flags))
101 return ", ".join(names)
102
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000103def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000104 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000105 if hasattr(x, '__func__'): # Method
106 x = x.__func__
107 if hasattr(x, '__code__'): # Function
108 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000109 if hasattr(x, 'gi_code'): # Generator
110 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000111 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000112 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000113 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000114 return x
115 raise TypeError("don't know how to disassemble %s objects" %
116 type(x).__name__)
117
118def code_info(x):
119 """Formatted details of methods, functions, or code."""
120 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000121
122def _format_code_info(co):
123 lines = []
124 lines.append("Name: %s" % co.co_name)
125 lines.append("Filename: %s" % co.co_filename)
126 lines.append("Argument count: %s" % co.co_argcount)
127 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
128 lines.append("Number of locals: %s" % co.co_nlocals)
129 lines.append("Stack size: %s" % co.co_stacksize)
130 lines.append("Flags: %s" % pretty_flags(co.co_flags))
131 if co.co_consts:
132 lines.append("Constants:")
133 for i_c in enumerate(co.co_consts):
134 lines.append("%4d: %r" % i_c)
135 if co.co_names:
136 lines.append("Names:")
137 for i_n in enumerate(co.co_names):
138 lines.append("%4d: %s" % i_n)
139 if co.co_varnames:
140 lines.append("Variable names:")
141 for i_n in enumerate(co.co_varnames):
142 lines.append("%4d: %s" % i_n)
143 if co.co_freevars:
144 lines.append("Free variables:")
145 for i_n in enumerate(co.co_freevars):
146 lines.append("%4d: %s" % i_n)
147 if co.co_cellvars:
148 lines.append("Cell variables:")
149 for i_n in enumerate(co.co_cellvars):
150 lines.append("%4d: %s" % i_n)
151 return "\n".join(lines)
152
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000153def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300154 """Print details of methods, functions, or code to *file*.
155
156 If *file* is not provided, the output is printed on stdout.
157 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000158 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000159
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000160_Instruction = collections.namedtuple("_Instruction",
161 "opname opcode arg argval argrepr offset starts_line is_jump_target")
162
163class Instruction(_Instruction):
164 """Details for a bytecode operation
165
166 Defined fields:
167 opname - human readable name for operation
168 opcode - numeric code for operation
169 arg - numeric argument to operation (if any), otherwise None
170 argval - resolved arg value (if known), otherwise same as arg
171 argrepr - human readable description of operation argument
172 offset - start index of operation within bytecode sequence
173 starts_line - line started by this opcode (if any), otherwise None
174 is_jump_target - True if other code jumps to here, otherwise False
175 """
176
177 def _disassemble(self, lineno_width=3, mark_as_current=False):
178 """Format instruction details for inclusion in disassembly output
179
180 *lineno_width* sets the width of the line number field (0 omits it)
181 *mark_as_current* inserts a '-->' marker arrow as part of the line
182 """
183 fields = []
184 # Column: Source code line number
185 if lineno_width:
186 if self.starts_line is not None:
187 lineno_fmt = "%%%dd" % lineno_width
188 fields.append(lineno_fmt % self.starts_line)
189 else:
190 fields.append(' ' * lineno_width)
191 # Column: Current instruction indicator
192 if mark_as_current:
193 fields.append('-->')
194 else:
195 fields.append(' ')
196 # Column: Jump target marker
197 if self.is_jump_target:
198 fields.append('>>')
199 else:
200 fields.append(' ')
201 # Column: Instruction offset from start of code sequence
202 fields.append(repr(self.offset).rjust(4))
203 # Column: Opcode name
204 fields.append(self.opname.ljust(20))
205 # Column: Opcode argument
206 if self.arg is not None:
207 fields.append(repr(self.arg).rjust(5))
208 # Column: Opcode argument details
209 if self.argrepr:
210 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000211 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000212
213
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000214def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000215 """Iterator for the opcodes in methods, functions or code
216
217 Generates a series of Instruction named tuples giving the details of
218 each operations in the supplied code.
219
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000220 If *first_line* is not None, it indicates the line number that should
221 be reported for the first source line in the disassembled code.
222 Otherwise, the source line information (if any) is taken directly from
223 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000224 """
225 co = _get_code_object(x)
226 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000227 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000228 if first_line is not None:
229 line_offset = first_line - co.co_firstlineno
230 else:
231 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000232 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
233 co.co_consts, cell_names, linestarts,
234 line_offset)
235
236def _get_const_info(const_index, const_list):
237 """Helper to get optional details about const references
238
239 Returns the dereferenced constant and its repr if the constant
240 list is defined.
241 Otherwise returns the constant index and its repr().
242 """
243 argval = const_index
244 if const_list is not None:
245 argval = const_list[const_index]
246 return argval, repr(argval)
247
248def _get_name_info(name_index, name_list):
249 """Helper to get optional details about named references
250
251 Returns the dereferenced name as both value and repr if the name
252 list is defined.
253 Otherwise returns the name index and its repr().
254 """
255 argval = name_index
256 if name_list is not None:
257 argval = name_list[name_index]
258 argrepr = argval
259 else:
260 argrepr = repr(argval)
261 return argval, argrepr
262
263
264def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
265 cells=None, linestarts=None, line_offset=0):
266 """Iterate over the instructions in a bytecode string.
267
268 Generates a sequence of Instruction namedtuples giving the details of each
269 opcode. Additional information about the code's runtime environment
270 (e.g. variable names, constants) can be specified using optional
271 arguments.
272
273 """
274 labels = findlabels(code)
275 extended_arg = 0
276 starts_line = None
277 free = None
278 # enumerate() is not an option, since we sometimes process
279 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000280 n = len(code)
281 i = 0
Tim Peters88869f92001-01-14 23:36:06 +0000282 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000283 op = code[i]
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000284 offset = i
285 if linestarts is not None:
286 starts_line = linestarts.get(i, None)
287 if starts_line is not None:
288 starts_line += line_offset
289 is_jump_target = i in labels
Tim Peters88869f92001-01-14 23:36:06 +0000290 i = i+1
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000291 arg = None
292 argval = None
293 argrepr = ''
Tim Peters88869f92001-01-14 23:36:06 +0000294 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 arg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000296 extended_arg = 0
297 i = i+2
298 if op == EXTENDED_ARG:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000299 extended_arg = arg*65536
300 # Set argval to the dereferenced value of the argument when
301 # availabe, and argrepr to the string representation of argval.
302 # _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:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 argval = i + arg
311 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)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400319 elif op in hasnargs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000320 argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
321 yield Instruction(opname[op], op,
322 arg, argval, argrepr,
323 offset, starts_line, is_jump_target)
324
325def disassemble(co, lasti=-1, *, file=None):
326 """Disassemble a code object."""
327 cell_names = co.co_cellvars + co.co_freevars
328 linestarts = dict(findlinestarts(co))
329 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
330 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000331
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000332def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000333 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000334 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000335 # Omit the line number column entirely if we have no line number info
336 show_lineno = linestarts is not None
337 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
338 lineno_width = 3 if show_lineno else 0
339 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000340 constants, cells, linestarts,
341 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000342 new_source_line = (show_lineno and
343 instr.starts_line is not None and
344 instr.offset > 0)
345 if new_source_line:
346 print(file=file)
347 is_current_instr = instr.offset == lasti
348 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000349
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000350def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000351 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000352 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000353
Tim Peters88869f92001-01-14 23:36:06 +0000354disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000355
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000356def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000357 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000358
Tim Peters88869f92001-01-14 23:36:06 +0000359 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000360
Tim Peters88869f92001-01-14 23:36:06 +0000361 """
362 labels = []
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000363 # enumerate() is not an option, since we sometimes process
364 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000365 n = len(code)
366 i = 0
367 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000368 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000369 i = i+1
370 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000371 arg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000372 i = i+2
373 label = -1
374 if op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000375 label = i+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()