forked from qt-creator/qt-creator
Debugger: Make our std::vector and QList dumper work with LLDB
Change-Id: If6e182c32874f7a5234bede59eb8d7dd3ab7f711 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user