diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py index 59b7f340bb1d286baab0e20abe78854f383ad1db..e2647d9ec86b528f87e323bc72d6cbc2c6437bee 100644 --- a/share/qtcreator/gdbmacros/dumper.py +++ b/share/qtcreator/gdbmacros/dumper.py @@ -32,8 +32,8 @@ def isGoodGdb(): return 'parse_and_eval' in dir(gdb) def cleanAddress(addr): - # we cannot use str(addr) as it yields rubbish for char pointers - # that might trigger Unicode encoding errors + # We cannot use str(addr) as it yields rubbish for char pointers + # that might trigger Unicode encoding errors. return addr.cast(gdb.lookup_type("void").pointer()) def parseAndEvaluate(exp): @@ -50,17 +50,27 @@ def parseAndEvaluate(exp): gdb.execute("set logging off") return gdb.history(0) -def listOfLocals(): +def listOfLocals(varList): try: frame = gdb.selected_frame() #warn("FRAME %s: " % frame) except RuntimeError: + warn("FRAME NOT ACCESSIBLE") return [] + # gdb-6.8-symbianelf fails here + hasBlock = 'block' in dir(frame) + items = [] - if isGoodGdb(): - # archer-tromey-python - block = frame.block() + if hasBlock and isGoodGdb(): + warn("IS GOOD: %s " % varList) + try: + block = frame.block() + #warn("BLOCK: %s " % block) + except: + warn("BLOCK NOT ACCESSIBLE") + return items + while True: if block is None: warn("UNEXPECTED 'None' BLOCK") @@ -94,31 +104,55 @@ def listOfLocals(): # Assuming gdb 7.0 release or 6.8-symbianelf. file = tempfile.mkstemp(prefix="gdbpy_") filename = file[1] + #warn("VARLIST: %s " % varList) + #warn("VARLIST: %s " % len(varList)) gdb.execute("set logging off") gdb.execute("set logging redirect off") gdb.execute("set logging file %s" % filename) gdb.execute("set logging redirect on") gdb.execute("set logging on") - gdb.execute("info locals") - gdb.execute("info args") + try: + gdb.execute("info args") + # We cannot use "info locals" as at least 6.8-symbianelf + # aborts as soon as we hit unreadable memory. + # gdb.execute("interpreter mi '-stack-list-locals 0'") + # results in &"Recursive internal problem.\n", so we have + # the frontend pass us the list of locals. + + # There are two cases, either varList is empty, so we have + # to fetch the list here, or it is not empty with the + # first entry being a dummy. + if len(varList) == 0: + gdb.execute("info locals") + else: + varList = varList[1:] + except: + pass gdb.execute("set logging off") gdb.execute("set logging redirect off") + file = open(filename, "r") for line in file: if len(line) == 0 or line.startswith(" "): continue + # The function parameters pos = line.find(" = ") if pos < 0: continue - name = line[0:pos] + varList.append(line[0:pos]) + file.close() + os.remove(filename) + + #warn("VARLIST: %s " % varList) + for name in varList: + #warn("NAME %s " % name) item = Item(0, "local", name, name) try: item.value = frame.read_var(name) # this is a gdb value except RuntimeError: - continue + pass + #continue items.append(item) - file.close() - os.remove(filename) return items @@ -155,8 +189,8 @@ def isStringType(d, typeobj): or type == "wstring" def warn(message): - if verbosity > 0: - print "XXX: %s " % message.encode("latin1") + if True or verbosity > 0: + print "XXX: %s\n" % message.encode("latin1") pass def check(exp): @@ -317,13 +351,24 @@ class FrameCommand(gdb.Command): def invoke(self, arg, from_tty): args = arg.split(' ') + #warn("ARG: %s" % arg) #warn("ARGS: %s" % args) options = args[0].split(",") + varList = args[1][1:] + if len(varList) == 0: + varList = [] + else: + varList = varList.split(",") + expandedINames = set(args[2].split(",")) + watchers = "" + if len(args) > 3: + watchers = base64.b16decode(args[3], True) + #warn("WATCHERS: %s" % watchers) + useFancy = "fancy" in options - expandedINames = set() - if len(args) > 1: - expandedINames = set(args[1].split(",")) + + #warn("VARIABLES: %s" % varList) #warn("EXPANDED INAMES: %s" % expandedINames) module = sys.modules[__name__] self.dumpers = {} @@ -337,7 +382,7 @@ class FrameCommand(gdb.Command): output += '"' + key[7:] + '"' output += "]," #output += "qtversion=[%d,%d,%d]" - output += "qtversion=[4,6,0]," + #output += "qtversion=[4,6,0]," output += "namespace=\"%s\"," % qtNamespace() output += "dumperversion=\"2.0\"," output += "sizes=[]," @@ -349,7 +394,6 @@ class FrameCommand(gdb.Command): if useFancy: for key, value in module.__dict__.items(): - #if callable(value): if key.startswith("qdump__"): self.dumpers[key[7:]] = value @@ -365,14 +409,28 @@ class FrameCommand(gdb.Command): # # Locals # - for item in listOfLocals(): + for item in listOfLocals(varList): #warn("ITEM NAME %s: " % item.name) - #warn("ITEM VALUE %s: " % item.value) + try: + #warn("ITEM VALUE %s: " % item.value) + # Throw on funny stuff, catch below. + dummy = str(item.value) + except: + # Locals with failing memory access. + d.beginHash() + d.put('iname="%s",' % item.iname) + d.put('name="%s",' % item.name) + d.put('addr="<not accessible>",') + d.put('value="<not accessible>",') + d.put('type="%s",' % item.value.type) + d.put('numchild="0"'); + d.endHash() + continue type = item.value.type if type.code == gdb.TYPE_CODE_PTR \ and item.name == "argv" and str(type) == "char **": - # Special handling for char** argv: + # Special handling for char** argv. n = 0 p = item.value while not isNull(p.dereference()) and n <= 100: @@ -398,7 +456,7 @@ class FrameCommand(gdb.Command): d.endHash() else: - # A "normal" local variable or parameter + # A "normal" local variable or parameter. try: addr = cleanAddress(item.value.address) d.beginHash() @@ -407,9 +465,8 @@ class FrameCommand(gdb.Command): d.safePutItemHelper(item) d.endHash() except AttributeError: - # thrown by cleanAddreas with message - # "'NoneType' object has no attribute 'cast'" - # for optimized-out values + # Thrown by cleanAddress with message "'NoneType' object + # has no attribute 'cast'" for optimized-out values. d.beginHash() d.put('iname="%s",' % item.iname) d.put('name="%s",' % item.name) @@ -426,9 +483,6 @@ class FrameCommand(gdb.Command): # Watchers # d.safeoutput = "" - watchers = "" - if len(args) > 2: - watchers = base64.b16decode(args[2], True) if len(watchers) > 0: for watcher in watchers.split("##"): (exp, iname) = watcher.split("#") @@ -764,7 +818,8 @@ class Dumper: #warn("REAL VALUE: %s " % item.value) #try: # warn("REAL VALUE: %s " % item.value) - #except UnicodeEncodeError: + #except: + # #UnicodeEncodeError: # warn("REAL VALUE: <unprintable>") value = item.value diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 61ad74dcd4ea1884bf125e6514df23871e86813b..9450c741993872c1e4a926ee15d46e7c2e88f5cf 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -743,7 +743,7 @@ void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags, void GdbEngine::postCommandHelper(const GdbCommand &cmd) { if (!stateAcceptsGdbCommands(state())) { - PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + cmd.command); + PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command)); debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2") .arg(_(cmd.command)).arg(state())); return; @@ -1019,6 +1019,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command) // Called from CoreAdapter and AttachAdapter void GdbEngine::updateAll() { + PENDING_DEBUG("UPDATING ALL\n"); QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/); tryLoadDebuggingHelpers(); reloadModulesInternal(); @@ -2469,12 +2470,14 @@ void GdbEngine::handleStackSelectThread(const GdbResponse &) void GdbEngine::reloadFullStack() { + PENDING_DEBUG("RELOAD FULL STACK"); postCommand("-stack-list-frames", WatchUpdate, CB(handleStackListFrames), QVariant::fromValue<StackCookie>(StackCookie(true, true))); } void GdbEngine::reloadStack(bool forceGotoLocation) { + PENDING_DEBUG("RELOAD STACK"); QByteArray cmd = "-stack-list-frames"; int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt(); if (stackDepth && !m_gdbAdapter->isTrkAdapter()) @@ -2485,6 +2488,7 @@ void GdbEngine::reloadStack(bool forceGotoLocation) // access the memory belonging to the lower frames. But as we know // this sometimes happens, ask the second time immediately instead // of waiting for the first request to fail. + // FIXME: Seems to work with 6.8. if (m_gdbAdapter->isTrkAdapter()) postCommand(cmd, WatchUpdate); postCommand(cmd, WatchUpdate, CB(handleStackListFrames), @@ -3640,52 +3644,12 @@ void GdbEngine::updateLocals(const QVariant &cookie) { m_pendingRequests = 0; if (isSynchroneous()) { - m_processedNames.clear(); - manager()->watchHandler()->beginCycle(); - //m_toolTipExpression.clear(); - WatchHandler *handler = m_manager->watchHandler(); - - QByteArray expanded; - QSet<QByteArray> expandedINames = handler->expandedINames(); - QSetIterator<QByteArray> jt(expandedINames); - while (jt.hasNext()) { - expanded.append(jt.next()); - expanded.append(','); - } - if (expanded.isEmpty()) - expanded.append("defaults,"); - expanded.chop(1); - - QByteArray watchers; - if (!m_toolTipExpression.isEmpty()) - watchers += m_toolTipExpression.toLatin1() - + "#" + tooltipINameForExpression(m_toolTipExpression.toLatin1()); - - QHash<QByteArray, int> watcherNames = handler->watcherNames(); - QHashIterator<QByteArray, int> it(watcherNames); - while (it.hasNext()) { - it.next(); - if (!watchers.isEmpty()) - watchers += "##"; - if (it.key() == WatchHandler::watcherEditPlaceHolder().toLatin1()) - watchers += "<Edit>#watch." + QByteArray::number(it.value()); - else - watchers += it.key() + "#watch." + QByteArray::number(it.value()); + if (m_gdbAdapter->isTrkAdapter()) { + postCommand("-stack-list-locals 0", + WatchUpdate, CB(handleStackListLocals0)); + } else { + updateLocalsSync(QByteArray()); } - - QByteArray options; - if (theDebuggerBoolSetting(UseDebuggingHelpers)) - options += "fancy,"; - if (theDebuggerBoolSetting(AutoDerefPointers)) - options += "autoderef,"; - if (options.isEmpty()) - options += "defaults,"; - options.chop(1); - - postCommand("-interpreter-exec console \"bb " - + options + ' ' + expanded + ' ' + watchers.toHex() + '"', - Discardable, - CB(handleStackFrame)); } else { m_processedNames.clear(); @@ -3710,6 +3674,69 @@ void GdbEngine::updateLocals(const QVariant &cookie) } } +void GdbEngine::handleStackListLocals0(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + // 44^done,data={locals=[name="model",name="backString",...]} + QByteArray varList = "vars"; // Dummy entry, will be stripped by dumper. + foreach (const GdbMi &child, response.data.findChild("locals").children()) { + varList.append(','); + varList.append(child.data()); + } + updateLocalsSync(varList); + } +} + +void GdbEngine::updateLocalsSync(const QByteArray &varList) +{ + m_processedNames.clear(); + manager()->watchHandler()->beginCycle(); + //m_toolTipExpression.clear(); + WatchHandler *handler = m_manager->watchHandler(); + + QByteArray expanded; + QSet<QByteArray> expandedINames = handler->expandedINames(); + QSetIterator<QByteArray> jt(expandedINames); + while (jt.hasNext()) { + expanded.append(jt.next()); + expanded.append(','); + } + if (expanded.isEmpty()) + expanded.append("defaults,"); + expanded.chop(1); + + QByteArray watchers; + if (!m_toolTipExpression.isEmpty()) + watchers += m_toolTipExpression.toLatin1() + + "#" + tooltipINameForExpression(m_toolTipExpression.toLatin1()); + + QHash<QByteArray, int> watcherNames = handler->watcherNames(); + QHashIterator<QByteArray, int> it(watcherNames); + while (it.hasNext()) { + it.next(); + if (!watchers.isEmpty()) + watchers += "##"; + if (it.key() == WatchHandler::watcherEditPlaceHolder().toLatin1()) + watchers += "<Edit>#watch." + QByteArray::number(it.value()); + else + watchers += it.key() + "#watch." + QByteArray::number(it.value()); + } + + QByteArray options; + if (theDebuggerBoolSetting(UseDebuggingHelpers)) + options += "fancy,"; + if (theDebuggerBoolSetting(AutoDerefPointers)) + options += "autoderef,"; + if (options.isEmpty()) + options += "defaults,"; + options.chop(1); + + postCommand("bb " + options + " @" + varList + ' ' + + expanded + ' ' + watchers.toHex(), + WatchUpdate, CB(handleStackFrame)); +} + + void GdbEngine::handleStackFrame(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index e7fb08ab2015d2b40c2a1a73ec86a49fcf87e020..8123827b6345d527f586bf89faa828fce5997da2 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -450,6 +450,7 @@ private: ////////// View & Data Stuff ////////// void updateLocals(const QVariant &cookie = QVariant()); void handleStackListLocals(const GdbResponse &response); + void handleStackListLocals0(const GdbResponse &response); WatchData localVariable(const GdbMi &item, const QStringList &uninitializedVariables, QMap<QByteArray, int> *seen); @@ -484,6 +485,8 @@ private: ////////// Convenience Functions ////////// int buttons = 0); void debugMessage(const QString &msg); QMainWindow *mainWindow() const; + + void updateLocalsSync(const QByteArray &varList); }; } // namespace Internal