"""Some convenience macros for gdb. If you have pypy in your path, you can simply do:(gdb) python import pypy.tool.gdb_pypyOr, alternatively:(gdb) python execfile('/path/to/gdb_pypy.py')"""from__future__importwith_statementimportreimportsysimportos.pathtry:# when running inside gdbfromgdbimportCommandexceptImportError:# whenn running outside gdb: mock class for testingclassCommand(object):def__init__(self,name,command_class):passdeffind_field_with_suffix(val,suffix):""" Return ``val[field]``, where ``field`` is the only one whose name ends with ``suffix``. If there is no such field, or more than one, raise KeyError. """names=[]forfieldinval.type.fields():iffield.name.endswith(suffix):names.append(field.name)#iflen(names)==1:returnval[names[0]]eliflen(names)==0:raiseKeyError,"cannot find field *%s"%suffixelse:raiseKeyError,"too many matching fields: %s"%', '.join(names)deflookup(val,suffix):""" Lookup a field which ends with ``suffix`` following the rpython struct inheritance hierarchy (i.e., looking both at ``val`` and ``val['*_super']``, recursively. """try:returnfind_field_with_suffix(val,suffix)exceptKeyError:baseobj=find_field_with_suffix(val,'_super')returnlookup(baseobj,suffix)classRPyType(Command):""" Prints the RPython type of the expression (remember to dereference it!) It assumes to find ``typeids.txt`` in the current directory. E.g.: (gdb) rpy_type *l_v123 GcStruct pypy.foo.Bar { super, inst_xxx, inst_yyy } """prog2typeids={}def__init__(self,gdb=None):# dependency injection, for testsifgdbisNone:importgdbself.gdb=gdbCommand.__init__(self,"rpy_type",self.gdb.COMMAND_NONE)definvoke(self,arg,from_tty):# some magic code to automatically reload the python file while developing## from pypy.tool import gdb_pypy## reload(gdb_pypy)## gdb_pypy.RPyType.prog2typeids = self.prog2typeids # persist the cache## self.__class__ = gdb_pypy.RPyTypeprintself.do_invoke(arg,from_tty)defdo_invoke(self,arg,from_tty):obj=self.gdb.parse_and_eval(arg)hdr=lookup(obj,'_gcheader')tid=hdr['h_tid']offset=tid&0xFFFFFFFF# 64bit onlyoffset=int(offset)# convert from gdb.Value to python inttypeids=self.get_typeids()ifoffsetintypeids:returntypeids[offset]else:return'Cannot find the type with offset %d'%offsetdefget_typeids(self):progspace=self.gdb.current_progspace()try:returnself.prog2typeids[progspace]exceptKeyError:typeids=self.load_typeids(progspace)self.prog2typeids[progspace]=typeidsreturntypeidsdefload_typeids(self,progspace):""" Returns a mapping offset --> description """exename=progspace.filenameroot=os.path.dirname(exename)typeids_txt=os.path.join(root,'typeids.txt')ifnotos.path.exists(typeids_txt):newroot=os.path.dirname(root)typeids_txt=os.path.join(newroot,'typeids.txt')print'loading',typeids_txttypeids={}withopen(typeids_txt)asf:forlineinf:member,descr=map(str.strip,line.split(None,1))expr="((char*)(&pypy_g_typeinfo.%s)) - (char*)&pypy_g_typeinfo"%memberoffset=int(self.gdb.parse_and_eval(expr))typeids[offset]=descrreturntypeidsdefis_ptr(type,gdb):ifgdbisNone:importgdb# so we can pass a fake one from the testsreturntype.code==gdb.TYPE_CODE_PTRclassRPyStringPrinter(object):""" Pretty printer for rpython strings. Note that this pretty prints *pointers* to strings: this way you can do "p val" and see the nice string, and "p *val" to see the underyling struct fields """def__init__(self,val):self.val=val@classmethoddeflookup(cls,val,gdb=None):t=val.typeifis_ptr(t,gdb)andt.target().tag=='pypy_rpy_string0':returncls(val)returnNonedefto_string(self):chars=self.val['rs_chars']length=int(chars['length'])items=chars['items']res=[chr(items[i])foriinrange(length)]string=''.join(res)return'r'+repr(string)classRPyListPrinter(object):""" Pretty printer for rpython lists Note that this pretty prints *pointers* to lists: this way you can do "p val" and see the nice repr, and "p *val" to see the underyling struct fields """def__init__(self,val):self.val=val@classmethoddeflookup(cls,val,gdb=None):t=val.typeif(is_ptr(t,gdb)andt.target().tagisnotNoneandre.match(r'pypy_list\d*',t.target().tag)):returncls(val)returnNonedefto_string(self):length=int(self.val['l_length'])array=self.val['l_items']allocated=int(array['length'])items=array['items']itemlist=[]foriinrange(length):item=items[i]itemlist.append(str(item))str_items=', '.join(itemlist)return'r[%s] (len=%d, alloc=%d)'%(str_items,length,allocated)try:importgdbRPyType()# side effectsgdb.pretty_printers+=[RPyStringPrinter.lookup,RPyListPrinter.lookup]exceptImportError:pass