def is_pyobject_ptr(addr): try: _type_pyop = caching_lookup_type('PyObject').pointer() _type_pyvarop = caching_lookup_type('PyVarObject').pointer() except RuntimeError: # not linked against python return None pyop = gdb.Value(addr).cast(_type_pyop) try: ob_refcnt = pyop['ob_refcnt'] if ob_refcnt >=0 and ob_refcnt < 0xffff: obtype = pyop['ob_type'] if obtype != 0: type_refcnt = obtype.cast(_type_pyop)['ob_refcnt'] if type_refcnt > 0 and type_refcnt < 0xffff: type_ob_size = obtype.cast(_type_pyvarop)['ob_size'] if type_ob_size > 0xffff: return 0 for fieldname in ('tp_del', 'tp_mro', 'tp_init', 'tp_getset'): if not looks_like_ptr(obtype[fieldname]): return 0 # Then this looks like a Python object: return PyObjectPtr.from_pyobject_ptr(pyop) except (RuntimeError, UnicodeDecodeError): pass # Not a python object (or corrupt)
def get_class_name(addr, size): # Try to detect a vtable ptr at the top of this object: vtable = gdb.Value(addr).cast(void_ptr_ptr).dereference() if not looks_like_ptr(vtable): return None info = execute('info sym (void *)0x%x' % long(vtable)) # "vtable for Foo + 8 in section .rodata of /home/david/heap/test_cplusplus" m = re.match('vtable for (.*) \+ (.*)', info) if m: return m.group(1) # Not matched: return None
def is_pyobject_ptr(addr): try: _type_pyop = caching_lookup_type('PyObject').pointer() _type_pyvarop = caching_lookup_type('PyVarObject').pointer() except RuntimeError: # not linked against python return None try: typeop = pyop = gdb.Value(addr).cast(_type_pyop) # If we follow type chain on a PyObject long enough, we should arrive # at 'type' and type(type) should be 'type'. # The levels are: a <- b means a = type(b) # 0 - type # 1 - type <- class A # type <- class M(type) # 2 - type <- class A <- A() # type <- class M(type) <- class B(metaclass=M) # 3 - type <- class M(type) <- class B(metaclass=M) <- B() for i in range(4): if typeop['ob_type'] == typeop: return PyObjectPtr.from_pyobject_ptr(pyop) typeop = typeop['ob_type'].cast(_type_pyop) return 0 # gdb.write('PYOP {}\n'.format(pyop)) ob_refcnt = pyop['ob_refcnt'] if ob_refcnt >= 0 and ob_refcnt < 0xffff: # gdb.write('refcnt ok {}\n'.format(int(ob_refcnt))) obtype = pyop['ob_type'] if looks_like_ptr(obtype): # gdb.write('obtype ok {}\n'.format(obtype)) type_refcnt = obtype.cast(_type_pyop)['ob_refcnt'] if type_refcnt > 0 and type_refcnt < 0xffff: # gdb.write('type refcnt ok\n') # type_ob_size = obtype.cast(_type_pyvarop)['ob_size'] # if type_ob_size > 0xffff: # return 0 # gdb.write('ob size ok\n') for fieldname in ('tp_base', 'tp_free', 'tp_repr', 'tp_new'): if not looks_like_ptr(obtype[fieldname]): return 0 # gdb.write('methods ok\n') # Then this looks like a Python object: return PyObjectPtr.from_pyobject_ptr(pyop) except UnicodeDecodeError as e: # print('is_pyobject_ptr 0x{:x}'.format(addr)) # gdb.write(str(e) + '\n') pass except RuntimeError: pass # Not a python object (or corrupt)