summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2016-12-01 09:22:53 +0100
committerChristian Stenger <christian.stenger@qt.io>2016-12-02 11:23:46 +0000
commit2275d683739ac90602d28bde5b8455d075e9cc37 (patch)
treee608e18448fdb57cf328c6250edf07f10492ea03
parenta9b5e518d0408aad0b140c6465dd080a072d8d66 (diff)
downloadqt-creator-2275d683739ac90602d28bde5b8455d075e9cc37.tar.gz
Debugger: Switch on QObject name display by default
... and use the option to govern general QObject guts display. This allows people to completely avoid the performance impact of attempted QObject display and still makes the feature more prominent for our favorite use case. Change-Id: I1e53b6448f646ab7eea9168a3cd24c77769e6328 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
-rw-r--r--share/qtcreator/debugger/dumper.py120
-rw-r--r--share/qtcreator/debugger/gdbbridge.py11
-rw-r--r--share/qtcreator/debugger/lldbbridge.py5
-rw-r--r--src/plugins/debugger/debuggeractions.cpp6
-rw-r--r--tests/auto/debugger/tst_dumpers.cpp8
5 files changed, 62 insertions, 88 deletions
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 1bb9df7437..3f820ddf9a 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -253,6 +253,7 @@ class DumperBase:
self.typesReported = {}
self.typesToReport = {}
self.qtNamespaceToReport = None
+ self.qtCustomEventFunc = 0
self.passExceptions = False
self.isTesting = False
@@ -303,7 +304,7 @@ class DumperBase:
self.forceQtNamespace = int(args.get('forcens', '0'))
self.passExceptions = int(args.get('passexceptions', '0'))
self.isTesting = int(args.get('testing', '0'))
- self.showQObjectNames = int(args.get('qobjectnames', '0'))
+ self.showQObjectNames = int(args.get('qobjectnames', '1'))
self.nativeMixed = int(args.get('nativemixed', '0'))
self.autoDerefPointers = int(args.get('autoderef', '0'))
self.partialVariable = args.get('partialvar', '')
@@ -1373,11 +1374,13 @@ class DumperBase:
def putQObjectNameValue(self, value):
try:
- intSize = 4
- ptrSize = self.ptrSize()
# dd = value['d_ptr']['d'] is just behind the vtable.
(vtable, dd) = self.split('pp', value)
+ if not self.couldBeQObjectVTable(vtable):
+ return False
+ intSize = 4
+ ptrSize = self.ptrSize()
if self.qtVersion() < 0x050000:
# Size of QObjectData: 5 pointer + 2 int
# - vtable
@@ -1428,97 +1431,47 @@ class DumperBase:
except:
# warn('NO QOBJECT: %s' % value.type)
- pass
+ return False
- def canBePointer(self, p):
+ def couldBePointer(self, p):
if self.ptrSize() == 4:
return p > 100000 and (p & 0x3 == 0)
else:
return p > 100000 and (p & 0x7 == 0) and (p < 0x7fffffffffff)
- def canBeVTableEntry(self, p):
+ def couldBeVTableEntry(self, p):
if self.ptrSize() == 4:
return p > 100000 and (p & 0x1 == 0)
else:
return p > 100000 and (p & 0x1 == 0) and (p < 0x7fffffffffff)
- def couldBeQObject(self, objectPtr):
+ def couldBeQObjectPointer(self, objectPtr):
try:
- (vtablePtr, dd) = self.split('pp', objectPtr)
+ vtablePtr, dd = self.split('pp', objectPtr)
except:
self.bump('nostruct-1')
return False
- if not self.canBePointer(vtablePtr):
- self.bump('vtable')
- return False
- if not self.canBePointer(dd):
- self.bump('d_d_ptr')
- return False
-
- try:
- metaObjectFunc, metaCastFunc, metaCallFunc = self.split('ppp', vtablePtr)
- except:
- return False
-
- # The first three entries are in a fairly rigid relationship defined
- # by the Q_OBJECT macro.
- if not self.canBeVTableEntry(metaObjectFunc):
- return False
- if not self.canBeVTableEntry(metaCastFunc):
- return False
- if not self.canBeVTableEntry(metaCallFunc):
- return False
- if metaCastFunc < metaObjectFunc or metaCastFunc > metaObjectFunc + 200:
- # The metaObject implementation is just that:
- # QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject()
- # : &staticMetaObject;
- # That should not exceed 200 bytes. Observed on x86_64 debug 72.
- return False
- if metaCallFunc < metaCastFunc or metaCallFunc > metaCastFunc + 200:
- # if (!_clname) return nullptr;
- # if (!strcmp(_clname, qt_meta_stringdata_Bar__TestObject.stringdata0))
- # return static_cast<void*>(const_cast< TestObject*>(this));
- # return QWidget::qt_metacast(_clname);
- # That should not exceed 200 bytes. Observed on x86_64 debug 80.
- return False
-
try:
- (dvtablePtr, qptr, parentPtr, childrenDPtr, flags) \
- = self.split('ppppI', dd)
+ dvtablePtr, qptr, parentPtr = self.split('ppp', dd)
except:
self.bump('nostruct-2')
return False
- #warn('STRUCT DD: %s 0x%x' % (self.currentIName, qptr))
- if not self.canBePointer(dvtablePtr):
- self.bump('dvtable')
- #warn('DVT: 0x%x' % dvtablePtr)
- return False
# Check d_ptr.d.q_ptr == objectPtr
if qptr != objectPtr:
- #warn('QPTR: 0x%x 0x%x' % (qptr, objectPtr))
self.bump('q_ptr')
return False
- if parentPtr and not self.canBePointer(parentPtr):
- #warn('PAREN')
- self.bump('parent')
- return False
- if not self.canBePointer(childrenDPtr):
- #warn('CHILD')
- self.bump('children')
+
+ return self.couldBeQObjectVTable(vtablePtr)
+
+ def couldBeQObjectVTable(self, vtablePtr):
+ try:
+ customEventFunc = self.extractPointer(vtablePtr + 9 * self.ptrSize())
+ except:
+ self.bump('nostruct-3')
return False
- #if flags >= 0x80: # Only 7 flags are defined
- # warn('FLAGS: 0x%x %s' % (flags, self.currentIName))
- # self.bump('flags')
- # return False
- #warn('OK')
- #if dynMetaObjectPtr and not self.canBePointer(dynMetaObjectPtr):
- # self.bump('dynmo')
- # return False
-
- self.bump('couldBeQObject')
- return True
+ return self.qtCustomEventFunc == customEventFunc
def extractMetaObjectPtr(self, objectPtr, typeobj):
""" objectPtr - address of *potential* instance of QObject derived class
@@ -1528,7 +1481,7 @@ class DumperBase:
self.checkIntType(objectPtr)
def extractMetaObjectPtrFromAddress():
- return 0
+ #return 0
# FIXME: Calling 'works' but seems to impact memory contents(!)
# in relevant places. One symptom is that object name
# contents 'vanishes' as the reported size of the string
@@ -1542,7 +1495,7 @@ class DumperBase:
res = self.parseAndEvaluate(cmd)
#warn('MO RES: %s' % res)
self.bump('successfulMetaObjectCall')
- return toInteger(res)
+ return res.pointer()
except:
self.bump('failedMetaObjectCall')
#warn('COULD NOT EXECUTE: %s' % cmd)
@@ -1594,7 +1547,8 @@ class DumperBase:
# if base is not None and base != someTypeObj: # sanity check
# result = extractStaticMetaObjectPtrFromType(base)
- self.knownStaticMetaObjects[someTypeName] = result
+ if result:
+ self.knownStaticMetaObjects[someTypeName] = result
return result
@@ -1610,7 +1564,7 @@ class DumperBase:
#warn('CACHED RESULT: %s %s 0x%x' % (self.currentIName, typeName, result))
return result
- if not self.couldBeQObject(objectPtr):
+ if not self.couldBeQObjectPointer(objectPtr):
self.bump('cannotBeQObject')
#warn('DOES NOT LOOK LIKE A QOBJECT: %s' % self.currentIName)
return 0
@@ -1690,8 +1644,11 @@ class DumperBase:
self.putNumChild(0)
# This is called is when a QObject derived class is expanded
- def putQObjectGuts(self, qobject, metaObjectPtr):
- self.putQObjectGutsHelper(qobject, qobject.address(), -1, metaObjectPtr, 'QObject')
+ def tryPutQObjectGuts(self, value):
+ metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
+ if metaObjectPtr:
+ self.putQObjectGutsHelper(value, value.address(),
+ -1, metaObjectPtr, 'QObject')
def metaString(self, metaObjectPtr, index, revision):
ptrSize = self.ptrSize()
@@ -2686,23 +2643,16 @@ class DumperBase:
self.putNumChild(1)
self.putEmptyValue()
#warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
- metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
if self.showQObjectNames:
self.preping(self.currentIName)
- metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
- self.ping(self.currentIName)
- if metaObjectPtr:
- self.context = value
self.putQObjectNameValue(value)
- #warn('STRUCT GUTS: %s MO: 0x%x ' % (self.currentIName, metaObjectPtr))
+ self.ping(self.currentIName)
if self.isExpanded():
self.putField('sortable', 1)
with Children(self, 1, childType=None):
self.putFields(value)
- if not self.showQObjectNames:
- metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type)
- if metaObjectPtr:
- self.putQObjectGuts(value, metaObjectPtr)
+ if self.showQObjectNames:
+ self.tryPutQObjectGuts(value)
def symbolAddress(self, symbolName):
res = self.parseAndEvaluate('(size_t)&' + symbolName)
@@ -3282,7 +3232,7 @@ class DumperBase:
except:
return None
#warn('VTBL: 0x%x' % vtbl)
- if not self.dumper.canBePointer(vtbl):
+ if not self.dumper.couldBePointer(vtbl):
return None
return self.dumper.nativeDynamicTypeName(address, self)
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index f78b5fc6f4..a84293d35c 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -1039,6 +1039,17 @@ class Dumper(DumperBase):
except:
pass
+ try:
+ lenns = len(ns)
+ if lenns:
+ sym = '_ZN%d%s7QObject11customEventEPNS_6QEventE' % \
+ (lenns - 2, ns[:lenns - 2])
+ else:
+ sym = '_ZN7QObject11customEventEP6QEvent'
+ self.qtCustomEventFunc = toInteger(gdb.parse_and_eval('(size_t)&%s' % sym))
+ except:
+ pass
+
# This might be wrong, but we can't do better: We found
# a libQt5Core and could not extract a namespace.
# The best guess is that there isn't any.
diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py
index b54a34b4f4..9ac37beeb6 100644
--- a/share/qtcreator/debugger/lldbbridge.py
+++ b/share/qtcreator/debugger/lldbbridge.py
@@ -679,6 +679,11 @@ class Dumper(DumperBase):
qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
self.qtVersion = lambda: qtVersion
+ funcs = self.target.FindFunctions('QObject::customEvent')
+ if len(funcs):
+ symbol = funcs[0].GetSymbol()
+ self.qtCustomEventFunc = symbol.GetStartAddress().GetLoadAddress(self.target)
+
return (qtNamespace, qtVersion)
return ('', 0x50200)
diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
index 5c225aed95..4e4b28bd61 100644
--- a/src/plugins/debugger/debuggeractions.cpp
+++ b/src/plugins/debugger/debuggeractions.cpp
@@ -257,15 +257,15 @@ DebuggerSettings::DebuggerSettings()
insertItem(ShowQtNamespace, item);
item = new SavedAction(this);
- item->setSettingsKey(debugModeGroup, QLatin1String("ShowQObjectNames"));
+ item->setSettingsKey(debugModeGroup, QLatin1String("ShowQObjectNames2"));
item->setText(tr("Show QObject names if available"));
item->setDialogText(tr("Show QObject names if available"));
item->setToolTip(tr("<p>Displays the objectName property of QObject based items. "
"Note that this can negatively impact debugger performance "
"even if no QObjects are present."));
item->setCheckable(true);
- item->setDefaultValue(false);
- item->setValue(false);
+ item->setDefaultValue(true);
+ item->setValue(true);
insertItem(ShowQObjectNames, item);
item = new SavedAction(this);
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index 0d1126a17f..48e10ce52d 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -3398,6 +3398,14 @@ void tst_Dumpers::dumper_data()
"{\n"
" void run()\n"
" {\n"
+ " auto mo = &QThread::metaObject;\n"
+ " auto mc = &QThread::qt_metacast;\n"
+ " auto p0 = (*(void***)this)[0]; unused(&p0);\n"
+ " auto p1 = (*(void***)this)[1]; unused(&p1);\n"
+ " auto p2 = (*(void***)this)[2]; unused(&p2);\n"
+ " auto p3 = (*(void***)this)[3]; unused(&p3);\n"
+ " auto p4 = (*(void***)this)[4]; unused(&p4);\n"
+ " auto p5 = (*(void***)this)[5]; unused(&p5);\n"
" if (m_id == 3) {\n"
" BREAK;\n"
" }\n"