25 #include "internal/berryCTKPluginActivator.h"
30 #include <Poco/Bugcheck.h>
31 #include <Poco/NumberParser.h>
32 #include <Poco/DOM/NodeList.h>
33 #include <Poco/DOM/DOMParser.h>
34 #include <Poco/DOM/Document.h>
35 #include <Poco/DOM/Element.h>
36 #include <Poco/DOM/DOMWriter.h>
37 #include <Poco/SAX/InputSource.h>
38 #include <Poco/SAX/SAXException.h>
40 #include <Poco/FileStream.h>
51 const QString DebugUtil::DEBUG_UTIL_XML =
"debugutil.xml";
52 const QString DebugUtil::DEBUGUTIL_TAG =
"debugutil";
53 const QString DebugUtil::TRACEOBJECT_TAG =
"traceObject";
54 const QString DebugUtil::TRACECLASS_TAG =
"traceClass";
55 const QString DebugUtil::ID_ATTR =
"id";
56 const QString DebugUtil::NAME_ATTR =
"name";
58 QHash<quint32, QList<unsigned int> > DebugUtil::m_TraceIdToSmartPointerMap;
59 QHash<quint32, const Object*> DebugUtil::m_TraceIdToObjectMap;
60 QSet<unsigned int> DebugUtil::m_TracedObjects;
61 QSet<QString> DebugUtil::m_TracedClasses;
63 class NotClassName:
public std::unary_function<const Object*, bool>
69 NotClassName(
const QString& s) :
73 bool operator()(
const Object* entry)
const
79 class AccumulateClassNames:
public std::binary_function<QSet<QString>*, const Object*, QSet<QString>*>
82 QSet<QString>* operator()(QSet<QString>* names,
const Object* entry)
84 names->insert(entry->GetClassName());
92 return &breakpointManager;
95 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
98 BERRY_INFO <<
"Tracing enabled for: " <<
object->GetTraceId() << std::endl;
99 m_TracedObjects.insert(object->GetTraceId());
108 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
111 BERRY_INFO <<
"Tracing enabled for: " << traceId << std::endl;
112 m_TracedObjects.insert(traceId);
113 TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId);
114 if (i != m_TraceIdToObjectMap.end())
125 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
128 BERRY_INFO <<
"Tracing enabled for: " << className << std::endl;
129 m_TracedClasses.insert(className);
138 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
142 BERRY_INFO <<
"Tracing stopped for: " << traceId << std::endl;
143 m_TracedObjects.remove(traceId);
144 TraceIdToObjectType::ConstIterator i = m_TraceIdToObjectMap.find(traceId);
145 if (i != m_TraceIdToObjectMap.end())
156 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
159 BERRY_INFO <<
"Tracing stopped for: " << obj->GetTraceId() << std::endl;
160 m_TracedObjects.remove(obj->GetTraceId());
169 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
172 BERRY_INFO <<
"Tracing stopped for: " << className << std::endl;
173 m_TracedClasses.remove(className);
182 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
185 if (m_TracedObjects.find(object->GetTraceId()) != m_TracedObjects.end())
188 if (m_TracedClasses.find(object->
GetClassName()) != m_TracedClasses.end())
200 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
203 if (m_TracedObjects.find(traceId) != m_TracedObjects.end())
206 TraceIdToObjectType::Iterator it = m_TraceIdToObjectMap.find(traceId);
207 if (it != m_TraceIdToObjectMap.end())
209 if (m_TracedClasses.find(it.value()->GetClassName()) != m_TracedClasses.end())
222 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
225 return m_TracedClasses.find(className) != m_TracedClasses.end();
236 return m_TracedObjects;
241 return m_TraceIdToObjectMap[traceId];
244 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
246 const Object* objectPointer,
const QList<unsigned int>& excludeList)
248 Q_ASSERT(objectPointer != 0);
249 QList<unsigned int> ids = m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()];
250 for (QList<unsigned int>::const_iterator iter = excludeList.begin();
251 iter != excludeList.end(); ++iter)
252 ids.removeAll(*iter);
257 const Object* ,
const QList<unsigned int>& )
259 return QList<unsigned int>();
265 return m_TraceIdToObjectMap.values();
270 qDebug() <<
"SmartPointer IDs [ ";
274 for (QList<unsigned int>::const_iterator iter = ids.begin();
275 iter != ids.end(); ++iter)
277 qDebug() << *iter <<
" ";
299 m_TraceIdToObjectMap.clear();
300 m_TraceIdToSmartPointerMap.clear();
301 m_TracedObjects.clear();
307 std::accumulate(m_TraceIdToObjectMap.begin(), m_TraceIdToObjectMap.end(), &names, AccumulateClassNames());
309 if (!names.isEmpty())
311 std::cout << std::endl << std::endl <<
"#########################################################" << std::endl;
312 std::cout <<
"######## berry::Object leakage summary: ########" << std::endl << std::endl;
314 for (QSet<QString>::const_iterator i = names.begin();
315 i != names.end(); ++i)
318 if (details) std::cout << std::endl;
321 std::cout << std::endl <<
"#########################################################" << std::endl << std::endl;
324 return !names.isEmpty();
329 TraceIdToObjectType::ConstIterator endIter =
330 std::remove_if(m_TraceIdToObjectMap.begin(), m_TraceIdToObjectMap.end(), NotClassName(className));
332 qDebug() <<
"Class:" << className;
333 if (details) std::cout << std::endl;
335 std::size_t count = 0;
336 for (TraceIdToObjectType::ConstIterator iter = m_TraceIdToObjectMap.begin();
337 iter != endIter; ++iter, ++count)
341 qDebug() << (*(iter.value()));
345 qDebug() <<
"(" << count <<
" instances)\n";
351 static unsigned int counter = 0;
355 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
358 poco_assert(objectPointer != 0);
360 m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].removeAll(smartPointerId);
369 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
372 poco_assert(objectPointer != 0);
374 if (m_TracedClasses.find(objectPointer->
GetClassName()) != m_TracedClasses.end() ||
375 m_TracedObjects.find(objectPointer->GetTraceId()) != m_TracedObjects.end())
377 m_TraceIdToSmartPointerMap[objectPointer->GetTraceId()].push_back(smartPointerId);
382 poco_debugger_msg(
"SmartPointer Breakpoint reached");
390 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
393 m_TraceIdToObjectMap.insert(objectPointer->GetTraceId(), objectPointer);
398 std::string msg =
"SmartPointer Breakpoint reached for ";
400 poco_debugger_msg(msg.c_str());
409 #ifdef BLUEBERRY_DEBUG_SMARTPOINTER
412 m_TraceIdToObjectMap.remove(objectPointer->GetTraceId());
421 bool DebugUtil::GetPersistencePath(QDir& path)
423 QFileInfo statePath = CTKPluginActivator::getPluginContext()->getDataFile(QString());
424 path = statePath.absoluteFilePath();
430 QString saveFile = path.absoluteFilePath(DEBUG_UTIL_XML);
432 auto doc =
new Poco::XML::Document();
433 Poco::XML::Element* debugutil = doc->createElement(DEBUGUTIL_TAG.toStdString());
434 doc->appendChild(debugutil)->release();
436 for (QSet<unsigned int>::const_iterator i = m_TracedObjects.begin();
437 i != m_TracedObjects.end(); ++i)
439 Poco::XML::Element* traceObject = doc->createElement(TRACEOBJECT_TAG.toStdString());
440 debugutil->appendChild(traceObject)->release();
441 traceObject->setAttribute(ID_ATTR.toStdString(), QString::number(*i).toStdString());
444 for (QSet<QString>::const_iterator i = m_TracedClasses.begin();
445 i != m_TracedClasses.end(); ++i)
447 Poco::XML::Element* traceClass = doc->createElement(TRACECLASS_TAG.toStdString());
448 debugutil->appendChild(traceClass)->release();
449 traceClass->setAttribute(NAME_ATTR.toStdString(), i->toStdString());
454 Poco::FileOutputStream writer(saveFile.toStdString());
455 Poco::XML::DOMWriter out;
457 out.writeNode(writer, doc);
465 catch (Poco::FileException& e)
474 QString restoreFile = path.absoluteFilePath(DEBUG_UTIL_XML);
478 Poco::XML::DOMParser parser;
480 Poco::FileInputStream reader(restoreFile.toStdString());
481 Poco::XML::InputSource source(reader);
484 Poco::XML::Document* doc = parser.parse(&source);
485 Poco::XML::Element* debugutil = doc->documentElement();
490 Poco::XML::NodeList* elementList = debugutil->getElementsByTagName(TRACEOBJECT_TAG.toStdString());
491 for (std::size_t i = 0; i < elementList->length(); i++)
493 Poco::XML::Element* elem =
494 dynamic_cast<Poco::XML::Element*
> (elementList->item(static_cast<unsigned long>(i)));
496 if (!elem->hasAttribute(ID_ATTR.toStdString()))
continue;
498 const std::string& attr = elem->getAttribute(ID_ATTR.toStdString());
503 traceId = Poco::NumberParser::parse(attr);
505 catch (
const Poco::SyntaxException& e)
512 elementList->release();
515 elementList = debugutil->getElementsByTagName(TRACECLASS_TAG.toStdString());
516 for (std::size_t i = 0; i < elementList->length(); i++)
518 Poco::XML::Element* elem =
519 dynamic_cast<Poco::XML::Element*
> (elementList->item(static_cast<unsigned long>(i)));
521 if (!elem->hasAttribute(NAME_ATTR.toStdString()))
continue;
523 const std::string& traceClass = elem->getAttribute(NAME_ATTR.toStdString());
524 if (!traceClass.empty())
527 elementList->release();
532 catch (Poco::XML::SAXParseException& e)
536 catch (Poco::FileNotFoundException&)
540 catch (Poco::FileException& e)
static void RemoveObjectListener(IDebugObjectListener *listener)
static void UnregisterSmartPointer(unsigned int smartPointerId, const Object *objectPointer)
SmartPointerEventType spDestroyedEvent
Light weight base class for most BlueBerry classes.
void AddListener(IDebugObjectListener *listener)
static const Object * GetObject(unsigned int traceId)
static void TraceClass(const QString &className)
static QList< unsigned int > GetSmartPointerIDs(const Object *objectPointer, const QList< unsigned int > &excludeList=QList< unsigned int >())
static unsigned int & GetSmartPointerCounter()
static void RestoreState(const QDir &path)
static void ResetObjectSummary()
static IDebugObjectListener::Events _G_ObjectEvents
virtual QString GetClassName() const
static const std::string BREAKPOINTS_XML
TracingEventType objTracingEvent
static void RegisterSmartPointer(unsigned int smartPointerId, const Object *objectPointer, bool recordStack=false)
static QSet< unsigned int > GetTracedObjects()
static bool IsTraced(const Object *object)
static void RegisterObject(const Object *objectPointer)
ObjectEventType objCreatedEvent
void SaveState(const QString &path) const
static bool PrintObjectSummary(bool details=false)
ObjectEventType objDestroyedEvent
static DebugBreakpointManager * GetBreakpointManager()
static void PrintSmartPointerIDs(const Object *objectPointer, const QList< unsigned int > &excludeList=QList< unsigned int >())
static QList< const Object * > GetRegisteredObjects()
static void AddObjectListener(IDebugObjectListener *listener)
static void SaveState(const QDir &path)
void RemoveListener(IDebugObjectListener *listener)
SmartPointerEventType spCreatedEvent
static void StopTracing(unsigned int traceId)
static void TraceObject(const Object *)
void RestoreState(const QString &path)
static void UnregisterObject(const Object *objectPointer)