#include #include "object.h" #if OBJECT_DEBUG #include #include #include #include #include #include #include #include using namespace std; string demangle(const char *name) { if (!name) return ""; int status; char *demangled = abi::__cxa_demangle(name,NULL,NULL,&status); if (demangled && status==0) { string res = demangled; free(demangled); return res; } return name; } string getFunctionName(void * address) { char buf[1024]; Dl_info info; if (dladdr(address, &info)) { snprintf(buf, 1024, "%s+0x%xd: %p", demangle(info.dli_sname).c_str(), (char*)address - (char*)info.dli_saddr, address); } else { snprintf(buf, 1024, ": %p", address); } return buf; } struct Context { void **ctx; int size; Context() { size = 0; } Context(void **buf, int n) { ctx = new void*[n]; for(int i=0; i0) delete [] ctx; } bool operator<(const Context & other) const { int n = std::min(size, other.size); for(int i=0; i other.ctx[i]) return false; } return size < other.size; } void operator=(const Context & other) { if (size > 0) delete[] ctx; size = other.size; ctx = new void*[size]; for(int i=0; i ObjectSet; typedef map SingleContextMap; typedef map > ContextMap; typedef map, int> CounterMap; ObjectSet *_objects=0; inline ObjectSet & objects() { return *(_objects?_objects:(_objects=new ObjectSet)); } SingleContextMap *_construct_contexts=0; inline SingleContextMap & construct_contexts() { return *(_construct_contexts?_construct_contexts:(_construct_contexts=new SingleContextMap)); } ContextMap *_context_map=0; inline ContextMap & context_map() { return *(_context_map?_context_map:(_context_map=new ContextMap)); } CounterMap *_counter_map=0; inline CounterMap & counter_map() { return *(_counter_map?_counter_map:(_counter_map=new CounterMap)); } Object::Object() : refs(0) { objects().insert(this); construct_contexts()[this] = get_context(); } Object::~Object() { objects().erase(this); fprintf(stderr, "Num objects: %d\n", objects().size()); } void Object::ref() { refs++; Context ctx = get_context(2); context_map()[this].insert(ctx); counter_map()[make_pair(this,ctx)]++; }; void Object::unref() { refs--; Context ctx = get_context(2); context_map()[this].insert(ctx); counter_map()[make_pair(this,ctx)]--; if (refs == 0) { printf("%s commits suicide.\n", demangle(typeid(*this).name()).c_str()); delete this; printf("dead.\n"); } }; void Object::addReference(const Context * ctx) { references.insert(ctx); } void Object::removeReference(const Context * ctx) { References::iterator i = references.find(ctx); if ( i != references.end() ) { references.erase(i); } else { printf("Warning: addReference/removeReference mismatch!\n"); } } void object_debuginfo_at_exit () __attribute__ ((destructor)); void object_debuginfo_at_exit () { Object::debug(); printf("Done writing debug info stats\n"); } #endif void Object::debug() { #if OBJECT_DEBUG typedef ObjectSet::iterator Iter; typedef set::iterator CtxIter; typedef Object::References::iterator RefsIter; int count=0; fprintf(stdout, "Printing debug info for %d objects.\n", objects().size()); fprintf(stderr, "Printing debug info for %d objects.\n", objects().size()); for(Iter i=objects().begin(); i!=objects().end(); ++i) { Object *o = *i; Context c = construct_contexts()[o]; fprintf(stderr, "%d: %s at %p with %d refs created in:\n", count, demangle(typeid(*o).name()).c_str(), o, o->getRefs()); c.dump(); fprintf(stderr, "-- With references:\n"); int rcount = 1; for (RefsIter i = o->references.begin(); i!=o->references.end(); ++i) { fprintf(stderr, " * ref %d created in:\n", rcount++); (*i)->dump(4); } set contexts = context_map()[o]; for(CtxIter j = contexts.begin(); j!= contexts.end(); ++j) { Context ctx = *j; int ccount = counter_map()[make_pair(o,ctx)]; fprintf(stderr, "-- Count %d for context:\n", ccount); ctx.dump(4); } count++; } #else fprintf(stderr, "Object Debugging not enabled.\n"); #endif } void Object::debug(Object *o) { #if OBJECT_DEBUG typedef set::iterator CtxIter; Context c = construct_contexts()[o]; fprintf(stderr, "%s at %p with %d refs created in:\n", demangle(typeid(*o).name()).c_str(), o, o->getRefs()); c.dump(); set contexts = context_map()[o]; for(CtxIter j = contexts.begin(); j!= contexts.end(); ++j) { Context ctx = *j; int ccount = counter_map()[make_pair(o,ctx)]; fprintf(stderr, "-- Count %d for context:\n", ccount); ctx.dump(4); } #else fprintf(stderr, "Object Debugging not enabled.\n"); #endif } void Object::backtrace() { #if OBJECT_DEBUG doBacktrace(); #else printf("Object Debugging not enabled.\n"); #endif } #if OBJECT_DEBUG DebugPtr::DebugPtr() { ctx = new Context(get_context()); } DebugPtr::~DebugPtr() { delete ctx; } #endif