blob: e958c8ad1c148a1ed7b47400693bad664d7fde31 [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",
Yury Selivanoveb636452016-09-08 22:01:51 -070090 512: "ASYNC_GENERATOR",
Guido van Rossum3e1b85e2007-05-30 02:07:00 +000091}
92
93def pretty_flags(flags):
94 """Return pretty representation of code flags."""
95 names = []
96 for i in range(32):
97 flag = 1<<i
98 if flags & flag:
Nick Coghlan09c81232010-08-17 10:18:16 +000099 names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000100 flags ^= flag
101 if not flags:
102 break
103 else:
104 names.append(hex(flags))
105 return ", ".join(names)
106
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000107def _get_code_object(x):
Nick Coghlanefd5df92014-07-25 23:02:56 +1000108 """Helper to handle methods, functions, generators, strings and raw code objects"""
Nick Coghlaneae2da12010-08-17 08:03:36 +0000109 if hasattr(x, '__func__'): # Method
110 x = x.__func__
111 if hasattr(x, '__code__'): # Function
112 x = x.__code__
Nick Coghlanefd5df92014-07-25 23:02:56 +1000113 if hasattr(x, 'gi_code'): # Generator
114 x = x.gi_code
Nick Coghlaneae2da12010-08-17 08:03:36 +0000115 if isinstance(x, str): # Source code
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000116 x = _try_compile(x, "<disassembly>")
Nick Coghlaneae2da12010-08-17 08:03:36 +0000117 if hasattr(x, 'co_code'): # Code object
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000118 return x
119 raise TypeError("don't know how to disassemble %s objects" %
120 type(x).__name__)
121
122def code_info(x):
123 """Formatted details of methods, functions, or code."""
124 return _format_code_info(_get_code_object(x))
Nick Coghlaneae2da12010-08-17 08:03:36 +0000125
126def _format_code_info(co):
127 lines = []
128 lines.append("Name: %s" % co.co_name)
129 lines.append("Filename: %s" % co.co_filename)
130 lines.append("Argument count: %s" % co.co_argcount)
131 lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
132 lines.append("Number of locals: %s" % co.co_nlocals)
133 lines.append("Stack size: %s" % co.co_stacksize)
134 lines.append("Flags: %s" % pretty_flags(co.co_flags))
135 if co.co_consts:
136 lines.append("Constants:")
137 for i_c in enumerate(co.co_consts):
138 lines.append("%4d: %r" % i_c)
139 if co.co_names:
140 lines.append("Names:")
141 for i_n in enumerate(co.co_names):
142 lines.append("%4d: %s" % i_n)
143 if co.co_varnames:
144 lines.append("Variable names:")
145 for i_n in enumerate(co.co_varnames):
146 lines.append("%4d: %s" % i_n)
147 if co.co_freevars:
148 lines.append("Free variables:")
149 for i_n in enumerate(co.co_freevars):
150 lines.append("%4d: %s" % i_n)
151 if co.co_cellvars:
152 lines.append("Cell variables:")
153 for i_n in enumerate(co.co_cellvars):
154 lines.append("%4d: %s" % i_n)
155 return "\n".join(lines)
156
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000157def show_code(co, *, file=None):
Ezio Melotti6e6c6ac2013-08-23 22:41:39 +0300158 """Print details of methods, functions, or code to *file*.
159
160 If *file* is not provided, the output is printed on stdout.
161 """
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000162 print(code_info(co), file=file)
Guido van Rossum3e1b85e2007-05-30 02:07:00 +0000163
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000164_Instruction = collections.namedtuple("_Instruction",
165 "opname opcode arg argval argrepr offset starts_line is_jump_target")
166
Raymond Hettinger5b798ab2015-08-17 22:04:45 -0700167_Instruction.opname.__doc__ = "Human readable name for operation"
168_Instruction.opcode.__doc__ = "Numeric code for operation"
169_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
170_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
171_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
172_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
173_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
174_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
175
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000176class Instruction(_Instruction):
177 """Details for a bytecode operation
178
179 Defined fields:
180 opname - human readable name for operation
181 opcode - numeric code for operation
182 arg - numeric argument to operation (if any), otherwise None
183 argval - resolved arg value (if known), otherwise same as arg
184 argrepr - human readable description of operation argument
185 offset - start index of operation within bytecode sequence
186 starts_line - line started by this opcode (if any), otherwise None
187 is_jump_target - True if other code jumps to here, otherwise False
188 """
189
190 def _disassemble(self, lineno_width=3, mark_as_current=False):
191 """Format instruction details for inclusion in disassembly output
192
193 *lineno_width* sets the width of the line number field (0 omits it)
194 *mark_as_current* inserts a '-->' marker arrow as part of the line
195 """
196 fields = []
197 # Column: Source code line number
198 if lineno_width:
199 if self.starts_line is not None:
200 lineno_fmt = "%%%dd" % lineno_width
201 fields.append(lineno_fmt % self.starts_line)
202 else:
203 fields.append(' ' * lineno_width)
204 # Column: Current instruction indicator
205 if mark_as_current:
206 fields.append('-->')
207 else:
208 fields.append(' ')
209 # Column: Jump target marker
210 if self.is_jump_target:
211 fields.append('>>')
212 else:
213 fields.append(' ')
214 # Column: Instruction offset from start of code sequence
215 fields.append(repr(self.offset).rjust(4))
216 # Column: Opcode name
217 fields.append(self.opname.ljust(20))
218 # Column: Opcode argument
219 if self.arg is not None:
220 fields.append(repr(self.arg).rjust(5))
221 # Column: Opcode argument details
222 if self.argrepr:
223 fields.append('(' + self.argrepr + ')')
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000224 return ' '.join(fields).rstrip()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000225
226
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000227def get_instructions(x, *, first_line=None):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000228 """Iterator for the opcodes in methods, functions or code
229
230 Generates a series of Instruction named tuples giving the details of
231 each operations in the supplied code.
232
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000233 If *first_line* is not None, it indicates the line number that should
234 be reported for the first source line in the disassembled code.
235 Otherwise, the source line information (if any) is taken directly from
236 the disassembled code object.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000237 """
238 co = _get_code_object(x)
239 cell_names = co.co_cellvars + co.co_freevars
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000240 linestarts = dict(findlinestarts(co))
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000241 if first_line is not None:
242 line_offset = first_line - co.co_firstlineno
243 else:
244 line_offset = 0
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000245 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
246 co.co_consts, cell_names, linestarts,
247 line_offset)
248
249def _get_const_info(const_index, const_list):
250 """Helper to get optional details about const references
251
252 Returns the dereferenced constant and its repr if the constant
253 list is defined.
254 Otherwise returns the constant index and its repr().
255 """
256 argval = const_index
257 if const_list is not None:
258 argval = const_list[const_index]
259 return argval, repr(argval)
260
261def _get_name_info(name_index, name_list):
262 """Helper to get optional details about named references
263
264 Returns the dereferenced name as both value and repr if the name
265 list is defined.
266 Otherwise returns the name index and its repr().
267 """
268 argval = name_index
269 if name_list is not None:
270 argval = name_list[name_index]
271 argrepr = argval
272 else:
273 argrepr = repr(argval)
274 return argval, argrepr
275
276
277def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
278 cells=None, linestarts=None, line_offset=0):
279 """Iterate over the instructions in a bytecode string.
280
281 Generates a sequence of Instruction namedtuples giving the details of each
282 opcode. Additional information about the code's runtime environment
283 (e.g. variable names, constants) can be specified using optional
284 arguments.
285
286 """
287 labels = findlabels(code)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000288 starts_line = None
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300289 for offset, op, arg in _unpack_opargs(code):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000290 if linestarts is not None:
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300291 starts_line = linestarts.get(offset, None)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000292 if starts_line is not None:
293 starts_line += line_offset
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300294 is_jump_target = offset in labels
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000295 argval = None
296 argrepr = ''
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300297 if arg is not None:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000298 # Set argval to the dereferenced value of the argument when
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300299 # available, and argrepr to the string representation of argval.
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000300 # _disassemble_bytes needs the string repr of the
301 # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
302 argval = arg
Tim Peters88869f92001-01-14 23:36:06 +0000303 if op in hasconst:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000304 argval, argrepr = _get_const_info(arg, constants)
Tim Peters88869f92001-01-14 23:36:06 +0000305 elif op in hasname:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000306 argval, argrepr = _get_name_info(arg, names)
Tim Peters88869f92001-01-14 23:36:06 +0000307 elif op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300308 argval = offset + 2 + arg
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000309 argrepr = "to " + repr(argval)
Tim Peters88869f92001-01-14 23:36:06 +0000310 elif op in haslocal:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000311 argval, argrepr = _get_name_info(arg, varnames)
Tim Peters88869f92001-01-14 23:36:06 +0000312 elif op in hascompare:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000313 argval = cmp_op[arg]
314 argrepr = argval
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000315 elif op in hasfree:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000316 argval, argrepr = _get_name_info(arg, cells)
Victor Stinnerf9b760f2016-09-09 10:17:08 -0700317 elif op in hasnargs: # unused
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300318 argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000319 yield Instruction(opname[op], op,
320 arg, argval, argrepr,
321 offset, starts_line, is_jump_target)
322
323def disassemble(co, lasti=-1, *, file=None):
324 """Disassemble a code object."""
325 cell_names = co.co_cellvars + co.co_freevars
326 linestarts = dict(findlinestarts(co))
327 _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,
328 co.co_consts, cell_names, linestarts, file=file)
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000329
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000330def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000331 constants=None, cells=None, linestarts=None,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000332 *, file=None, line_offset=0):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000333 # Omit the line number column entirely if we have no line number info
334 show_lineno = linestarts is not None
335 # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000?
336 lineno_width = 3 if show_lineno else 0
337 for instr in _get_instructions_bytes(code, varnames, names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000338 constants, cells, linestarts,
339 line_offset=line_offset):
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000340 new_source_line = (show_lineno and
341 instr.starts_line is not None and
342 instr.offset > 0)
343 if new_source_line:
344 print(file=file)
345 is_current_instr = instr.offset == lasti
346 print(instr._disassemble(lineno_width, is_current_instr), file=file)
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000347
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000348def _disassemble_str(source, *, file=None):
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000349 """Compile the source string, then disassemble the code object."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000350 disassemble(_try_compile(source, '<dis>'), file=file)
Nick Coghlan5c8b54e2010-07-03 07:36:51 +0000351
Tim Peters88869f92001-01-14 23:36:06 +0000352disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000353
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300354def _unpack_opargs(code):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300355 extended_arg = 0
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300356 for i in range(0, len(code), 2):
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300357 op = code[i]
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300358 if op >= HAVE_ARGUMENT:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300359 arg = code[i+1] | extended_arg
360 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
361 else:
362 arg = None
363 yield (i, op, arg)
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300364
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000365def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000366 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000367
Tim Peters88869f92001-01-14 23:36:06 +0000368 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000369
Tim Peters88869f92001-01-14 23:36:06 +0000370 """
371 labels = []
Serhiy Storchaka02d9f5e2016-05-08 23:43:50 +0300372 for offset, op, arg in _unpack_opargs(code):
373 if arg is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000374 if op in hasjrel:
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300375 label = offset + 2 + arg
Tim Peters88869f92001-01-14 23:36:06 +0000376 elif op in hasjabs:
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000377 label = arg
Serhiy Storchakab0f80b02016-05-24 09:15:14 +0300378 else:
379 continue
380 if label not in labels:
381 labels.append(label)
Tim Peters88869f92001-01-14 23:36:06 +0000382 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000383
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000384def findlinestarts(code):
385 """Find the offsets in a byte code which are start of lines in the source.
386
387 Generate pairs (offset, lineno) as described in Python/compile.c.
388
389 """
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100390 byte_increments = code.co_lnotab[0::2]
391 line_increments = code.co_lnotab[1::2]
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000392
393 lastlineno = None
394 lineno = code.co_firstlineno
395 addr = 0
396 for byte_incr, line_incr in zip(byte_increments, line_increments):
397 if byte_incr:
398 if lineno != lastlineno:
399 yield (addr, lineno)
400 lastlineno = lineno
401 addr += byte_incr
Victor Stinnerf3914eb2016-01-20 12:16:21 +0100402 if line_incr >= 0x80:
403 # line_increments is an array of 8-bit signed integers
404 line_incr -= 0x100
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000405 lineno += line_incr
406 if lineno != lastlineno:
407 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000408
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000409class Bytecode:
410 """The bytecode operations of a piece of code
411
412 Instantiate this with a function, method, string of code, or a code object
413 (as returned by compile()).
414
415 Iterating over this yields the bytecode operations as Instruction instances.
416 """
Nick Coghlan50c48b82013-11-23 00:57:00 +1000417 def __init__(self, x, *, first_line=None, current_offset=None):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000418 self.codeobj = co = _get_code_object(x)
419 if first_line is None:
420 self.first_line = co.co_firstlineno
421 self._line_offset = 0
422 else:
423 self.first_line = first_line
424 self._line_offset = first_line - co.co_firstlineno
425 self._cell_names = co.co_cellvars + co.co_freevars
426 self._linestarts = dict(findlinestarts(co))
427 self._original_object = x
Nick Coghlan50c48b82013-11-23 00:57:00 +1000428 self.current_offset = current_offset
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000429
430 def __iter__(self):
431 co = self.codeobj
432 return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000433 co.co_consts, self._cell_names,
434 self._linestarts,
435 line_offset=self._line_offset)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000436
437 def __repr__(self):
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000438 return "{}({!r})".format(self.__class__.__name__,
439 self._original_object)
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000440
Nick Coghlan50c48b82013-11-23 00:57:00 +1000441 @classmethod
442 def from_traceback(cls, tb):
443 """ Construct a Bytecode from the given traceback """
444 while tb.tb_next:
445 tb = tb.tb_next
446 return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
447
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000448 def info(self):
449 """Return formatted information about the code object."""
450 return _format_code_info(self.codeobj)
451
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000452 def dis(self):
453 """Return a formatted view of the bytecode operations."""
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000454 co = self.codeobj
Nick Coghlan50c48b82013-11-23 00:57:00 +1000455 if self.current_offset is not None:
456 offset = self.current_offset
457 else:
458 offset = -1
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000459 with io.StringIO() as output:
460 _disassemble_bytes(co.co_code, varnames=co.co_varnames,
461 names=co.co_names, constants=co.co_consts,
462 cells=self._cell_names,
463 linestarts=self._linestarts,
464 line_offset=self._line_offset,
Nick Coghlan50c48b82013-11-23 00:57:00 +1000465 file=output,
466 lasti=offset)
Nick Coghlan90b8e7d2013-11-06 22:08:36 +1000467 return output.getvalue()
Nick Coghlanb39fd0c2013-05-06 23:59:20 +1000468
469
Guido van Rossum1fdae122000-02-04 17:47:55 +0000470def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000471 """Simple test program to disassemble a file."""
Nick Coghlan09566892013-08-25 00:48:17 +1000472 import argparse
473
474 parser = argparse.ArgumentParser()
475 parser.add_argument('infile', type=argparse.FileType(), nargs='?', default='-')
476 args = parser.parse_args()
477 with args.infile as infile:
478 source = infile.read()
479 code = compile(source, args.infile.name, "exec")
Tim Peters88869f92001-01-14 23:36:06 +0000480 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000481
482if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000483 _test()