blob: 841208ffa147831c9b3a1b18d00541f3e01251d0 [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)
278 extended_arg = 0
279 starts_line = None
280 free = None
281 # enumerate() is not an option, since we sometimes process
282 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000283 n = len(code)
284 i = 0
Tim Peters88869f92001-01-14 23:36:06 +0000285 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000286 op = code[i]
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000287 offset = i
288 if linestarts is not None:
289 starts_line = linestarts.get(i, None)
290 if starts_line is not None:
291 starts_line += line_offset
292 is_jump_target = i in labels
Tim Peters88869f92001-01-14 23:36:06 +0000293 i = i+1
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000294 arg = None
295 argval = None
296 argrepr = ''
Tim Peters88869f92001-01-14 23:36:06 +0000297 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000298 arg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000299 extended_arg = 0
300 i = i+2
301 if op == EXTENDED_ARG:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000302 extended_arg = arg*65536
303 # Set argval to the dereferenced value of the argument when
304 # availabe, and argrepr to the string representation of argval.
305 # _disassemble_bytes needs the string repr of the
306 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
307 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000308 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000309 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000310 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000311 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000312 elif op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000313 argval = i + arg
314 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000315 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000316 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000317 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000318 argval = cmp_op[arg]
319 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000320 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000321 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400322 elif op in hasnargs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000323 argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
324 yield Instruction(opname[op], op,
325 arg, argval, argrepr,
326 offset, starts_line, is_jump_target)
327
328def disassemble(co, lasti=-1, *, file=None):
329 """Disassemble a code object."""
330 cell_names = co.co_cellvars + co.co_freevars
331 linestarts = dict(findlinestarts(co))
332 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
333 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000334
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000335def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000336 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000337 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000338 # Omit the line number column entirely if we have no line number info
339 show_lineno = linestarts is not None
340 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
341 lineno_width = 3 if show_lineno else 0
342 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000343 constants, cells, linestarts,
344 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000345 new_source_line = (show_lineno and
346 instr.starts_line is not None and
347 instr.offset > 0)
348 if new_source_line:
349 print(file=file)
350 is_current_instr = instr.offset == lasti
351 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000352
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000353def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000354 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000355 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000356
Tim Peters88869f92001-01-14 23:36:06 +0000357disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000358
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000359def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000360 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000361
Tim Peters88869f92001-01-14 23:36:06 +0000362 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000363
Tim Peters88869f92001-01-14 23:36:06 +0000364 """
365 labels = []
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000366 # enumerate() is not an option, since we sometimes process
367 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000368 n = len(code)
369 i = 0
370 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000371 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000372 i = i+1
373 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000374 arg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000375 i = i+2
376 label = -1
377 if op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000378 label = i+arg
Tim Peters88869f92001-01-14 23:36:06 +0000379 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000380 label = arg
Tim Peters88869f92001-01-14 23:36:06 +0000381 if label >= 0:
382 if label not in labels:
383 labels.append(label)
384 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000385
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000386def findlinestarts(code):
387 """Find the offsets in a byte code which are start of lines in the source.
388
389 Generate pairs (offset, lineno) as described in Python/compile.c.
390
391 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000392 byte_increments = list(code.co_lnotab[0::2])
393 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000394
395 lastlineno = None
396 lineno = code.co_firstlineno
397 addr = 0
398 for byte_incr, line_incr in zip(byte_increments, line_increments):
399 if byte_incr:
400 if lineno != lastlineno:
401 yield (addr, lineno)
402 lastlineno = lineno
403 addr += byte_incr
404 lineno += line_incr
405 if lineno != lastlineno:
406 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000407
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000408class Bytecode:
409 """The bytecode operations of a piece of code
410
411 Instantiate this with a function, method, string of code, or a code object
412 (as returned by compile()).
413
414 Iterating over this yields the bytecode operations as Instruction instances.
415 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000416 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000417 self.codeobj = co = _get_code_object(x)
418 if first_line is None:
419 self.first_line = co.co_firstlineno
420 self._line_offset = 0
421 else:
422 self.first_line = first_line
423 self._line_offset = first_line - co.co_firstlineno
424 self._cell_names = co.co_cellvars + co.co_freevars
425 self._linestarts = dict(findlinestarts(co))
426 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000427 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000428
429 def __iter__(self):
430 co = self.codeobj
431 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000432 co.co_consts, self._cell_names,
433 self._linestarts,
434 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000435
436 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000437 return "{}({!r})".format(self.__class__.__name__,
438 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000439
Nick Coghlan50c48b82013-11-23 00:57:00 +1000440 @classmethod
441 def from_traceback(cls, tb):
442 """ Construct a Bytecode from the given traceback """
443 while tb.tb_next:
444 tb = tb.tb_next
445 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
446
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000447 def info(self):
448 """Return formatted information about the code object."""
449 return _format_code_info(self.codeobj)
450
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000451 def dis(self):
452 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000453 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000454 if self.current_offset is not None:
455 offset = self.current_offset
456 else:
457 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000458 with io.StringIO() as output:
459 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
460 names=co.co_names, constants=co.co_consts,
461 cells=self._cell_names,
462 linestarts=self._linestarts,
463 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000464 file=output,
465 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000466 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000467
468
Guido van Rossum1fdae122000-02-04 17:47:55 +0000469def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000470 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000471 import argparse
472
473 parser = argparse.ArgumentParser()
474 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
475 args = parser.parse_args()
476 with args.infile as infile:
477 source = infile.read()
478 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000479 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000480
481if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000482 _test()