forked from qt-creator/qt-creator
Debugger: Enable QObject property display with LLDB
Finally. Change-Id: I3257ffbb23ca2ea4eec9a97335a95580c9c4482b Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -347,7 +347,7 @@ class DumperBase:
|
|||||||
return base64.b16encode(s).decode("utf8")
|
return base64.b16encode(s).decode("utf8")
|
||||||
|
|
||||||
#def toBlob(self, value):
|
#def toBlob(self, value):
|
||||||
# return self.extractBlob(value.address, value.type.sizeof)
|
# """Abstract"""
|
||||||
|
|
||||||
def isArmArchitecture(self):
|
def isArmArchitecture(self):
|
||||||
return False
|
return False
|
||||||
@@ -897,7 +897,8 @@ class DumperBase:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
except:
|
except:
|
||||||
self.knownNonQObjectTypes.insert(str(value.type))
|
#warn("NO QOBJECT: %s" % value.type)
|
||||||
|
#self.knownNonQObjectTypes.add(str(value.type))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -921,10 +922,7 @@ class DumperBase:
|
|||||||
|
|
||||||
|
|
||||||
# This is called is when a QObject derived class is expanded
|
# This is called is when a QObject derived class is expanded
|
||||||
def putQObjectGuts(self, qobject):
|
def putQObjectGuts(self, qobject, smo):
|
||||||
smo = self.childWithName(qobject, "staticMetaObject")
|
|
||||||
if smo is None:
|
|
||||||
return
|
|
||||||
with SubItem(self, "[properties]"):
|
with SubItem(self, "[properties]"):
|
||||||
propertyNames = self.staticQObjectPropertyNames(smo)
|
propertyNames = self.staticQObjectPropertyNames(smo)
|
||||||
propertyCount = len(propertyNames)
|
propertyCount = len(propertyNames)
|
||||||
|
|||||||
@@ -1418,7 +1418,8 @@ class Dumper(DumperBase):
|
|||||||
with Children(self, 1, childType=innerType):
|
with Children(self, 1, childType=innerType):
|
||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
if isQObject:
|
if isQObject:
|
||||||
self.putQObjectGuts(value)
|
smo = value["staticMetaObject"]
|
||||||
|
self.putQObjectGuts(value, smo)
|
||||||
|
|
||||||
|
|
||||||
def putPlainChildren(self, value):
|
def putPlainChildren(self, value):
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ import lldb
|
|||||||
|
|
||||||
qqWatchpointOffset = 10000
|
qqWatchpointOffset = 10000
|
||||||
|
|
||||||
|
lldb.theDumper = None
|
||||||
|
|
||||||
def warn(message):
|
def warn(message):
|
||||||
print('\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'"))
|
print('\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'"))
|
||||||
@@ -182,16 +183,7 @@ def impl_SBValue__getitem__(value, index):
|
|||||||
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
|
address = address & 0xFFFFFFFFFFFFFFFF # Force unsigned
|
||||||
return value.CreateValueFromAddress(None, address, innertype)
|
return value.CreateValueFromAddress(None, address, innertype)
|
||||||
return value.GetChildAtIndex(index)
|
return value.GetChildAtIndex(index)
|
||||||
result = value.GetChildMemberWithName(index)
|
return value.GetChildMemberWithName(index)
|
||||||
if int(result.GetLoadAddress()) == 0xffffffffffffffff:
|
|
||||||
options = lldb.SBExpressionOptions()
|
|
||||||
typeClass = result.GetType().GetTypeClass()
|
|
||||||
if typeClass != lldb.eTypeClassBuiltin:
|
|
||||||
i = value.GetIndexOfChildWithName(index)
|
|
||||||
field = value.GetType().GetFieldAtIndex(i)
|
|
||||||
addr = value.GetLoadAddress() + field.GetOffsetInBytes()
|
|
||||||
result = value.CreateValueFromAddress(result.GetName(), addr, result.GetType())
|
|
||||||
return result
|
|
||||||
|
|
||||||
def impl_SBValue__deref(value):
|
def impl_SBValue__deref(value):
|
||||||
result = value.Dereference()
|
result = value.Dereference()
|
||||||
@@ -263,6 +255,8 @@ class Dumper(DumperBase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
DumperBase.__init__(self)
|
DumperBase.__init__(self)
|
||||||
|
|
||||||
|
lldb.theDumper = self
|
||||||
|
|
||||||
self.debugger = lldb.SBDebugger.Create()
|
self.debugger = lldb.SBDebugger.Create()
|
||||||
#self.debugger.SetLoggingCallback(loggingCallback)
|
#self.debugger.SetLoggingCallback(loggingCallback)
|
||||||
#Same as: self.debugger.HandleCommand("log enable lldb dyld step")
|
#Same as: self.debugger.HandleCommand("log enable lldb dyld step")
|
||||||
@@ -408,7 +402,7 @@ class Dumper(DumperBase):
|
|||||||
type = value.type.name
|
type = value.type.name
|
||||||
exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
|
||||||
#warn("CALL: %s" % exp)
|
#warn("CALL: %s" % exp)
|
||||||
result = value.CreateValueFromExpression('$tmp', exp)
|
result = value.CreateValueFromExpression('', exp)
|
||||||
#warn(" -> %s" % result)
|
#warn(" -> %s" % result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -857,6 +851,9 @@ class Dumper(DumperBase):
|
|||||||
error = lldb.SBError()
|
error = lldb.SBError()
|
||||||
return Blob(self.process.ReadMemory(base, size, error))
|
return Blob(self.process.ReadMemory(base, size, error))
|
||||||
|
|
||||||
|
def readCArray(self, base, size):
|
||||||
|
return self.extractBlob(base, size).toBytes()
|
||||||
|
|
||||||
def toBlob(self, value):
|
def toBlob(self, value):
|
||||||
data = value.GetData()
|
data = value.GetData()
|
||||||
size = int(data.GetByteSize())
|
size = int(data.GetByteSize())
|
||||||
@@ -868,15 +865,9 @@ class Dumper(DumperBase):
|
|||||||
return Blob(bytes(buf))
|
return Blob(bytes(buf))
|
||||||
|
|
||||||
def isQObject(self, value):
|
def isQObject(self, value):
|
||||||
try:
|
needle = value.GetType().GetName() + "::staticMetaObject"
|
||||||
vtable = value.Cast(self.voidPtrType().GetPointerType())
|
value = self.target.FindFirstGlobalVariable(needle)
|
||||||
metaObjectEntry = vtable.Dereference()
|
return value.IsValid()
|
||||||
addr = lldb.SBAddress(long(metaObjectEntry), self.target)
|
|
||||||
symbol = addr.GetSymbol()
|
|
||||||
name = symbol.GetMangledName()
|
|
||||||
return name.find("10metaObjectEv") > 0
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def stripNamespaceFromType(self, typeName):
|
def stripNamespaceFromType(self, typeName):
|
||||||
#type = stripClassTag(typeName)
|
#type = stripClassTag(typeName)
|
||||||
@@ -898,7 +889,7 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
def putSubItem(self, component, value, tryDynamic=True):
|
def putSubItem(self, component, value, tryDynamic=True):
|
||||||
if not value.IsValid():
|
if not value.IsValid():
|
||||||
warn("INVALID SUBITEM")
|
warn("INVALID SUBITEM: %s" % value.GetName())
|
||||||
return
|
return
|
||||||
with SubItem(self, component):
|
with SubItem(self, component):
|
||||||
self.putItem(value, tryDynamic)
|
self.putItem(value, tryDynamic)
|
||||||
@@ -1004,8 +995,10 @@ class Dumper(DumperBase):
|
|||||||
#numchild = 1 if value.MightHaveChildren() else 0
|
#numchild = 1 if value.MightHaveChildren() else 0
|
||||||
numchild = value.GetNumChildren()
|
numchild = value.GetNumChildren()
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
|
isQObject = False
|
||||||
if typeClass == lldb.eTypeClassStruct or typeClass == lldb.eTypeClassClass:
|
if typeClass == lldb.eTypeClassStruct or typeClass == lldb.eTypeClassClass:
|
||||||
if self.isQObject(value):
|
if self.isQObject(value):
|
||||||
|
isQObject = True
|
||||||
self.context = value
|
self.context = value
|
||||||
if not self.putQObjectNameValue(value): # Is this too expensive?
|
if not self.putQObjectNameValue(value): # Is this too expensive?
|
||||||
self.putEmptyValue()
|
self.putEmptyValue()
|
||||||
@@ -1023,6 +1016,10 @@ class Dumper(DumperBase):
|
|||||||
if self.currentIName in self.expandedINames:
|
if self.currentIName in self.expandedINames:
|
||||||
with Children(self):
|
with Children(self):
|
||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
|
if isQObject:
|
||||||
|
needle = value.GetType().GetName() + "::staticMetaObject"
|
||||||
|
smo = self.target.FindFirstGlobalVariable(needle)
|
||||||
|
self.putQObjectGuts(value, smo)
|
||||||
|
|
||||||
def warn(self, msg):
|
def warn(self, msg):
|
||||||
self.put('{name="%s",value="",type=""},' % msg)
|
self.put('{name="%s",value="",type=""},' % msg)
|
||||||
|
|||||||
@@ -2228,7 +2228,6 @@ void tst_Dumpers::dumper_data()
|
|||||||
QTest::newRow("QObject2")
|
QTest::newRow("QObject2")
|
||||||
<< Data("#include <QWidget>\n"
|
<< Data("#include <QWidget>\n"
|
||||||
"#include <QApplication>\n"
|
"#include <QApplication>\n"
|
||||||
"namespace Names {\n"
|
|
||||||
"namespace Bar {\n"
|
"namespace Bar {\n"
|
||||||
" struct Ui { Ui() { w = 0; } QWidget *w; };\n"
|
" struct Ui { Ui() { w = 0; } QWidget *w; };\n"
|
||||||
" class TestObject : public QObject\n"
|
" class TestObject : public QObject\n"
|
||||||
@@ -2257,11 +2256,10 @@ void tst_Dumpers::dumper_data()
|
|||||||
" QByteArray m_myProp2;\n"
|
" QByteArray m_myProp2;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"} // namespace Bar\n"
|
"} // namespace Bar\n"
|
||||||
"} // namespace Names\n"
|
|
||||||
"#include <main.moc>\n",
|
"#include <main.moc>\n",
|
||||||
""
|
""
|
||||||
"QApplication app(argc, argv);\n"
|
"QApplication app(argc, argv);\n"
|
||||||
"Names::Bar::TestObject test;\n"
|
"Bar::TestObject test;\n"
|
||||||
"test.setMyProp1(\"Hello\");\n"
|
"test.setMyProp1(\"Hello\");\n"
|
||||||
"test.setMyProp2(\"World\");\n"
|
"test.setMyProp2(\"World\");\n"
|
||||||
"QString s = test.myProp1();\n"
|
"QString s = test.myProp1();\n"
|
||||||
@@ -2269,7 +2267,7 @@ void tst_Dumpers::dumper_data()
|
|||||||
"unused(&app, &test, &s);\n")
|
"unused(&app, &test, &s);\n")
|
||||||
% GuiProfile()
|
% GuiProfile()
|
||||||
% Check("s", "\"HelloWorld\"", "@QString")
|
% Check("s", "\"HelloWorld\"", "@QString")
|
||||||
% Check("test", "", "Names::Bar::TestObject")
|
% Check("test", "", "Bar::TestObject")
|
||||||
% Check("test.[properties]", "<4 items>", "")
|
% Check("test.[properties]", "<4 items>", "")
|
||||||
% Check("test.[properties].myProp1", "\"Hello\"", "@QVariant (QString)")
|
% Check("test.[properties].myProp1", "\"Hello\"", "@QVariant (QString)")
|
||||||
% Check("test.[properties].myProp2", "\"World\"", "@QVariant (QByteArray)")
|
% Check("test.[properties].myProp2", "\"World\"", "@QVariant (QByteArray)")
|
||||||
|
|||||||
Reference in New Issue
Block a user