blob: 59886f1e37e060608a4963b0d41adc897cdfbfeb [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
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700166_Instruction.opname.__doc__ = "Human readable name for operation"
167_Instruction.opcode.__doc__ = "Numeric code for operation"
168_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
169_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
170_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
171_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
172_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
173_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
174
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000175class Instruction(_Instruction):
176 """Details for a bytecode operation
177
178 Defined fields:
179 opname - human readable name for operation
180 opcode - numeric code for operation
181 arg - numeric argument to operation (if any), otherwise None
182 argval - resolved arg value (if known), otherwise same as arg
183 argrepr - human readable description of operation argument
184 offset - start index of operation within bytecode sequence
185 starts_line - line started by this opcode (if any), otherwise None
186 is_jump_target - True if other code jumps to here, otherwise False
187 """
188
189 def _disassemble(self, lineno_width=3, mark_as_current=False):
190 """Format instruction details for inclusion in disassembly output
191
192 *lineno_width* sets the width of the line number field (0 omits it)
193 *mark_as_current* inserts a '-->' marker arrow as part of the line
194 """
195 fields = []
196 # Column: Source code line number
197 if lineno_width:
198 if self.starts_line is not None:
199 lineno_fmt = "%%%dd" % lineno_width
200 fields.append(lineno_fmt % self.starts_line)
201 else:
202 fields.append(' ' * lineno_width)
203 # Column: Current instruction indicator
204 if mark_as_current:
205 fields.append('-->')
206 else:
207 fields.append(' ')
208 # Column: Jump target marker
209 if self.is_jump_target:
210 fields.append('>>')
211 else:
212 fields.append(' ')
213 # Column: Instruction offset from start of code sequence
214 fields.append(repr(self.offset).rjust(4))
215 # Column: Opcode name
216 fields.append(self.opname.ljust(20))
217 # Column: Opcode argument
218 if self.arg is not None:
219 fields.append(repr(self.arg).rjust(5))
220 # Column: Opcode argument details
221 if self.argrepr:
222 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000223 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000224
225
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000226def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000227 """Iterator for the opcodes in methods, functions or code
228
229 Generates a series of Instruction named tuples giving the details of
230 each operations in the supplied code.
231
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000232 If *first_line* is not None, it indicates the line number that should
233 be reported for the first source line in the disassembled code.
234 Otherwise, the source line information (if any) is taken directly from
235 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000236 """
237 co = _get_code_object(x)
238 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000239 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000240 if first_line is not None:
241 line_offset = first_line - co.co_firstlineno
242 else:
243 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000244 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
245 co.co_consts, cell_names, linestarts,
246 line_offset)
247
248def _get_const_info(const_index, const_list):
249 """Helper to get optional details about const references
250
251 Returns the dereferenced constant and its repr if the constant
252 list is defined.
253 Otherwise returns the constant index and its repr().
254 """
255 argval = const_index
256 if const_list is not None:
257 argval = const_list[const_index]
258 return argval, repr(argval)
259
260def _get_name_info(name_index, name_list):
261 """Helper to get optional details about named references
262
263 Returns the dereferenced name as both value and repr if the name
264 list is defined.
265 Otherwise returns the name index and its repr().
266 """
267 argval = name_index
268 if name_list is not None:
269 argval = name_list[name_index]
270 argrepr = argval
271 else:
272 argrepr = repr(argval)
273 return argval, argrepr
274
275
276def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
277 cells=None, linestarts=None, line_offset=0):
278 """Iterate over the instructions in a bytecode string.
279
280 Generates a sequence of Instruction namedtuples giving the details of each
281 opcode. Additional information about the code's runtime environment
282 (e.g. variable names, constants) can be specified using optional
283 arguments.
284
285 """
286 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000287 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300288 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000289 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300290 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000291 if starts_line is not None:
292 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300293 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000294 argval = None
295 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300296 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000297 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300298 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000299 # _disassemble_bytes needs the string repr of the
300 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
301 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000302 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000303 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000304 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000305 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000306 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300307 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000308 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000309 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000310 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000311 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000312 argval = cmp_op[arg]
313 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000314 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000315 argval, argrepr = _get_name_info(arg, cells)
Alexander Belopolsky74482202012-06-07 14:28:14 -0400316 elif op in hasnargs:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300317 argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000318 yield Instruction(opname[op], op,
319 arg, argval, argrepr,
320 offset, starts_line, is_jump_target)
321
322def disassemble(co, lasti=-1, *, file=None):
323 """Disassemble a code object."""
324 cell_names = co.co_cellvars + co.co_freevars
325 linestarts = dict(findlinestarts(co))
326 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
327 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000328
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000329def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000330 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000331 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000332 # Omit the line number column entirely if we have no line number info
333 show_lineno = linestarts is not None
334 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
335 lineno_width = 3 if show_lineno else 0
336 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000337 constants, cells, linestarts,
338 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000339 new_source_line = (show_lineno and
340 instr.starts_line is not None and
341 instr.offset > 0)
342 if new_source_line:
343 print(file=file)
344 is_current_instr = instr.offset == lasti
345 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000346
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000347def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000348 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000349 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000350
Tim Peters88869f92001-01-14 23:36:06 +0000351disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000352
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300353def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300354 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300355 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300356 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300357 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300358 arg = code[i+1] | extended_arg
359 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
360 else:
361 arg = None
362 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300363
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000364def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000365 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000366
Tim Peters88869f92001-01-14 23:36:06 +0000367 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000368
Tim Peters88869f92001-01-14 23:36:06 +0000369 """
370 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300371 for offset, op, arg in _unpack_opargs(code):
372 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000373 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300374 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000375 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000376 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300377 else:
378 continue
379 if label not in labels:
380 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000381 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 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100389 byte_increments = code.co_lnotab[0::2]
390 line_increments = 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
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100401 if line_incr >= 0x80:
402 # line_increments is an array of 8-bit signed integers
403 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000404 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()