forked from qt-creator/qt-creator
Debugger: Avoid quadratic behavior for larger debug output
Task-number: QTCREATORBUG-28111 Change-Id: I0567b6af9f74c2d335d19a52765834ef7cee9449 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -353,9 +353,6 @@ class Dumper(DumperBase):
|
|||||||
self.ptrSize = lambda: size
|
self.ptrSize = lambda: size
|
||||||
return size
|
return size
|
||||||
|
|
||||||
def put(self, stuff):
|
|
||||||
self.output += stuff
|
|
||||||
|
|
||||||
def stripQintTypedefs(self, typeName):
|
def stripQintTypedefs(self, typeName):
|
||||||
if typeName.startswith('qint'):
|
if typeName.startswith('qint'):
|
||||||
prefix = ''
|
prefix = ''
|
||||||
@@ -423,7 +420,7 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
self.setVariableFetchingOptions(args)
|
self.setVariableFetchingOptions(args)
|
||||||
|
|
||||||
self.output = ''
|
self.output = []
|
||||||
|
|
||||||
self.currentIName = 'local'
|
self.currentIName = 'local'
|
||||||
self.put('data=[')
|
self.put('data=[')
|
||||||
@@ -445,10 +442,11 @@ class Dumper(DumperBase):
|
|||||||
self.qtNamespaceToReport = self.qtNamespace()
|
self.qtNamespaceToReport = self.qtNamespace()
|
||||||
|
|
||||||
if self.qtNamespaceToReport:
|
if self.qtNamespaceToReport:
|
||||||
self.output += ',qtnamespace="%s"' % self.qtNamespaceToReport
|
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
||||||
self.qtNamespaceToReport = None
|
self.qtNamespaceToReport = None
|
||||||
|
|
||||||
self.reportResult(self.output, args)
|
self.reportResult(''.join(self.output), args)
|
||||||
|
self.output = []
|
||||||
|
|
||||||
def report(self, stuff):
|
def report(self, stuff):
|
||||||
sys.stdout.write(stuff + "\n")
|
sys.stdout.write(stuff + "\n")
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class Children():
|
|||||||
self.d.currentNumChild = self.savedNumChild
|
self.d.currentNumChild = self.savedNumChild
|
||||||
self.d.currentMaxNumChild = self.savedMaxNumChild
|
self.d.currentMaxNumChild = self.savedMaxNumChild
|
||||||
if self.d.isCli:
|
if self.d.isCli:
|
||||||
self.d.output += '\n' + ' ' * self.d.indent
|
self.d.put('\n' + ' ' * self.d.indent)
|
||||||
self.d.put(self.d.childrenSuffix)
|
self.d.put(self.d.childrenSuffix)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ class DumperBase():
|
|||||||
self.displayStringLimit = 100
|
self.displayStringLimit = 100
|
||||||
self.useTimeStamps = False
|
self.useTimeStamps = False
|
||||||
|
|
||||||
self.output = ''
|
self.output = []
|
||||||
self.typesReported = {}
|
self.typesReported = {}
|
||||||
self.typesToReport = {}
|
self.typesToReport = {}
|
||||||
self.qtNamespaceToReport = None
|
self.qtNamespaceToReport = None
|
||||||
@@ -309,9 +309,9 @@ class DumperBase():
|
|||||||
self.putField('name', item.name)
|
self.putField('name', item.name)
|
||||||
else:
|
else:
|
||||||
self.indent += 1
|
self.indent += 1
|
||||||
self.output += '\n' + ' ' * self.indent
|
self.put('\n' + ' ' * self.indent)
|
||||||
if isinstance(item.name, str):
|
if isinstance(item.name, str):
|
||||||
self.output += item.name + ' = '
|
self.put(item.name + ' = ')
|
||||||
item.savedIName = self.currentIName
|
item.savedIName = self.currentIName
|
||||||
item.savedValue = self.currentValue
|
item.savedValue = self.currentValue
|
||||||
item.savedType = self.currentType
|
item.savedType = self.currentType
|
||||||
@@ -869,7 +869,12 @@ class DumperBase():
|
|||||||
self.putPlainChildren(value)
|
self.putPlainChildren(value)
|
||||||
|
|
||||||
def put(self, stuff):
|
def put(self, stuff):
|
||||||
self.output += stuff
|
self.output.append(stuff)
|
||||||
|
|
||||||
|
def takeOutput(self):
|
||||||
|
res = '\n'.join(self.output)
|
||||||
|
self.output = []
|
||||||
|
return res
|
||||||
|
|
||||||
def check(self, exp):
|
def check(self, exp):
|
||||||
if not exp:
|
if not exp:
|
||||||
|
|||||||
@@ -175,24 +175,6 @@ def importPlainDumpers(args):
|
|||||||
registerCommand('importPlainDumpers', importPlainDumpers)
|
registerCommand('importPlainDumpers', importPlainDumpers)
|
||||||
|
|
||||||
|
|
||||||
class OutputSaver():
|
|
||||||
def __init__(self, d):
|
|
||||||
self.d = d
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.savedOutput = self.d.output
|
|
||||||
self.d.output = ''
|
|
||||||
|
|
||||||
def __exit__(self, exType, exValue, exTraceBack):
|
|
||||||
if self.d.passExceptions and exType is not None:
|
|
||||||
self.d.showException('OUTPUTSAVER', exType, exValue, exTraceBack)
|
|
||||||
self.d.output = self.savedOutput
|
|
||||||
else:
|
|
||||||
self.savedOutput += self.d.output
|
|
||||||
self.d.output = self.savedOutput
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
#
|
#
|
||||||
# The Dumper Class
|
# The Dumper Class
|
||||||
@@ -214,7 +196,7 @@ class Dumper(DumperBase):
|
|||||||
self.interpreterBreakpointResolvers = []
|
self.interpreterBreakpointResolvers = []
|
||||||
|
|
||||||
def prepare(self, args):
|
def prepare(self, args):
|
||||||
self.output = ''
|
self.output = []
|
||||||
self.setVariableFetchingOptions(args)
|
self.setVariableFetchingOptions(args)
|
||||||
|
|
||||||
def fromFrameValue(self, nativeValue):
|
def fromFrameValue(self, nativeValue):
|
||||||
@@ -690,7 +672,7 @@ class Dumper(DumperBase):
|
|||||||
safePrint(res)
|
safePrint(res)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.output += 'data=['
|
self.put('data=[')
|
||||||
|
|
||||||
partialVar = args.get('partialvar', '')
|
partialVar = args.get('partialvar', '')
|
||||||
isPartial = len(partialVar) > 0
|
isPartial = len(partialVar) > 0
|
||||||
@@ -713,27 +695,26 @@ class Dumper(DumperBase):
|
|||||||
self.handleLocals(variables)
|
self.handleLocals(variables)
|
||||||
self.handleWatches(args)
|
self.handleWatches(args)
|
||||||
|
|
||||||
self.output += '],typeinfo=['
|
self.put('],typeinfo=[')
|
||||||
for name in self.typesToReport.keys():
|
for name in self.typesToReport.keys():
|
||||||
typeobj = self.typesToReport[name]
|
typeobj = self.typesToReport[name]
|
||||||
# Happens e.g. for '(anonymous namespace)::InsertDefOperation'
|
# Happens e.g. for '(anonymous namespace)::InsertDefOperation'
|
||||||
#if not typeobj is None:
|
#if not typeobj is None:
|
||||||
# self.output.append('{name="%s",size="%s"}'
|
# self.put('{name="%s",size="%s"}' % (self.hexencode(name), typeobj.sizeof))
|
||||||
# % (self.hexencode(name), typeobj.sizeof))
|
self.put(']')
|
||||||
self.output += ']'
|
|
||||||
self.typesToReport = {}
|
self.typesToReport = {}
|
||||||
|
|
||||||
if self.forceQtNamespace:
|
if self.forceQtNamespace:
|
||||||
self.qtNamespaceToReport = self.qtNamespace()
|
self.qtNamespaceToReport = self.qtNamespace()
|
||||||
|
|
||||||
if self.qtNamespaceToReport:
|
if self.qtNamespaceToReport:
|
||||||
self.output += ',qtnamespace="%s"' % self.qtNamespaceToReport
|
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
||||||
self.qtNamespaceToReport = None
|
self.qtNamespaceToReport = None
|
||||||
|
|
||||||
self.output += ',partial="%d"' % isPartial
|
self.put(',partial="%d"' % isPartial)
|
||||||
self.output += ',counts=%s' % self.counts
|
self.put(',counts=%s' % self.counts)
|
||||||
self.output += ',timings=%s' % self.timings
|
self.put(',timings=%s' % self.timings)
|
||||||
self.reportResult(self.output, args)
|
self.reportResult(''.join(self.output), args)
|
||||||
|
|
||||||
def parseAndEvaluate(self, exp):
|
def parseAndEvaluate(self, exp):
|
||||||
val = self.nativeParseAndEvaluate(exp)
|
val = self.nativeParseAndEvaluate(exp)
|
||||||
@@ -1321,7 +1302,7 @@ class Dumper(DumperBase):
|
|||||||
limit = 10000
|
limit = 10000
|
||||||
|
|
||||||
self.prepare(args)
|
self.prepare(args)
|
||||||
self.output = ''
|
self.output = []
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
if extraQml:
|
if extraQml:
|
||||||
@@ -1375,8 +1356,9 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
frame = gdb.newest_frame()
|
frame = gdb.newest_frame()
|
||||||
self.currentCallContext = None
|
self.currentCallContext = None
|
||||||
|
self.output = []
|
||||||
|
self.put('stack={frames=[')
|
||||||
while i < limit and frame:
|
while i < limit and frame:
|
||||||
with OutputSaver(self):
|
|
||||||
name = frame.name()
|
name = frame.name()
|
||||||
functionName = '??' if name is None else name
|
functionName = '??' if name is None else name
|
||||||
fileName = ''
|
fileName = ''
|
||||||
@@ -1426,7 +1408,8 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
frame = frame.older()
|
frame = frame.older()
|
||||||
i += 1
|
i += 1
|
||||||
self.reportResult('stack={frames=[' + self.output + ']}', args)
|
self.put(']}')
|
||||||
|
self.reportResult(self.takeOutput(), args)
|
||||||
|
|
||||||
def createResolvePendingBreakpointsHookBreakpoint(self, args):
|
def createResolvePendingBreakpointsHookBreakpoint(self, args):
|
||||||
class Resolver(gdb.Breakpoint):
|
class Resolver(gdb.Breakpoint):
|
||||||
@@ -1512,6 +1495,7 @@ class Dumper(DumperBase):
|
|||||||
onHit=self.tracepointHit,
|
onHit=self.tracepointHit,
|
||||||
onExpression=lambda tp, expr, val: self.tracepointExpression(tp, expr, val, args))
|
onExpression=lambda tp, expr, val: self.tracepointExpression(tp, expr, val, args))
|
||||||
self.reportResult("tracepoint=%s" % self.resultToMi(tp.dicts()), args)
|
self.reportResult("tracepoint=%s" % self.resultToMi(tp.dicts()), args)
|
||||||
|
|
||||||
class CliDumper(Dumper):
|
class CliDumper(Dumper):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Dumper.__init__(self)
|
Dumper.__init__(self)
|
||||||
@@ -1559,16 +1543,18 @@ class CliDumper(Dumper):
|
|||||||
self.expandableINames = set()
|
self.expandableINames = set()
|
||||||
self.prepare(args)
|
self.prepare(args)
|
||||||
|
|
||||||
self.output = name + ' = '
|
self.output = []
|
||||||
|
self.put(name + ' = ')
|
||||||
value = self.parseAndEvaluate(name)
|
value = self.parseAndEvaluate(name)
|
||||||
with TopLevelItem(self, name):
|
with TopLevelItem(self, name):
|
||||||
self.putItem(value)
|
self.putItem(value)
|
||||||
|
|
||||||
if not self.expandableINames:
|
if not self.expandableINames:
|
||||||
return self.output + '\n\nNo drill down available.\n'
|
self.put('\n\nNo drill down available.\n')
|
||||||
|
return self.takeOutput()
|
||||||
|
|
||||||
pattern = ' pp ' + name + ' ' + '%s'
|
pattern = ' pp ' + name + ' ' + '%s'
|
||||||
return (self.output
|
return (self.takeOutput()
|
||||||
+ '\n\nDrill down:\n '
|
+ '\n\nDrill down:\n '
|
||||||
+ '\n '.join(pattern % x for x in self.expandableINames)
|
+ '\n '.join(pattern % x for x in self.expandableINames)
|
||||||
+ '\n')
|
+ '\n')
|
||||||
|
|||||||
@@ -1270,7 +1270,7 @@ class Dumper(DumperBase):
|
|||||||
self.reportResult('error="No frame"', args)
|
self.reportResult('error="No frame"', args)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.output = ''
|
self.output = []
|
||||||
isPartial = len(self.partialVariable) > 0
|
isPartial = len(self.partialVariable) > 0
|
||||||
|
|
||||||
self.currentIName = 'local'
|
self.currentIName = 'local'
|
||||||
@@ -1323,7 +1323,7 @@ class Dumper(DumperBase):
|
|||||||
self.handleWatches(args)
|
self.handleWatches(args)
|
||||||
|
|
||||||
self.put('],partial="%d"' % isPartial)
|
self.put('],partial="%d"' % isPartial)
|
||||||
self.reportResult(self.output, args)
|
self.reportResult(self.takeOutput(), args)
|
||||||
|
|
||||||
|
|
||||||
def fetchRegisters(self, args=None):
|
def fetchRegisters(self, args=None):
|
||||||
@@ -2101,7 +2101,7 @@ class SummaryDumper(Dumper, LogMixin):
|
|||||||
|
|
||||||
self.dumpermodules = ['qttypes']
|
self.dumpermodules = ['qttypes']
|
||||||
self.loadDumpers({})
|
self.loadDumpers({})
|
||||||
self.output = ''
|
self.output = []
|
||||||
|
|
||||||
def report(self, stuff):
|
def report(self, stuff):
|
||||||
return # Don't mess up lldb output
|
return # Don't mess up lldb output
|
||||||
@@ -2123,12 +2123,12 @@ class SummaryDumper(Dumper, LogMixin):
|
|||||||
self.expandedINames = [value.name] if expanded else []
|
self.expandedINames = [value.name] if expanded else []
|
||||||
|
|
||||||
savedOutput = self.output
|
savedOutput = self.output
|
||||||
self.output = ''
|
self.output = []
|
||||||
with TopLevelItem(self, value.name):
|
with TopLevelItem(self, value.name):
|
||||||
self.putItem(value)
|
self.putItem(value)
|
||||||
|
|
||||||
# FIXME: Hook into putField, etc to build up object instead of parsing MI
|
# FIXME: Hook into putField, etc to build up object instead of parsing MI
|
||||||
response = gdbmiparser.parse_response("^ok,summary=%s" % self.output)
|
response = gdbmiparser.parse_response("^ok,summary=%s" % self.takeOutput()))
|
||||||
|
|
||||||
self.output = savedOutput
|
self.output = savedOutput
|
||||||
self.expandedINames = oldExpanded
|
self.expandedINames = oldExpanded
|
||||||
|
|||||||
Reference in New Issue
Block a user