blob: 5aa09c95b6d8df8354e38be0d5163e9796302cb3 [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
Guido van Rossum217a5fa1990-12-26 15:40:07 +00005
Skip Montanaro19c6ba32003-02-27 21:29:27 +00006from opcode import *
7from opcode import __all__ as _opcodes_all
8
Georg Brandl775c3072009-01-01 12:09:40 +00009__all__ = ["dis", "disassemble", "distb", "disco",
10 "findlinestarts", "findlabels"] + _opcodes_all
Skip Montanaro19c6ba32003-02-27 21:29:27 +000011del _opcodes_all
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000012
Benjamin Peterson76a23c12010-04-04 23:23:22 +000013_have_code = (types.MethodType, types.FunctionType, types.CodeType,
14 types.ClassType, type)
15
Guido van Rossumbd307951997-01-17 20:05:04 +000016def dis(x=None):
Tim Peters88869f92001-01-14 23:36:06 +000017 """Disassemble classes, methods, functions, or code.
Guido van Rossum421c2241997-11-18 15:47:55 +000018
Tim Peters88869f92001-01-14 23:36:06 +000019 With no argument, disassemble the last traceback.
Guido van Rossum421c2241997-11-18 15:47:55 +000020
Tim Peters88869f92001-01-14 23:36:06 +000021 """
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000022 if x is None:
Tim Peters88869f92001-01-14 23:36:06 +000023 distb()
24 return
Benjamin Petersone1577fb2009-05-10 14:16:47 +000025 if isinstance(x, types.InstanceType):
Tim Peters88869f92001-01-14 23:36:06 +000026 x = x.__class__
Guido van Rossumfc53c132001-01-19 02:41:41 +000027 if hasattr(x, 'im_func'):
28 x = x.im_func
29 if hasattr(x, 'func_code'):
30 x = x.func_code
Tim Peters88869f92001-01-14 23:36:06 +000031 if hasattr(x, '__dict__'):
32 items = x.__dict__.items()
33 items.sort()
34 for name, x1 in items:
Benjamin Peterson76a23c12010-04-04 23:23:22 +000035 if isinstance(x1, _have_code):
Tim Peters88869f92001-01-14 23:36:06 +000036 print "Disassembly of %s:" % name
37 try:
38 dis(x1)
39 except TypeError, msg:
40 print "Sorry:", msg
41 print
Guido van Rossumfc53c132001-01-19 02:41:41 +000042 elif hasattr(x, 'co_code'):
43 disassemble(x)
Skip Montanaro19c6ba32003-02-27 21:29:27 +000044 elif isinstance(x, str):
45 disassemble_string(x)
Tim Peters88869f92001-01-14 23:36:06 +000046 else:
Guido van Rossumfc53c132001-01-19 02:41:41 +000047 raise TypeError, \
48 "don't know how to disassemble %s objects" % \
49 type(x).__name__
Guido van Rossum217a5fa1990-12-26 15:40:07 +000050
Guido van Rossumbd307951997-01-17 20:05:04 +000051def distb(tb=None):
Tim Peters88869f92001-01-14 23:36:06 +000052 """Disassemble a traceback (default: last traceback)."""
Raymond Hettinger0f4940c2002-06-01 00:57:55 +000053 if tb is None:
Tim Peters88869f92001-01-14 23:36:06 +000054 try:
55 tb = sys.last_traceback
56 except AttributeError:
57 raise RuntimeError, "no last traceback to disassemble"
58 while tb.tb_next: tb = tb.tb_next
59 disassemble(tb.tb_frame.f_code, tb.tb_lasti)
Guido van Rossum217a5fa1990-12-26 15:40:07 +000060
Guido van Rossumbd307951997-01-17 20:05:04 +000061def disassemble(co, lasti=-1):
Tim Peters88869f92001-01-14 23:36:06 +000062 """Disassemble a code object."""
63 code = co.co_code
64 labels = findlabels(code)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +000065 linestarts = dict(findlinestarts(co))
Tim Peters88869f92001-01-14 23:36:06 +000066 n = len(code)
67 i = 0
68 extended_arg = 0
Jeremy Hyltona39414b2001-01-25 20:08:47 +000069 free = None
Tim Peters88869f92001-01-14 23:36:06 +000070 while i < n:
71 c = code[i]
72 op = ord(c)
Armin Rigo9c8f7ea2003-10-28 12:17:25 +000073 if i in linestarts:
Michael W. Hudsondd32a912002-08-15 14:59:02 +000074 if i > 0:
75 print
Armin Rigo9c8f7ea2003-10-28 12:17:25 +000076 print "%3d" % linestarts[i],
Michael W. Hudsondd32a912002-08-15 14:59:02 +000077 else:
78 print ' ',
79
Tim Peters88869f92001-01-14 23:36:06 +000080 if i == lasti: print '-->',
81 else: print ' ',
82 if i in labels: print '>>',
83 else: print ' ',
Walter Dörwald70a6b492004-02-12 17:35:32 +000084 print repr(i).rjust(4),
Eric S. Raymond373c55e2001-02-09 08:25:29 +000085 print opname[op].ljust(20),
Tim Peters88869f92001-01-14 23:36:06 +000086 i = i+1
87 if op >= HAVE_ARGUMENT:
88 oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
89 extended_arg = 0
90 i = i+2
91 if op == EXTENDED_ARG:
92 extended_arg = oparg*65536L
Walter Dörwald70a6b492004-02-12 17:35:32 +000093 print repr(oparg).rjust(5),
Tim Peters88869f92001-01-14 23:36:06 +000094 if op in hasconst:
Walter Dörwald70a6b492004-02-12 17:35:32 +000095 print '(' + repr(co.co_consts[oparg]) + ')',
Tim Peters88869f92001-01-14 23:36:06 +000096 elif op in hasname:
97 print '(' + co.co_names[oparg] + ')',
98 elif op in hasjrel:
Walter Dörwald70a6b492004-02-12 17:35:32 +000099 print '(to ' + repr(i + oparg) + ')',
Tim Peters88869f92001-01-14 23:36:06 +0000100 elif op in haslocal:
101 print '(' + co.co_varnames[oparg] + ')',
102 elif op in hascompare:
103 print '(' + cmp_op[oparg] + ')',
Jeremy Hyltona39414b2001-01-25 20:08:47 +0000104 elif op in hasfree:
105 if free is None:
106 free = co.co_cellvars + co.co_freevars
107 print '(' + free[oparg] + ')',
Tim Peters88869f92001-01-14 23:36:06 +0000108 print
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000109
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000110def disassemble_string(code, lasti=-1, varnames=None, names=None,
111 constants=None):
Tim Peters669454e2003-03-07 17:30:48 +0000112 labels = findlabels(code)
113 n = len(code)
114 i = 0
115 while i < n:
116 c = code[i]
117 op = ord(c)
Tim Peters669454e2003-03-07 17:30:48 +0000118 if i == lasti: print '-->',
119 else: print ' ',
120 if i in labels: print '>>',
121 else: print ' ',
Walter Dörwald70a6b492004-02-12 17:35:32 +0000122 print repr(i).rjust(4),
Tim Peters669454e2003-03-07 17:30:48 +0000123 print opname[op].ljust(15),
124 i = i+1
125 if op >= HAVE_ARGUMENT:
126 oparg = ord(code[i]) + ord(code[i+1])*256
127 i = i+2
Walter Dörwald70a6b492004-02-12 17:35:32 +0000128 print repr(oparg).rjust(5),
Tim Peters669454e2003-03-07 17:30:48 +0000129 if op in hasconst:
130 if constants:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000131 print '(' + repr(constants[oparg]) + ')',
Tim Peters669454e2003-03-07 17:30:48 +0000132 else:
133 print '(%d)'%oparg,
134 elif op in hasname:
135 if names is not None:
136 print '(' + names[oparg] + ')',
137 else:
138 print '(%d)'%oparg,
139 elif op in hasjrel:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000140 print '(to ' + repr(i + oparg) + ')',
Tim Peters669454e2003-03-07 17:30:48 +0000141 elif op in haslocal:
142 if varnames:
143 print '(' + varnames[oparg] + ')',
144 else:
145 print '(%d)' % oparg,
146 elif op in hascompare:
147 print '(' + cmp_op[oparg] + ')',
148 print
Skip Montanaro19c6ba32003-02-27 21:29:27 +0000149
Tim Peters88869f92001-01-14 23:36:06 +0000150disco = disassemble # XXX For backwards compatibility
Guido van Rossumbd307951997-01-17 20:05:04 +0000151
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000152def findlabels(code):
Tim Peters88869f92001-01-14 23:36:06 +0000153 """Detect all offsets in a byte code which are jump targets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000154
Tim Peters88869f92001-01-14 23:36:06 +0000155 Return the list of offsets.
Guido van Rossum421c2241997-11-18 15:47:55 +0000156
Tim Peters88869f92001-01-14 23:36:06 +0000157 """
158 labels = []
159 n = len(code)
160 i = 0
161 while i < n:
162 c = code[i]
163 op = ord(c)
164 i = i+1
165 if op >= HAVE_ARGUMENT:
166 oparg = ord(code[i]) + ord(code[i+1])*256
167 i = i+2
168 label = -1
169 if op in hasjrel:
170 label = i+oparg
171 elif op in hasjabs:
172 label = oparg
173 if label >= 0:
174 if label not in labels:
175 labels.append(label)
176 return labels
Guido van Rossum217a5fa1990-12-26 15:40:07 +0000177
Armin Rigo9c8f7ea2003-10-28 12:17:25 +0000178def findlinestarts(code):
179 """Find the offsets in a byte code which are start of lines in the source.
180
181 Generate pairs (offset, lineno) as described in Python/compile.c.
182
183 """
184 byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
185 line_increments = [ord(c) for c in code.co_lnotab[1::2]]
186
187 lastlineno = None
188 lineno = code.co_firstlineno
189 addr = 0
190 for byte_incr, line_incr in zip(byte_increments, line_increments):
191 if byte_incr:
192 if lineno != lastlineno:
193 yield (addr, lineno)
194 lastlineno = lineno
195 addr += byte_incr
196 lineno += line_incr
197 if lineno != lastlineno:
198 yield (addr, lineno)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000199
200def _test():
Tim Peters88869f92001-01-14 23:36:06 +0000201 """Simple test program to disassemble a file."""
202 if sys.argv[1:]:
203 if sys.argv[2:]:
204 sys.stderr.write("usage: python dis.py [-|file]\n")
205 sys.exit(2)
206 fn = sys.argv[1]
207 if not fn or fn == "-":
208 fn = None
209 else:
210 fn = None
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000211 if fn is None:
Tim Peters88869f92001-01-14 23:36:06 +0000212 f = sys.stdin
213 else:
214 f = open(fn)
215 source = f.read()
Raymond Hettinger0f4940c2002-06-01 00:57:55 +0000216 if fn is not None:
Tim Peters88869f92001-01-14 23:36:06 +0000217 f.close()
218 else:
219 fn = "<stdin>"
220 code = compile(source, fn, "exec")
221 dis(code)
Guido van Rossum1fdae122000-02-04 17:47:55 +0000222
223if __name__ == "__main__":
Tim Peters88869f92001-01-14 23:36:06 +0000224 _test()