forked from qt-creator/qt-creator
Debugger: Fix more LLDB dumpers
Simple QVariants, references, const pointers, QObject names, QList<Foo*>, ... Change-Id: Iaa3fb9e4db1c249817e59239029db7dd220ba5b3 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -1777,6 +1777,12 @@ class Dumper:
|
|||||||
self.put('",')
|
self.put('",')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def isReferenceType(self, typeobj):
|
||||||
|
return typeobj.code == gdb.TYPE_CODE_REF
|
||||||
|
|
||||||
|
def isStructType(self, typeobj):
|
||||||
|
return typeobj.code == gdb.TYPE_CODE_STRUCT
|
||||||
|
|
||||||
def putPlotData(self, type, base, n, plotFormat):
|
def putPlotData(self, type, base, n, plotFormat):
|
||||||
if self.isExpanded():
|
if self.isExpanded():
|
||||||
self.putArrayData(type, base, n)
|
self.putArrayData(type, base, n)
|
||||||
|
|||||||
@@ -73,9 +73,6 @@ DisplayLatin1String, \
|
|||||||
DisplayUtf8String \
|
DisplayUtf8String \
|
||||||
= range(7)
|
= range(7)
|
||||||
|
|
||||||
def lookupType(name):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def isSimpleType(typeobj):
|
def isSimpleType(typeobj):
|
||||||
typeClass = typeobj.GetTypeClass()
|
typeClass = typeobj.GetTypeClass()
|
||||||
#warn("TYPECLASS: %s" % typeClass)
|
#warn("TYPECLASS: %s" % typeClass)
|
||||||
@@ -179,36 +176,7 @@ def fileName(file):
|
|||||||
return str(file) if file.IsValid() else ''
|
return str(file) if file.IsValid() else ''
|
||||||
|
|
||||||
|
|
||||||
PointerCode = None
|
|
||||||
ArrayCode = None
|
|
||||||
StructCode = None
|
|
||||||
UnionCode = None
|
|
||||||
EnumCode = None
|
|
||||||
FlagsCode = None
|
|
||||||
FunctionCode = None
|
|
||||||
IntCode = None
|
|
||||||
FloatCode = None
|
|
||||||
VoidCode = None
|
|
||||||
SetCode = None
|
|
||||||
RangeCode = None
|
|
||||||
StringCode = None
|
|
||||||
BitStringCode = None
|
|
||||||
ErrorTypeCode = None
|
|
||||||
MethodCode = None
|
|
||||||
MethodPointerCode = None
|
|
||||||
MemberPointerCode = None
|
|
||||||
ReferenceCode = None
|
|
||||||
CharCode = None
|
|
||||||
BoolCode = None
|
|
||||||
ComplexCode = None
|
|
||||||
TypedefCode = None
|
|
||||||
NamespaceCode = None
|
|
||||||
SimpleValueCode = None # LLDB only
|
|
||||||
|
|
||||||
|
|
||||||
# Data members
|
# Data members
|
||||||
SimpleValueCode = 100
|
|
||||||
StructCode = 101
|
|
||||||
PointerCode = 102
|
PointerCode = 102
|
||||||
|
|
||||||
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
|
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
|
||||||
@@ -245,7 +213,7 @@ def checkPointer(p, align = 1):
|
|||||||
p.Dereference()
|
p.Dereference()
|
||||||
|
|
||||||
def isNull(p):
|
def isNull(p):
|
||||||
return long(p) == 0
|
return p.GetValueAsUnsigned() == 0
|
||||||
|
|
||||||
Value = lldb.SBValue
|
Value = lldb.SBValue
|
||||||
|
|
||||||
@@ -340,9 +308,6 @@ lldb.SBType.__str__ = lldb.SBType.GetName
|
|||||||
def simpleEncoding(typeobj):
|
def simpleEncoding(typeobj):
|
||||||
code = typeobj.GetTypeClass()
|
code = typeobj.GetTypeClass()
|
||||||
size = typeobj.sizeof
|
size = typeobj.sizeof
|
||||||
#if code == BoolCode or code == CharCode:
|
|
||||||
# return Hex2EncodedInt1
|
|
||||||
#if code == IntCode:
|
|
||||||
if code == lldb.eTypeClassBuiltin:
|
if code == lldb.eTypeClassBuiltin:
|
||||||
name = str(typeobj)
|
name = str(typeobj)
|
||||||
if name == "float":
|
if name == "float":
|
||||||
@@ -390,7 +355,7 @@ class Children:
|
|||||||
#if isSimpleType(childType):
|
#if isSimpleType(childType):
|
||||||
# self.d.put('childnumchild="0",')
|
# self.d.put('childnumchild="0",')
|
||||||
# self.childNumChild = 0
|
# self.childNumChild = 0
|
||||||
#elif childType.code == PointerCode:
|
#elif childType.code == lldb.eTypeClassPointer:
|
||||||
# self.d.put('childnumchild="1",')
|
# self.d.put('childnumchild="1",')
|
||||||
# self.childNumChild = 1
|
# self.childNumChild = 1
|
||||||
else:
|
else:
|
||||||
@@ -469,6 +434,8 @@ class SubItem:
|
|||||||
self.d.put('{')
|
self.d.put('{')
|
||||||
#if not self.name is None:
|
#if not self.name is None:
|
||||||
if isinstance(self.name, str):
|
if isinstance(self.name, str):
|
||||||
|
if self.name == '**&':
|
||||||
|
self.name = '*'
|
||||||
self.d.put('name="%s",' % self.name)
|
self.d.put('name="%s",' % self.name)
|
||||||
self.savedIName = self.d.currentIName
|
self.savedIName = self.d.currentIName
|
||||||
self.savedCurrentAddress = self.d.currentAddress
|
self.savedCurrentAddress = self.d.currentAddress
|
||||||
@@ -597,7 +564,7 @@ class Dumper:
|
|||||||
|
|
||||||
def templateArgument(self, typeobj, index):
|
def templateArgument(self, typeobj, index):
|
||||||
type = typeobj.GetTemplateArgumentType(index)
|
type = typeobj.GetTemplateArgumentType(index)
|
||||||
if len(type.GetName()):
|
if type.IsValid():
|
||||||
return type
|
return type
|
||||||
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
||||||
return self.lookupType(inner)
|
return self.lookupType(inner)
|
||||||
@@ -606,6 +573,12 @@ class Dumper:
|
|||||||
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
inner = self.extractTemplateArgument(typeobj.GetName(), index)
|
||||||
return int(inner)
|
return int(inner)
|
||||||
|
|
||||||
|
def isReferenceType(self, typeobj):
|
||||||
|
return typeobj.IsReferenceType()
|
||||||
|
|
||||||
|
def isStructType(self, typeobj):
|
||||||
|
return typeobj.GetTypeClass() in (lldb.eTypeClassStruct, lldb.eTypeClassClass)
|
||||||
|
|
||||||
def qtVersion(self):
|
def qtVersion(self):
|
||||||
return 0x050000
|
return 0x050000
|
||||||
|
|
||||||
@@ -678,10 +651,11 @@ class Dumper:
|
|||||||
return format
|
return format
|
||||||
|
|
||||||
def isMovableType(self, type):
|
def isMovableType(self, type):
|
||||||
if type.code == PointerCode:
|
if type.GetTypeClass() in (lldb.eTypeClassBuiltin,
|
||||||
return True
|
lldb.eTypeClassPointer):
|
||||||
if isSimpleType(type):
|
|
||||||
return True
|
return True
|
||||||
|
warn("MOVABLE: %s" % type)
|
||||||
|
warn("CODE: %s" % type.GetTypeClass())
|
||||||
return self.stripNamespaceFromType(type.GetName()) in movableTypes
|
return self.stripNamespaceFromType(type.GetName()) in movableTypes
|
||||||
|
|
||||||
def putIntItem(self, name, value):
|
def putIntItem(self, name, value):
|
||||||
@@ -745,7 +719,7 @@ class Dumper:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def putPlotData(self, type, base, n, plotFormat):
|
def putPlotData(self, type, base, n, plotFormat):
|
||||||
warn("PLOTDATA: %s %s" % (type, n))
|
#warn("PLOTDATA: %s %s" % (type, n))
|
||||||
if self.isExpanded():
|
if self.isExpanded():
|
||||||
self.putArrayData(type, base, n)
|
self.putArrayData(type, base, n)
|
||||||
self.putValue(self.currentValue)
|
self.putValue(self.currentValue)
|
||||||
@@ -789,9 +763,14 @@ class Dumper:
|
|||||||
self.putFields(value)
|
self.putFields(value)
|
||||||
|
|
||||||
def lookupType(self, name):
|
def lookupType(self, name):
|
||||||
|
if name.endswith('*'):
|
||||||
|
type = self.lookupType(name[:-1].strip())
|
||||||
|
return type.GetPointerType() if type.IsValid() else None
|
||||||
#warn("LOOKUP TYPE NAME: %s" % name)
|
#warn("LOOKUP TYPE NAME: %s" % name)
|
||||||
#warn("LOOKUP RESULT: %s" % self.target.FindFirstType(name))
|
#warn("LOOKUP RESULT: %s" % self.target.FindFirstType(name))
|
||||||
return self.target.FindFirstType(name)
|
#warn("LOOKUP RESULT: %s" % self.target.FindFirstType(name))
|
||||||
|
type = self.target.FindFirstType(name)
|
||||||
|
return type if type.IsValid() else None
|
||||||
|
|
||||||
def setupInferior(self, args):
|
def setupInferior(self, args):
|
||||||
executable = args['executable']
|
executable = args['executable']
|
||||||
@@ -942,6 +921,17 @@ class Dumper:
|
|||||||
contents = self.process.ReadMemory(base, size, error)
|
contents = self.process.ReadMemory(base, size, error)
|
||||||
return binascii.hexlify(contents)
|
return binascii.hexlify(contents)
|
||||||
|
|
||||||
|
def isQObject(self, value):
|
||||||
|
try:
|
||||||
|
vtable = value.Cast(self.voidPtrType().GetPointerType())
|
||||||
|
metaObjectEntry = vtable.Dereference()
|
||||||
|
addr = lldb.SBAddress(long(metaObjectEntry), self.target)
|
||||||
|
symbol = addr.GetSymbol()
|
||||||
|
name = symbol.GetMangledName()
|
||||||
|
return name.find("10metaObjectEv") > 0
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
def computeLimit(self, size, limit):
|
def computeLimit(self, size, limit):
|
||||||
if limit is None:
|
if limit is None:
|
||||||
return size
|
return size
|
||||||
@@ -967,6 +957,10 @@ class Dumper:
|
|||||||
pos1 = type.rfind(">", pos)
|
pos1 = type.rfind(">", pos)
|
||||||
type = type[0:pos] + type[pos1+1:]
|
type = type[0:pos] + type[pos1+1:]
|
||||||
pos = type.find("<")
|
pos = type.find("<")
|
||||||
|
if type.startswith("const "):
|
||||||
|
type = type[6:]
|
||||||
|
if type.startswith("volatile "):
|
||||||
|
type = type[9:]
|
||||||
return type
|
return type
|
||||||
|
|
||||||
def putSubItem(self, component, value, tryDynamic=True):
|
def putSubItem(self, component, value, tryDynamic=True):
|
||||||
@@ -987,6 +981,7 @@ class Dumper:
|
|||||||
#value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
|
#value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
|
||||||
typeName = value.GetTypeName()
|
typeName = value.GetTypeName()
|
||||||
value.SetPreferDynamicValue(tryDynamic)
|
value.SetPreferDynamicValue(tryDynamic)
|
||||||
|
typeClass = value.GetType().GetTypeClass()
|
||||||
|
|
||||||
if tryDynamic:
|
if tryDynamic:
|
||||||
self.putAddress(value.address)
|
self.putAddress(value.address)
|
||||||
@@ -1020,29 +1015,30 @@ class Dumper:
|
|||||||
value.SetPreferSyntheticValue(False)
|
value.SetPreferSyntheticValue(False)
|
||||||
|
|
||||||
# Arrays
|
# Arrays
|
||||||
if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
|
if typeClass == lldb.eTypeClassArray:
|
||||||
qdump____c_style_array__(self, value)
|
qdump____c_style_array__(self, value)
|
||||||
return
|
return
|
||||||
|
|
||||||
# References
|
# References
|
||||||
if value.GetType().IsReferenceType():
|
if value.GetType().IsReferenceType():
|
||||||
origType = value.GetTypeName();
|
origType = value.GetTypeName();
|
||||||
type = value.GetType().GetDereferencedType()
|
type = value.GetType().GetDereferencedType().GetUnqualifiedType()
|
||||||
addr = int(value.GetAddress()) & 0xFFFFFFFFFFFFFFFF
|
addr = int(value) & 0xFFFFFFFFFFFFFFFF
|
||||||
self.putItem(value.CreateValueFromAddress(None, addr, type))
|
self.putItem(value.CreateValueFromAddress(None, addr, type))
|
||||||
|
#self.putItem(value.CreateValueFromData(None, value.GetData(), type))
|
||||||
self.putBetterType(origType)
|
self.putBetterType(origType)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Pointers
|
# Pointers
|
||||||
if value.GetType().IsPointerType() and self.autoDerefPointers:
|
if value.GetType().IsPointerType():
|
||||||
|
|
||||||
if isNull(value):
|
if isNull(value):
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue("0x0")
|
self.putValue("0x0")
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
innerType = value.GetType().GetPointeeType()
|
if self.autoDerefPointers:
|
||||||
|
innerType = value.GetType().GetPointeeType().GetUnqualifiedType()
|
||||||
self.putType(innerType)
|
self.putType(innerType)
|
||||||
savedCurrentChildType = self.currentChildType
|
savedCurrentChildType = self.currentChildType
|
||||||
self.currentChildType = str(innerType)
|
self.currentChildType = str(innerType)
|
||||||
@@ -1053,6 +1049,20 @@ class Dumper:
|
|||||||
self.put('origaddr="%s",' % value.address)
|
self.put('origaddr="%s",' % value.address)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
numchild = value.GetNumChildren()
|
||||||
|
self.put('iname="%s",' % self.currentIName)
|
||||||
|
self.putType(typeName)
|
||||||
|
self.putValue('0x%x' % value.GetValueAsUnsigned())
|
||||||
|
self.put('numchild="1",')
|
||||||
|
self.put('addr="0x%x",' % value.GetLoadAddress())
|
||||||
|
if self.currentIName in self.expandedINames:
|
||||||
|
with Children(self):
|
||||||
|
child = value.Dereference()
|
||||||
|
with SubItem(self, child):
|
||||||
|
self.putItem(child)
|
||||||
|
|
||||||
|
|
||||||
#warn("VALUE: %s" % value)
|
#warn("VALUE: %s" % value)
|
||||||
#warn("FANCY: %s" % self.useFancy)
|
#warn("FANCY: %s" % self.useFancy)
|
||||||
if self.useFancy:
|
if self.useFancy:
|
||||||
@@ -1066,12 +1076,24 @@ class Dumper:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Normal value
|
# Normal value
|
||||||
v = value.GetValue()
|
|
||||||
#numchild = 1 if value.MightHaveChildren() else 0
|
#numchild = 1 if value.MightHaveChildren() else 0
|
||||||
numchild = value.GetNumChildren()
|
numchild = value.GetNumChildren()
|
||||||
self.put('iname="%s",' % self.currentIName)
|
self.put('iname="%s",' % self.currentIName)
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue('' if v is None else v)
|
if typeClass == lldb.eTypeClassStruct or typeClass == lldb.eTypeClassClass:
|
||||||
|
if self.isQObject(value):
|
||||||
|
self.context = value
|
||||||
|
if not self.putQObjectNameValue(value): # Is this too expensive?
|
||||||
|
self.putEmptyValue()
|
||||||
|
else:
|
||||||
|
self.putEmptyValue()
|
||||||
|
else:
|
||||||
|
v = value.GetValue()
|
||||||
|
if v:
|
||||||
|
self.putValue(v)
|
||||||
|
else:
|
||||||
|
self.putEmptyValue()
|
||||||
|
|
||||||
self.put('numchild="%s",' % numchild)
|
self.put('numchild="%s",' % numchild)
|
||||||
self.put('addr="0x%x",' % value.GetLoadAddress())
|
self.put('addr="0x%x",' % value.GetLoadAddress())
|
||||||
if self.currentIName in self.expandedINames:
|
if self.currentIName in self.expandedINames:
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ def qPutQObjectNameValue(d, value):
|
|||||||
# - QDynamicMetaObjectData *metaObject;
|
# - QDynamicMetaObjectData *metaObject;
|
||||||
extra = d.dereference(dd + 5 * ptrSize + 2 * intSize)
|
extra = d.dereference(dd + 5 * ptrSize + 2 * intSize)
|
||||||
if extra == 0:
|
if extra == 0:
|
||||||
return
|
return False
|
||||||
|
|
||||||
# Offset of objectName in ExtraData: 6 pointer
|
# Offset of objectName in ExtraData: 6 pointer
|
||||||
# - QVector<QObjectUserData *> userData; only #ifndef QT_NO_USERDATA
|
# - QVector<QObjectUserData *> userData; only #ifndef QT_NO_USERDATA
|
||||||
@@ -174,9 +174,12 @@ def qPutQObjectNameValue(d, value):
|
|||||||
|
|
||||||
data, size, alloc = qByteArrayData(d, objectName)
|
data, size, alloc = qByteArrayData(d, objectName)
|
||||||
|
|
||||||
if size > 0:
|
if size == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
str = d.readRawMemory(data, 2 * size)
|
str = d.readRawMemory(data, 2 * size)
|
||||||
d.putValue(str, Hex4EncodedLittleEndian, 1)
|
d.putValue(str, Hex4EncodedLittleEndian, 1)
|
||||||
|
return True
|
||||||
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@@ -1973,7 +1976,7 @@ def qdumpHelper__QVariant(d, value):
|
|||||||
sizePD = d.lookupType(d.ns + 'QVariant::Private::Data').sizeof
|
sizePD = d.lookupType(d.ns + 'QVariant::Private::Data').sizeof
|
||||||
if innerType.sizeof > sizePD:
|
if innerType.sizeof > sizePD:
|
||||||
sizePS = d.lookupType(d.ns + 'QVariant::PrivateShared').sizeof
|
sizePS = d.lookupType(d.ns + 'QVariant::PrivateShared').sizeof
|
||||||
val = (sizePS + data.cast(d.charPtrType())) \
|
val = (data.cast(d.charPtrType()) + sizePS) \
|
||||||
.cast(innerType.pointer()).dereference()
|
.cast(innerType.pointer()).dereference()
|
||||||
else:
|
else:
|
||||||
val = data.cast(innerType)
|
val = data.cast(innerType)
|
||||||
@@ -2573,7 +2576,7 @@ def qdump__boost__optional(d, value):
|
|||||||
else:
|
else:
|
||||||
type = d.templateArgument(value.type, 0)
|
type = d.templateArgument(value.type, 0)
|
||||||
storage = value["m_storage"]
|
storage = value["m_storage"]
|
||||||
if type.code == ReferenceCode:
|
if d.isReferenceType(type):
|
||||||
d.putItem(storage.cast(type.target().pointer()).dereference())
|
d.putItem(storage.cast(type.target().pointer()).dereference())
|
||||||
else:
|
else:
|
||||||
d.putItem(storage.cast(type))
|
d.putItem(storage.cast(type))
|
||||||
@@ -2925,7 +2928,7 @@ def qdump__Eigen__Matrix(d, value):
|
|||||||
nrows = value["m_storage"]["m_rows"] if argRow == -1 else int(argRow)
|
nrows = value["m_storage"]["m_rows"] if argRow == -1 else int(argRow)
|
||||||
ncols = value["m_storage"]["m_cols"] if argCol == -1 else int(argCol)
|
ncols = value["m_storage"]["m_cols"] if argCol == -1 else int(argCol)
|
||||||
p = storage["m_data"]
|
p = storage["m_data"]
|
||||||
if p.type.code == StructCode: # Static
|
if d.isStructType(p.type): # Static
|
||||||
p = p["array"].cast(innerType.pointer())
|
p = p["array"].cast(innerType.pointer())
|
||||||
d.putValue("(%s x %s), %s" % (nrows, ncols, ["ColumnMajor", "RowMajor"][rowMajor]))
|
d.putValue("(%s x %s), %s" % (nrows, ncols, ["ColumnMajor", "RowMajor"][rowMajor]))
|
||||||
d.putField("keeporder", "1")
|
d.putField("keeporder", "1")
|
||||||
|
|||||||
@@ -3138,6 +3138,17 @@ void tst_Dumpers::dumper_data()
|
|||||||
% Check("this.@1", "[@QThread]", "\"This is thread #3\"", "@QThread")
|
% Check("this.@1", "[@QThread]", "\"This is thread #3\"", "@QThread")
|
||||||
% Check("this.@1.@1", "[@QObject]", "\"This is thread #3\"", "@QObject");
|
% Check("this.@1.@1", "[@QObject]", "\"This is thread #3\"", "@QObject");
|
||||||
|
|
||||||
|
QTest::newRow("QVariant0")
|
||||||
|
<< Data("#include <QVariant>\n",
|
||||||
|
"QVariant value;\n"
|
||||||
|
"QVariant::Type t = QVariant::String;\n"
|
||||||
|
"value = QVariant(t, (void*)0);\n"
|
||||||
|
"*(QString*)value.data() = QString(\"Some string\");\n")
|
||||||
|
% CoreProfile()
|
||||||
|
% GdbOnly()
|
||||||
|
% Check("t", "@QVariant::String (10)", "@QVariant::Type")
|
||||||
|
% Check("value", "\"Some string\"", "@QVariant (QString)");
|
||||||
|
|
||||||
QTest::newRow("QVariant1")
|
QTest::newRow("QVariant1")
|
||||||
<< Data("#include <QVariant>\n",
|
<< Data("#include <QVariant>\n",
|
||||||
"QVariant value;\n"
|
"QVariant value;\n"
|
||||||
@@ -3145,7 +3156,8 @@ void tst_Dumpers::dumper_data()
|
|||||||
"value = QVariant(t, (void*)0);\n"
|
"value = QVariant(t, (void*)0);\n"
|
||||||
"*(QString*)value.data() = QString(\"Some string\");\n")
|
"*(QString*)value.data() = QString(\"Some string\");\n")
|
||||||
% CoreProfile()
|
% CoreProfile()
|
||||||
% Check("t", "@QVariant::String (10)", "@QVariant::Type")
|
% LldbOnly()
|
||||||
|
% Check("t", "String", "@QVariant::Type")
|
||||||
% Check("value", "\"Some string\"", "@QVariant (QString)");
|
% Check("value", "\"Some string\"", "@QVariant (QString)");
|
||||||
|
|
||||||
QTest::newRow("QVariant2")
|
QTest::newRow("QVariant2")
|
||||||
|
|||||||
Reference in New Issue
Block a user