diff --git a/share/qtcreator/dumper/bridge.py b/share/qtcreator/dumper/bridge.py index af91e6196534dfb5ffa618ec0baaa7120abdf992..b95a57d8158736071da0a76d4ab98a6149e423b0 100644 --- a/share/qtcreator/dumper/bridge.py +++ b/share/qtcreator/dumper/bridge.py @@ -559,6 +559,53 @@ try: def fieldCount(type): return type.fieldCount(); + def threadsData(threadsOptions): + result = "threads={threads=[" + for i in range(lldb.process.num_threads): + thread = lldb.process.GetThreadAtIndex(i) + result += "{id=\"%d\"" % thread.id + result += ",target-id=\"%s\"" % thread.id + result += ",stop-reason=\"%s\"" % thread.stop_reason + + if thread.IsSuspended(): + result += ",state=\"stopped\"" + else: + result += ",state=\"running\"" + + if not thread.name is None: + result += ",name=\"%s\"" % thread.name + + result += ",frame={" + frame = thread.GetFrameAtIndex(0) + result += "pc=\"%s\"" % frame.pc + result += ",level=\"%d\"" % i + result += ",addr=\"%s\"" % frame.pc + result += ",fp=\"%s\"" % frame.fp + result += ",func=\"%s\"" % frame.function.name + result += ",line=\"%s\"" % frame.line_entry.line + result += ",fullname=\"%s\"" % frame.line_entry.file + result += ",file=\"%s\"" % frame.line_entry.file + result += "}}," + + result += "],current-thread-id=\"%s\"}" % lldb.process.GetSelectedThread().id + return result + + def stackData(stackOptions): + result = "stack=[" + result += "]," + return result + + def updateData(parts, localsOptions, stackOptions, threadsOptions): + result = ""; + if parts & 1: + result += bb(localsOptions) + ',' + if parts & 2: + result += stackData(stackOptions) + if parts & 4: + result += threadsData(threadsOptions) + return result + + except: #warn("LOADING LLDB FAILED") pass diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 24eb084d4e38cd18827f7b9b32fc7290a962016a..509ed97dda5edd8e72c5059c8e642c2f05459dae 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -43,6 +43,7 @@ #include "registerhandler.h" #include "stackhandler.h" #include "sourceutils.h" +#include "threadshandler.h" #include "watchhandler.h" #include "watchutils.h" @@ -360,13 +361,13 @@ void LldbEngine::activateFrame(int frameIndex) return; postCommand("frame select " + QByteArray::number(frameIndex), - CB(handleUpdateAll)); + CB(triggerUpdateAll)); } void LldbEngine::selectThread(ThreadId threadId) { postCommand("thread select " + QByteArray::number(threadId.raw()), - CB(handleUpdateAll)); + CB(triggerUpdateAll)); } bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const @@ -757,7 +758,7 @@ void LldbEngine::handleFirstCommand(const LldbResponse &response) Q_UNUSED(response); } -void LldbEngine::handleUpdateAll(const LldbResponse &response) +void LldbEngine::triggerUpdateAll(const LldbResponse &response) { Q_UNUSED(response); updateAll(); @@ -765,43 +766,53 @@ void LldbEngine::handleUpdateAll(const LldbResponse &response) void LldbEngine::updateAll() { - //postCommand("bt", CB(handleBacktrace)); - updateLocals(); + updateData(DataKind(LocalsData | StackData | ThreadData)); } -void LldbEngine::updateLocals() +void LldbEngine::updateData(DataKind kind) { - QByteArray watchers; - //if (!m_toolTipExpression.isEmpty()) - // watchers += m_toolTipExpression.toLatin1() - // + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1()); + QByteArray localsOptions; + QByteArray stackOptions; + QByteArray threadsOptions; - WatchHandler *handler = watchHandler(); - QHash<QByteArray, int> watcherNames = handler->watcherNames(); - QHashIterator<QByteArray, int> it(watcherNames); - while (it.hasNext()) { - it.next(); - if (!watchers.isEmpty()) - watchers += "##"; - watchers += it.key() + "#watch." + QByteArray::number(it.value()); - } + if (kind & LocalsData) { + QByteArray watchers; + //if (!m_toolTipExpression.isEmpty()) + // watchers += m_toolTipExpression.toLatin1() + // + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1()); - QByteArray options; - if (debuggerCore()->boolSetting(UseDebuggingHelpers)) - options += "fancy,"; - if (debuggerCore()->boolSetting(AutoDerefPointers)) - options += "autoderef,"; - if (options.isEmpty()) - options += "defaults,"; - options.chop(1); + WatchHandler *handler = watchHandler(); + QHash<QByteArray, int> watcherNames = handler->watcherNames(); + QHashIterator<QByteArray, int> it(watcherNames); + while (it.hasNext()) { + it.next(); + if (!watchers.isEmpty()) + watchers += "##"; + watchers += it.key() + "#watch." + QByteArray::number(it.value()); + } - postCommand("script bb('options:" + options + " " - + "vars: " - + "expanded:" + handler->expansionRequests() + " " - + "typeformats:" + handler->typeFormatRequests() + " " - + "formats:" + handler->individualFormatRequests() + " " - + "watcher:" + watchers.toHex() + "')", - CB(handleListLocals)); + QByteArray options; + if (debuggerCore()->boolSetting(UseDebuggingHelpers)) + options += "fancy,"; + if (debuggerCore()->boolSetting(AutoDerefPointers)) + options += "autoderef,"; + if (options.isEmpty()) + options += "defaults,"; + options.chop(1); + + localsOptions = "options:" + options + " " + + "vars: " + + "expanded:" + handler->expansionRequests() + " " + + "typeformats:" + handler->typeFormatRequests() + " " + + "formats:" + handler->individualFormatRequests() + " " + + "watcher:" + watchers.toHex(); + } + + postCommand("script updateData(" + QByteArray::number(kind) + ',' + + '\'' + localsOptions + "'," + + '\'' + stackOptions + "'," + + '\'' + threadsOptions + "')", + CB(handleUpdateData)); } void LldbEngine::handleBacktrace(const LldbResponse &response) @@ -847,62 +858,69 @@ void LldbEngine::handleBacktrace(const LldbResponse &response) gotoLocation(stackFrames.at(currentIndex)); } - updateLocals(); + updateData(LocalsData); } -void LldbEngine::handleListLocals(const LldbResponse &response) +GdbMi LldbEngine::parseFromString(QByteArray out) { - //qDebug() << " LOCALS: '" << response.data << "'"; - QByteArray out = response.data; + GdbMi all; - { - int pos = out.indexOf("data="); - if (pos == -1) { - showMessage(_("UNEXPECTED LOCALS OUTPUT:" + out)); - return; - } + int pos = out.indexOf("data="); + if (pos == -1) { + showMessage(_("UNEXPECTED LOCALS OUTPUT:" + out)); + return all; + } - // The value in 'out' should be single-quoted as this is - // what the command line does with strings. - if (pos != 1) { - showMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: " - + out.left(pos))); - } - out = out.mid(pos); - if (out.endsWith('\'')) - out.chop(1); - else - showMessage(_("JUNK AT END OF RESPONSE: " + out)); + // The value in 'out' should be single-quoted as this is + // what the command line does with strings. + if (pos != 1) { + showMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: " + + out.left(pos))); } + out = out.mid(pos); + if (out.endsWith('\'')) + out.chop(1); + else + showMessage(_("JUNK AT END OF RESPONSE: " + out)); - GdbMi all; all.fromStringMultiple(out); - GdbMi data = all.findChild("data"); - - const bool partial = response.cookie.toBool(); - WatchHandler *handler = watchHandler(); - QList<WatchData> list; + return all; +} - if (!partial) { - list.append(*handler->findData("local")); - list.append(*handler->findData("watch")); - list.append(*handler->findData("return")); - } +void LldbEngine::handleUpdateData(const LldbResponse &response) +{ + //qDebug() << " LOCALS: '" << response.data << "'"; + GdbMi all = parseFromString(response.data); + + GdbMi vars = all.findChild("data"); + if (vars.isValid()) { + const bool partial = response.cookie.toBool(); + WatchHandler *handler = watchHandler(); + QList<WatchData> list; + + if (!partial) { + list.append(*handler->findData("local")); + list.append(*handler->findData("watch")); + list.append(*handler->findData("return")); + } - foreach (const GdbMi &child, data.children()) { - WatchData dummy; - dummy.iname = child.findChild("iname").data(); - GdbMi wname = child.findChild("wname"); - if (wname.isValid()) { - // Happens (only) for watched expressions. They are encoded as - // base64 encoded 8 bit data, without quotes - dummy.name = decodeData(wname.data(), Base64Encoded8Bit); - dummy.exp = dummy.name.toUtf8(); - } else { - dummy.name = _(child.findChild("name").data()); + foreach (const GdbMi &child, vars.children()) { + WatchData dummy; + dummy.iname = child.findChild("iname").data(); + GdbMi wname = child.findChild("wname"); + if (wname.isValid()) { + // Happens (only) for watched expressions. They are encoded as + // base64 encoded 8 bit data, without quotes + dummy.name = decodeData(wname.data(), Base64Encoded8Bit); + dummy.exp = dummy.name.toUtf8(); + } else { + dummy.name = _(child.findChild("name").data()); + } + parseWatchData(handler->expandedINames(), dummy, child, &list); } - parseWatchData(handler->expandedINames(), dummy, child, &list); + handler->insertData(list); } + // const GdbMi typeInfo = all.findChild("typeinfo"); // if (typeInfo.type() == GdbMi::List) { // foreach (const GdbMi &s, typeInfo.children()) { @@ -919,11 +937,23 @@ void LldbEngine::handleListLocals(const LldbResponse &response) // list[i].size = ti.size; // } - handler->insertData(list); + GdbMi stack = all.findChild("stack"); + if (stack.isValid()) { + //if (!partial) + // emit stackFrameCompleted(); + } - //rebuildWatchModel(); - if (!partial) - emit stackFrameCompleted(); + GdbMi threads = all.findChild("threads"); + if (threads.isValid()) { + ThreadsHandler *handler = threadsHandler(); + handler->updateThreads(threads); + if (!handler->currentThread().isValid()) { + ThreadId other = handler->threadAt(0); + if (other.isValid()) + selectThread(other); + } + updateViews(); // Adjust Threads combobox. + } } void LldbEngine::loadPythonDumpers() diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 9efe1e8589e1d08a9485dbb7ccba7e9b33e6aab9..7071d31bfa451fb2ef73ebc9b8f7cb2c9be92e49 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -121,10 +121,13 @@ private: Q_SLOT void handleOutput2(const QByteArray &data); void handleResponse(const QByteArray &ba); + enum DataKind { LocalsData = 1, StackData = 2, ThreadData = 4 }; + void loadPythonDumpers(); void updateAll(); - void updateLocals(); - void handleUpdateAll(const LldbResponse &response); + void updateData(DataKind kind); + void triggerUpdateAll(const LldbResponse &response); + void handleUpdateData(const LldbResponse &response); void handleFirstCommand(const LldbResponse &response); void handleExecuteDebuggerCommand(const LldbResponse &response); void handleInferiorSetup(const LldbResponse &response); @@ -152,6 +155,8 @@ private: void handleListModules(const LldbResponse &response); void handleListSymbols(const LldbResponse &response); void handleBreakInsert(const LldbResponse &response); + void handleUpdateStack(const LldbResponse &response); + void handleUpdateThreads(const LldbResponse &response); void handleChildren(const WatchData &data0, const GdbMi &item, QList<WatchData> *list); @@ -160,6 +165,7 @@ private: const char *callbackName = 0, const QVariant &cookie = QVariant()); void postDirectCommand(const QByteArray &command); + GdbMi parseFromString(QByteArray out); QQueue<LldbCommand> m_commands;