Debugger: Rework display length limitation systems

There are two values now, one to limit an entry in the L&E view
(default 100) and a hard upper limit (at 1 mio).

If displayed values are elided, the true length is shown in addition.

Change-Id: I180b70446c18e258c164e5af75b88d4c8b6c53f2
Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
hjk
2014-05-16 00:18:17 +02:00
parent 382730b130
commit 40052046fd
14 changed files with 179 additions and 154 deletions

View File

@@ -71,6 +71,19 @@ except:
return "Normal" return "Normal"
class ReportItem:
"""
Helper structure to keep temporary "best" information about a value
or a type scheduled to be reported. This might get overridden be
subsequent better guesses during a putItem() run.
"""
def __init__(self):
self.value = None
self.priority = -100
self.encoding = None
self.elided = 0
class Blob(object): class Blob(object):
""" """
Helper structure to keep a blob of bytes, possibly Helper structure to keep a blob of bytes, possibly
@@ -310,6 +323,7 @@ class DumperBase:
# Later set, or not set: # Later set, or not set:
# cachedQtVersion # cachedQtVersion
self.stringCutOff = 10000 self.stringCutOff = 10000
self.displayStringLimit = 100
# This is a cache mapping from 'type name' to 'display alternatives'. # This is a cache mapping from 'type name' to 'display alternatives'.
self.qqFormats = {} self.qqFormats = {}
@@ -375,12 +389,11 @@ class DumperBase:
# assume no Qt 3 support by default # assume no Qt 3 support by default
return False return False
# Clamps size to limit.
def computeLimit(self, size, limit): def computeLimit(self, size, limit):
if limit is None: if limit is None or size <= limit:
return size return 0, size
if limit == 0: return size, limit
return min(size, self.stringCutOff)
return min(size, limit)
def vectorDataHelper(self, addr): def vectorDataHelper(self, addr):
if self.qtVersion() >= 0x050000: if self.qtVersion() >= 0x050000:
@@ -419,53 +432,50 @@ class DumperBase:
return data, size, alloc return data, size, alloc
# addr is the begin of a QByteArrayData structure # addr is the begin of a QByteArrayData structure
def encodeStringHelper(self, addr, limit = 0): def encodeStringHelper(self, addr, limit):
# Should not happen, but we get it with LLDB as result # Should not happen, but we get it with LLDB as result
# of inferior calls # of inferior calls
if addr == 0: if addr == 0:
return "" return 0, ""
data, size, alloc = self.byteArrayDataHelper(addr) data, size, alloc = self.byteArrayDataHelper(addr)
if alloc != 0: if alloc != 0:
self.check(0 <= size and size <= alloc and alloc <= 100*1000*1000) self.check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
limit = self.computeLimit(size, limit) elided, shown = self.computeLimit(size, limit)
s = self.readMemory(data, 2 * limit) return elided, self.readMemory(data, 2 * shown)
if limit < size:
s += "2e002e002e00"
return s
def encodeByteArrayHelper(self, addr, limit = None): def encodeByteArrayHelper(self, addr, limit):
data, size, alloc = self.byteArrayDataHelper(addr) data, size, alloc = self.byteArrayDataHelper(addr)
if alloc != 0: if alloc != 0:
self.check(0 <= size and size <= alloc and alloc <= 100*1000*1000) self.check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
limit = self.computeLimit(size, limit) elided, shown = self.computeLimit(size, limit)
s = self.readMemory(data, limit) return elided, self.readMemory(data, shown)
if limit < size:
s += "2e2e2e"
return s
def readMemory(self, addr, size): def readMemory(self, addr, size):
data = self.extractBlob(addr, size).toBytes() data = self.extractBlob(addr, size).toBytes()
return self.hexencode(data) return self.hexencode(data)
def encodeByteArray(self, value, limit = 0): def encodeByteArray(self, value, limit = 0):
return self.encodeByteArrayHelper(self.extractPointer(value), limit) elided, data = self.encodeByteArrayHelper(self.extractPointer(value), limit)
return data
def byteArrayData(self, value): def byteArrayData(self, value):
return self.byteArrayDataHelper(self.extractPointer(value)) return self.byteArrayDataHelper(self.extractPointer(value))
def putByteArrayValue(self, value): def putByteArrayValue(self, value):
return self.putValue(self.encodeByteArray(value, self.stringCutOff), Hex2EncodedLatin1) elided, data = self.encodeByteArrayHelper(self.extractPointer(value), self.displayStringLimit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
def putByteArrayValueByAddress(self, addr): def putByteArrayValueByAddress(self, addr):
self.putValue(self.encodeByteArrayHelper(self.extractPointer(addr)), elided, data = self.encodeByteArrayHelper(addr, self.displayStringLimit)
Hex2EncodedLatin1) self.putValue(data, Hex2EncodedLatin1, elided=elided)
def putStringValueByAddress(self, addr): def putStringValueByAddress(self, addr):
self.putValue(self.encodeStringHelper(self.extractPointer(addr)), elided, data = self.encodeStringHelper(self.extractPointer(addr), self.displayStringLimit)
Hex4EncodedLittleEndian) self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
def encodeString(self, value, limit = 0): def encodeString(self, value, limit = 0):
return self.encodeStringHelper(self.extractPointer(value), limit) elided, data = self.encodeStringHelper(self.extractPointer(value), limit)
return data
def stringData(self, value): def stringData(self, value):
return self.byteArrayDataHelper(self.extractPointer(value)) return self.byteArrayDataHelper(self.extractPointer(value))
@@ -499,7 +509,8 @@ class DumperBase:
return inner.strip() return inner.strip()
def putStringValue(self, value): def putStringValue(self, value):
return self.putValue(self.encodeString(value, self.stringCutOff), Hex4EncodedLittleEndian) elided, data = self.encodeStringHelper(self.extractPointer(value), self.displayStringLimit)
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
def putAddressItem(self, name, value, type = ""): def putAddressItem(self, name, value, type = ""):
with SubItem(self, name): with SubItem(self, name):
@@ -619,27 +630,16 @@ class DumperBase:
def findFirstZero(self, p, maximum): def findFirstZero(self, p, maximum):
for i in xrange(maximum): for i in xrange(maximum):
if int(p.dereference()) == 0: if int(p.dereference()) == 0:
return i return 0, i
p = p + 1 p = p + 1
return maximum + 1 # Real end is unknown.
return -1, maximum
def encodeCArray(self, p, innerType, suffix): def encodeCArray(self, p, innerType, limit):
t = self.lookupType(innerType) t = self.lookupType(innerType)
p = p.cast(t.pointer()) p = p.cast(t.pointer())
limit = self.findFirstZero(p, self.stringCutOff) elided, shown = self.findFirstZero(p, limit)
s = self.readMemory(p, limit * t.sizeof) return elided, self.readMemory(p, shown * t.sizeof)
if limit > self.stringCutOff:
s += suffix
return s
def encodeCharArray(self, p):
return self.encodeCArray(p, "unsigned char", "2e2e2e")
def encodeChar2Array(self, p):
return self.encodeCArray(p, "unsigned short", "2e002e002e00")
def encodeChar4Array(self, p):
return self.encodeCArray(p, "unsigned int", "2e0000002e0000002e000000")
def putItemCount(self, count, maximum = 1000000000): def putItemCount(self, count, maximum = 1000000000):
# This needs to override the default value, so don't use 'put' directly. # This needs to override the default value, so don't use 'put' directly.
@@ -654,26 +654,34 @@ class DumperBase:
def putType(self, type, priority = 0): def putType(self, type, priority = 0):
# Higher priority values override lower ones. # Higher priority values override lower ones.
if priority >= self.currentTypePriority: if priority >= self.currentType.priority:
self.currentType = str(type) self.currentType.value = str(type)
self.currentTypePriority = priority self.currentType.priority = priority
def putValue(self, value, encoding = None, priority = 0): def putValue(self, value, encoding = None, priority = 0, elided = None):
# Higher priority values override lower ones. # Higher priority values override lower ones.
if priority >= self.currentValuePriority: # elided = 0 indicates all data is available in value,
self.currentValue = value # otherwise it's the true length.
self.currentValuePriority = priority if priority >= self.currentValue.priority:
self.currentValueEncoding = encoding self.currentValue.value = value
self.currentValue.priority = priority
self.currentValue.encoding = encoding
self.currentValue.elided = elided
def putEmptyValue(self, priority = -10): def putEmptyValue(self, priority = -10):
if priority >= self.currentValuePriority: if priority >= self.currentValue.priority:
self.currentValue = "" self.currentValue.value = ""
self.currentValuePriority = priority self.currentValue.priority = priority
self.currentValueEncoding = None self.currentValue.encoding = None
self.currentValue.elided = None
def putName(self, name): def putName(self, name):
self.put('name="%s",' % name) self.put('name="%s",' % name)
def putBetterType(self, type):
self.currentType.value = str(type)
self.currentType.priority += 1
def putNoType(self): def putNoType(self):
# FIXME: replace with something that does not need special handling # FIXME: replace with something that does not need special handling
# in SubItem.__exit__(). # in SubItem.__exit__().
@@ -682,7 +690,7 @@ class DumperBase:
def putInaccessible(self): def putInaccessible(self):
#self.putBetterType(" ") #self.putBetterType(" ")
self.putNumChild(0) self.putNumChild(0)
self.currentValue = None self.currentValue.value = None
def putNamedSubItem(self, component, value, name): def putNamedSubItem(self, component, value, name):
with SubItem(self, component): with SubItem(self, component):
@@ -805,7 +813,8 @@ class DumperBase:
if format == None and innerTypeName == "char": if format == None and innerTypeName == "char":
# Use Latin1 as default for char *. # Use Latin1 as default for char *.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1) (elided, data) = self.encodeCArray(value, "unsigned char", self.displayStringLimit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
@@ -823,35 +832,40 @@ class DumperBase:
if format == Latin1StringFormat: if format == Latin1StringFormat:
# Explicitly requested Latin1 formatting. # Explicitly requested Latin1 formatting.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1) (elided, data) = self.encodeCArray(value, "unsigned char", self.displayStringLimit)
self.putValue(data, Hex2EncodedLatin1, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
if format == Utf8StringFormat: if format == Utf8StringFormat:
# Explicitly requested UTF-8 formatting. # Explicitly requested UTF-8 formatting.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeCharArray(value), Hex2EncodedUtf8) (elided, data) = self.encodeCArray(value, "unsigned char", self.displayStringLimit)
self.putValue(data, Hex2EncodedUtf8, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
if format == Local8BitStringFormat: if format == Local8BitStringFormat:
# Explicitly requested local 8 bit formatting. # Explicitly requested local 8 bit formatting.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeCharArray(value), Hex2EncodedLocal8Bit) (elided, data) = self.encodeCArray(value, "unsigned char", self.displayStringLimit)
self.putValue(data, Hex2EncodedLocal8Bit, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
if format == Utf16StringFormat: if format == Utf16StringFormat:
# Explicitly requested UTF-16 formatting. # Explicitly requested UTF-16 formatting.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeChar2Array(value), Hex4EncodedLittleEndian) (elided, data) = self.encodeCArray(value, "unsigned short", self.displayStringLimit)
self.putValue(data, Hex4EncodedLittleEndian, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
if format == Ucs4StringFormat: if format == Ucs4StringFormat:
# Explicitly requested UCS-4 formatting. # Explicitly requested UCS-4 formatting.
self.putType(typeName) self.putType(typeName)
self.putValue(self.encodeChar4Array(value), Hex8EncodedLittleEndian) (elided, data) = self.encodeCArray(value, "unsigned int", self.displayStringLimit)
self.putValue(data, Hex8EncodedLittleEndian, elided=elided)
self.putNumChild(0) self.putNumChild(0)
return return
@@ -1226,7 +1240,7 @@ class DumperBase:
format = self.formats.get(self.currentIName) format = self.formats.get(self.currentIName)
if format is None: if format is None:
if type is None: if type is None:
type = self.currentType type = self.currentType.value
needle = self.stripForFormat(str(type)) needle = self.stripForFormat(str(type))
format = self.typeformats.get(needle) format = self.typeformats.get(needle)
return format return format
@@ -1256,8 +1270,8 @@ class DumperBase:
if not hasPlot(): if not hasPlot():
return return
if not self.isSimpleType(typeobj): if not self.isSimpleType(typeobj):
#self.putValue(self.currentValue + " (not plottable)") #self.putValue(self.currentValue.value + " (not plottable)")
self.putValue(self.currentValue) self.putValue(self.currentValue.value)
self.putField("plottable", "0") self.putField("plottable", "0")
return return
global gnuplotPipe global gnuplotPipe
@@ -1435,8 +1449,8 @@ class DumperBase:
value = self.parseAndEvaluate(exp) value = self.parseAndEvaluate(exp)
self.putItem(value) self.putItem(value)
except RuntimeError: except RuntimeError:
self.currentType = " " self.currentType.value = " "
self.currentValue = "<no such value>" self.currentValue.value = "<no such value>"
self.currentChildNumChild = -1 self.currentChildNumChild = -1
self.currentNumChild = 0 self.currentNumChild = 0
self.putNumChild(0) self.putNumChild(0)

View File

@@ -367,11 +367,8 @@ class Dumper(DumperBase):
self.currentChildNumChild = -1 self.currentChildNumChild = -1
self.currentMaxNumChild = -1 self.currentMaxNumChild = -1
self.currentNumChild = -1 self.currentNumChild = -1
self.currentValue = None self.currentValue = ReportItem()
self.currentValuePriority = -100 self.currentType = ReportItem()
self.currentValueEncoding = None
self.currentType = None
self.currentTypePriority = -100
self.currentAddress = None self.currentAddress = None
self.typeformats = {} self.typeformats = {}
self.formats = {} self.formats = {}
@@ -402,6 +399,8 @@ class Dumper(DumperBase):
self.expandedINames = set(arg[pos:].split(",")) self.expandedINames = set(arg[pos:].split(","))
elif arg.startswith("stringcutoff:"): elif arg.startswith("stringcutoff:"):
self.stringCutOff = int(arg[pos:]) self.stringCutOff = int(arg[pos:])
elif arg.startswith("displaystringlimit:"):
self.displayStringLimit = int(arg[pos:])
elif arg.startswith("typeformats:"): elif arg.startswith("typeformats:"):
for f in arg[pos:].split(","): for f in arg[pos:].split(","):
pos = f.find("=") pos = f.find("=")
@@ -525,39 +524,39 @@ class Dumper(DumperBase):
self.put('name="%s",' % item.name) self.put('name="%s",' % item.name)
item.savedIName = self.currentIName item.savedIName = self.currentIName
item.savedValue = self.currentValue item.savedValue = self.currentValue
item.savedValuePriority = self.currentValuePriority
item.savedValueEncoding = self.currentValueEncoding
item.savedType = self.currentType item.savedType = self.currentType
item.savedTypePriority = self.currentTypePriority
item.savedCurrentAddress = self.currentAddress item.savedCurrentAddress = self.currentAddress
self.currentIName = item.iname self.currentIName = item.iname
self.currentValuePriority = -100 self.currentValue = ReportItem();
self.currentValueEncoding = None self.currentType = ReportItem();
self.currentType = ""
self.currentTypePriority = -100
self.currentAddress = None self.currentAddress = None
def exitSubItem(self, item, exType, exValue, exTraceBack): def exitSubItem(self, item, exType, exValue, exTraceBack):
#warn(" CURRENT VALUE: %s %s %s" % (self.currentValue, #warn("CURRENT VALUE: %s: %s %s %s %s" % (
# self.currentValueEncoding, self.currentValuePriority)) # self.currentIName,
# self.currentValue.value,
# self.currentValue.elided,
# self.currentValue.encoding,
# self.currentValue.priority))
if not exType is None: if not exType is None:
if self.passExceptions: if self.passExceptions:
showException("SUBITEM", exType, exValue, exTraceBack) showException("SUBITEM", exType, exValue, exTraceBack)
self.putNumChild(0) self.putNumChild(0)
self.putValue("<not accessible>") self.putValue("<not accessible>")
try: try:
#warn("TYPE VALUE: %s" % self.currentValue) #warn("CURRENT TYPE: %s" % self.currentType.value)
typeName = stripClassTag(self.currentType) typeName = stripClassTag(self.currentType.value)
#warn("TYPE: '%s' DEFAULT: '%s' % (typeName, self.currentChildType))
if len(typeName) > 0 and typeName != self.currentChildType: if len(typeName) > 0 and typeName != self.currentChildType:
self.put('type="%s",' % typeName) # str(type.unqualified()) ? self.put('type="%s",' % typeName) # str(type.unqualified()) ?
if self.currentValue is None: if self.currentValue.value is None:
self.put('value="<not accessible>",numchild="0",') self.put('value="<not accessible>",numchild="0",')
else: else:
if not self.currentValueEncoding is None: if not self.currentValue.encoding is None:
self.put('valueencoded="%d",' % self.currentValueEncoding) self.put('valueencoded="%d",' % self.currentValue.encoding)
self.put('value="%s",' % self.currentValue) if self.currentValue.elided:
self.put('valueelided="%d",' % self.currentValue.elided)
self.put('value="%s",' % self.currentValue.value)
except: except:
pass pass
if not self.currentAddress is None: if not self.currentAddress is None:
@@ -565,10 +564,7 @@ class Dumper(DumperBase):
self.put('},') self.put('},')
self.currentIName = item.savedIName self.currentIName = item.savedIName
self.currentValue = item.savedValue self.currentValue = item.savedValue
self.currentValuePriority = item.savedValuePriority
self.currentValueEncoding = item.savedValueEncoding
self.currentType = item.savedType self.currentType = item.savedType
self.currentTypePriority = item.savedTypePriority
self.currentAddress = item.savedCurrentAddress self.currentAddress = item.savedCurrentAddress
return True return True
@@ -888,10 +884,6 @@ class Dumper(DumperBase):
self.isQt3Support = lambda: self.cachedIsQt3Suport self.isQt3Support = lambda: self.cachedIsQt3Suport
return self.cachedIsQt3Suport return self.cachedIsQt3Suport
def putBetterType(self, type):
self.currentType = str(type)
self.currentTypePriority = self.currentTypePriority + 1
def putAddress(self, addr): def putAddress(self, addr):
if self.currentPrintsAddress: if self.currentPrintsAddress:
try: try:

View File

@@ -261,11 +261,8 @@ class Dumper(DumperBase):
self.typeformats = {} self.typeformats = {}
self.currentIName = None self.currentIName = None
self.currentValuePriority = -100 self.currentValue = ReportItem()
self.currentValueEncoding = None self.currentType = ReportItem()
self.currentType = ""
self.currentTypePriority = -100
self.currentValue = None
self.currentNumChild = None self.currentNumChild = None
self.currentMaxNumChild = None self.currentMaxNumChild = None
self.currentPrintsAddress = None self.currentPrintsAddress = None
@@ -310,15 +307,10 @@ class Dumper(DumperBase):
self.put('name="%s",' % item.name) self.put('name="%s",' % item.name)
item.savedIName = self.currentIName item.savedIName = self.currentIName
item.savedValue = self.currentValue item.savedValue = self.currentValue
item.savedValuePriority = self.currentValuePriority
item.savedValueEncoding = self.currentValueEncoding
item.savedType = self.currentType item.savedType = self.currentType
item.savedTypePriority = self.currentTypePriority
self.currentIName = item.iname self.currentIName = item.iname
self.currentValuePriority = -100 self.currentValue = ReportItem()
self.currentValueEncoding = None self.currentType = ReportItem()
self.currentType = ""
self.currentTypePriority = -100
def exitSubItem(self, item, exType, exValue, exTraceBack): def exitSubItem(self, item, exType, exValue, exTraceBack):
if not exType is None: if not exType is None:
@@ -327,24 +319,23 @@ class Dumper(DumperBase):
self.putNumChild(0) self.putNumChild(0)
self.putValue("<not accessible>") self.putValue("<not accessible>")
try: try:
typeName = self.currentType typeName = self.currentType.value
if len(typeName) > 0 and typeName != self.currentChildType: if len(typeName) > 0 and typeName != self.currentChildType:
self.put('type="%s",' % typeName) # str(type.unqualified()) ? self.put('type="%s",' % typeName) # str(type.unqualified()) ?
if self.currentValue is None: if self.currentValue.value is None:
self.put('value="<not accessible>",numchild="0",') self.put('value="<not accessible>",numchild="0",')
else: else:
if not self.currentValueEncoding is None: if not self.currentValue.encoding is None:
self.put('valueencoded="%s",' % self.currentValueEncoding) self.put('valueencoded="%s",' % self.currentValue.encoding)
self.put('value="%s",' % self.currentValue) if self.currentValue.elided:
self.put('valueelided="%s",' % self.currentValue.elided)
self.put('value="%s",' % self.currentValue.value)
except: except:
pass pass
self.put('},') self.put('},')
self.currentIName = item.savedIName self.currentIName = item.savedIName
self.currentValue = item.savedValue self.currentValue = item.savedValue
self.currentValuePriority = item.savedValuePriority
self.currentValueEncoding = item.savedValueEncoding
self.currentType = item.savedType self.currentType = item.savedType
self.currentTypePriority = item.savedTypePriority
return True return True
def isSimpleType(self, typeobj): def isSimpleType(self, typeobj):
@@ -856,14 +847,6 @@ class Dumper(DumperBase):
def reportStackTop(self): def reportStackTop(self):
self.report('stack-top={}') self.report('stack-top={}')
def putBetterType(self, type):
try:
self.currentType = type.GetName()
except:
self.currentType = str(type)
self.currentTypePriority = self.currentTypePriority + 1
#warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
def extractBlob(self, base, size): def extractBlob(self, base, size):
if size == 0: if size == 0:
return Blob("") return Blob("")

View File

@@ -274,7 +274,7 @@ def qdump__QDateTime(d, value):
tz = "" tz = ""
else: else:
idBase = tzp + 2 * d.ptrSize() # [QSharedData] + [vptr] idBase = tzp + 2 * d.ptrSize() # [QSharedData] + [vptr]
tz = d.encodeByteArrayHelper(d.extractPointer(idBase)) tz = d.encodeByteArrayHelper(d.extractPointer(idBase), limit=100)
d.putValue("%s/%s/%s/%s/%s" % (msecs, spec, offset, tz, status), d.putValue("%s/%s/%s/%s/%s" % (msecs, spec, offset, tz, status),
DateTimeInternal) DateTimeInternal)
else: else:
@@ -705,7 +705,7 @@ def qdump__QHostAddress(d, value):
ipStringAddress = privAddress + (0 if isQt5 else 24) ipStringAddress = privAddress + (0 if isQt5 else 24)
isParsedAddress = privAddress + 24 + 2 * sizeofQString isParsedAddress = privAddress + 24 + 2 * sizeofQString
# value.d.d->ipString # value.d.d->ipString
ipString = d.encodeStringHelper(d.extractPointer(ipStringAddress)) ipString = d.encodeStringHelper(d.extractPointer(ipStringAddress), limit=100)
if d.extractByte(isParsedAddress) and len(ipString) > 0: if d.extractByte(isParsedAddress) and len(ipString) > 0:
d.putValue(ipString, Hex4EncodedLittleEndian) d.putValue(ipString, Hex4EncodedLittleEndian)
else: else:
@@ -720,7 +720,7 @@ def qdump__QHostAddress(d, value):
data = d.readMemory(privAddress + a6Offset, 16) data = d.readMemory(privAddress + a6Offset, 16)
address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4)) address = ':'.join("%x" % int(data[i:i+4], 16) for i in xrange(0, 32, 4))
scopeId = privAddress + sizeofQString + (0 if isQt5 else 24) scopeId = privAddress + sizeofQString + (0 if isQt5 else 24)
scopeId = d.encodeStringHelper(d.extractPointer(scopeId)) scopeId = d.encodeStringHelper(d.extractPointer(scopeId), limit=100)
d.putValue("%s%%%s" % (address, scopeId), IPv6AddressAndHexScopeId) d.putValue("%s%%%s" % (address, scopeId), IPv6AddressAndHexScopeId)
elif proto == 0: elif proto == 0:
# value.d.d->a # value.d.d->a
@@ -1730,7 +1730,7 @@ def qdump__QString(d, value):
d.putDisplay(StopDisplay) d.putDisplay(StopDisplay)
elif format == 2: elif format == 2:
d.putField("editformat", DisplayUtf16String) d.putField("editformat", DisplayUtf16String)
d.putField("editvalue", d.encodeString(value)) d.putField("editvalue", d.encodeString(value, limit=None))
def qdump__QStringRef(d, value): def qdump__QStringRef(d, value):
@@ -1759,7 +1759,7 @@ def qdump__QTemporaryFile(d, value):
def qdump__QTextCodec(d, value): def qdump__QTextCodec(d, value):
name = d.call(value, "name") name = d.call(value, "name")
d.putValue(d.encodeByteArray(d, name), 6) d.putValue(d.encodeByteArray(name, limit=100), 6)
d.putNumChild(2) d.putNumChild(2)
if d.isExpanded(): if d.isExpanded():
with Children(d): with Children(d):
@@ -1843,13 +1843,13 @@ def qdump__QUrl(d, value):
d.putValue("<invalid>") d.putValue("<invalid>")
return return
schemeAddr = privAddress + 2 * d.intSize() schemeAddr = privAddress + 2 * d.intSize()
scheme = d.encodeStringHelper(d.extractPointer(schemeAddr)) scheme = d.encodeStringHelper(d.extractPointer(schemeAddr), limit=1000)
userName = d.encodeStringHelper(d.extractPointer(schemeAddr + 1 * d.ptrSize())) userName = d.encodeStringHelper(d.extractPointer(schemeAddr + 1 * d.ptrSize()), limit=100)
password = d.encodeStringHelper(d.extractPointer(schemeAddr + 2 * d.ptrSize())) password = d.encodeStringHelper(d.extractPointer(schemeAddr + 2 * d.ptrSize()), limit=100)
host = d.encodeStringHelper(d.extractPointer(schemeAddr + 3 * d.ptrSize())) host = d.encodeStringHelper(d.extractPointer(schemeAddr + 3 * d.ptrSize()), limit=100)
path = d.encodeStringHelper(d.extractPointer(schemeAddr + 4 * d.ptrSize())) path = d.encodeStringHelper(d.extractPointer(schemeAddr + 4 * d.ptrSize()), limit=1000)
query = d.encodeStringHelper(d.extractPointer(schemeAddr + 5 * d.ptrSize())) query = d.encodeStringHelper(d.extractPointer(schemeAddr + 5 * d.ptrSize()), limit=10000)
fragment = d.encodeStringHelper(d.extractPointer(schemeAddr + 6 * d.ptrSize())) fragment = d.encodeStringHelper(d.extractPointer(schemeAddr + 6 * d.ptrSize()), limit=10000)
port = d.extractInt(d.extractPointer(value) + d.intSize()) port = d.extractInt(d.extractPointer(value) + d.intSize())
url = scheme url = scheme

View File

@@ -418,10 +418,8 @@ def qdump__std__stringHelper1__QNX(d, value, charSize):
qdump_stringHelper(d, sizePtr, size * charSize, charSize) qdump_stringHelper(d, sizePtr, size * charSize, charSize)
def qdump_stringHelper(d, data, size, charSize): def qdump_stringHelper(d, data, size, charSize):
cutoff = min(size, d.stringCutOff) elided, shown = d.computeLimit(size, d.displayStringLimit)
mem = d.readMemory(data, cutoff) mem = d.readMemory(data, shown)
if size > d.stringCutOff:
mem += "2e2e2e"
if charSize == 1: if charSize == 1:
encodingType = Hex2EncodedLatin1 encodingType = Hex2EncodedLatin1
displayType = DisplayLatin1String displayType = DisplayLatin1String
@@ -433,7 +431,7 @@ def qdump_stringHelper(d, data, size, charSize):
displayType = DisplayUtf16String displayType = DisplayUtf16String
d.putNumChild(0) d.putNumChild(0)
d.putValue(mem, encodingType) d.putValue(mem, encodingType, elided=elided)
format = d.currentItemFormat() format = d.currentItemFormat()
if format == 1: if format == 1:

View File

@@ -121,6 +121,14 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
spinBoxMaximalStringLength->setSingleStep(1000); spinBoxMaximalStringLength->setSingleStep(1000);
spinBoxMaximalStringLength->setValue(10000); spinBoxMaximalStringLength->setValue(10000);
labelDisplayStringLimit = new QLabel(tr("Display string limit:"), behaviorBox);
spinBoxDisplayStringLimit = new QSpinBox(behaviorBox);
spinBoxDisplayStringLimit->setSpecialValueText(tr("<unlimited>"));
spinBoxDisplayStringLimit->setMaximum(10000);
spinBoxDisplayStringLimit->setSingleStep(10);
spinBoxDisplayStringLimit->setValue(100);
sourcesMappingWidget = new DebuggerSourcePathMappingWidget(this); sourcesMappingWidget = new DebuggerSourcePathMappingWidget(this);
QHBoxLayout *horizontalLayout = new QHBoxLayout(); QHBoxLayout *horizontalLayout = new QHBoxLayout();
@@ -128,6 +136,11 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
horizontalLayout->addWidget(spinBoxMaximalStackDepth); horizontalLayout->addWidget(spinBoxMaximalStackDepth);
horizontalLayout->addStretch(); horizontalLayout->addStretch();
QHBoxLayout *horizontalLayout1 = new QHBoxLayout();
horizontalLayout1->addWidget(labelDisplayStringLimit);
horizontalLayout1->addWidget(spinBoxDisplayStringLimit);
horizontalLayout1->addStretch();
QHBoxLayout *horizontalLayout2 = new QHBoxLayout(); QHBoxLayout *horizontalLayout2 = new QHBoxLayout();
horizontalLayout2->addWidget(labelMaximalStringLength); horizontalLayout2->addWidget(labelMaximalStringLength);
horizontalLayout2->addWidget(spinBoxMaximalStringLength); horizontalLayout2->addWidget(spinBoxMaximalStringLength);
@@ -148,7 +161,8 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
gridLayout->addWidget(checkBoxShowQmlObjectTree, 3, 1, 1, 1); gridLayout->addWidget(checkBoxShowQmlObjectTree, 3, 1, 1, 1);
gridLayout->addWidget(checkBoxKeepEditorStationaryWhileStepping, 4, 1, 1, 1); gridLayout->addWidget(checkBoxKeepEditorStationaryWhileStepping, 4, 1, 1, 1);
gridLayout->addWidget(checkBoxRegisterForPostMortem, 5, 1, 1, 1); gridLayout->addWidget(checkBoxRegisterForPostMortem, 5, 1, 1, 1);
gridLayout->addLayout(horizontalLayout2, 6, 1, 1, 2); gridLayout->addLayout(horizontalLayout1, 6, 1, 1, 2);
gridLayout->addLayout(horizontalLayout2, 7, 1, 1, 2);
QVBoxLayout *verticalLayout = new QVBoxLayout(this); QVBoxLayout *verticalLayout = new QVBoxLayout(this);
verticalLayout->addWidget(behaviorBox); verticalLayout->addWidget(behaviorBox);
@@ -193,6 +207,7 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
m_group->insert(dc->action(UseAddressInStackView), 0); m_group->insert(dc->action(UseAddressInStackView), 0);
m_group->insert(dc->action(AlwaysAdjustStackColumnWidths), 0); m_group->insert(dc->action(AlwaysAdjustStackColumnWidths), 0);
m_group->insert(dc->action(MaximalStackDepth), spinBoxMaximalStackDepth); m_group->insert(dc->action(MaximalStackDepth), spinBoxMaximalStackDepth);
m_group->insert(dc->action(DisplayStringLimit), spinBoxDisplayStringLimit);
m_group->insert(dc->action(MaximalStringLength), spinBoxMaximalStringLength); m_group->insert(dc->action(MaximalStringLength), spinBoxMaximalStringLength);
m_group->insert(dc->action(ShowStdNamespace), 0); m_group->insert(dc->action(ShowStdNamespace), 0);
m_group->insert(dc->action(ShowQtNamespace), 0); m_group->insert(dc->action(ShowQtNamespace), 0);

View File

@@ -77,9 +77,11 @@ private:
QCheckBox *checkBoxWarnOnReleaseBuilds; QCheckBox *checkBoxWarnOnReleaseBuilds;
QCheckBox *checkBoxKeepEditorStationaryWhileStepping; QCheckBox *checkBoxKeepEditorStationaryWhileStepping;
QLabel *labelMaximalStackDepth; QLabel *labelMaximalStackDepth;
QLabel *labelDisplayStringLimit;
QLabel *labelMaximalStringLength; QLabel *labelMaximalStringLength;
QSpinBox *spinBoxMaximalStackDepth; QSpinBox *spinBoxMaximalStackDepth;
QSpinBox *spinBoxMaximalStringLength; QSpinBox *spinBoxMaximalStringLength;
QSpinBox *spinBoxDisplayStringLimit;
DebuggerSourcePathMappingWidget *sourcesMappingWidget; DebuggerSourcePathMappingWidget *sourcesMappingWidget;
const QSharedPointer<Utils::SavedActionSet> m_group; const QSharedPointer<Utils::SavedActionSet> m_group;

View File

@@ -631,8 +631,18 @@ DebuggerSettings::DebuggerSettings()
item->setDefaultValue(20); item->setDefaultValue(20);
insertItem(MaximalStackDepth, item); insertItem(MaximalStackDepth, item);
item = new SavedAction(this);
item->setSettingsKey(debugModeGroup, QLatin1String("DisplayStringLimit"));
item->setToolTip(tr("The maximal length of string entries in the "
"Locals and Expressions pane. Longer than that are cut off "
"and displayed with an ellipsis attached."));
item->setDefaultValue(100);
insertItem(DisplayStringLimit, item);
item = new SavedAction(this); item = new SavedAction(this);
item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStringLength")); item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStringLength"));
item->setToolTip(tr("The maximal length for strings in separated windows. "
"Longer strings are cut off and displayed with an ellipsis attached."));
item->setDefaultValue(10000); item->setDefaultValue(10000);
insertItem(MaximalStringLength, item); insertItem(MaximalStringLength, item);

View File

@@ -148,6 +148,7 @@ enum DebuggerActionCode
AutoDerefPointers, AutoDerefPointers,
AlwaysAdjustLocalsColumnWidths, AlwaysAdjustLocalsColumnWidths,
MaximalStringLength, MaximalStringLength,
DisplayStringLimit,
// Source List // Source List
ListSourceFiles, ListSourceFiles,

View File

@@ -219,7 +219,6 @@ QDataStream &operator<<(QDataStream &stream, const WatchData &wd)
stream << wd.value; stream << wd.value;
stream << wd.editvalue; stream << wd.editvalue;
stream << wd.editformat; stream << wd.editformat;
stream << wd.valuetooltip;
stream << wd.typeFormats; stream << wd.typeFormats;
stream << wd.type; stream << wd.type;
stream << wd.displayedType; stream << wd.displayedType;
@@ -243,7 +242,6 @@ QDataStream &operator>>(QDataStream &stream, WatchData &wd)
stream >> wd.value; stream >> wd.value;
stream >> wd.editvalue; stream >> wd.editvalue;
stream >> wd.editformat; stream >> wd.editformat;
stream >> wd.valuetooltip;
stream >> wd.typeFormats; stream >> wd.typeFormats;
stream >> wd.type; stream >> wd.type;
stream >> wd.displayedType; stream >> wd.displayedType;

View File

@@ -4841,7 +4841,10 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
expanded += "formats:" + handler->individualFormatRequests(); expanded += "formats:" + handler->individualFormatRequests();
QByteArray cutOff = " stringcutoff:" QByteArray cutOff = " stringcutoff:"
+ debuggerCore()->action(MaximalStringLength)->value().toByteArray(); + debuggerCore()->action(MaximalStringLength)->value().toByteArray()
+ " displaystringlimit:"
+ debuggerCore()->action(DisplayStringLimit)->value().toByteArray();
QByteArray watchers; QByteArray watchers;
const QString fileName = stackHandler()->currentFrame().file; const QString fileName = stackHandler()->currentFrame().file;

View File

@@ -126,6 +126,7 @@ WatchData::WatchData() :
size(0), size(0),
bitpos(0), bitpos(0),
bitsize(0), bitsize(0),
elided(0),
hasChildren(false), hasChildren(false),
valueEnabled(true), valueEnabled(true),
valueEditable(true), valueEditable(true),
@@ -142,12 +143,12 @@ bool WatchData::isEqual(const WatchData &other) const
&& name == other.name && name == other.name
&& value == other.value && value == other.value
&& editvalue == other.editvalue && editvalue == other.editvalue
&& valuetooltip == other.valuetooltip
&& type == other.type && type == other.type
&& displayedType == other.displayedType && displayedType == other.displayedType
&& variable == other.variable && variable == other.variable
&& address == other.address && address == other.address
&& size == other.size && size == other.size
&& elided == other.elided
&& hasChildren == other.hasChildren && hasChildren == other.hasChildren
&& valueEnabled == other.valueEnabled && valueEnabled == other.valueEnabled
&& valueEditable == other.valueEditable && valueEditable == other.valueEditable
@@ -312,6 +313,9 @@ QString WatchData::toString() const
if (isValueKnown() && !value.isEmpty()) if (isValueKnown() && !value.isEmpty())
str << "value=\"" << value << doubleQuoteComma; str << "value=\"" << value << doubleQuoteComma;
if (elided)
str << "valueelided=\"" << elided << doubleQuoteComma;
if (!editvalue.isEmpty()) if (!editvalue.isEmpty())
str << "editvalue=\"<...>\","; str << "editvalue=\"<...>\",";
// str << "editvalue=\"" << editvalue << doubleQuoteComma; // str << "editvalue=\"" << editvalue << doubleQuoteComma;
@@ -382,7 +386,7 @@ QString WatchData::toToolTip() const
formatToolTipRow(str, tr("Internal Type"), QLatin1String(type)); formatToolTipRow(str, tr("Internal Type"), QLatin1String(type));
if (!displayedType.isEmpty()) if (!displayedType.isEmpty())
formatToolTipRow(str, tr("Displayed Type"), displayedType); formatToolTipRow(str, tr("Displayed Type"), displayedType);
QString val = valuetooltip.isEmpty() ? value : valuetooltip; QString val = value;
// Automatically display hex value for unsigned integers. // Automatically display hex value for unsigned integers.
if (!val.isEmpty() && val.at(0).isDigit() && isIntType(type)) { if (!val.isEmpty() && val.at(0).isDigit() && isIntType(type)) {
bool ok; bool ok;
@@ -458,13 +462,6 @@ void WatchData::updateValue(const GdbMi &item)
} }
} }
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
int encoding)
{
if (mi.isValid())
data.valuetooltip = decodeData(mi.data(), encoding);
}
void WatchData::updateChildCount(const GdbMi &mi) void WatchData::updateChildCount(const GdbMi &mi)
{ {
if (mi.isValid()) if (mi.isValid())
@@ -629,6 +626,10 @@ void parseWatchData(const QSet<QByteArray> &expandedINames,
if (mi.isValid()) if (mi.isValid())
data.typeFormats = QString::fromUtf8(mi.data()); data.typeFormats = QString::fromUtf8(mi.data());
mi = item["valueelided"];
if (mi.isValid())
data.elided = mi.toInt();
mi = item["bitpos"]; mi = item["bitpos"];
if (mi.isValid()) if (mi.isValid())
data.bitpos = mi.toInt(); data.bitpos = mi.toInt();

View File

@@ -126,7 +126,6 @@ public:
QString value; // Displayed value QString value; // Displayed value
QByteArray editvalue; // Displayed value QByteArray editvalue; // Displayed value
qint32 editformat; // Format of displayed value qint32 editformat; // Format of displayed value
QString valuetooltip; // Tooltip in value column
QString typeFormats; // Selection of formats of displayed value QString typeFormats; // Selection of formats of displayed value
QByteArray type; // Type for further processing QByteArray type; // Type for further processing
QString displayedType;// Displayed type (optional) QString displayedType;// Displayed type (optional)
@@ -135,6 +134,7 @@ public:
uint size; // Size uint size; // Size
uint bitpos; // Position within bit fields uint bitpos; // Position within bit fields
uint bitsize; // Size in case of bit fields uint bitsize; // Size in case of bit fields
int elided; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise
bool hasChildren; bool hasChildren;
bool valueEnabled; // Value will be enabled or not bool valueEnabled; // Value will be enabled or not
bool valueEditable; // Value will be editable bool valueEditable; // Value will be editable

View File

@@ -695,6 +695,14 @@ QString WatchModel::formattedValue(const WatchData &data) const
} }
} }
if (data.elided) {
QString v = value;
v.chop(1);
QString len = data.elided > 0 ? QString::number(data.elided)
: QLatin1String("unknown length");
return v + QLatin1String("\"... (") + len + QLatin1Char(')');
}
return translate(value); return translate(value);
} }