From c4648e97972df56a90e99aeff446da19c5d0ed75 Mon Sep 17 00:00:00 2001 From: Martin Bohacek Date: Mon, 11 Nov 2013 09:54:54 +0100 Subject: [PATCH] Debugger: Python dumper support for QNX targets on arm/x86. gdbbridge.py + dumper.py: added detection on QNX target and ARM arch added detection of Qt 3 support fixed detection of Qt version qttypes.py: fixes of different memory alignment stdtypes.py: support of different libstdc++ internal structures on QNX Change-Id: I808ee048c66c73c38bf5a8403e9cf881e767442e Reviewed-by: hjk --- share/qtcreator/debugger/dumper.py | 9 ++ share/qtcreator/debugger/gdbbridge.py | 23 ++- share/qtcreator/debugger/qttypes.py | 11 +- share/qtcreator/debugger/stdtypes.py | 200 ++++++++++++++++++++++++++ 4 files changed, 239 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 395add860c..de8f5c9740 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -260,10 +260,19 @@ class DumperBase: self.cachedFormats[typeName] = stripped return stripped + def isArmArchitecture(self): + return False + + def isQnxTarget(self): + return False def is32bit(self): return self.ptrSize() == 4 + def isQt3Support(self): + # assume no Qt 3 support by default + return False + def computeLimit(self, size, limit): if limit is None: return size diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 9d6cc7d363..0a64555b9e 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -990,6 +990,12 @@ class Dumper(DumperBase): return xrange(0, toInteger(self.currentNumChild)) return xrange(min(toInteger(self.currentMaxNumChild), toInteger(self.currentNumChild))) + def isArmArchitecture(self): + return 'arm' in gdb.TARGET_CONFIG.lower() + + def isQnxTarget(self): + return 'qnx' in gdb.TARGET_CONFIG.lower() + def qtVersion(self): try: version = str(gdb.parse_and_eval("qVersion()")) @@ -998,7 +1004,7 @@ class Dumper(DumperBase): except: try: # This will fail on Qt 5 - gdb.execute("ptype QString::shared_empty", to_string=True) + gdb.execute("ptype QString::shared_null", to_string=True) self.cachedQtVersion = 0x040800 except: #self.cachedQtVersion = 0x050000 @@ -1009,6 +1015,21 @@ class Dumper(DumperBase): self.qtVersion = lambda: self.cachedQtVersion return self.cachedQtVersion + def isQt3Support(self): + if self.qtVersion() >= 0x050000: + return False + else: + try: + # This will fail on Qt 4 without Qt 3 support + gdb.execute("ptype QChar::null", to_string=True) + self.cachedIsQt3Suport = True + except: + self.cachedIsQt3Suport = False + + # Memoize good results. + self.isQt3Support = lambda: self.cachedIsQt3Suport + return self.cachedIsQt3Suport + def putType(self, type, priority = 0): # Higher priority values override lower ones. if priority >= self.currentTypePriority: diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 8ee8c2560a..ab937d40ce 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -291,6 +291,7 @@ def qdump__QDir(d, value): privAddress = d.dereferenceValue(value) bit32 = d.is32bit() qt5 = d.qtVersion() >= 0x050000 + qt3support = d.isQt3Support() # QDirPrivate: # QAtomicInt ref # QStringList nameFilters; @@ -306,7 +307,7 @@ def qdump__QDir(d, value): # QFileInfoList fileInfos; # QFileSystemEntry dirEntry; # QFileSystemEntry absoluteDirEntry; - qt3SupportAddition = 0 if qt5 else d.ptrSize() # qt5 doesn't have qt3support + qt3SupportAddition = d.ptrSize() if qt3support else 0 filesOffset = (24 if bit32 else 40) + qt3SupportAddition fileInfosOffset = filesOffset + d.ptrSize() dirEntryOffset = fileInfosOffset + d.ptrSize() @@ -733,6 +734,7 @@ def qdump__QImage(d, value): ptrSize = d.ptrSize() isQt5 = d.qtVersion() >= 0x050000 + qt3Support = d.isQt3Support() offset = (3 if isQt5 else 2) * ptrSize base = d.dereference(d.addressOf(value) + offset) width = d.extractInt(base + 4) @@ -740,7 +742,7 @@ def qdump__QImage(d, value): nbytes = d.extractInt(base + 16) padding = d.ptrSize() - d.intSize() pixelRatioSize = 8 if isQt5 else 0 - jumpTableSize = ptrSize if not isQt5 else 0 # FIXME: Assumes Qt3 Support + jumpTableSize = ptrSize if qt3Support else 0 bits = d.dereference(base + 20 + padding + pixelRatioSize + ptrSize) iformat = d.extractInt(base + 20 + padding + pixelRatioSize + jumpTableSize + 2 * ptrSize) d.putValue("(%dx%d)" % (width, height)) @@ -870,7 +872,10 @@ def qdumpHelper__Qt4_QMap(d, value, forceLong): # Or possibly 2 * sizeof(void *) nodeType = d.lookupType(d.qtNamespace() + "QMapNode<%s,%s>" % (keyType, valueType)) nodePointerType = nodeType.pointer() - payloadSize = nodeType.sizeof - 2 * nodePointerType.sizeof + if d.isArmArchitecture() and d.isQnxTarget() and str(valueType) == 'QVariant': # symbols reports payload size at wrong size 24 + payloadSize = 28 + else: + payloadSize = nodeType.sizeof - 2 * nodePointerType.sizeof if isCompact: innerType = valueType diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index a6270f9142..4e94bf468d 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -90,6 +90,10 @@ def qdump__std__complex(d, value): def qdump__std__deque(d, value): + if d.isQnxTarget(): + qdump__std__deque__QNX(d, value) + return + innerType = d.templateArgument(value.type, 0) innerSize = innerType.sizeof bufsize = 1 @@ -122,11 +126,47 @@ def qdump__std__deque(d, value): plast = pfirst + bufsize pcur = pfirst +def qdump__std__deque__QNX(d, value): + innerType = d.templateArgument(value.type, 0) + innerSize = innerType.sizeof + if innerSize <= 1: + bufsize = 16 + elif innerSize <= 2: + bufsize = 8 + elif innerSize <= 4: + bufsize = 4 + elif innerSize <= 8: + bufsize = 2 + else: + bufsize = 1 + + myoff = value['_Myoff'] + mysize = value['_Mysize'] + mapsize = value['_Mapsize'] + + d.check(0 <= mapsize and mapsize <= 1000 * 1000 * 1000) + d.putItemCount(mysize) + d.putNumChild(mysize) + if d.isExpanded(): + with Children(d, mysize, maxNumChild=2000, childType=innerType): + map = value['_Map'] + for i in d.childRange(): + block = myoff / bufsize + offset = myoff - (block * bufsize) + if mapsize <= block: + block -= mapsize + d.putSubItem(i, map[block][offset]) + myoff += 1; + def qdump__std____debug__deque(d, value): qdump__std__deque(d, value) def qdump__std__list(d, value): + if d.isQnxTarget(): + qdump__std__list__QNX(d, value) + return + head = d.dereferenceValue(value) impl = value["_M_impl"] node = impl["_M_node"] @@ -148,6 +188,21 @@ def qdump__std__list(d, value): d.putSubItem(i, (p + 1).cast(innerPointer).dereference()) p = p["_M_next"] +def qdump__std__list__QNX(d, value): + node = value["_Myhead"] + size = value["_Mysize"] + + d.putItemCount(size, 1000) + d.putNumChild(size) + + if d.isExpanded(): + p = node["_Next"] + innerType = d.templateArgument(value.type, 0) + with Children(d, size, maxNumChild=1000, childType=innerType): + for i in d.childRange(): + d.putSubItem(i, p['_Myval']) + p = p["_Next"] + def qdump__std____debug__list(d, value): qdump__std__list(d, value) @@ -155,6 +210,10 @@ def qform__std__map(): return mapForms() def qdump__std__map(d, value): + if d.isQnxTarget(): + qdump__std__map__QNX(d, value) + return + impl = value["_M_t"]["_M_impl"] size = int(impl["_M_node_count"]) d.check(0 <= size and size <= 100*1000*1000) @@ -210,6 +269,63 @@ def qdump__std__map(d, value): while not d.isNull(node["_M_left"]): node = node["_M_left"] +def qdump__std__map__QNX(d, value): + size = value['_Mysize'] + d.check(0 <= size and size <= 100*1000*1000) + d.putItemCount(size) + d.putNumChild(size) + + if d.isExpanded(): + keyType = d.templateArgument(value.type, 0) + valueType = d.templateArgument(value.type, 1) + try: + # Does not work on gcc 4.4, the allocator type (fourth template + # argument) seems not to be available. + pairType = d.templateArgument(d.templateArgument(value.type, 3), 0) + pairPointer = pairType.pointer() + except: + # So use this as workaround: + pairType = d.templateArgument(impl.type, 1) + pairPointer = pairType.pointer() + isCompact = d.isMapCompact(keyType, valueType) + innerType = pairType + if isCompact: + innerType = valueType + head = value['_Myhead'] + node = head['_Left'] + nodeType = head.type + childType = innerType + if size == 0: + childType = pairType + childNumChild = 2 + if isCompact: + childNumChild = None + with Children(d, size, maxNumChild=1000, + childType=childType, childNumChild=childNumChild): + for i in d.childRange(): + with SubItem(d, i): + pair = node.cast(nodeType).dereference()['_Myval'] + if isCompact: + d.putMapName(pair["first"]) + d.putItem(pair["second"]) + else: + d.putEmptyValue() + if d.isExpanded(): + with Children(d, 2): + d.putSubItem("first", pair["first"]) + d.putSubItem("second", pair["second"]) + if not node['_Right']['_Isnil']: + node = node['_Right'] + while not node['_Left']['_Isnil']: + node = node['_Left'] + else: + parent = node['_Parent'] + while node == parent['_Right']['_Isnil']: + node = parent + parent = parent['_Parent'] + if node['_Right'] != parent: + node = parent + def qdump__std____debug__map(d, value): qdump__std__map(d, value) @@ -271,6 +387,10 @@ def qdump__std____cxx1998__set(d, value): qdump__std__set(d, value) def qdump__std__set(d, value): + if d.isQnxTarget(): + qdump__std__set__QNX(d, value) + return + impl = value["_M_t"]["_M_impl"] size = int(impl["_M_node_count"]) d.check(0 <= size and size <= 100*1000*1000) @@ -294,6 +414,30 @@ def qdump__std__set(d, value): while not d.isNull(node["_M_left"]): node = node["_M_left"] +def qdump__std__set__QNX(d, value): + size = value['_Mysize'] + d.check(0 <= size and size <= 100*1000*1000) + d.putItemCount(size) + d.putNumChild(size) + if d.isExpanded(): + valueType = d.templateArgument(value.type, 0) + head = value['_Myhead'] + node = head['_Left'] + nodeType = head.type + with Children(d, size, maxNumChild=1000, childType=valueType): + for i in d.childRange(): + d.putSubItem(i, node.cast(nodeType).dereference()['_Myval']) + if not node['_Right']['_Isnil']: + node = node['_Right'] + while not node['_Left']['_Isnil']: + node = node['_Left'] + else: + parent = node['_Parent'] + while node == parent['_Right']['_Isnil']: + node = parent + parent = parent['_Parent'] + if node['_Right'] != parent: + node = parent def qdump__std__stack(d, value): qdump__std__deque(d, value["c"]) @@ -308,6 +452,10 @@ def qdump__std__string(d, value): qdump__std__stringHelper1(d, value, 1) def qdump__std__stringHelper1(d, value, charSize): + if d.isQnxTarget(): + qdump__std__stringHelper1__QNX(d, value, charSize) + return + data = value["_M_dataplus"]["_M_p"] # We can't lookup the std::string::_Rep type without crashing LLDB, # so hard-code assumption on member position @@ -320,6 +468,20 @@ def qdump__std__stringHelper1(d, value, charSize): d.check(0 <= size and size <= alloc and alloc <= 100*1000*1000) qdump_stringHelper(d, sizePtr, size * charSize, charSize) +def qdump__std__stringHelper1__QNX(d, value, charSize): + size = value['_Mysize'] + alloc = value['_Myres'] + _BUF_SIZE = 16 / charSize + if _BUF_SIZE <= alloc: #(_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf); + data = value['_Bx']['_Ptr'] + else: + data = value['_Bx']['_Buf'] + sizePtr = data.cast(d.charType().pointer()) + refcount = int(sizePtr[-1]) + d.check(refcount >= -1) # Can be -1 accoring to docs. + d.check(0 <= size and size <= alloc and alloc <= 100*1000*1000) + qdump_stringHelper(d, sizePtr, size * charSize, charSize) + def qdump_stringHelper(d, data, size, charSize): cutoff = min(size, d.stringCutOff) mem = d.readMemory(data, cutoff) @@ -545,6 +707,10 @@ def qedit__std__vector(expr, value): gdb.execute(cmd) def qdump__std__vector(d, value): + if d.isQnxTarget(): + qdump__std__vector__QNX(d, value) + return + impl = value["_M_impl"] type = d.templateArgument(value.type, 0) alloc = impl["_M_end_of_storage"] @@ -580,6 +746,40 @@ def qdump__std__vector(d, value): else: d.putArrayData(type, start, size) +def qdump__std__vector__QNX(d, value): + type = d.templateArgument(value.type, 0) + isBool = str(type) == 'bool' + if isBool: + impl = value['_Myvec'] + start = impl['_Myfirst'] + last = impl['_Mylast'] + end = impl['_Myend'] + size = value['_Mysize'] + storagesize = start.dereference().type.sizeof * 8 + else: + start = value['_Myfirst'] + last = value['_Mylast'] + end = value['_Myend'] + size = int (last - start) + alloc = int (end - start) + + d.check(0 <= size and size <= 1000 * 1000 * 1000) + d.check(last <= end) + d.checkPointer(start) + d.checkPointer(last) + d.checkPointer(end) + + d.putItemCount(size) + d.putNumChild(size) + if d.isExpanded(): + if isBool: + with Children(d, size, maxNumChild=10000, childType=type): + for i in d.childRange(): + q = start + int(i / storagesize) + d.putBoolItem(str(i), (q.dereference() >> (i % storagesize)) & 1) + else: + d.putArrayData(type, start, size) + def qdump__std____1__vector(d, value): innerType = d.templateArgument(value.type, 0) if d.isLldb and d.childAt(value, 0).type == innerType: -- GitLab