"""Disassembler of Python byte code into mnemonics.Comes from standard library, modified for the purpose of having a structuredview on things"""importsysimporttypesimportinspectfromopcodeimport*fromopcodeimport__all__as_opcodes_all__all__=["dis","disassemble","distb","disco"]+_opcodes_alldel_opcodes_allclassOpcode(object):""" An abstract base class for all opcode implementations """def__init__(self,pos,lineno,arg=None,argstr=''):self.pos=posself.arg=argself.argstr=argstrself.lineno=linenoself.line_starts_here=Falsedef__repr__(self):ifself.argisNone:return"<%s at %d>"%(self.__class__.__name__,self.pos)return"<%s (%s) at %d>"%(self.__class__.__name__,self.arg,self.pos)classCodeRepresentation(object):""" Representation of opcodes """def__init__(self,opcodes,co,source):self.opcodes=opcodesself.co=coself.map={}current_lineno=Noneforopcodeinopcodes:self.map[opcode.pos]=opcodeifopcode.lineno!=current_lineno:opcode.line_starts_here=Truecurrent_lineno=opcode.linenoself.source=source.split("\n")def_setup():foropcodeinopname:ifnotopcode.startswith('<'):classO(Opcode):passopcode=opcode.replace('+','_')O.__name__=opcodeglobals()[opcode]=O_setup()defdis(x=None):"""Disassemble classes, methods, functions, or code. With no argument, disassemble the last traceback. """ifxisNone:distb()returniftype(x)istypes.InstanceType:x=x.__class__ifhasattr(x,'im_func'):x=x.im_funcifhasattr(x,'func_code'):x=x.func_codeifhasattr(x,'__dict__'):xxxitems=x.__dict__.items()items.sort()forname,x1initems:iftype(x1)in(types.MethodType,types.FunctionType,types.CodeType,types.ClassType):print"Disassembly of %s:"%nametry:dis(x1)exceptTypeError,msg:print"Sorry:",msgprintelifhasattr(x,'co_code'):returndisassemble(x)elifisinstance(x,str):returndisassemble_string(x)else:raiseTypeError, \
"don't know how to disassemble %s objects"% \
type(x).__name__defdistb(tb=None):"""Disassemble a traceback (default: last traceback)."""iftbisNone:try:tb=sys.last_tracebackexceptAttributeError:raiseRuntimeError,"no last traceback to disassemble"whiletb.tb_next:tb=tb.tb_nextdisassemble(tb.tb_frame.f_code,tb.tb_lasti)defdisassemble(co,lasti=-1):"""Disassemble a code object."""source=inspect.getsource(co)code=co.co_codelabels=findlabels(code)linestarts=dict(findlinestarts(co))n=len(code)i=0extended_arg=0free=Noneres=[]lastline=co.co_firstlinenowhilei<n:c=code[i]op=ord(c)ifiinlinestarts:lastline=linestarts[i]#if i == lasti:# xxx# print '-->',#else:# xxx# print ' ',#if i in labels:# xxx# print '>>',#else:# xxx# print ' ',#xxxpos=ii=i+1ifop>=HAVE_ARGUMENT:oparg=ord(code[i])+ord(code[i+1])*256+extended_argopargstr=str(oparg)extended_arg=0i=i+2ifop==EXTENDED_ARG:extended_arg=oparg*65536Lifopinhasconst:opargstr=repr(co.co_consts[oparg])elifopinhasname:opargstr=co.co_names[oparg]elifopinhasjrel:opargstr='to '+repr(i+oparg)elifopinhaslocal:opargstr=co.co_varnames[oparg]elifopinhascompare:opargstr=cmp_op[oparg]elifopinhasfree:iffreeisNone:free=co.co_cellvars+co.co_freevarsopargstr=free[oparg]else:oparg=Noneopargstr=''opcls=globals()[opname[op].replace('+','_')]res.append(opcls(pos,lastline,oparg,opargstr))returnCodeRepresentation(res,co,source)defdisassemble_string(code,lasti=-1,varnames=None,names=None,constants=None):labels=findlabels(code)n=len(code)i=0whilei<n:c=code[i]op=ord(c)ifi==lasti:xxxprint'-->',else:xxxprint' ',ifiinlabels:xxxprint'>>',else:xxxprint' ',xxxxprintrepr(i).rjust(4),printopname[op].ljust(15),i=i+1ifop>=HAVE_ARGUMENT:oparg=ord(code[i])+ord(code[i+1])*256i=i+2xxxprintrepr(oparg).rjust(5),ifopinhasconst:ifconstants:xxxprint'('+repr(constants[oparg])+')',else:xxxprint'(%d)'%oparg,elifopinhasname:ifnamesisnotNone:xxxprint'('+names[oparg]+')',else:xxxprint'(%d)'%oparg,elifopinhasjrel:xxxprint'(to '+repr(i+oparg)+')',elifopinhaslocal:ifvarnames:xxxprint'('+varnames[oparg]+')',else:xxxprint'(%d)'%oparg,elifopinhascompare:xxxprint'('+cmp_op[oparg]+')',xxxprintdisco=disassemble# XXX For backwards compatibilitydeffindlabels(code):"""Detect all offsets in a byte code which are jump targets. Return the list of offsets. """labels=[]n=len(code)i=0whilei<n:c=code[i]op=ord(c)i=i+1ifop>=HAVE_ARGUMENT:oparg=ord(code[i])+ord(code[i+1])*256i=i+2label=-1ifopinhasjrel:label=i+opargelifopinhasjabs:label=opargiflabel>=0:iflabelnotinlabels:labels.append(label)returnlabelsdeffindlinestarts(code):"""Find the offsets in a byte code which are start of lines in the source. Generate pairs (offset, lineno) as described in Python/compile.c. """byte_increments=[ord(c)forcincode.co_lnotab[0::2]]line_increments=[ord(c)forcincode.co_lnotab[1::2]]lastlineno=Nonelineno=code.co_firstlinenoaddr=0forbyte_incr,line_incrinzip(byte_increments,line_increments):ifbyte_incr:iflineno!=lastlineno:yield(addr,lineno)lastlineno=linenoaddr+=byte_incrlineno+=line_incriflineno!=lastlineno:yield(addr,lineno)def_test():"""Simple test program to disassemble a file."""ifsys.argv[1:]:ifsys.argv[2:]:sys.stderr.write("usage: python dis.py [-|file]\n")sys.exit(2)fn=sys.argv[1]ifnotfnorfn=="-":fn=Noneelse:fn=NoneiffnisNone:f=sys.stdinelse:f=open(fn)source=f.read()iffnisnotNone:f.close()else:fn="<stdin>"code=compile(source,fn,"exec")dis(code)