diff options
author | hjk <hjk@theqtcompany.com> | 2015-10-08 16:19:57 +0200 |
---|---|---|
committer | Christian Stenger <christian.stenger@theqtcompany.com> | 2015-10-09 05:19:45 +0000 |
commit | 525c33f9991766342b41a0518b534836dc60ed69 (patch) | |
tree | 33f0bb24beeae02eb71e85c46e08943a033f0133 /src/plugins/debugger | |
parent | ea39476ef2c0017f54021693ba545117ad53afa6 (diff) | |
download | qt-creator-525c33f9991766342b41a0518b534836dc60ed69.tar.gz |
Debugger: Infrastructure for reworked native mixed debugging
- Remove old experimental native mixed approach.
- Move some common stack parsing to Stackhandler.
- Mark gdbbridge.py debug output explicitly to remove it
from actual reponse handling
New native mixed needs QtDeclarative changes and
QTC_DEBUGGER_NATIVE_MIXED=1 for now.
Change-Id: I09eed1da51cea878636d36756015b7bfaed34203
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
Diffstat (limited to 'src/plugins/debugger')
25 files changed, 319 insertions, 275 deletions
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 44a0ad06f3..b95d196589 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -757,14 +757,15 @@ const BreakpointParameters &Breakpoint::parameters() const void Breakpoint::addToCommand(DebuggerCommand *cmd) const { cmd->arg("modelid", id().toByteArray()); + cmd->arg("id", int(response().id.majorPart())); cmd->arg("type", type()); cmd->arg("ignorecount", ignoreCount()); cmd->arg("condition", condition().toHex()); cmd->arg("function", functionName().toUtf8()); cmd->arg("oneshot", isOneShot()); cmd->arg("enabled", isEnabled()); - cmd->arg("fileName", fileName().toUtf8()); - cmd->arg("lineNumber", lineNumber()); + cmd->arg("file", fileName().toUtf8()); + cmd->arg("line", lineNumber()); cmd->arg("address", address()); cmd->arg("expression", expression()); } diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 22ce1c2278..1a69843726 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2539,28 +2539,29 @@ bool CdbEngine::stateAcceptsBreakpointChanges() const bool CdbEngine::acceptsBreakpoint(Breakpoint bp) const { - if (!bp.parameters().isCppBreakpoint()) - return false; - switch (bp.type()) { - case UnknownBreakpointType: - case LastBreakpointType: - case BreakpointAtFork: - case WatchpointAtExpression: - case BreakpointAtSysCall: - case BreakpointOnQmlSignalEmit: - case BreakpointAtJavaScriptThrow: - return false; - case WatchpointAtAddress: - case BreakpointByFileAndLine: - case BreakpointByFunction: - case BreakpointByAddress: - case BreakpointAtThrow: - case BreakpointAtCatch: - case BreakpointAtMain: - case BreakpointAtExec: - break; + if (bp.parameters().isCppBreakpoint()) { + switch (bp.type()) { + case UnknownBreakpointType: + case LastBreakpointType: + case BreakpointAtFork: + case WatchpointAtExpression: + case BreakpointAtSysCall: + case BreakpointOnQmlSignalEmit: + case BreakpointAtJavaScriptThrow: + return false; + case WatchpointAtAddress: + case BreakpointByFileAndLine: + case BreakpointByFunction: + case BreakpointByAddress: + case BreakpointAtThrow: + case BreakpointAtCatch: + case BreakpointAtMain: + case BreakpointAtExec: + break; + } + return true; } - return true; + return isNativeMixedEnabled(); } // Context for fixing file/line-type breakpoints, for delayed creation. @@ -2801,7 +2802,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = 0) break; } StackFrame frame; - frame.level = i; + frame.level = QByteArray::number(i); const GdbMi fullName = frameMi["fullname"]; if (fullName.isValid()) { frame.file = QFile::decodeName(fullName.data()); @@ -2811,9 +2812,10 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = 0) if (languageMi.isValid() && languageMi.data() == "js") frame.language = QmlLanguage; } - frame.function = QLatin1String(frameMi["func"].data()); - frame.from = QLatin1String(frameMi["from"].data()); - frame.address = frameMi["addr"].data().toULongLong(0, 16); + frame.function = QLatin1String(frameMi["function"].data()); + frame.module = QLatin1String(frameMi["from"].data()); + frame.context = frameMi["context"].data(); + frame.address = frameMi["address"].data().toULongLong(0, 16); rc.push_back(frame); } return rc; @@ -2895,7 +2897,7 @@ void CdbEngine::handleAdditionalQmlStack(const DebuggerResponse &response) break; } for (int i = 0; i < qmlFrameCount; ++i) - qmlFrames[i].fixQmlFrame(runParameters()); + qmlFrames[i].fixQrcFrame(runParameters()); stackHandler()->prependFrames(qmlFrames); } while (false); if (!errorMessage.isEmpty()) diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index e249c0c6b2..c165487a9f 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -15,6 +15,7 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "CppTools" } Depends { name: "ProjectExplorer" } + Depends { name: "QtSupport" } Depends { name: "TextEditor" } cpp.includePaths: base.concat([project.sharedSourcesDir + "/registryaccess"]) diff --git a/src/plugins/debugger/debugger_dependencies.pri b/src/plugins/debugger/debugger_dependencies.pri index d337d67c3d..259d30c6b1 100644 --- a/src/plugins/debugger/debugger_dependencies.pri +++ b/src/plugins/debugger/debugger_dependencies.pri @@ -12,6 +12,7 @@ QTC_PLUGIN_DEPENDS += \ coreplugin \ cpptools \ projectexplorer \ + qtsupport \ texteditor QTC_PLUGIN_RECOMMENDS += \ cppeditor diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index bd025d77a2..b1d7e193dc 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -185,18 +185,6 @@ DebuggerSettings::DebuggerSettings() insertItem(OperateByInstruction, item); item = new SavedAction(this); - item->setText(tr("Native Mixed Mode")); - item->setCheckable(true); - item->setDefaultValue(true); - item->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK))); - item->setToolTip(tr("<p>This switches the debugger to native-mixed " - "operation mode. In this mode, stepping and data display will " - "be handled by the native debugger backend (GDB, LLDB or CDB) " - "for C++, QML and JS sources.")); - item->setIconVisibleInMenu(false); - insertItem(OperateNativeMixed, item); - - item = new SavedAction(this); item->setText(tr("Dereference Pointers Automatically")); item->setCheckable(true); item->setDefaultValue(true); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 843d0dfadb..c7dabd7015 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -99,7 +99,6 @@ enum DebuggerActionCode LogTimeStamps, VerboseLog, OperateByInstruction, - OperateNativeMixed, CloseSourceBuffersOnExit, CloseMemoryBuffersOnExit, SwitchModeOnExit, diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 9484990362..0fc33fefec 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -61,7 +61,6 @@ const char NEXT[] = "Debugger.NextLine"; const char REVERSE[] = "Debugger.ReverseDirection"; const char RESET[] = "Debugger.Reset"; const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction"; -const char OPERATE_NATIVE_MIXED[] = "Debugger.OperateNativeMixed"; const char QML_SHOW_APP_ON_TOP[] = "Debugger.QmlShowAppOnTop"; const char QML_SELECTTOOL[] = "Debugger.QmlSelectTool"; const char QML_ZOOMTOOL[] = "Debugger.QmlZoomTool"; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index 7e091496d8..7e983ca362 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -110,8 +110,6 @@ DebuggerEngine *currentEngine(); QMessageBox *showMessageBox(int icon, const QString &title, const QString &text, int buttons = 0); -bool isNativeMixedActive(); -bool isNativeMixedEnabled(); bool isReverseDebuggingEnabled(); } // namespace Internal diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 6b242de2a6..2d5f14c0eb 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -78,6 +78,11 @@ #include <QFileInfo> #include <QDir> +#include <QJsonArray> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonValue> + using namespace Core; using namespace Debugger::Internal; using namespace ProjectExplorer; @@ -126,7 +131,7 @@ Location::Location(const StackFrame &frame, bool marker) m_functionName = frame.function; m_hasDebugInfo = frame.isUsable(); m_address = frame.address; - m_from = frame.from; + m_from = frame.module; } @@ -192,7 +197,7 @@ public: m_modulesHandler(engine), m_registerHandler(engine), m_sourceFilesHandler(), - m_stackHandler(), + m_stackHandler(engine), m_threadsHandler(), m_watchHandler(engine), m_disassemblerAgent(engine), @@ -203,8 +208,6 @@ public: this, &DebuggerEnginePrivate::resetLocation); connect(action(IntelFlavor), &Utils::SavedAction::valueChanged, this, &DebuggerEnginePrivate::reloadDisassembly); - connect(action(OperateNativeMixed), &QAction::triggered, - engine, &DebuggerEngine::reloadFullStack); Utils::globalMacroExpander()->registerFileVariables(PrefixDebugExecutable, tr("Debugged executable"), @@ -2023,6 +2026,26 @@ void DebuggerEngine::checkState(DebuggerState state, const char *file, int line) qDebug("%s", qPrintable(msg)); } +bool DebuggerEngine::isNativeMixedEnabled() const +{ + return runParameters().nativeMixedEnabled && (runParameters().languages & QmlLanguage); +} + +bool DebuggerEngine::isNativeMixedActive() const +{ + return isNativeMixedEnabled(); //&& boolSetting(OperateNativeMixed); +} + +bool DebuggerEngine::isNativeMixedActiveFrame() const +{ + if (!isNativeMixedActive()) + return false; + if (stackHandler()->frames().isEmpty()) + return false; + StackFrame frame = stackHandler()->frameAt(0); + return frame.language == QmlLanguage; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 15357a7221..b4edd5eeaa 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -117,6 +117,8 @@ public: // Used by AttachCrashedExternal. QString crashParameter; + bool nativeMixedEnabled = false; + // For Debugger testing. int testCase = 0; }; @@ -443,6 +445,9 @@ protected: void updateLocalsView(const GdbMi &all); void checkState(DebuggerState state, const char *file, int line); + bool isNativeMixedEnabled() const; + bool isNativeMixedActive() const; + bool isNativeMixedActiveFrame() const; private: // Wrapper engine needs access to state of its subengines. diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index bd7716ee9d..d644824e19 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -474,7 +474,6 @@ bool DummyEngine::hasCapability(unsigned cap) const return cap & (WatchpointByAddressCapability | BreakConditionCapability | TracePointCapability - | OperateNativeMixed | OperateByInstructionCapability); // This is a Qml or unknown engine. @@ -2321,17 +2320,6 @@ QMessageBox *showMessageBox(int icon, const QString &title, return mb; } -bool isNativeMixedEnabled() -{ - static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_NATIVE_MIXED"); - return enabled; -} - -bool isNativeMixedActive() -{ - return isNativeMixedEnabled() && boolSetting(OperateNativeMixed); -} - bool isReverseDebuggingEnabled() { static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_ENABLE_REVERSE"); @@ -2769,16 +2757,6 @@ void DebuggerPluginPrivate::extensionsInitialized() cmd->setAttribute(Command::CA_Hide); debugMenu->addAction(cmd); - if (isNativeMixedEnabled()) { - SavedAction *act = action(OperateNativeMixed); - act->setValue(true); - cmd = ActionManager::registerAction(act, Constants::OPERATE_NATIVE_MIXED); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - connect(cmd->action(), &QAction::triggered, - [this] { currentEngine()->updateAll(); }); - } - cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak"); cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); debugMenu->addAction(cmd); @@ -2912,8 +2890,6 @@ void DebuggerPluginPrivate::extensionsInitialized() hbox->addWidget(toolButton(Constants::STEPOUT)); hbox->addWidget(toolButton(Constants::RESET)); hbox->addWidget(toolButton(Constants::OPERATE_BY_INSTRUCTION)); - if (isNativeMixedEnabled()) - hbox->addWidget(toolButton(Constants::OPERATE_NATIVE_MIXED)); if (isReverseDebuggingEnabled()) { m_reverseToolButton = toolButton(Constants::REVERSE); diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index 651a8c1a2b..763c9477c6 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -80,7 +80,7 @@ void GdbMi::parseResultOrValue(const char *&from, const char *to) if (from == to || *from == '(') return; const char *ptr = from; - while (ptr < to && *ptr != '=') { + while (ptr < to && *ptr != '=' && *ptr != ':') { //qDebug() << "adding" << QChar(*ptr) << "to name"; ++ptr; } @@ -770,6 +770,12 @@ QString decodeData(const QByteArray &ba, DebuggerEncoding encoding) case SpecialEmptyStructureValue: { // 39 return QLatin1String("{...}"); } + case SpecialUndefinedValue: { // 40 + return QLatin1String("Undefined"); + } + case SpecialNullValue: { // 41 + return QLatin1String("Null"); + } } qDebug() << "ENCODING ERROR: " << encoding; return QCoreApplication::translate("Debugger", "<Encoding error>"); @@ -857,5 +863,22 @@ QByteArray DebuggerCommand::argsToString() const return args.toString().toLatin1(); } +DebuggerEncoding debuggerEncoding(const QByteArray &data) +{ + if (data == "utf16") + return Hex4EncodedLittleEndianWithQuotes; + if (data == "empty") + return SpecialEmptyValue; + if (data == "minimumitemcount") + return SpecialMinimumItemCountValue; + if (data == "undefined") + return SpecialUndefinedValue; + if (data == "null") + return SpecialNullValue; + if (data == "itemcount") + return SpecialItemCountValue; + return DebuggerEncoding(data.toInt()); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h index c8dc3a307d..a8006172ae 100644 --- a/src/plugins/debugger/debuggerprotocol.h +++ b/src/plugins/debugger/debuggerprotocol.h @@ -252,9 +252,13 @@ enum DebuggerEncoding SpecialNotCallableValue = 36, SpecialNullReferenceValue = 37, SpecialOptimizedOutValue = 38, - SpecialEmptyStructureValue = 39 + SpecialEmptyStructureValue = 39, + SpecialUndefinedValue = 40, + SpecialNullValue = 41 }; +DebuggerEncoding debuggerEncoding(const QByteArray &data); + // Decode string data as returned by the dumper helpers. QString decodeData(const QByteArray &baIn, DebuggerEncoding encoding); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 9e4af8fd71..2c323a3b1e 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -59,6 +59,8 @@ #include <coreplugin/icore.h> #include <qmldebug/qmldebugcommandlinearguments.h> +#include <qtsupport/qtkitinformation.h> + #include <QTcpServer> using namespace Debugger::Internal; @@ -416,6 +418,19 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const if (m_project && m_rp.projectSourceFiles.isEmpty()) m_rp.projectSourceFiles = m_project->files(Project::ExcludeGeneratedFiles); + if (m_project && m_rp.projectSourceFiles.isEmpty()) + m_rp.projectSourceFiles = m_project->files(Project::ExcludeGeneratedFiles); + + if (false && m_project && m_kit) { + const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(m_kit); + m_rp.nativeMixedEnabled = version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 7, 0); + } + + bool ok = false; + int nativeMixedOverride = qgetenv("QTC_DEBUGGER_NATIVE_MIXED").toInt(&ok); + if (ok) + m_rp.nativeMixedEnabled = bool(nativeMixedOverride); + // validate debugger if C++ debugging is enabled if (m_rp.languages & CppLanguage) { const QList<Task> tasks = DebuggerKitInformation::validateDebugger(m_kit); @@ -482,9 +497,6 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const const QString optimizerKey = _("QML_DISABLE_OPTIMIZER"); if (!m_rp.environment.hasKey(optimizerKey)) m_rp.environment.set(optimizerKey, _("1")); - - QtcProcess::addArg(&m_rp.processArgs, QmlDebug::qmlDebugCommandLineArguments( - QmlDebug::QmlDebuggerServices, m_rp.qmlServerPort)); } } } @@ -502,14 +514,23 @@ void DebuggerRunControlCreator::enrich(const RunConfiguration *runConfig, const } if (m_rp.masterEngineType == NoEngineType && m_debuggerAspect) { - const bool useCppDebugger = m_debuggerAspect->useCppDebugger() && (m_rp.languages & CppLanguage); - const bool useQmlDebugger = m_debuggerAspect->useQmlDebugger() && (m_rp.languages & QmlLanguage); - - if (useQmlDebugger) { - if (useCppDebugger) - m_rp.masterEngineType = QmlCppEngineType; - else + const bool wantCppDebugger = m_debuggerAspect->useCppDebugger() && (m_rp.languages & CppLanguage); + const bool wantQmlDebugger = m_debuggerAspect->useQmlDebugger() && (m_rp.languages & QmlLanguage); + + if (wantQmlDebugger) { + QString qmlArgs; + if (wantCppDebugger) { + if (m_rp.nativeMixedEnabled) { + qmlArgs = QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlNativeDebuggerServices); + } else { + m_rp.masterEngineType = QmlCppEngineType; + qmlArgs = QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlDebuggerServices, m_rp.qmlServerPort); + } + } else { m_rp.masterEngineType = QmlEngineType; + qmlArgs = QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlDebuggerServices, m_rp.qmlServerPort); + } + QtcProcess::addArg(&m_rp.processArgs, qmlArgs); } } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index a3686221b2..5692a00245 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -625,6 +625,18 @@ void GdbEngine::handleResponse(const QByteArray &buff) case '~': { QByteArray data = GdbMi::parseCString(from, to); + if (data.startsWith("bridgemessage={")) { + //showMessage(_(data), LogDebug); + break; + } + if (data.startsWith("bridgeresult={")) { + //showMessage(_(data), LogDebug); + DebuggerResponse response; + response.resultClass = ResultDone; + response.data.fromStringMultiple(data); + handleResultRecord(&response); + break; + } m_pendingConsoleStreamOutput += data; // Parse pid from noise. @@ -1369,9 +1381,13 @@ void GdbEngine::handleStopResponse(const GdbMi &data) int lineNumber = 0; QString fullName; QByteArray function; + QByteArray language; if (frame.isValid()) { const GdbMi lineNumberG = frame["line"]; - function = frame["func"].data(); + function = frame["function"].data(); // V4 protocol + if (function.isEmpty()) + function = frame["func"].data(); // GDB's *stopped messages + language = frame["language"].data(); if (lineNumberG.isValid()) { lineNumber = lineNumberG.toInt(); fullName = cleanupFullName(QString::fromLocal8Bit(frame["fullname"].data())); @@ -1384,9 +1400,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data) if (rid.isValid() && frame.isValid() && !isQFatalBreakpoint(rid)) { // Use opportunity to update the breakpoint marker position. - //qDebug() << " PROBLEM: " << m_qmlBreakpointNumbers << rid - // << isQmlStepBreakpoint1(rid) - // << isQmlStepBreakpoint2(rid) Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid); const BreakpointResponse &response = bp.response(); QString fileName = response.fileName; @@ -1403,7 +1416,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data) if (lineNumber && !boolSetting(OperateByInstruction) && QFileInfo::exists(fullName) && !isQFatalBreakpoint(rid) - && function != "qt_v4TriggeredBreakpointHook") + && function != "qt_v4TriggeredBreakpointHook" + && function != "qt_qmlDebugEventFromService" + && language != "js") gotoLocation(Location(fullName, lineNumber)); if (state() == InferiorRunOk) { @@ -1479,7 +1494,7 @@ void GdbEngine::handleStop1(const GdbMi &data) if (boolSetting(SkipKnownFrames)) { if (reason == "end-stepping-range" || reason == "function-finished") { //showMessage(frame.toString()); - QString funcName = _(frame["func"].data()); + QString funcName = _(frame["function"].data()); QString fileName = QString::fromLocal8Bit(frame["file"].data()); if (isLeavableFunction(funcName, fileName)) { //showMessage(_("LEAVING ") + funcName); @@ -1978,9 +1993,15 @@ void GdbEngine::continueInferiorInternal() notifyInferiorRunRequested(); showStatusMessage(tr("Running requested..."), 5000); CHECK_STATE(InferiorRunRequested); - DebuggerCommand cmd("-exec-continue", RunRequest); - cmd.callback = CB(handleExecuteContinue); - runCommand(cmd); + if (isNativeMixedActiveFrame()) { + DebuggerCommand cmd("executeContinue", RunRequest|PythonCommand); + cmd.callback = CB(handleExecuteContinue); + runCommand(cmd); + } else { + DebuggerCommand cmd("-exec-continue", RunRequest); + cmd.callback = CB(handleExecuteContinue); + runCommand(cmd); + } } void GdbEngine::continueInferior() @@ -1996,10 +2017,10 @@ void GdbEngine::executeStep() setTokenBarrier(); notifyInferiorRunRequested(); showStatusMessage(tr("Step requested..."), 5000); - if (isNativeMixedActive()) { - DebuggerCommand cmd("prepareQmlStep", PythonCommand); + if (isNativeMixedActiveFrame()) { + DebuggerCommand cmd("executeStep", RunRequest|PythonCommand); + cmd.callback = CB(handleExecuteStep); runCommand(cmd); - continueInferiorInternal(); } else { DebuggerCommand cmd(isReverseDebugging() ? "reverse-step" : "-exec-step", RunRequest); cmd.callback = CB(handleExecuteStep); @@ -2061,12 +2082,17 @@ void GdbEngine::executeStepOut() setTokenBarrier(); notifyInferiorRunRequested(); showStatusMessage(tr("Finish function requested..."), 5000); - runCommand("-exec-finish", CB(handleExecuteContinue), RunRequest); - // -exec-finish in 'main' results (correctly) in - // 40^error,msg="\"finish\" not meaningful in the outermost frame." - // However, this message does not seem to get flushed before - // anything else happen - i.e. "never". Force some extra output. - runCommand("print 32"); + if (isNativeMixedActiveFrame()) { + DebuggerCommand cmd("executeStepOut", RunRequest|PythonCommand); + runCommand(cmd); + } else { + runCommand("-exec-finish", CB(handleExecuteContinue), RunRequest); + // -exec-finish in 'main' results (correctly) in + // 40^error,msg="\"finish\" not meaningful in the outermost frame." + // However, this message does not seem to get flushed before + // anything else happen - i.e. "never". Force some extra output. + runCommand("print 32"); + } } void GdbEngine::executeNext() @@ -2075,10 +2101,9 @@ void GdbEngine::executeNext() setTokenBarrier(); notifyInferiorRunRequested(); showStatusMessage(tr("Step next requested..."), 5000); - if (isNativeMixedActive()) { - DebuggerCommand cmd("prepareQmlStep", PythonCommand); + if (isNativeMixedActiveFrame()) { + DebuggerCommand cmd("executeNext", RunRequest|PythonCommand); runCommand(cmd); - continueInferiorInternal(); } else { DebuggerCommand cmd(isReverseDebugging() ? "reverse-next" : "-exec-next", RunRequest); cmd.callback = CB(handleExecuteNext); @@ -2656,10 +2681,9 @@ bool GdbEngine::acceptsBreakpoint(Breakpoint bp) const { if (runParameters().startMode == AttachCore) return false; - // We handle QML breakpoint unless specifically - if (isNativeMixedEnabled() && !(runParameters().languages & QmlLanguage)) + if (bp.parameters().isCppBreakpoint()) return true; - return bp.parameters().isCppBreakpoint(); + return isNativeMixedEnabled(); } void GdbEngine::insertBreakpoint(Breakpoint bp) @@ -2672,7 +2696,7 @@ void GdbEngine::insertBreakpoint(Breakpoint bp) const BreakpointParameters &data = bp.parameters(); if (!data.isCppBreakpoint()) { - DebuggerCommand cmd("insertQmlBreakpoint", PythonCommand); + DebuggerCommand cmd("insertInterpreterBreakpoint", PythonCommand); bp.addToCommand(&cmd); runCommand(cmd); bp.notifyBreakpointInsertOk(); @@ -2791,7 +2815,7 @@ void GdbEngine::removeBreakpoint(Breakpoint bp) const BreakpointParameters &data = bp.parameters(); if (!data.isCppBreakpoint()) { - DebuggerCommand cmd("removeQmlBreakpoint", PythonCommand); + DebuggerCommand cmd("removeInterpreterBreakpoint", PythonCommand); bp.addToCommand(&cmd); runCommand(cmd); bp.notifyBreakpointRemoveOk(); @@ -3140,13 +3164,11 @@ void GdbEngine::reloadFullStack() runCommand(cmd); } -void GdbEngine::loadAdditionalQmlStack() +static QString msgCannotLoadQmlStack(const QString &why) { - // Scan for QV4::ExecutionContext parameter in the parameter list of a V4 call. - runCommand("-stack-list-arguments --simple-values", CB(handleQmlStackFrameArguments), NeedsStop); + return _("Unable to load QML stack: ") + why; } -// Scan the arguments of a stack list for the address of a QV4::ExecutionContext. static quint64 findJsExecutionContextAddress(const GdbMi &stackArgsResponse, const QByteArray &qtNamespace) { const GdbMi frameList = stackArgsResponse.childAt(0); @@ -3169,29 +3191,30 @@ static quint64 findJsExecutionContextAddress(const GdbMi &stackArgsResponse, con return 0; } -static QString msgCannotLoadQmlStack(const QString &why) -{ - return _("Unable to load QML stack: ") + why; -} - -void GdbEngine::handleQmlStackFrameArguments(const DebuggerResponse &response) +void GdbEngine::loadAdditionalQmlStack() { - if (!response.data.isValid()) { - showMessage(msgCannotLoadQmlStack(_("No stack obtained.")), LogError); - return; - } - const quint64 contextAddress = findJsExecutionContextAddress(response.data, qtNamespace()); - if (!contextAddress) { - showMessage(msgCannotLoadQmlStack(_("The address of the JS execution context could not be found.")), LogError); - return; - } - // Call the debug function of QML with the context address to obtain the QML stack trace. - DebuggerCommand cmd = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x" - + QByteArray::number(contextAddress, 16) + ")\""; - cmd.callback = CB(handleQmlStackTrace); + // Scan for QV4::ExecutionContext parameter in the parameter list of a V4 call. + DebuggerCommand cmd("-stack-list-arguments --simple-values", NeedsStop); + cmd.callback = [this](const DebuggerResponse &response) { + if (!response.data.isValid()) { + showMessage(msgCannotLoadQmlStack(_("No stack obtained.")), LogError); + return; + } + const quint64 contextAddress = findJsExecutionContextAddress(response.data, qtNamespace()); + if (!contextAddress) { + showMessage(msgCannotLoadQmlStack(_("The address of the JS execution context could not be found.")), LogError); + return; + } + // Call the debug function of QML with the context address to obtain the QML stack trace. + DebuggerCommand cmd = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x" + + QByteArray::number(contextAddress, 16) + ")\""; + cmd.callback = CB(handleQmlStackTrace); + runCommand(cmd); + }; runCommand(cmd); } +// Scan the arguments of a stack list for the address of a QV4::ExecutionContext. void GdbEngine::handleQmlStackTrace(const DebuggerResponse &response) { if (!response.data.isValid()) { @@ -3216,11 +3239,8 @@ void GdbEngine::handleQmlStackTrace(const DebuggerResponse &response) } QList<StackFrame> qmlFrames; qmlFrames.reserve(qmlFrameCount); - for (int i = 0; i < qmlFrameCount; ++i) { - StackFrame frame = parseStackFrame(stackMi.childAt(i), i); - frame.fixQmlFrame(runParameters()); - qmlFrames.append(frame); - } + for (int i = 0; i < qmlFrameCount; ++i) + qmlFrames.append(StackFrame::parseFrame(stackMi.childAt(i), runParameters())); stackHandler()->prependFrames(qmlFrames); } @@ -3228,7 +3248,7 @@ DebuggerCommand GdbEngine::stackCommand(int depth) { DebuggerCommand cmd("stackListFrames"); cmd.arg("limit", depth); - cmd.arg("options", isNativeMixedActive() ? "nativemixed" : ""); + cmd.arg("nativemixed", isNativeMixedActive()); return cmd; } @@ -3241,35 +3261,6 @@ void GdbEngine::reloadStack() runCommand(cmd); } -StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level) -{ - //qDebug() << "HANDLING FRAME:" << frameMi.toString(); - StackFrame frame; - frame.level = level; - GdbMi fullName = frameMi["fullname"]; - if (fullName.isValid()) - frame.file = cleanupFullName(QFile::decodeName(fullName.data())); - else - frame.file = QFile::decodeName(frameMi["file"].data()); - frame.function = _(frameMi["func"].data()); - frame.from = _(frameMi["from"].data()); - frame.line = frameMi["line"].toInt(); - frame.address = frameMi["addr"].toAddress(); - GdbMi usable = frameMi["usable"]; - if (usable.isValid()) - frame.usable = usable.data().toInt(); - else - frame.usable = QFileInfo(frame.file).isReadable(); - if (frameMi["language"].data() == "js" - || frame.file.endsWith(QLatin1String(".js")) - || frame.file.endsWith(QLatin1String(".qml"))) { - frame.file = QFile::decodeName(frameMi["file"].data()); - frame.language = QmlLanguage; - frame.fixQmlFrame(runParameters()); - } - return frame; -} - void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isFull) { if (response.resultClass != ResultDone) { @@ -3284,8 +3275,10 @@ void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isF QList<StackFrame> stackFrames; GdbMi stack = response.data["stack"]; // C++ - if (!stack.isValid() || stack.childCount() == 0) // Mixed. + if (!stack.isValid() || stack.childCount() == 0) { // Mixed. stack.fromStringMultiple(response.consoleStreamOutput); + stack = stack["frames"]; + } if (!stack.isValid()) { qDebug() << "FIXME: stack:" << stack.toString(); @@ -3296,7 +3289,7 @@ void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isF int n = stack.childCount(); for (int i = 0; i != n; ++i) { - stackFrames.append(parseStackFrame(stack.childAt(i), i)); + stackFrames.append(StackFrame::parseFrame(stack.childAt(i), runParameters())); const StackFrame &frame = stackFrames.back(); // Initialize top frame to the first valid frame. @@ -3407,7 +3400,7 @@ void GdbEngine::handleThreadNames(const DebuggerResponse &response) ThreadData thread; thread.id = ThreadId(name["id"].toInt()); thread.name = decodeData(name["value"].data(), - DebuggerEncoding(name["valueencoded"].toInt())); + debuggerEncoding(name["valueencoded"].data())); handler->updateThread(thread); } updateViews(); @@ -4622,7 +4615,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms) watchHandler()->notifyUpdateStarted(params.partialVariables()); - DebuggerCommand cmd("showData", Discardable | InUpdateLocals | PythonCommand); + DebuggerCommand cmd("fetchVariables", Discardable|InUpdateLocals|PythonCommand); watchHandler()->appendFormatRequests(&cmd); watchHandler()->appendWatchersAndTooltipRequests(&cmd); @@ -4637,23 +4630,20 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms) cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("nativemixed", isNativeMixedActive()); - if (isNativeMixedActive()) { - StackFrame frame = stackHandler()->currentFrame(); - if (frame.language == QmlLanguage) - cmd.arg("qmlcontext", "0x" + QByteArray::number(frame.address, 16)); - } + StackFrame frame = stackHandler()->currentFrame(); + cmd.arg("context", frame.context); cmd.arg("resultvarname", m_resultVarName); cmd.arg("partialVariable", params.partialVariable); cmd.arg("sortStructMembers", boolSetting(SortStructMembers)); - cmd.callback = CB(handleStackFrame); + cmd.callback = CB(handleFetchVariables); runCommand(cmd); cmd.arg("passExceptions", true); m_lastDebuggableCommand = cmd; } -void GdbEngine::handleStackFrame(const DebuggerResponse &response) +void GdbEngine::handleFetchVariables(const DebuggerResponse &response) { m_inUpdateLocals = false; diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index cc4bc0b86c..70e2816404 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -216,7 +216,6 @@ protected: void handleStop1(const GdbMi &data); void handleStop2(const GdbMi &data); Q_SLOT void handleStop2(); - StackFrame parseStackFrame(const GdbMi &mi, int level); void resetCommandQueue(); bool isSynchronous() const override { return true; } @@ -367,7 +366,6 @@ protected: Q_SLOT void reloadStack(); Q_SLOT virtual void reloadFullStack() override; virtual void loadAdditionalQmlStack() override; - void handleQmlStackFrameArguments(const DebuggerResponse &response); void handleQmlStackTrace(const DebuggerResponse &response); int currentFrame() const; @@ -399,7 +397,7 @@ protected: Q_SLOT void createFullBacktrace(); void doUpdateLocals(const UpdateParameters ¶meters) override; - void handleStackFrame(const DebuggerResponse &response); + void handleFetchVariables(const DebuggerResponse &response); void setLocals(const QList<GdbMi> &locals); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 39a2936cc0..de99a107b3 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -537,7 +537,7 @@ void LldbEngine::selectThread(ThreadId threadId) cmd.arg("id", threadId.raw()); cmd.callback = [this](const DebuggerResponse &) { DebuggerCommand cmd("fetchStack"); - cmd.arg("nativeMixed", isNativeMixedActive()); + cmd.arg("nativemixed", isNativeMixedActive()); cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt()); runCommand(cmd); updateLocals(); @@ -563,10 +563,9 @@ bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const { if (runParameters().startMode == AttachCore) return false; - // We handle QML breakpoint unless specifically disabled. - if (isNativeMixedEnabled() && !(runParameters().languages & QmlLanguage)) + if (bp.parameters().isCppBreakpoint()) return true; - return bp.parameters().isCppBreakpoint(); + return isNativeMixedEnabled(); } void LldbEngine::insertBreakpoint(Breakpoint bp) @@ -753,37 +752,12 @@ void LldbEngine::reloadFullStack() void LldbEngine::fetchStack(int limit) { DebuggerCommand cmd("fetchStack"); - cmd.arg("nativeMixed", isNativeMixedActive()); + cmd.arg("nativemixed", isNativeMixedActive()); cmd.arg("stacklimit", limit); + cmd.arg("context", stackHandler()->currentFrame().context); cmd.callback = [this](const DebuggerResponse &response) { const GdbMi &stack = response.data["stack"]; - StackHandler *handler = stackHandler(); - StackFrames frames; - foreach (const GdbMi &item, stack["frames"].children()) { - StackFrame frame; - frame.level = item["level"].toInt(); - frame.file = item["file"].toUtf8(); - frame.function = item["func"].toUtf8(); - frame.from = item["func"].toUtf8(); - frame.line = item["line"].toInt(); - frame.address = item["addr"].toAddress(); - GdbMi usable = item["usable"]; - if (usable.isValid()) - frame.usable = usable.data().toInt(); - else - frame.usable = QFileInfo(frame.file).isReadable(); - if (item["language"].data() == "js" - || frame.file.endsWith(QLatin1String(".js")) - || frame.file.endsWith(QLatin1String(".qml"))) { - frame.language = QmlLanguage; - frame.fixQmlFrame(runParameters()); - } - frames.append(frame); - } - bool canExpand = stack["hasmore"].toInt(); - action(ExpandStack)->setEnabled(canExpand); - handler->setFrames(frames, canExpand); - + stackHandler()->setAllFrames(stack["frames"], stack["hasmore"].toInt()); updateLocals(); }; runCommand(cmd); @@ -816,7 +790,7 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms) watchHandler()->notifyUpdateStarted(params.partialVariables()); DebuggerCommand cmd("fetchLocals"); - cmd.arg("nativeMixed", isNativeMixedActive()); + cmd.arg("nativemixed", isNativeMixedActive()); watchHandler()->appendFormatRequests(&cmd); watchHandler()->appendWatchersAndTooltipRequests(&cmd); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 0adc23d058..7fa3801567 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -532,12 +532,12 @@ void PdbEngine::refreshStack(const GdbMi &stack) StackFrames frames; foreach (const GdbMi &item, stack["frames"].children()) { StackFrame frame; - frame.level = item["level"].toInt(); + frame.level = item["level"].data(); frame.file = item["file"].toUtf8(); - frame.function = item["func"].toUtf8(); - frame.from = item["func"].toUtf8(); + frame.function = item["function"].toUtf8(); + frame.module = item["function"].toUtf8(); frame.line = item["line"].toInt(); - frame.address = item["addr"].toAddress(); + frame.address = item["address"].toAddress(); GdbMi usable = item["usable"]; if (usable.isValid()) frame.usable = usable.data().toInt(); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index a91ae925be..5031575d29 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -2062,10 +2062,9 @@ void QmlEnginePrivate::handleBacktrace(const QVariantMap &response) stackIndexLookup.clear(); foreach (const QVariant &frame, frames) { StackFrame stackFrame = extractStackFrame(frame); - if (stackFrame.level < 0) + if (stackFrame.level.isEmpty()) continue; - stackIndexLookup.insert(i, stackFrame.level); - stackFrame.level = i; + stackIndexLookup.insert(i, stackFrame.level.toInt()); stackFrames << stackFrame; i++; } @@ -2111,10 +2110,10 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) const QVariantMap body = bodyVal.toMap(); StackFrame stackFrame; - stackFrame.level = body.value(_("index")).toInt(); + stackFrame.level = body.value(_("index")).toByteArray(); //Do not insert the frame corresponding to the internal function if (body.value(QLatin1String("sourceLineText")) == QLatin1String(INTERNAL_FUNCTION)) { - stackFrame.level = -1; + stackFrame.level.clear(); return stackFrame; } @@ -2129,7 +2128,7 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) stackFrame.usable = QFileInfo(stackFrame.file).isReadable(); objectData = extractData(body.value(_("receiver"))); - stackFrame.to = objectData.value.toString(); + stackFrame.receiver = objectData.value.toString(); stackFrame.line = body.value(_("line")).toInt() + 1; diff --git a/src/plugins/debugger/stackframe.cpp b/src/plugins/debugger/stackframe.cpp index cc07c4406e..11fa1a99e5 100644 --- a/src/plugins/debugger/stackframe.cpp +++ b/src/plugins/debugger/stackframe.cpp @@ -31,6 +31,7 @@ #include "stackframe.h" #include "debuggerengine.h" +#include "debuggerprotocol.h" #include "watchutils.h" #include <QDebug> @@ -49,16 +50,16 @@ namespace Internal { //////////////////////////////////////////////////////////////////////// StackFrame::StackFrame() - : language(CppLanguage), level(-1), line(-1), address(0), usable(false) + : language(CppLanguage), line(-1), address(0), usable(false) {} void StackFrame::clear() { - line = level = -1; + line = -1; function.clear(); file.clear(); - from.clear(); - to.clear(); + module.clear(); + receiver.clear(); address = 0; } @@ -79,11 +80,44 @@ QString StackFrame::toString() const << tr("Function:") << ' ' << function << ' ' << tr("File:") << ' ' << file << ' ' << tr("Line:") << ' ' << line << ' ' - << tr("From:") << ' ' << from << ' ' - << tr("To:") << ' ' << to; + << tr("From:") << ' ' << module << ' ' + << tr("To:") << ' ' << receiver; return res; } +QList<StackFrame> StackFrame::parseFrames(const GdbMi &data, const DebuggerRunParameters &rp) +{ + StackFrames frames; + frames.reserve(data.children().size()); + foreach (const GdbMi &item, data.children()) + frames.append(parseFrame(item, rp)); + return frames; +} + +StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParameters &rp) +{ + StackFrame frame; + frame.level = frameMi["level"].data(); + frame.function = frameMi["function"].toUtf8(); + frame.module = frameMi["module"].toUtf8(); + frame.file = QFile::decodeName(frameMi["file"].data()); + frame.line = frameMi["line"].toInt(); + frame.address = frameMi["address"].toAddress(); + frame.context = frameMi["context"].data(); + if (frameMi["language"].data() == "js" + || frame.file.endsWith(QLatin1String(".js")) + || frame.file.endsWith(QLatin1String(".qml"))) { + frame.language = QmlLanguage; + frame.fixQrcFrame(rp); + } + GdbMi usable = frameMi["usable"]; + if (usable.isValid()) + frame.usable = usable.data().toInt(); + else + frame.usable = QFileInfo(frame.file).isReadable(); + return frame; +} + QString StackFrame::toToolTip() const { const QString filePath = QDir::toNativeSeparators(file); @@ -101,10 +135,10 @@ QString StackFrame::toToolTip() const str << "<tr><td>" << tr("File:") << "</td><td>" << filePath << "</td></tr>"; if (line != -1) str << "<tr><td>" << tr("Line:") << "</td><td>" << line << "</td></tr>"; - if (!from.isEmpty()) - str << "<tr><td>" << tr("From:") << "</td><td>" << from << "</td></tr>"; - if (!to.isEmpty()) - str << "<tr><td>" << tr("To:") << "</td><td>" << to << "</td></tr>"; + if (!module.isEmpty()) + str << "<tr><td>" << tr("Module:") << "</td><td>" << module << "</td></tr>"; + if (!receiver.isEmpty()) + str << "<tr><td>" << tr("Receiver:") << "</td><td>" << receiver << "</td></tr>"; str << "</table>"; str <<"<br> <br><i>" << tr("Note:") << " </i> "; @@ -133,8 +167,8 @@ QString StackFrame::toToolTip() const return res; } -// Try to resolve files of a QML stack (resource files). -void StackFrame::fixQmlFrame(const DebuggerRunParameters &rp) +// Try to resolve files coming from resource files. +void StackFrame::fixQrcFrame(const DebuggerRunParameters &rp) { if (language != QmlLanguage) return; @@ -146,19 +180,19 @@ void StackFrame::fixQmlFrame(const DebuggerRunParameters &rp) if (!file.startsWith(QLatin1String("qrc:/"))) return; const QString relativeFile = file.right(file.size() - 5); - if (!rp.projectSourceDirectory.isEmpty()) { - const QFileInfo pFi(rp.projectSourceDirectory + QLatin1Char('/') + relativeFile); - if (pFi.isFile()) { - file = pFi.absoluteFilePath(); - usable = true; - return; - } - const QFileInfo cFi(QDir::currentPath() + QLatin1Char('/') + relativeFile); - if (cFi.isFile()) { - file = cFi.absoluteFilePath(); - usable = true; - return; - } + if (rp.projectSourceDirectory.isEmpty()) + return; + const QFileInfo pFi(rp.projectSourceDirectory + QLatin1Char('/') + relativeFile); + if (pFi.isFile()) { + file = pFi.absoluteFilePath(); + usable = true; + return; + } + const QFileInfo cFi(QDir::currentPath() + QLatin1Char('/') + relativeFile); + if (cFi.isFile()) { + file = cFi.absoluteFilePath(); + usable = true; + return; } } @@ -171,10 +205,10 @@ QDebug operator<<(QDebug d, const StackFrame &f) str << ' ' << f.function; if (!f.file.isEmpty()) str << ' ' << f.file << ':' << f.line; - if (!f.from.isEmpty()) - str << " from=" << f.from; - if (!f.to.isEmpty()) - str << " to=" << f.to; + if (!f.module.isEmpty()) + str << " from=" << f.module; + if (!f.receiver.isEmpty()) + str << " to=" << f.receiver; d.nospace() << res; return d; } diff --git a/src/plugins/debugger/stackframe.h b/src/plugins/debugger/stackframe.h index 8d29f3f004..b9b23dfced 100644 --- a/src/plugins/debugger/stackframe.h +++ b/src/plugins/debugger/stackframe.h @@ -44,6 +44,7 @@ namespace Debugger { namespace Internal { class DebuggerRunParameters; +class GdbMi; class StackFrame { @@ -53,24 +54,25 @@ public: bool isUsable() const; QString toToolTip() const; QString toString() const; - void fixQmlFrame(const DebuggerRunParameters &rp); + static StackFrame parseFrame(const GdbMi &data, const DebuggerRunParameters &rp); + static QList<StackFrame> parseFrames(const GdbMi &data, const DebuggerRunParameters &rp); + void fixQrcFrame(const DebuggerRunParameters &rp); public: DebuggerLanguage language; - qint32 level; + QByteArray level; QString function; - QString file; // We try to put an absolute file name in there. - QString from; // Sometimes something like "/usr/lib/libstdc++.so.6" - QString to; // Used in ScriptEngine only. + QString file; // We try to put an absolute file name in there. + QString module; // Sometimes something like "/usr/lib/libstdc++.so.6" + QString receiver; // Used in ScriptEngine only. qint32 line; quint64 address; bool usable; + QByteArray context; // Opaque value produced and consumed by the native backends. Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::StackHandler) }; -QDebug operator<<(QDebug d, const StackFrame &frame); - typedef QList<StackFrame> StackFrames; } // namespace Internal diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index ec5fe96641..39bbae9a20 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -32,6 +32,7 @@ #include "debuggeractions.h" #include "debuggercore.h" +#include "debuggerengine.h" #include "simplifytype.h" #include <utils/fileutils.h> @@ -55,8 +56,9 @@ namespace Internal { QTreeView. */ -StackHandler::StackHandler() - : m_positionIcon(QIcon(QLatin1String(":/debugger/images/location_16.png"))), +StackHandler::StackHandler(DebuggerEngine *engine) + : m_engine(engine), + m_positionIcon(QIcon(QLatin1String(":/debugger/images/location_16.png"))), m_emptyIcon(QIcon(QLatin1String(":/debugger/images/debugger_empty_14.png"))) { setObjectName(QLatin1String("StackModel")); @@ -103,11 +105,11 @@ QVariant StackHandler::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole) { switch (index.column()) { case StackLevelColumn: - return QString::number(frame.level); + return QString::number(index.row() + 1); case StackFunctionNameColumn: return simplifyType(frame.function); case StackFileNameColumn: - return frame.file.isEmpty() ? frame.from : Utils::FileName::fromString(frame.file).fileName(); + return frame.file.isEmpty() ? frame.module : Utils::FileName::fromString(frame.file).fileName(); case StackLineNumberColumn: return frame.line > 0 ? QVariant(frame.line) : QVariant(); case StackAddressColumn: @@ -166,6 +168,12 @@ StackFrame StackHandler::currentFrame() const return m_stackFrames.at(m_currentIndex); } +void StackHandler::setAllFrames(const GdbMi &frames, bool canExpand) +{ + action(ExpandStack)->setEnabled(canExpand); + setFrames(StackFrame::parseFrames(frames, m_engine->runParameters()), canExpand); +} + void StackHandler::setCurrentIndex(int level) { if (level == -1 || level == m_currentIndex) diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index 0713042dc1..3607eb7d6c 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -38,6 +38,8 @@ namespace Debugger { namespace Internal { +class DebuggerEngine; + enum StackColumns { StackLevelColumn, @@ -48,18 +50,12 @@ enum StackColumns StackColumnCount }; -//////////////////////////////////////////////////////////////////////// -// -// StackModel -// -//////////////////////////////////////////////////////////////////////// - class StackHandler : public QAbstractTableModel { Q_OBJECT public: - StackHandler(); + explicit StackHandler(DebuggerEngine *engine); ~StackHandler(); void setFrames(const StackFrames &frames, bool canExpand = false); @@ -72,6 +68,7 @@ public: const StackFrame &frameAt(int index) const { return m_stackFrames.at(index); } int stackSize() const { return m_stackFrames.size(); } quint64 topAddress() const { return m_stackFrames.at(0).address; } + void setAllFrames(const GdbMi &frames, bool canExpand); // Called from StackHandler after a new stack list has been received void removeAll(); @@ -93,6 +90,7 @@ private: Qt::ItemFlags flags(const QModelIndex &index) const; Q_SLOT void resetModel() { beginResetModel(); endResetModel(); } + DebuggerEngine *m_engine; StackFrames m_stackFrames; int m_currentIndex; const QVariant m_positionIcon; diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp index cf07816ae5..b6654c466b 100644 --- a/src/plugins/debugger/stackwindow.cpp +++ b/src/plugins/debugger/stackwindow.cpp @@ -108,7 +108,7 @@ static inline StackFrame inputFunctionForDisassembly() return frame; const int bangPos = function.indexOf(QLatin1Char('!')); if (bangPos != -1) { - frame.from = function.left(bangPos); + frame.module = function.left(bangPos); frame.function = function.mid(bangPos + 1); } else { frame.function = function; diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index bab3546552..188fe5cd82 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -392,8 +392,8 @@ void WatchData::updateValue(const GdbMi &item) { GdbMi value = item["value"]; if (value.isValid()) { - int encoding = item["valueencoded"].toInt(); - setValue(decodeData(value.data(), DebuggerEncoding(encoding))); + DebuggerEncoding encoding = debuggerEncoding(item["valueencoded"].data()); + setValue(decodeData(value.data(), encoding)); } else { setValueNeeded(); } |