blob: 3540b4714d9af477b7e49cc185f529e66e608df1 [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
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700165_Instruction.opname.__doc__ = "Human readable name for operation"
166_Instruction.opcode.__doc__ = "Numeric code for operation"
167_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
168_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
169_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
170_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
171_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
172_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
173
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000174class Instruction(_Instruction):
175 """Details for a bytecode operation
176
177 Defined fields:
178 opname - human readable name for operation
179 opcode - numeric code for operation
180 arg - numeric argument to operation (if any), otherwise None
181 argval - resolved arg value (if known), otherwise same as arg
182 argrepr - human readable description of operation argument
183 offset - start index of operation within bytecode sequence
184 starts_line - line started by this opcode (if any), otherwise None
185 is_jump_target - True if other code jumps to here, otherwise False
186 """
187
188 def _disassemble(self, lineno_width=3, mark_as_current=False):
189 """Format instruction details for inclusion in disassembly output
190
191 *lineno_width* sets the width of the line number field (0 omits it)
192 *mark_as_current* inserts a '-->' marker arrow as part of the line
193 """
194 fields = []
195 # Column: Source code line number
196 if lineno_width:
197 if self.starts_line is not None:
198 lineno_fmt = "%%%dd" % lineno_width
199 fields.append(lineno_fmt % self.starts_line)
200 else:
201 fields.append(' ' * lineno_width)
202 # Column: Current instruction indicator
203 if mark_as_current:
204 fields.append('-->')
205 else:
206 fields.append(' ')
207 # Column: Jump target marker
208 if self.is_jump_target:
209 fields.append('>>')
210 else:
211 fields.append(' ')
212 # Column: Instruction offset from start of code sequence
213 fields.append(repr(self.offset).rjust(4))
214 # Column: Opcode name
215 fields.append(self.opname.ljust(20))
216 # Column: Opcode argument
217 if self.arg is not None:
218 fields.append(repr(self.arg).rjust(5))
219 # Column: Opcode argument details
220 if self.argrepr:
221 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000222 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000223
224
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000225def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000226 """Iterator for the opcodes in methods, functions or code
227
228 Generates a series of Instruction named tuples giving the details of
229 each operations in the supplied code.
230
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000231 If *first_line* is not None, it indicates the line number that should
232 be reported for the first source line in the disassembled code.
233 Otherwise, the source line information (if any) is taken directly from
234 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000235 """
236 co = _get_code_object(x)
237 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000238 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000239 if first_line is not None:
240 line_offset = first_line - co.co_firstlineno
241 else:
242 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000243 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
244 co.co_consts, cell_names, linestarts,
245 line_offset)
246
247def _get_const_info(const_index, const_list):
248 """Helper to get optional details about const references
249
250 Returns the dereferenced constant and its repr if the constant
251 list is defined.
252 Otherwise returns the constant index and its repr().
253 """
254 argval = const_index
255 if const_list is not None:
256 argval = const_list[const_index]
257 return argval, repr(argval)
258
259def _get_name_info(name_index, name_list):
260 """Helper to get optional details about named references
261
262 Returns the dereferenced name as both value and repr if the name
263 list is defined.
264 Otherwise returns the name index and its repr().
265 """
266 argval = name_index
267 if name_list is not None:
268 argval = name_list[name_index]
269 argrepr = argval
270 else:
271 argrepr = repr(argval)
272 return argval, argrepr
273
274
275def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
276 cells=None, linestarts=None, line_offset=0):
277 """Iterate over the instructions in a bytecode string.
278
279 Generates a sequence of Instruction namedtuples giving the details of each
280 opcode. Additional information about the code's runtime environment
281 (e.g. variable names, constants) can be specified using optional
282 arguments.
283
284 """
285 labels = findlabels(code)
286 extended_arg = 0
287 starts_line = None
288 free = None
289 # enumerate() is not an option, since we sometimes process
290 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000291 n = len(code)
292 i = 0
Tim Peters88869f92001-01-14 23:36:06 +0000293 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000294 op = code[i]
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 offset = i
296 if linestarts is not None:
297 starts_line = linestarts.get(i, None)
298 if starts_line is not None:
299 starts_line += line_offset
300 is_jump_target = i in labels
Tim Peters88869f92001-01-14 23:36:06 +0000301 i = i+1
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000302 arg = None
303 argval = None
304 argrepr = ''
Tim Peters88869f92001-01-14 23:36:06 +0000305 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 arg = code[i] + code[i+1]*256 + extended_arg
Tim Peters88869f92001-01-14 23:36:06 +0000307 extended_arg = 0
308 i = i+2
309 if op == EXTENDED_ARG:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 extended_arg = arg*65536
311 # Set argval to the dereferenced value of the argument when
312 # availabe, and argrepr to the string representation of argval.
313 # _disassemble_bytes needs the string repr of the
314 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
315 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000316 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000317 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000318 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000319 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000320 elif op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000321 argval = i + arg
322 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000323 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000324 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000325 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000326 argval = cmp_op[arg]
327 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000328 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000329 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400330 elif op in hasnargs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000331 argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
332 yield Instruction(opname[op], op,
333 arg, argval, argrepr,
334 offset, starts_line, is_jump_target)
335
336def disassemble(co, lasti=-1, *, file=None):
337 """Disassemble a code object."""
338 cell_names = co.co_cellvars + co.co_freevars
339 linestarts = dict(findlinestarts(co))
340 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
341 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000342
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000343def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000344 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000345 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000346 # Omit the line number column entirely if we have no line number info
347 show_lineno = linestarts is not None
348 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
349 lineno_width = 3 if show_lineno else 0
350 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000351 constants, cells, linestarts,
352 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000353 new_source_line = (show_lineno and
354 instr.starts_line is not None and
355 instr.offset > 0)
356 if new_source_line:
357 print(file=file)
358 is_current_instr = instr.offset == lasti
359 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000360
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000361def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000362 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000363 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000364
Tim Peters88869f92001-01-14 23:36:06 +0000365disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000366
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000367def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000368 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000369
Tim Peters88869f92001-01-14 23:36:06 +0000370 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000371
Tim Peters88869f92001-01-14 23:36:06 +0000372 """
373 labels = []
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000374 # enumerate() is not an option, since we sometimes process
375 # multiple elements on a single pass through the loop
Tim Peters88869f92001-01-14 23:36:06 +0000376 n = len(code)
377 i = 0
378 while i < n:
Guido van Rossum75a902d2007-10-19 22:06:24 +0000379 op = code[i]
Tim Peters88869f92001-01-14 23:36:06 +0000380 i = i+1
381 if op >= HAVE_ARGUMENT:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000382 arg = code[i] + code[i+1]*256
Tim Peters88869f92001-01-14 23:36:06 +0000383 i = i+2
384 label = -1
385 if op in hasjrel:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000386 label = i+arg
Tim Peters88869f92001-01-14 23:36:06 +0000387 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000388 label = arg
Tim Peters88869f92001-01-14 23:36:06 +0000389 if label >= 0:
390 if label not in labels:
391 labels.append(label)
392 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000393
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000394def findlinestarts(code):
395 """Find the offsets in a byte code which are start of lines in the source.
396
397 Generate pairs (offset, lineno) as described in Python/compile.c.
398
399 """
Guido van Rossum75a902d2007-10-19 22:06:24 +0000400 byte_increments = list(code.co_lnotab[0::2])
401 line_increments = list(code.co_lnotab[1::2])
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000402
403 lastlineno = None
404 lineno = code.co_firstlineno
405 addr = 0
406 for byte_incr, line_incr in zip(byte_increments, line_increments):
407 if byte_incr:
408 if lineno != lastlineno:
409 yield (addr, lineno)
410 lastlineno = lineno
411 addr += byte_incr
412 lineno += line_incr
413 if lineno != lastlineno:
414 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000415
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000416class Bytecode:
417 """The bytecode operations of a piece of code
418
419 Instantiate this with a function, method, string of code, or a code object
420 (as returned by compile()).
421
422 Iterating over this yields the bytecode operations as Instruction instances.
423 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000424 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000425 self.codeobj = co = _get_code_object(x)
426 if first_line is None:
427 self.first_line = co.co_firstlineno
428 self._line_offset = 0
429 else:
430 self.first_line = first_line
431 self._line_offset = first_line - co.co_firstlineno
432 self._cell_names = co.co_cellvars + co.co_freevars
433 self._linestarts = dict(findlinestarts(co))
434 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000435 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000436
437 def __iter__(self):
438 co = self.codeobj
439 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000440 co.co_consts, self._cell_names,
441 self._linestarts,
442 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000443
444 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000445 return "{}({!r})".format(self.__class__.__name__,
446 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000447
Nick Coghlan50c48b82013-11-23 00:57:00 +1000448 @classmethod
449 def from_traceback(cls, tb):
450 """ Construct a Bytecode from the given traceback """
451 while tb.tb_next:
452 tb = tb.tb_next
453 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
454
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000455 def info(self):
456 """Return formatted information about the code object."""
457 return _format_code_info(self.codeobj)
458
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000459 def dis(self):
460 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000461 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000462 if self.current_offset is not None:
463 offset = self.current_offset
464 else:
465 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000466 with io.StringIO() as output:
467 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
468 names=co.co_names, constants=co.co_consts,
469 cells=self._cell_names,
470 linestarts=self._linestarts,
471 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000472 file=output,
473 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000474 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000475
476
Guido van Rossum1fdae122000-02-04 17:47:55 +0000477def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000478 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000479 import argparse
480
481 parser = argparse.ArgumentParser()
482 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
483 args = parser.parse_args()
484 with args.infile as infile:
485 source = infile.read()
486 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000487 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000488
489if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000490 _test()