From 9df463da848b1d9cff6900594afa6855d10f39ae Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 11 Feb 2015 17:51:15 +0100 Subject: [PATCH] Debugger: Convert bb extension to use runCommand Change-Id: I528c51d2b02dccd91429778ef8c940fe5565345f Reviewed-by: Christian Stenger --- share/qtcreator/debugger/gdbbridge.py | 177 +++++++++---------------- src/plugins/debugger/gdb/gdbengine.cpp | 82 +++++------- src/plugins/debugger/gdb/gdbengine.h | 2 +- tests/auto/debugger/tst_dumpers.cpp | 9 +- 4 files changed, 104 insertions(+), 166 deletions(-) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 1a65ae10cdb..ac3ac5e3879 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -208,22 +208,6 @@ def stripTypedefs(typeobj): return typeobj -####################################################################### -# -# Frame Command -# -####################################################################### - - -def bb(args): - try: - print(theDumper.run(args)) - except: - import traceback - traceback.print_exc() - -registerCommand("bb", bb) - ####################################################################### # # The Dumper Class @@ -236,7 +220,7 @@ class Dumper(DumperBase): def __init__(self): DumperBase.__init__(self) - # These values will be kept between calls to 'run'. + # These values will be kept between calls to 'showData'. self.isGdb = True self.childEventAddress = None self.typesReported = {} @@ -256,60 +240,40 @@ class Dumper(DumperBase): self.currentValue = ReportItem() self.currentType = ReportItem() self.currentAddress = None - self.typeformats = {} - self.formats = {} - self.useDynamicType = True - self.expandedINames = {} - self.qmlcontext = "" - # The guess does not need to be updated during a run() + # The guess does not need to be updated during a showData() # as the result is fixed during that time (ignoring "active" # dumpers causing loading of shared objects etc). self.currentQtNamespaceGuess = None - self.watchers = "" - self.resultVarName = "" - self.varList = [] - self.options = [] + self.varList = args.get("vars", []) + self.resultVarName = args.get("resultvarname", "") + self.expandedINames = set(args.get("expanded", [])) + self.stringCutOff = int(args.get("stringcutoff", 10000)) + self.displayStringLimit = int(args.get("displaystringlimit", 10000)) - for arg in args.split(' '): - pos = arg.find(":") + 1 - if arg.startswith("options:"): - self.options = arg[pos:].split(",") - elif arg.startswith("vars:"): - if len(arg[pos:]) > 0: - self.varList = arg[pos:].split(",") - elif arg.startswith("resultvarname:"): - self.resultVarName = arg[pos:] - elif arg.startswith("expanded:"): - self.expandedINames = set(arg[pos:].split(",")) - elif arg.startswith("stringcutoff:"): - self.stringCutOff = int(arg[pos:]) - elif arg.startswith("displaystringlimit:"): - self.displayStringLimit = int(arg[pos:]) - elif arg.startswith("typeformats:"): - for f in arg[pos:].split(","): - pos = f.find("=") - if pos != -1: - typeName = self.hexdecode(f[0:pos]) - self.typeformats[typeName] = int(f[pos+1:]) - elif arg.startswith("formats:"): - for f in arg[pos:].split(","): - pos = f.find("=") - if pos != -1: - self.formats[f[0:pos]] = int(f[pos+1:]) - elif arg.startswith("watchers:"): - self.watchers = self.hexdecode(arg[pos:]) - elif arg.startswith("qmlcontext:"): - self.qmlcontext = int(arg[pos:], 0) + self.typeformats = {} + for f in args.get("typeformats", "").split(","): + pos = f.find("=") + if pos != -1: + typeName = self.hexdecode(f[0:pos]) + self.typeformats[typeName] = int(f[pos+1:]) - self.useDynamicType = "dyntype" in self.options - self.useFancy = "fancy" in self.options - self.forceQtNamespace = "forcens" in self.options - self.passExceptions = "pe" in self.options - self.nativeMixed = "nativemixed" in self.options - self.autoDerefPointers = "autoderef" in self.options - self.partialUpdate = "partial" in self.options + self.formats = {} + for f in args.get("formats", "").split(","): + pos = f.find("=") + if pos != -1: + self.formats[f[0:pos]] = int(f[pos+1:]) + + self.watchers = args.get("watchers", {}) + self.qmlcontext = int(args.get("qmlcontext", "0")) + self.useDynamicType = int(args.get("dyntype", "0")) + self.useFancy = int(args.get("fancy", "0")) + self.forceQtNamespace = int(args.get("forcens", "0")) + self.passExceptions = int(args.get("passExceptions", "0")) + self.nativeMixed = int(args.get("nativemixed", "0")) + self.autoDerefPointers = int(args.get("autoderef", "0")) + self.partialUpdate = int(args.get("partial", "0")) self.fallbackQtVersion = 0x50200 #warn("NAMESPACE: '%s'" % self.qtNamespace()) #warn("VARIABLES: %s" % self.varList) @@ -319,10 +283,10 @@ class Dumper(DumperBase): def handleWatches(self): with OutputSafer(self): - if len(self.watchers) > 0: - for watcher in self.watchers.split("##"): - (exp, iname) = watcher.split("#") - self.handleWatch(exp, exp, iname) + for watcher in self.watchers: + iname = watcher['iname'] + exp = self.hexdecode(watcher['exp']) + self.handleWatch(exp, exp, iname) def listOfLocals(self): frame = gdb.selected_frame() @@ -405,7 +369,7 @@ class Dumper(DumperBase): return items - def run(self, args): + def showData(self, args): self.prepare(args) # @@ -481,14 +445,13 @@ class Dumper(DumperBase): self.output.append(']') self.typesToReport = {} - if "forcens" in self.options: + if self.forceQtNamespace: self.qtNamepaceToReport = self.qtNamespace() if self.qtNamespaceToReport: self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport) self.qtNamespaceToReport = None - - return "".join(self.output) + print(''.join(self.output)) def enterSubItem(self, item): if not item.iname: @@ -1619,8 +1582,11 @@ class Dumper(DumperBase): if limit <= 0: limit = 10000 options = args['options'] + opts = {} + if options == "nativemixed": + opts["nativemixed"] = 1 - self.prepare("options:" + options + ",pe") + self.prepare(opts) self.output = [] frame = gdb.newest_frame() @@ -1699,6 +1665,21 @@ class Dumper(DumperBase): matplotQuit() gdb.execute("quit") + def profile1(self, args): + """Internal profiling""" + import tempfile + import cProfile + tempDir = tempfile.gettempdir() + "/bbprof" + cProfile.run('theDumper.showData(%s)' % args, tempDir) + import pstats + pstats.Stats(tempDir).sort_stats('time').print_stats() + + def profile2(self, args): + import timeit + print(timeit.repeat('theDumper.showData(%s)' % args, + 'from __main__ import theDumper', number=10)) + + class CliDumper(Dumper): def __init__(self): @@ -1788,7 +1769,7 @@ class CliDumper(Dumper): def putAddressRange(self, base, step): return True - def run(self, args): + def showData(self, args): arglist = args.split(' ') name = '' if len(arglist) >= 1: @@ -1797,7 +1778,12 @@ class CliDumper(Dumper): if len(arglist) >= 2: for sub in arglist[1].split(','): allexpanded.append(name + '.' + sub) - self.prepare("options:fancy,pe,autoderef expanded:" + ','.join(allexpanded)) + pars = {} + pars['fancy': 1] + pars['passException': 1] + pars['autoderef': 1] + pars['expanded': allexpanded] + self.prepare(pars) self.output = name + ' = ' frame = gdb.selected_frame() value = frame.read_var(name) @@ -1805,12 +1791,6 @@ class CliDumper(Dumper): self.putItem(value) return self.output -def pp(args): - return theDumper.run(args) - -registerCommand("pp", pp) - - # Global instance. if gdb.parameter('height') is None: theDumper = Dumper() @@ -1818,40 +1798,7 @@ else: import codecs theDumper = CliDumper() -####################################################################### -# -# Internal profiling -# -####################################################################### - -def p1(args): - import tempfile - import cProfile - tempDir = tempfile.gettempdir() + "/bbprof" - cProfile.run('bb("%s")' % args, tempDir) - import pstats - pstats.Stats(tempDir).sort_stats('time').print_stats() - return "" - -registerCommand("p1", p1) - -def p2(args): - import timeit - return timeit.repeat('bb("%s")' % args, - 'from __main__ import bb', number=10) - -registerCommand("p2", p2) - -def p3(args): - eval(args) - -def p3(args): - import timeit - return timeit.repeat('p3("%s")' % args, 'from __main__ import p3', number=10000) - -registerCommand("p3", p3) - -####################################################################### +###################################################################### # # ThreadNames Command # diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 335e1839c7b..2f98a4008d6 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4723,7 +4723,7 @@ QByteArray GdbEngine::dotEscape(QByteArray str) void GdbEngine::debugLastCommand() { - postCommand(m_lastDebuggableCommand, Discardable); + runCommand(m_lastDebuggableCommand); } // @@ -4761,73 +4761,59 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms) m_processedNames.clear(); WatchHandler *handler = watchHandler(); - QByteArray expanded = "expanded:" + handler->expansionRequests() + ' '; - expanded += "typeformats:" + handler->typeFormatRequests() + ' '; - expanded += "formats:" + handler->individualFormatRequests(); - QByteArray cutOff = " stringcutoff:" - + action(MaximalStringLength)->value().toByteArray() - + " displaystringlimit:" - + action(DisplayStringLimit)->value().toByteArray(); + DebuggerCommand cmd("showData"); + cmd.arg("expanded", handler->expansionRequests()); + cmd.arg("typeformats", handler->typeFormatRequests()); + cmd.arg("formats", handler->individualFormatRequests()); + + cmd.arg("stringcutoff", action(MaximalStringLength)->value().toByteArray()); + cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toByteArray()); // Re-create tooltip items that are not filters on existing local variables in // the tooltip model. - QByteArray watchers; + cmd.beginList("watchers"); DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this); foreach (const DebuggerToolTipContext &p, toolTips) { - if (!watchers.isEmpty()) - watchers += "##"; - watchers += p.expression.toLatin1(); - watchers += '#'; - watchers += p.iname; + cmd.beginGroup(); + cmd.arg("iname", p.iname); + cmd.arg("exp", p.expression.toLatin1().toHex()); + cmd.endGroup(); } - QHash watcherNames = handler->watcherNames(); - QHashIterator it(watcherNames); + QHashIterator it(WatchHandler::watcherNames()); while (it.hasNext()) { it.next(); - if (!watchers.isEmpty()) - watchers += "##"; - watchers += it.key() + "#watch." + QByteArray::number(it.value()); + cmd.beginGroup(); + cmd.arg("iname", "watch." + QByteArray::number(it.value())); + cmd.arg("exp", it.key().toHex()); + cmd.endGroup(); } + cmd.endList(); const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty(); - QByteArray options; - if (alwaysVerbose) - options += "pe,"; - if (boolSetting(UseDebuggingHelpers)) - options += "fancy,"; - if (boolSetting(AutoDerefPointers)) - options += "autoderef,"; - if (boolSetting(UseDynamicType)) - options += "dyntype,"; - if (isNativeMixedActive()) - options += "nativemixed,"; - if (options.isEmpty()) - options += "defaults,"; - if (params.tryPartial) - options += "partial,"; - options.chop(1); - QByteArray context; + cmd.arg("passExceptions", alwaysVerbose); + cmd.arg("fancy", boolSetting(UseDebuggingHelpers)); + cmd.arg("autoderef", boolSetting(AutoDerefPointers)); + cmd.arg("dyntype", boolSetting(UseDynamicType)); + cmd.arg("nativemixed", isNativeMixedActive()); + cmd.arg("partial", params.tryPartial); + if (isNativeMixedActive()) { StackFrame frame = stackHandler()->currentFrame(); if (frame.language == QmlLanguage) - context += " qmlcontext:0x" + QByteArray::number(frame.address, 16); + cmd.arg("qmlcontext", "0x" + QByteArray::number(frame.address, 16)); } - QByteArray resultVar; - if (!m_resultVarName.isEmpty()) - resultVar = "resultvarname:" + m_resultVarName + ' '; + cmd.arg("resultvarname", m_resultVarName); + cmd.arg("vars", params.varList); + cmd.flags = Discardable; + cmd.callback = [this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); }; + runCommand(cmd); - m_lastDebuggableCommand = - "bb options:pe," + options + " vars:" + params.varList + ' ' - + expanded + " watchers:" + watchers.toHex() + cutOff + context; - - postCommand("bb options:" + options + " vars:" + params.varList + ' ' - + resultVar + expanded + " watchers:" + watchers.toHex() + cutOff + context, - Discardable, - [this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); }); + cmd.arg("passExceptions", true); + m_lastDebuggableCommand = cmd; } void GdbEngine::handleStackFramePython(const DebuggerResponse &response, bool partial) diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 24130b6168d..39de6fdfa32 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -486,7 +486,7 @@ protected: static QByteArray dotEscape(QByteArray str); void debugLastCommand(); - QByteArray m_lastDebuggableCommand; + DebuggerCommand m_lastDebuggableCommand; protected: virtual void write(const QByteArray &data); diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 4ac7ac67790..b1c4d75b1ed 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1204,10 +1204,14 @@ void tst_Dumpers::dumper() } QByteArray expanded; + QByteArray expandedq; foreach (const QByteArray &iname, expandedINames) { - if (!expanded.isEmpty()) + if (!expanded.isEmpty()) { expanded.append(','); + expandedq.append(','); + } expanded += iname; + expandedq += '\'' + iname + '\''; } QByteArray exe = m_debuggerBinary; @@ -1238,7 +1242,8 @@ void tst_Dumpers::dumper() "python from gdbbridge import *\n" "python theDumper.setupDumper()\n" "run " + nograb + "\n" - "bb options:fancy,forcens,autoderef,dyntype,pe vars: expanded:" + expanded + " typeformats:\n"; + "python theDumper.showData({'fancy':1,'forcens':1,'autoderef':1," + "'dyntype':1,'passExceptions':1,'expanded':[" + expandedq + "]})\n"; cmds += "quit\n";