Skip to content

Instantly share code, notes, and snippets.

@cutthroat
Created June 16, 2011 18:11
Show Gist options
  • Save cutthroat/1029848 to your computer and use it in GitHub Desktop.
Save cutthroat/1029848 to your computer and use it in GitHub Desktop.
disassemble python byte code
# 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