forked from qt-creator/qt-creator
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 <hjk121@nokiamail.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user