]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/dis.py
dist/mkfile: run binds in subshell
[plan9front.git] / sys / lib / python / dis.py
1 """Disassembler of Python byte code into mnemonics."""
2
3 import sys
4 import types
5
6 from opcode import *
7 from opcode import __all__ as _opcodes_all
8
9 __all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
10 del _opcodes_all
11
12 def dis(x=None):
13     """Disassemble classes, methods, functions, or code.
14
15     With no argument, disassemble the last traceback.
16
17     """
18     if x is None:
19         distb()
20         return
21     if type(x) is types.InstanceType:
22         x = x.__class__
23     if hasattr(x, 'im_func'):
24         x = x.im_func
25     if hasattr(x, 'func_code'):
26         x = x.func_code
27     if hasattr(x, '__dict__'):
28         items = x.__dict__.items()
29         items.sort()
30         for name, x1 in items:
31             if type(x1) in (types.MethodType,
32                             types.FunctionType,
33                             types.CodeType,
34                             types.ClassType):
35                 print "Disassembly of %s:" % name
36                 try:
37                     dis(x1)
38                 except TypeError, msg:
39                     print "Sorry:", msg
40                 print
41     elif hasattr(x, 'co_code'):
42         disassemble(x)
43     elif isinstance(x, str):
44         disassemble_string(x)
45     else:
46         raise TypeError, \
47               "don't know how to disassemble %s objects" % \
48               type(x).__name__
49
50 def distb(tb=None):
51     """Disassemble a traceback (default: last traceback)."""
52     if tb is None:
53         try:
54             tb = sys.last_traceback
55         except AttributeError:
56             raise RuntimeError, "no last traceback to disassemble"
57         while tb.tb_next: tb = tb.tb_next
58     disassemble(tb.tb_frame.f_code, tb.tb_lasti)
59
60 def disassemble(co, lasti=-1):
61     """Disassemble a code object."""
62     code = co.co_code
63     labels = findlabels(code)
64     linestarts = dict(findlinestarts(co))
65     n = len(code)
66     i = 0
67     extended_arg = 0
68     free = None
69     while i < n:
70         c = code[i]
71         op = ord(c)
72         if i in linestarts:
73             if i > 0:
74                 print
75             print "%3d" % linestarts[i],
76         else:
77             print '   ',
78
79         if i == lasti: print '-->',
80         else: print '   ',
81         if i in labels: print '>>',
82         else: print '  ',
83         print repr(i).rjust(4),
84         print opname[op].ljust(20),
85         i = i+1
86         if op >= HAVE_ARGUMENT:
87             oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
88             extended_arg = 0
89             i = i+2
90             if op == EXTENDED_ARG:
91                 extended_arg = oparg*65536L
92             print repr(oparg).rjust(5),
93             if op in hasconst:
94                 print '(' + repr(co.co_consts[oparg]) + ')',
95             elif op in hasname:
96                 print '(' + co.co_names[oparg] + ')',
97             elif op in hasjrel:
98                 print '(to ' + repr(i + oparg) + ')',
99             elif op in haslocal:
100                 print '(' + co.co_varnames[oparg] + ')',
101             elif op in hascompare:
102                 print '(' + cmp_op[oparg] + ')',
103             elif op in hasfree:
104                 if free is None:
105                     free = co.co_cellvars + co.co_freevars
106                 print '(' + free[oparg] + ')',
107         print
108
109 def disassemble_string(code, lasti=-1, varnames=None, names=None,
110                        constants=None):
111     labels = findlabels(code)
112     n = len(code)
113     i = 0
114     while i < n:
115         c = code[i]
116         op = ord(c)
117         if i == lasti: print '-->',
118         else: print '   ',
119         if i in labels: print '>>',
120         else: print '  ',
121         print repr(i).rjust(4),
122         print opname[op].ljust(15),
123         i = i+1
124         if op >= HAVE_ARGUMENT:
125             oparg = ord(code[i]) + ord(code[i+1])*256
126             i = i+2
127             print repr(oparg).rjust(5),
128             if op in hasconst:
129                 if constants:
130                     print '(' + repr(constants[oparg]) + ')',
131                 else:
132                     print '(%d)'%oparg,
133             elif op in hasname:
134                 if names is not None:
135                     print '(' + names[oparg] + ')',
136                 else:
137                     print '(%d)'%oparg,
138             elif op in hasjrel:
139                 print '(to ' + repr(i + oparg) + ')',
140             elif op in haslocal:
141                 if varnames:
142                     print '(' + varnames[oparg] + ')',
143                 else:
144                     print '(%d)' % oparg,
145             elif op in hascompare:
146                 print '(' + cmp_op[oparg] + ')',
147         print
148
149 disco = disassemble                     # XXX For backwards compatibility
150
151 def findlabels(code):
152     """Detect all offsets in a byte code which are jump targets.
153
154     Return the list of offsets.
155
156     """
157     labels = []
158     n = len(code)
159     i = 0
160     while i < n:
161         c = code[i]
162         op = ord(c)
163         i = i+1
164         if op >= HAVE_ARGUMENT:
165             oparg = ord(code[i]) + ord(code[i+1])*256
166             i = i+2
167             label = -1
168             if op in hasjrel:
169                 label = i+oparg
170             elif op in hasjabs:
171                 label = oparg
172             if label >= 0:
173                 if label not in labels:
174                     labels.append(label)
175     return labels
176
177 def findlinestarts(code):
178     """Find the offsets in a byte code which are start of lines in the source.
179
180     Generate pairs (offset, lineno) as described in Python/compile.c.
181
182     """
183     byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
184     line_increments = [ord(c) for c in code.co_lnotab[1::2]]
185
186     lastlineno = None
187     lineno = code.co_firstlineno
188     addr = 0
189     for byte_incr, line_incr in zip(byte_increments, line_increments):
190         if byte_incr:
191             if lineno != lastlineno:
192                 yield (addr, lineno)
193                 lastlineno = lineno
194             addr += byte_incr
195         lineno += line_incr
196     if lineno != lastlineno:
197         yield (addr, lineno)
198
199 def _test():
200     """Simple test program to disassemble a file."""
201     if sys.argv[1:]:
202         if sys.argv[2:]:
203             sys.stderr.write("usage: python dis.py [-|file]\n")
204             sys.exit(2)
205         fn = sys.argv[1]
206         if not fn or fn == "-":
207             fn = None
208     else:
209         fn = None
210     if fn is None:
211         f = sys.stdin
212     else:
213         f = open(fn)
214     source = f.read()
215     if fn is not None:
216         f.close()
217     else:
218         fn = "<stdin>"
219     code = compile(source, fn, "exec")
220     dis(code)
221
222 if __name__ == "__main__":
223     _test()