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:
hjk
2013-07-03 13:32:19 +02:00
parent b05603a44d
commit a036f7f1e4
4 changed files with 111 additions and 68 deletions

View File

@@ -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)

View File

@@ -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:

View File

@@ -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")

View File

@@ -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")