diff --git a/src/plugins/android/androidrunfactories.cpp b/src/plugins/android/androidrunfactories.cpp index da0d100f0a9..4aff7edd3a2 100644 --- a/src/plugins/android/androidrunfactories.cpp +++ b/src/plugins/android/androidrunfactories.cpp @@ -80,8 +80,8 @@ RunControl *AndroidRunControlFactory::create(RunConfiguration *runConfig, case DebugRunModeWithBreakOnMain: case CallgrindRunMode: case MemcheckRunMode: + case MemcheckWithGdbRunMode: case ClangStaticAnalyzerMode: - default: QTC_CHECK(false); // The other run modes are not supported } return 0; diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 73af881c065..3770ca5e28f 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -274,6 +274,7 @@ enum RunMode { QmlProfilerRunMode, CallgrindRunMode, MemcheckRunMode, + MemcheckWithGdbRunMode, ClangStaticAnalyzerMode }; diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index e4a7430b41d..e21cfcf3fd0 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -198,6 +198,7 @@ RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, RunMode mo case NoRunMode: case CallgrindRunMode: case MemcheckRunMode: + case MemcheckWithGdbRunMode: case ClangStaticAnalyzerMode: case DebugRunModeWithBreakOnMain: QTC_ASSERT(false, return 0); diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index b49cc9bc94e..c1074a5b899 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -126,6 +126,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru case NoRunMode: case CallgrindRunMode: case MemcheckRunMode: + case MemcheckWithGdbRunMode: case ClangStaticAnalyzerMode: QTC_ASSERT(false, return 0); } diff --git a/src/plugins/valgrind/memcheck/memcheckrunner.cpp b/src/plugins/valgrind/memcheck/memcheckrunner.cpp index 37087fe53d2..baff42faec8 100644 --- a/src/plugins/valgrind/memcheck/memcheckrunner.cpp +++ b/src/plugins/valgrind/memcheck/memcheckrunner.cpp @@ -57,7 +57,8 @@ class MemcheckRunner::Private public: explicit Private() : parser(0), - logSocket(0) + logSocket(0), + disableXml(false) { } @@ -65,6 +66,7 @@ public: XmlProtocol::ThreadedParser *parser; QTcpServer logServer; QTcpSocket *logSocket; + bool disableXml; }; MemcheckRunner::MemcheckRunner(QObject *parent) @@ -106,6 +108,13 @@ bool MemcheckRunner::start() return ValgrindRunner::start(); } +// Workaround for valgrind bug when running vgdb with xml output +// https://bugs.kde.org/show_bug.cgi?id=343902 +void MemcheckRunner::disableXml() +{ + d->disableXml = true; +} + void MemcheckRunner::xmlSocketConnected() { QTcpSocket *socket = d->xmlServer.nextPendingConnection(); @@ -157,13 +166,15 @@ bool MemcheckRunner::startServers(const QHostAddress &localHostAddress) QStringList MemcheckRunner::memcheckLogArguments() const { - return QStringList() - << QLatin1String("--xml=yes") - << QString::fromLatin1("--xml-socket=%1:%2") - .arg(d->xmlServer.serverAddress().toString()).arg(d->xmlServer.serverPort()) - << QLatin1String("--child-silent-after-fork=yes") - << QString::fromLatin1("--log-socket=%1:%2") - .arg(d->logServer.serverAddress().toString()).arg(d->logServer.serverPort()); + QStringList arguments; + if (!d->disableXml) + arguments << QLatin1String("--xml=yes"); + arguments << QString::fromLatin1("--xml-socket=%1:%2") + .arg(d->xmlServer.serverAddress().toString()).arg(d->xmlServer.serverPort()) + << QLatin1String("--child-silent-after-fork=yes") + << QString::fromLatin1("--log-socket=%1:%2") + .arg(d->logServer.serverAddress().toString()).arg(d->logServer.serverPort()); + return arguments; } void MemcheckRunner::localHostAddressRetrieved(const QHostAddress &localHostAddress) diff --git a/src/plugins/valgrind/memcheck/memcheckrunner.h b/src/plugins/valgrind/memcheck/memcheckrunner.h index fd14fea22b7..ae2217ee875 100644 --- a/src/plugins/valgrind/memcheck/memcheckrunner.h +++ b/src/plugins/valgrind/memcheck/memcheckrunner.h @@ -52,6 +52,7 @@ public: void setParser(XmlProtocol::ThreadedParser *parser); bool start(); + void disableXml(); signals: void logMessageReceived(const QByteArray &); diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp index e23f384485c..145a04f88b0 100644 --- a/src/plugins/valgrind/memcheckengine.cpp +++ b/src/plugins/valgrind/memcheckengine.cpp @@ -30,14 +30,22 @@ ****************************************************************************/ #include "memcheckengine.h" - +#include "valgrindprocess.h" #include "valgrindsettings.h" +#include "xmlprotocol/error.h" +#include "xmlprotocol/status.h" +#include +#include +#include + +#include +#include +#include #include +#include #include - -#include -#include +#include #include @@ -65,7 +73,7 @@ QString MemcheckRunControl::progressTitle() const return tr("Analyzing Memory"); } -Valgrind::ValgrindRunner *MemcheckRunControl::runner() +ValgrindRunner *MemcheckRunControl::runner() { return &m_runner; } @@ -129,5 +137,70 @@ QStringList MemcheckRunControl::suppressionFiles() const return m_settings->suppressionFiles(); } +MemcheckWithGdbRunControl::MemcheckWithGdbRunControl(const AnalyzerStartParameters &sp, + RunConfiguration *runConfiguration) + : MemcheckRunControl(sp, runConfiguration) +{ + connect(&m_runner, &Memcheck::MemcheckRunner::started, + this, &MemcheckWithGdbRunControl::startDebugger); + connect(&m_runner, &Memcheck::MemcheckRunner::logMessageReceived, + this, &MemcheckWithGdbRunControl::appendLog); + disconnect(&m_parser, &ThreadedParser::internalError, + this, &MemcheckRunControl::internalParserError); + m_runner.disableXml(); +} + +QStringList MemcheckWithGdbRunControl::toolArguments() const +{ + return MemcheckRunControl::toolArguments() + << QLatin1String("--vgdb=yes") << QLatin1String("--vgdb-error=0"); +} + +void MemcheckWithGdbRunControl::startDebugger() +{ + const qint64 valgrindPid = runner()->valgrindProcess()->pid(); + const AnalyzerStartParameters &mySp = startParameters(); + Debugger::DebuggerStartParameters sp; + + RunConfiguration *rc = runConfiguration(); + const Target *target = rc->target(); + QTC_ASSERT(target, return); + + const Kit *kit = target->kit(); + QTC_ASSERT(kit, return); + + if (const ToolChain *tc = ToolChainKitInformation::toolChain(kit)) + sp.toolChainAbi = tc->targetAbi(); + + if (const Project *project = target->project()) { + sp.projectSourceDirectory = project->projectDirectory().toString(); + sp.projectSourceFiles = project->files(Project::ExcludeGeneratedFiles); + + if (const BuildConfiguration *bc = target->activeBuildConfiguration()) + sp.projectBuildDirectory = bc->buildDirectory().toString(); + } + + sp.executable = mySp.debuggee; + sp.sysRoot = SysRootKitInformation::sysRoot(kit).toString(); + sp.debuggerCommand = Debugger::DebuggerKitInformation::debuggerCommand(kit).toString(); + sp.languages |= Debugger::CppLanguage; + sp.startMode = Debugger::AttachToRemoteServer; + sp.displayName = QString::fromLatin1("VGdb %1").arg(valgrindPid); + sp.remoteChannel = QString::fromLatin1("| vgdb --pid=%1").arg(valgrindPid); + sp.useContinueInsteadOfRun = true; + + QString errorMessage; + RunControl *gdbRunControl = Debugger::DebuggerRunControlFactory::doCreate(sp, rc, &errorMessage); + QTC_ASSERT(gdbRunControl, return); + connect(gdbRunControl, &RunControl::finished, + gdbRunControl, &RunControl::deleteLater); + gdbRunControl->start(); +} + +void MemcheckWithGdbRunControl::appendLog(const QByteArray &data) +{ + appendMessage(QString::fromUtf8(data), Utils::StdOutFormat); +} + } // namespace Internal } // namespace Valgrind diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/valgrind/memcheckengine.h index b7d5ad767dc..3549f58af2b 100644 --- a/src/plugins/valgrind/memcheckengine.h +++ b/src/plugins/valgrind/memcheckengine.h @@ -59,15 +59,29 @@ signals: void suppressionCount(const QString &name, qint64 count); protected: - virtual QString progressTitle() const; - virtual QStringList toolArguments() const; - virtual ValgrindRunner *runner(); + QString progressTitle() const Q_DECL_OVERRIDE; + QStringList toolArguments() const Q_DECL_OVERRIDE; + ValgrindRunner *runner() Q_DECL_OVERRIDE; -private: +protected: XmlProtocol::ThreadedParser m_parser; Memcheck::MemcheckRunner m_runner; }; +class MemcheckWithGdbRunControl : public MemcheckRunControl +{ + Q_OBJECT + +public: + MemcheckWithGdbRunControl(const Analyzer::AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration); + +protected: + QStringList toolArguments() const Q_DECL_OVERRIDE; + void startDebugger(); + void appendLog(const QByteArray &data); +}; + } // namespace Internal } // namespace Valgrind diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 5add68d1c48..04cca4d42a0 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -438,7 +438,7 @@ AnalyzerRunControl *MemcheckTool::createRunControl(const AnalyzerStartParameters m_frameFinder->setFiles(runConfiguration ? runConfiguration->target() ->project()->files(Project::AllFiles) : QStringList()); - MemcheckRunControl *engine = new MemcheckRunControl(sp, runConfiguration); + MemcheckRunControl *engine = createMemcheckRunControl(sp, runConfiguration); connect(engine, &MemcheckRunControl::starting, this, &MemcheckTool::engineStarting); connect(engine, &MemcheckRunControl::parserError, this, &MemcheckTool::parserError); @@ -571,6 +571,12 @@ int MemcheckTool::updateUiAfterFinishedHelper() return issuesFound; } +MemcheckRunControl *MemcheckTool::createMemcheckRunControl(const AnalyzerStartParameters &sp, + RunConfiguration *runConfiguration) +{ + return new MemcheckRunControl(sp, runConfiguration); +} + void MemcheckTool::engineFinished() { const int issuesFound = updateUiAfterFinishedHelper(); @@ -593,5 +599,18 @@ void MemcheckTool::setBusyCursor(bool busy) m_errorView->setCursor(cursor); } +MemcheckWithGdbTool::MemcheckWithGdbTool(QObject *parent) : + MemcheckTool(parent) +{ + setRunMode(MemcheckWithGdbRunMode); + setObjectName(QLatin1String("MemcheckWithGdbTool")); +} + +MemcheckRunControl *MemcheckWithGdbTool::createMemcheckRunControl(const AnalyzerStartParameters &sp, + RunConfiguration *runConfiguration) +{ + return new MemcheckWithGdbRunControl(sp, runConfiguration); +} + } // namespace Internal } // namespace Valgrind diff --git a/src/plugins/valgrind/memchecktool.h b/src/plugins/valgrind/memchecktool.h index bf1795d1904..e830318365f 100644 --- a/src/plugins/valgrind/memchecktool.h +++ b/src/plugins/valgrind/memchecktool.h @@ -54,6 +54,7 @@ namespace Internal { class FrameFinder; class MemcheckErrorView; +class MemcheckRunControl; class ValgrindBaseSettings; class MemcheckErrorFilterProxyModel : public QSortFilterProxyModel @@ -108,6 +109,11 @@ private: void updateFromSettings(); int updateUiAfterFinishedHelper(); +protected: + virtual MemcheckRunControl *createMemcheckRunControl( + const Analyzer::AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration); + private: ValgrindBaseSettings *m_settings; QMenu *m_filterMenu; @@ -126,6 +132,17 @@ private: QAction *m_goNext; }; +class MemcheckWithGdbTool : public MemcheckTool +{ +public: + MemcheckWithGdbTool(QObject *parent); + +protected: + MemcheckRunControl *createMemcheckRunControl( + const Analyzer::AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration) Q_DECL_OVERRIDE; +}; + } // namespace Internal } // namespace Valgrind diff --git a/src/plugins/valgrind/valgrind_dependencies.pri b/src/plugins/valgrind/valgrind_dependencies.pri index 4faca50ffd7..0e3f39ac8a7 100644 --- a/src/plugins/valgrind/valgrind_dependencies.pri +++ b/src/plugins/valgrind/valgrind_dependencies.pri @@ -7,6 +7,7 @@ QTC_LIB_DEPENDS += \ QTC_PLUGIN_DEPENDS += \ analyzerbase \ coreplugin \ + debugger \ projectexplorer \ texteditor \ remotelinux diff --git a/src/plugins/valgrind/valgrindplugin.cpp b/src/plugins/valgrind/valgrindplugin.cpp index f1932c90efe..fb1dbe87cb0 100644 --- a/src/plugins/valgrind/valgrindplugin.cpp +++ b/src/plugins/valgrind/valgrindplugin.cpp @@ -116,6 +116,7 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) addAutoReleasedObject(new ValgrindOptionsPage()); m_memcheckTool = new MemcheckTool(this); + m_memcheckWithGdbTool = new MemcheckWithGdbTool(this); m_callgrindTool = new CallgrindTool(this); ValgrindAction *action = 0; @@ -126,6 +127,10 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) QString memcheckToolTip = tr("Valgrind Analyze Memory uses the " "\"memcheck\" tool to find memory leaks."); + QString memcheckWithGdbToolTip = tr( + "Valgrind Analyze Memory with GDB uses the \"memcheck\" tool to find memory leaks.\n" + "When a problem is detected, the application is interrupted and can be debugged"); + if (!Utils::HostOsInfo::isWindowsHost()) { action = new ValgrindAction(this); action->setId("Memcheck.Local"); @@ -137,6 +142,16 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) action->setEnabled(false); AnalyzerManager::addAction(action); + action = new ValgrindAction(this); + action->setId("MemcheckWithGdb.Local"); + action->setTool(m_memcheckWithGdbTool); + action->setText(tr("Valgrind Memory Analyzer with GDB")); + action->setToolTip(memcheckWithGdbToolTip); + action->setMenuGroup(Constants::G_ANALYZER_TOOLS); + action->setStartMode(StartLocal); + action->setEnabled(false); + AnalyzerManager::addAction(action); + action = new ValgrindAction(this); action->setId("Callgrind.Local"); action->setTool(m_callgrindTool); diff --git a/src/plugins/valgrind/valgrindplugin.h b/src/plugins/valgrind/valgrindplugin.h index 3e189d9d8e8..00706b3592e 100644 --- a/src/plugins/valgrind/valgrindplugin.h +++ b/src/plugins/valgrind/valgrindplugin.h @@ -40,6 +40,7 @@ namespace Internal { class ValgrindGlobalSettings; class MemcheckTool; +class MemcheckWithGdbTool; class CallgrindTool; class ValgrindPlugin : public ExtensionSystem::IPlugin @@ -58,6 +59,7 @@ public: private: MemcheckTool *m_memcheckTool; + MemcheckWithGdbTool *m_memcheckWithGdbTool; CallgrindTool *m_callgrindTool; }; diff --git a/src/plugins/valgrind/valgrindruncontrolfactory.cpp b/src/plugins/valgrind/valgrindruncontrolfactory.cpp index e207d78f855..af78a62cf12 100644 --- a/src/plugins/valgrind/valgrindruncontrolfactory.cpp +++ b/src/plugins/valgrind/valgrindruncontrolfactory.cpp @@ -65,7 +65,7 @@ ValgrindRunControlFactory::ValgrindRunControlFactory(QObject *parent) : bool ValgrindRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const { Q_UNUSED(runConfiguration); - return mode == CallgrindRunMode || mode == MemcheckRunMode; + return mode == CallgrindRunMode || mode == MemcheckRunMode || mode == MemcheckWithGdbRunMode; } RunControl *ValgrindRunControlFactory::create(RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage)