diff --git a/share/qtcreator/dumper/bridge.py b/share/qtcreator/dumper/bridge.py index 4033b7c6555df2a39febaa0b03ce2d029862ef44..948404faeaefcee28c3cd3f45f7c7edbc6323dc1 100644 --- a/share/qtcreator/dumper/bridge.py +++ b/share/qtcreator/dumper/bridge.py @@ -5,6 +5,12 @@ cdbLoaded = False lldbLoaded = False gdbLoaded = False +####################################################################### +# +# Helpers +# +####################################################################### + def warn(message): print "XXX: %s\n" % message.encode("latin1") @@ -18,37 +24,34 @@ def showException(msg, exType, exValue, exTraceback): except: pass -try: - #import cdb_bridge - cdbLoaded = True -except: - pass +####################################################################### +# +# CDB +# +####################################################################### try: - #import lldb_bridge - lldbLoaded = True + import cdb_bridge + cdbLoaded = True except: pass +####################################################################### +# +# GDB +# +####################################################################### + try: + if cdbLoaded: + raise "Not needed" + import gdb gdbLoaded = True - ####################################################################### - # - # Sanitize environment - # - ####################################################################### - - #try: - # gdb.execute("set auto-load-scripts no") - #except: - # pass - - ####################################################################### # # Infrastructure @@ -434,3 +437,89 @@ try: except: pass + +####################################################################### +# +# LLDB +# +####################################################################### + +try: + if gdbLoaded or cdbLoaded: + raise "Not needed" + + lldbLoaded = True + + PointerCode, \ + ArrayCode, \ + StructCode, \ + UnionCode, \ + EnumCode, \ + FlagsCode, \ + FunctionCode, \ + IntCode, \ + FloatCode, \ + VoidCode, \ + SetCode, \ + RangeCode, \ + StringCode, \ + BitStringCode, \ + ErrorTypeCode, \ + MethodCode, \ + MethodPointerCode, \ + MemberPointerCode, \ + ReferenceCode, \ + CharCode, \ + BoolCode, \ + ComplexCode, \ + TypedefCode, \ + NamespaceCode \ + = range(24) + + def registerCommand(name, func): + pass + + class Type: + def __init__(self, type): + self.raw = type + self.code = IntCode + + def __str__(self): + return self.raw.name + + + def unqualified(self): + return self + + class Value: + def __init__(self, var): + self.raw = var + self.is_optimized_out = False + self.type = Type(var.type) + self.type.value_type = var.value_type + + def __str__(self): + return self.name + + currentThread = None + currentFrame = None + + def listOfLocals(varList): + global currentThread + global currentFrame + + items = [] + currentThread = lldb.process.GetThreadAtIndex(0) + currentFrame = currentThread.GetFrameAtIndex(0) + for var in currentFrame.variables: + item = LocalItem() + item.iname = "local." + var.name + item.name = var.name + item.value = Value(var) + items.append(item) + return items + +except: + pass + + diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index a48da30ee59b91e718ca2364130dda61d6cc4b07..04e657ca645f0f2372df81f1ff853ba88ce73800 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -63,6 +63,8 @@ #include #include +#include + #define DEBUG_SCRIPT 1 #if DEBUG_SCRIPT @@ -87,7 +89,7 @@ static QByteArray quoteUnprintable(const QByteArray &ba) if (isprint(c)) { res += c; } else { - qsnprintf(buf, sizeof(buf) - 1, "\\%02x", int(c)); + qsnprintf(buf, sizeof(buf) - 1, "\\x%02x", int(c)); res += buf; } } @@ -105,6 +107,7 @@ LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters) : DebuggerEngine(startParameters) { setObjectName(QLatin1String("LldbEngine")); + m_pythonAttemptedToLoad = false; } LldbEngine::~LldbEngine() @@ -205,6 +208,43 @@ void LldbEngine::setupEngine() notifyEngineSetupFailed(); return; } + + loadPythonDumpers(); + postCommand("setting set auto-confirm on"); + postCommand("setting set interpreter.prompt-on-quit off"); + + // Default: + // frame-format (string) = "frame #${frame.index}: ${frame.pc} + // { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}} + // { at ${line.file.basename}:${line.number}}\n" + postCommand("settings set frame-format frame=\\{" + "index='${frame.index}'," + "pc='${frame.pc}'," + "module='${module.file.basename}'," + //"function='${function.name-with-args}'," + "function='${function.name}'," + "pcoffset='${function.pc-offset}'," + "file='${line.file.basename}'," + "line='${line.number}'" + "\\},"); + + + // Default: + // "thread #${thread.index}: tid = ${thread.id}{, ${frame.pc}} + // { ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}} + // { at ${line.file.basename}:${line.number}} + // {, stop reason = ${thread.stop-reason}}{\nReturn value: ${thread.return-value}}\n" + postCommand("settings set thread-format thread=\\{" + "index='${thread.index}'," + "tid='${thread.id}'," + "framepc='${frame.pc}'," + "module='${module.file.basename}'," + "function='${function.name}'," + "pcoffset='${function.pc-offset}'," + "stopreason='${thread.stop-reason}'" + //"returnvalue='${thread.return-value}'" + "\\},"); + notifyEngineSetupOk(); } @@ -644,11 +684,11 @@ void LldbEngine::readLldbStandardOutput() } if (j != n) out.resize(j); + //qDebug("\n\nLLDB STDOUT: '%s'", quoteUnprintable(out).constData()); if (out.isEmpty()) return; - //qDebug() << "READ: " << data; if (out.startsWith(8)) { if (!m_inbuffer.isEmpty()) m_inbuffer.chop(1); @@ -661,16 +701,33 @@ void LldbEngine::readLldbStandardOutput() qDebug("\nBUFFER FROM: '%s'", quoteUnprintable(m_inbuffer).constData()); while (true) { - int pos = m_inbuffer.indexOf("(lldb)"); + int pos = m_inbuffer.indexOf("(lldb) "); if (pos == -1) break; QByteArray response = m_inbuffer.left(pos).trimmed(); - m_inbuffer = m_inbuffer.mid(pos + 6); + m_inbuffer = m_inbuffer.mid(pos + 7); qDebug("\nBUFFER RECOGNIZED: '%s'", quoteUnprintable(response).constData()); emit outputReady(response); } qDebug("\nBUFFER LEFT: '%s'", quoteUnprintable(m_inbuffer).constData()); - //m_inbuffer.clear(); + + if (m_inbuffer.isEmpty()) + return; + + // Could be a 'stopped' message left. + // "[KProcess 5564 stopped" + // "* thread #1: tid = 0x15bc, 0x0804a17d untitled11`main(argc=1, + // argv=0xbfffeff4) + 61 at main.cpp:52, stop reason = breakpoint 1.1 ..." + const int pos = m_inbuffer.indexOf("\x1b[KProcess"); + if (pos != -1) { + int pid = 0; + const char *format = "\x1b[KProcess %d stopped"; + if (::sscanf(m_inbuffer.constData() + pos, format, &pid) == 1) { + notifyInferiorSpontaneousStop(); + m_inbuffer.clear(); + updateAll(); + } + } } void LldbEngine::handleOutput2(const QByteArray &data) @@ -680,6 +737,10 @@ void LldbEngine::handleOutput2(const QByteArray &data) showMessage(_(data)); QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return); LldbCommand cmd = m_commands.dequeue(); + // FIXME: Find a way to tell LLDB to no echo input. + if (response.data.startsWith(cmd.command)) + response.data = response.data.mid(cmd.command.size()); + response.cookie = cmd.cookie; qDebug("\nDEQUE: '%s' -> '%s'", cmd.command.constData(), cmd.callbackName); if (cmd.callback) { @@ -704,8 +765,8 @@ void LldbEngine::handleUpdateAll(const LldbResponse &response) void LldbEngine::updateAll() { - postCommand("bt", CB(handleBacktrace)); - //updateLocals(); + //postCommand("bt", CB(handleBacktrace)); + updateLocals(); } void LldbEngine::updateLocals() @@ -734,28 +795,17 @@ void LldbEngine::updateLocals() options += "defaults,"; options.chop(1); - postCommand("qdebug('" + options + "','" - + handler->expansionRequests() + "','" - + handler->typeFormatRequests() + "','" - + handler->individualFormatRequests() + "','" - + watchers.toHex() + "')", CB(handleListLocals)); + postCommand("script bb('options:" + options + " " + + "vars: " + + "expanded:" + handler->expansionRequests() + " " + + "typeformats:" + handler->typeFormatRequests() + " " + + "formats:" + handler->individualFormatRequests() + " " + + "watcher:" + watchers.toHex() + "')", + CB(handleListLocals)); } void LldbEngine::handleBacktrace(const LldbResponse &response) { - //qDebug() << " BACKTRACE: '" << response.data << "'"; - // " /usr/lib/python2.6/bdb.py(368)run()" - // "-> exec cmd in globals, locals" - // " (1)()" - // " /python/math.py(19)()" - // "-> main()" - // " /python/math.py(14)main()" - // "-> print cube(3)" - // " /python/math.py(7)cube()" - // "-> x = square(a)" - // "> /python/math.py(2)square()" - // "-> def square(a):" - // Populate stack view. StackFrames stackFrames; int level = 0; @@ -805,21 +855,92 @@ void LldbEngine::handleListLocals(const LldbResponse &response) //qDebug() << " LOCALS: '" << response.data << "'"; QByteArray out = response.data.trimmed(); +// GdbMi all; +// all.fromStringMultiple(out); +// //qDebug() << "ALL: " << all.toString(); + +// //GdbMi data = all.findChild("data"); +// QList list; +// WatchHandler *handler = watchHandler(); +// foreach (const GdbMi &child, all.children()) { +// WatchData dummy; +// dummy.iname = child.findChild("iname").data(); +// dummy.name = _(child.findChild("name").data()); +// //qDebug() << "CHILD: " << child.toString(); +// parseWatchData(handler->expandedINames(), dummy, child, &list); +// } +// handler->insertData(list); + + const bool partial = response.cookie.toBool(); + int pos = out.indexOf("data="); + if (pos != 0) { + showMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: " + + out.left(pos))); + out = out.mid(pos); + } GdbMi all; all.fromStringMultiple(out); - //qDebug() << "ALL: " << all.toString(); + GdbMi data = all.findChild("data"); - //GdbMi data = all.findChild("data"); - QList list; WatchHandler *handler = watchHandler(); - foreach (const GdbMi &child, all.children()) { + QList 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(); - dummy.name = _(child.findChild("name").data()); - //qDebug() << "CHILD: " << child.toString(); + 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); } +// const GdbMi typeInfo = all.findChild("typeinfo"); +// if (typeInfo.type() == GdbMi::List) { +// foreach (const GdbMi &s, typeInfo.children()) { +// const GdbMi name = s.findChild("name"); +// const GdbMi size = s.findChild("size"); +// if (name.isValid() && size.isValid()) +// m_typeInfoCache.insert(QByteArray::fromBase64(name.data()), +// TypeInfo(size.data().toUInt())); +// } +// } +// for (int i = 0; i != list.size(); ++i) { +// const TypeInfo ti = m_typeInfoCache.value(list.at(i).type); +// if (ti.size) +// list[i].size = ti.size; +// } + handler->insertData(list); + + //rebuildWatchModel(); + if (!partial) + emit stackFrameCompleted(); +} + +void LldbEngine::loadPythonDumpers() +{ + if (m_pythonAttemptedToLoad) + return; + m_pythonAttemptedToLoad = true; + + const QByteArray dumperSourcePath = + Core::ICore::resourcePath().toLocal8Bit() + "/dumper/"; + + postCommand("script execfile('" + dumperSourcePath + "bridge.py')"); + postCommand("script execfile('" + dumperSourcePath + "dumper.py')"); + postCommand("script execfile('" + dumperSourcePath + "qttypes.py')"); + postCommand("script bbsetup('')"); } bool LldbEngine::hasCapability(unsigned cap) const diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index f2a84178905a98b4809418fbbc89453be8efe6cf..9efe1e8589e1d08a9485dbb7ccba7e9b33e6aab9 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -60,7 +60,6 @@ class LldbEngine : public DebuggerEngine public: explicit LldbEngine(const DebuggerStartParameters &startParameters); ~LldbEngine(); - private: // DebuggerEngine implementation void executeStep(); @@ -121,6 +120,8 @@ private: Q_SLOT void readLldbStandardError(); Q_SLOT void handleOutput2(const QByteArray &data); void handleResponse(const QByteArray &ba); + + void loadPythonDumpers(); void updateAll(); void updateLocals(); void handleUpdateAll(const LldbResponse &response); @@ -166,6 +167,7 @@ private: QString m_scriptFileName; QProcess m_lldbProc; QString m_lldb; + bool m_pythonAttemptedToLoad; }; } // namespace Internal