Commit 8053deba authored by hjk's avatar hjk
Browse files

Debugger: Make our std::vector and QList dumper work with LLDB



Change-Id: If6e182c32874f7a5234bede59eb8d7dd3ab7f711
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent 18dff539
......@@ -19,6 +19,23 @@ except:
return ucs
return '?'
def childAt(value, index):
field = value.type.fields()[index]
if len(field.name):
return value[field.name]
# FIXME: Cheat. There seems to be no official way to access
# the real item, so we pass back the value. That at least
# enables later ...["name"] style accesses as gdb handles
# them transparently.
return value
def addressOf(value):
return gdb.Value(value.address).cast(value.type.pointer())
#gdb.Value.child = impl_Value_child
# Fails on SimulatorQt.
tempFileCounter = 0
try:
......@@ -617,16 +634,7 @@ def isNull(p):
except:
return False
movableTypes = set([
"QBrush", "QBitArray", "QByteArray", "QCustomTypeInfo", "QChar", "QDate",
"QDateTime", "QFileInfo", "QFixed", "QFixedPoint", "QFixedSize",
"QHashDummyValue", "QIcon", "QImage", "QLine", "QLineF", "QLatin1Char",
"QLocale", "QMatrix", "QModelIndex", "QPoint", "QPointF", "QPen",
"QPersistentModelIndex", "QResourceRoot", "QRect", "QRectF", "QRegExp",
"QSize", "QSizeF", "QString", "QTime", "QTextBlock", "QUrl", "QVariant",
"QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration",
"QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"
])
Value = gdb.Value
def stripClassTag(typeName):
if typeName.startswith("class "):
......@@ -838,15 +846,6 @@ class LocalItem:
#
#######################################################################
# This is a cache mapping from 'type name' to 'display alternatives'.
qqFormats = {}
# This is a cache of all known dumpers.
qqDumpers = {}
# This is a cache of all dumpers that support writing.
qqEditable = {}
# This keeps canonical forms of the typenames, without array indices etc.
qqStripForFormat = {}
......@@ -872,30 +871,6 @@ def stripForFormat(typeName):
return stripped
def registerDumper(function):
global qqDumpers, qqFormats, qqEditable
try:
funcname = function.func_name
if funcname.startswith("qdump__"):
type = funcname[7:]
qqDumpers[type] = function
qqFormats[type] = qqFormats.get(type, "")
elif funcname.startswith("qform__"):
type = funcname[7:]
formats = ""
try:
formats = function()
except:
pass
qqFormats[type] = formats
elif funcname.startswith("qedit__"):
type = funcname[7:]
try:
qqEditable[type] = function
except:
pass
except:
pass
#######################################################################
#
......
......@@ -333,6 +333,39 @@ class ScanStackCommand(gdb.Command):
ScanStackCommand()
# This is a cache mapping from 'type name' to 'display alternatives'.
qqFormats = {}
# This is a cache of all known dumpers.
qqDumpers = {}
# This is a cache of all dumpers that support writing.
qqEditable = {}
def registerDumper(function):
global qqDumpers, qqFormats, qqEditable
try:
funcname = function.func_name
if funcname.startswith("qdump__"):
type = funcname[7:]
qqDumpers[type] = function
qqFormats[type] = qqFormats.get(type, "")
elif funcname.startswith("qform__"):
type = funcname[7:]
formats = ""
try:
formats = function()
except:
pass
qqFormats[type] = formats
elif funcname.startswith("qedit__"):
type = funcname[7:]
try:
qqEditable[type] = function
except:
pass
except:
pass
def bbsetup(args = ''):
global qqDumpers, qqFormats, qqEditable, typeCache
......
......@@ -63,6 +63,8 @@ DisplayUtf8String \
= range(7)
def lookupType(name):
if name == "void":
return voidType
if name == "char":
return charType
if name == "char *":
......@@ -176,38 +178,10 @@ def qStringData(value):
# Qt 4.
return private['data'], int(private['size']), int(private['alloc'])
class Type:
def __init__(self, var):
self.raw = var
if var.num_children == 0:
self.code = SimpleValueCode
else:
self.code = StructCode
self.value_type = var.value_type
def __str__(self):
#try:
return self.raw.type.name
#except:
# return "<illegal type>"
def fieldCount(self):
return self.raw.num_children
def unqualified(self):
return self
def strip_typedefs(self):
return self
def currentFrame():
currentThread = self.process.GetThreadAtIndex(0)
return currentThread.GetFrameAtIndex(0)
def fieldCount(type):
return type.fieldCount();
def fileName(file):
return str(file) if file.IsValid() else ''
......@@ -287,6 +261,15 @@ def check(exp):
if not exp:
raise RuntimeError("Check failed")
def checkPointer(p, align = 1):
if not isNull(p):
p.Dereference()
def isNull(p):
return long(p) == 0
Value = lldb.SBValue
def checkSimpleRef(ref):
count = int(ref["_q_value"])
check(count > 0)
......@@ -306,24 +289,50 @@ def checkRef(ref):
def impl_SBValue__add__(self, offset):
if self.GetType().IsPointerType():
return self.GetChildAtIndex(int(offset), lldb.eNoDynamicValues, True).AddressOf()
raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
return NotImplemented
def impl_SBValue__sub__(self, other):
if self.GetType().IsPointerType() and other.GetType().IsPointerType():
return int(self) - int(other)
itemsize = self.GetType().GetDereferencedType().GetByteSize()
return (int(self) - int(other)) / itemsize
raise RuntimeError("SBValue.__sub__ not implemented")
return NotImplemented
def impl_SBValue__le__(self, other):
if self.GetType().IsPointerType() and other.GetType().IsPointerType():
return int(self) <= int(other)
raise RuntimeError("SBValue.__le__ not implemented")
return NotImplemented
def impl_SBValue__int__(self):
return int(self.GetValue(), 0)
def impl_SBValue__getitem__(self, name):
return self.GetChildMemberWithName(name)
def childAt(value, index):
return value.GetChildAtIndex(index)
def addressOf(value):
return value.address_of
lldb.SBValue.__add__ = impl_SBValue__add__
lldb.SBValue.__sub__ = impl_SBValue__sub__
lldb.SBValue.__le__ = impl_SBValue__le__
lldb.SBValue.__getitem__ = lambda self, name: self.GetChildMemberWithName(name)
lldb.SBValue.__int__ = lambda self: int(self.GetValue(), 0)
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)
lldb.SBValue.code = lambda self: self.GetTypeClass()
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
lldb.SBValue.dereference = lambda self: self.Dereference()
lldb.SBValue.address = property(lambda self: self.GetAddress())
lldb.SBType.unqualified = lambda self: self.GetUnqualifiedType()
lldb.SBType.pointer = lambda self: self.GetPointerType()
lldb.SBType.code = lambda self: self.GetTypeClass()
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
def simpleEncoding(typeobj):
......@@ -495,6 +504,7 @@ class Debugger:
self.options = {}
self.expandedINames = {}
self.passExceptions = True
self.ns = ""
self.currentIName = None
self.currentValuePriority = -100
......@@ -528,6 +538,13 @@ class Debugger:
#return format
return 0
def isMovableType(self, type):
if type.code == PointerCode:
return True
if isSimpleType(type):
return True
return self.stripNamespaceFromType(type.GetName()) in movableTypes
def putNumChild(self, numchild):
#warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
#if numchild != self.currentChildNumChild:
......@@ -777,6 +794,9 @@ class Debugger:
return type
def putSubItem(self, component, value, tryDynamic=True):
if not value.IsValid():
warn("INVALID")
return
with SubItem(self, component):
self.putItem(value, tryDynamic)
......@@ -784,7 +804,7 @@ class Debugger:
#value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
typeName = value.GetTypeName()
if value.GetTypeSynthetic().IsValid():
if False and value.GetTypeSynthetic().IsValid():
# FIXME: print "official" summary?
summary = value.GetTypeSummary()
if summary.IsValid():
......@@ -808,6 +828,7 @@ class Debugger:
self.putItem(child)
return
value.SetPreferSyntheticValue(False)
stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
#warn("VALUE: %s" % value)
if stripped in qqDumpers:
......@@ -850,7 +871,8 @@ class Debugger:
def reportData(self, _ = None):
# Hack.
global charPtrType, charType
global charPtrType, charType, voidType
voidType = self.target.GetModuleAtIndex(0).FindFirstType('void')
charType = self.target.GetModuleAtIndex(0).FindFirstType('char')
charPtrType = charType.GetPointerType()
......
......@@ -7,6 +7,16 @@
from __future__ import with_statement
movableTypes = set([
"QBrush", "QBitArray", "QByteArray", "QCustomTypeInfo", "QChar", "QDate",
"QDateTime", "QFileInfo", "QFixed", "QFixedPoint", "QFixedSize",
"QHashDummyValue", "QIcon", "QImage", "QLine", "QLineF", "QLatin1Char",
"QLocale", "QMatrix", "QModelIndex", "QPoint", "QPointF", "QPen",
"QPersistentModelIndex", "QResourceRoot", "QRect", "QRectF", "QRegExp",
"QSize", "QSizeF", "QString", "QTime", "QTextBlock", "QUrl", "QVariant",
"QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration",
"QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"
])
def mapForms():
return "Normal,Compact"
......@@ -63,6 +73,19 @@ def qdump__QByteArray(d, value):
d.putArrayData(lookupType("char"), data, size)
# Fails on Windows.
try:
import curses.ascii
def printableChar(ucs):
if curses.ascii.isprint(ucs):
return ucs
return '?'
except:
def printableChar(ucs):
if ucs >= 32 and ucs <= 126:
return ucs
return '?'
def qdump__QChar(d, value):
ucs = int(value["ucs"])
d.putValue("'%c' (%d)" % (printableChar(ucs), ucs))
......@@ -518,12 +541,11 @@ def qdump__QHostAddress(d, value):
with Children(d):
d.putFields(data)
def qdump__QList(d, value):
d_ptr = value["d"]
begin = d_ptr["begin"]
end = d_ptr["end"]
array = d_ptr["array"]
d_ptr = childAt(value, 0)["d"].dereference()
begin = int(d_ptr["begin"])
end = int(d_ptr["end"])
array = addressOf(d_ptr["array"])
check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000)
size = end - begin
check(size >= 0)
......@@ -534,7 +556,7 @@ def qdump__QList(d, value):
innerTypeIsPointer = innerType.code == PointerCode \
and str(innerType.target().unqualified()) != "char"
if innerTypeIsPointer:
p = gdb.Value(array).cast(innerType.pointer()) + begin
p = array.cast(innerType.pointer()) + begin
checkPointerRange(p, min(size, 100))
d.putItemCount(size)
......@@ -549,7 +571,7 @@ def qdump__QList(d, value):
isInternal = innerSize <= d_ptr.type.sizeof and d.isMovableType(innerType)
dummyType = lookupType("void").pointer().pointer()
innerTypePointer = innerType.pointer()
p = gdb.Value(array).cast(dummyType) + begin
p = array.cast(dummyType) + begin
if innerTypeIsPointer:
inner = innerType.target()
else:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment