Created
June 16, 2011 18:11
-
-
Save cutthroat/1029848 to your computer and use it in GitHub Desktop.
disassemble python byte code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# i got my 9 millimeter at my waist, papa | |
# i got my shotgun in the escalade, papa | |
from opcode import HAVE_ARGUMENT, EXTENDED_ARG, opname, opmap, cmp_op | |
from opcode import hasconst, hasfree, hasname, hasjrel, hasjabs, haslocal, hascompare | |
haspair = [opmap[x] for x in ('UNPACK_EX', 'CALL_FUNCTION')] | |
# global convention: | |
# i - position of the opcode in the byte stream | |
# c - opcode | |
# a - opcode argument | |
# decode argument value from integer code | |
class Decoder: | |
def __init__(self, code): | |
self.code = code | |
self.vars = code.co_cellvars + code.co_freevars | |
# handlers | |
def const(self, i, c, a): | |
v = self.code.co_consts[a] | |
self.debug(i, c, repr(v), Decoder.const) | |
return v | |
def free(self, i, c, a): | |
v = self.vars[a] | |
self.debug(i, c, v, Decoder.free) | |
return v | |
def name(self, i, c, a): | |
v = self.code.co_names[a] | |
self.debug(i, c, v, Decoder.name) | |
return v | |
def jrel(self, i, c, a): | |
v = (i, i + a) | |
self.debug(i, c, v, Decoder.jrel) | |
return v | |
def jabs(self, i, c, a): | |
v = a | |
self.debug(i, c, v, Decoder.jabs) | |
return v | |
def local(self, i, c, a): | |
v = self.code.co_varnames[a] | |
self.debug(i, c, v, Decoder.local) | |
return v | |
def compare(self, i, c, a): | |
v = cmp_op[a] | |
self.debug(i, c, v, Decoder.compare) | |
return v | |
def pair(self, i, c, a): | |
v = (a & 0xff, a >> 8 & 0xff) | |
self.debug(i, c, v, Decoder.pair) | |
return v | |
def other(self, i, c, a): | |
v = a | |
self.debug(i, c, v, None) | |
return v | |
CLASSES = [hasconst, hasfree, hasname, hasjrel, hasjabs, haslocal, hascompare, haspair] | |
HANDLERS = [const, free, name, jrel, jabs, local, compare, pair] | |
# build dispatch table | |
def dispatch(other, classes, handlers): | |
table = 256 * [other] | |
for k, h in zip(classes, handlers): | |
for c in k: | |
table[c] = h | |
return table | |
dispatch = dispatch(other, CLASSES, HANDLERS) | |
# the name of the game | |
def __call__(self, i, c, a): | |
return Decoder.dispatch[c](self, i, c, a) | |
# util | |
def debug(self, i, c, a, h): | |
print('{:>3} {:>17} {:>7} {}'.format(i, opname[c], h.__name__ if h else '', a if a is not None or h else '')) | |
# separate argument as single integer | |
def argue(co_code): | |
s, n = co_code, len(co_code) # code stream and length | |
i, a = 0, 0 # stream index and argument accumulator | |
while i < n: | |
c = s[i]; i += 1 | |
if c >= HAVE_ARGUMENT: | |
a |= s[i] | s[i+1] << 8; i += 2 | |
if c == EXTENDED_ARG: | |
a <<= 16 | |
continue | |
yield i, c, a | |
else: | |
yield i, c, None | |
a = 0 | |
def parse(code): | |
decode = Decoder(code) | |
for i, c, a in argue(code.co_code): | |
decode(i, c, a) | |
parse(argue.__code__) | |
# example from somewhere on the nets | |
""" | |
def outer(): | |
a = 1 | |
# creating a lexically nested function bar | |
def inner(): | |
# a is visible from outer's locals | |
return a | |
b = 2 > 1 # b is here for an example later on | |
return inner | |
# inner_nonlexical will be called from within | |
# outer_nonlexical but it is not lexically nested | |
def inner_nonlexical(): | |
return a # a is not visible | |
def outer_nonlexical(): | |
a = 1 | |
inner = inner_nonlexical | |
b = 2 # b is here for an example later on | |
return inner_nonlexical | |
""" | |
# vim: et sw=4 sts=4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment