1 """Disassembler of Python byte code into mnemonics."""
7 from opcode
import __all__
as _opcodes_all
9 __all__
= ["dis", "disassemble", "distb", "disco",
10 "findlinestarts", "findlabels"] + _opcodes_all
14 """Disassemble classes, methods, functions, or code.
16 With no argument, disassemble the last traceback.
22 if type(x
) is types
.InstanceType
:
24 if hasattr(x
, 'im_func'):
26 if hasattr(x
, 'func_code'):
28 if hasattr(x
, '__dict__'):
29 items
= x
.__dict
__.items()
31 for name
, x1
in items
:
32 if type(x1
) in (types
.MethodType
,
36 print "Disassembly of %s:" % name
39 except TypeError, msg
:
42 elif hasattr(x
, 'co_code'):
44 elif isinstance(x
, str):
48 "don't know how to disassemble %s objects" % \
52 """Disassemble a traceback (default: last traceback)."""
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
)
61 def disassemble(co
, lasti
=-1):
62 """Disassemble a code object."""
64 labels
= findlabels(code
)
65 linestarts
= dict(findlinestarts(co
))
76 print "%3d" % linestarts
[i
],
80 if i
== lasti
: print '-->',
82 if i
in labels
: print '>>',
84 print repr(i
).rjust(4),
85 print opname
[op
].ljust(20),
87 if op
>= HAVE_ARGUMENT
:
88 oparg
= ord(code
[i
]) + ord(code
[i
+1])*256 + extended_arg
91 if op
== EXTENDED_ARG
:
92 extended_arg
= oparg
*65536L
93 print repr(oparg
).rjust(5),
95 print '(' + repr(co
.co_consts
[oparg
]) + ')',
97 print '(' + co
.co_names
[oparg
] + ')',
99 print '(to ' + repr(i
+ oparg
) + ')',
101 print '(' + co
.co_varnames
[oparg
] + ')',
102 elif op
in hascompare
:
103 print '(' + cmp_op
[oparg
] + ')',
106 free
= co
.co_cellvars
+ co
.co_freevars
107 print '(' + free
[oparg
] + ')',
110 def disassemble_string(code
, lasti
=-1, varnames
=None, names
=None,
112 labels
= findlabels(code
)
118 if i
== lasti
: print '-->',
120 if i
in labels
: print '>>',
122 print repr(i
).rjust(4),
123 print opname
[op
].ljust(15),
125 if op
>= HAVE_ARGUMENT
:
126 oparg
= ord(code
[i
]) + ord(code
[i
+1])*256
128 print repr(oparg
).rjust(5),
131 print '(' + repr(constants
[oparg
]) + ')',
135 if names
is not None:
136 print '(' + names
[oparg
] + ')',
140 print '(to ' + repr(i
+ oparg
) + ')',
143 print '(' + varnames
[oparg
] + ')',
145 print '(%d)' % oparg
,
146 elif op
in hascompare
:
147 print '(' + cmp_op
[oparg
] + ')',
150 disco
= disassemble
# XXX For backwards compatibility
152 def findlabels(code
):
153 """Detect all offsets in a byte code which are jump targets.
155 Return the list of offsets.
165 if op
>= HAVE_ARGUMENT
:
166 oparg
= ord(code
[i
]) + ord(code
[i
+1])*256
174 if label
not in labels
:
178 def findlinestarts(code
):
179 """Find the offsets in a byte code which are start of lines in the source.
181 Generate pairs (offset, lineno) as described in Python/compile.c.
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]]
188 lineno
= code
.co_firstlineno
190 for byte_incr
, line_incr
in zip(byte_increments
, line_increments
):
192 if lineno
!= lastlineno
:
197 if lineno
!= lastlineno
:
201 """Simple test program to disassemble a file."""
204 sys
.stderr
.write("usage: python dis.py [-|file]\n")
207 if not fn
or fn
== "-":
220 code
= compile(source
, fn
, "exec")
223 if __name__
== "__main__":