diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.h b/src/plugins/debugger/gdb/abstractgdbadapter.h index 83a76682b042831c1f639da10cd17bea27b50aa7..8685e98a81c1dbec75f43c1890d7155e9e2d7029 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.h +++ b/src/plugins/debugger/gdb/abstractgdbadapter.h @@ -48,6 +48,11 @@ class AbstractGdbAdapter : public QObject Q_OBJECT public: + enum DumperHandling { DumperNotAvailable, + DumperLoadedByAdapter, + DumperLoadedByGdbPreload, + DumperLoadedByGdb }; + AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0); virtual ~AbstractGdbAdapter(); @@ -61,7 +66,7 @@ public: virtual void shutdown(); virtual const char *inferiorShutdownCommand() const; - virtual bool dumpersAvailable() const = 0; + virtual DumperHandling dumperHandling() const = 0; static QString msgGdbStopFailed(const QString &why); static QString msgInferiorStopFailed(const QString &why); diff --git a/src/plugins/debugger/gdb/attachgdbadapter.h b/src/plugins/debugger/gdb/attachgdbadapter.h index 006b49b1a5b6b37c854087e0a0c62e2d97f0aeb3..16a279f01b032856606410c9acb82794e407582b 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.h +++ b/src/plugins/debugger/gdb/attachgdbadapter.h @@ -48,7 +48,7 @@ class AttachGdbAdapter : public AbstractGdbAdapter public: AttachGdbAdapter(GdbEngine *engine, QObject *parent = 0); - bool dumpersAvailable() const { return true; } + virtual DumperHandling dumperHandling() const { return DumperLoadedByGdb; } void startAdapter(); void startInferior(); diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h index e0bc387c055a8eb4d4dbdda713454a5290b66ca2..bcf95039a41adb24540f767bf0dbbd2a496f09f2 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.h +++ b/src/plugins/debugger/gdb/coregdbadapter.h @@ -52,7 +52,7 @@ class CoreGdbAdapter : public AbstractGdbAdapter public: CoreGdbAdapter(GdbEngine *engine, QObject *parent = 0); - bool dumpersAvailable() const { return false; } + virtual DumperHandling dumperHandling() const { return DumperNotAvailable; } void startAdapter(); void startInferior(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index aa7abd010856aabc8345debe033f644c7f51b043..6c6c307bede2e1ba0d27f7f6c7b9f1746e236401 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1197,7 +1197,8 @@ void GdbEngine::handleStopResponse(const GdbMi &data) } } - bool initHelpers = (m_debuggingHelperState == DebuggingHelperUninitialized); + bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized + || m_debuggingHelperState == DebuggingHelperLoadTried; // Don't load helpers on stops triggered by signals unless it's // an intentional trap. if (initHelpers && reason == "signal-received" @@ -1529,7 +1530,7 @@ AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &s case AttachCore: return new CoreGdbAdapter(this); case StartRemote: - return new RemoteGdbAdapter(this); + return new RemoteGdbAdapter(this, sp->toolChainType); case AttachExternal: return new AttachGdbAdapter(this); default: @@ -1556,7 +1557,7 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp) m_gdbAdapter = createAdapter(sp); connectAdapter(); - if (startModeAllowsDumpers()) + if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) connectDebuggingHelperActions(); m_gdbAdapter->startAdapter(); @@ -2769,7 +2770,7 @@ bool GdbEngine::hasDebuggingHelperForType(const QString &type) const if (!theDebuggerBoolSetting(UseDebuggingHelpers)) return false; - if (!startModeAllowsDumpers()) { + if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) { // "call" is not possible in gdb when looking at core files return type == __("QString") || type.endsWith(__("::QString")) || type == __("QStringList") || type.endsWith(__("::QStringList")); @@ -2811,7 +2812,7 @@ void GdbEngine::runDirectDebuggingHelper(const WatchData &data, bool dumpChildre void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren) { - if (!startModeAllowsDumpers()) { + if (m_debuggingHelperState != DebuggingHelperAvailable) { runDirectDebuggingHelper(data0, dumpChildren); return; } @@ -3847,14 +3848,50 @@ void GdbEngine::assignValueInDebugger(const QString &expression, const QString & postCommand(_("-var-assign assign ") + value, Discardable, CB(handleVarAssign)); } +QString GdbEngine::qtDumperLibraryName() const +{ + return m_manager->qtDumperLibraryName(); +} + +bool GdbEngine::checkDebuggingHelpers() +{ + if (!manager()->qtDumperLibraryEnabled()) + return false; + const QString lib = qtDumperLibraryName(); + //qDebug() << "DUMPERLIB:" << lib; + const QFileInfo fi(lib); + if (!fi.exists()) { + const QStringList &locations = manager()->qtDumperLibraryLocations(); + const QString loc = locations.join(QLatin1String(", ")); + const QString msg = tr("The debugging helper library was not found at %1.").arg(loc); + debugMessage(msg); + manager()->showQtDumperLibraryWarning(msg); + return false; + } + return true; +} + +void GdbEngine::setDebuggingHelperState(DebuggingHelperState s) +{ + m_debuggingHelperState = s; +} + void GdbEngine::tryLoadDebuggingHelpers() { if (isSynchroneous()) return; - - if (m_debuggingHelperState != DebuggingHelperUninitialized) + switch (m_debuggingHelperState) { + case DebuggingHelperUninitialized: + break; + case DebuggingHelperLoadTried: + tryQueryDebuggingHelpers(); return; - if (!startModeAllowsDumpers()) { + case DebuggingHelperAvailable: + case DebuggingHelperUnavailable: + return; + } + + if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) { // Load at least gdb macro based dumpers. QFile file(_(":/gdb/gdbmacros.txt")); file.open(QIODevice::ReadOnly); @@ -3868,22 +3905,11 @@ void GdbEngine::tryLoadDebuggingHelpers() PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS"); m_debuggingHelperState = DebuggingHelperUnavailable; - if (!manager()->qtDumperLibraryEnabled()) - return; - const QString lib = manager()->qtDumperLibraryName(); - const QStringList &locations = manager()->qtDumperLibraryLocations(); - //qDebug() << "DUMPERLIB:" << lib; - // @TODO: same in CDB engine... - const QFileInfo fi(lib); - if (!fi.exists()) { - const QString loc = locations.join(QLatin1String(", ")); - const QString msg = tr("The debugging helper library was not found at %1.").arg(loc); - debugMessage(msg); - manager()->showQtDumperLibraryWarning(msg); + if (!checkDebuggingHelpers()) return; - } m_debuggingHelperState = DebuggingHelperLoadTried; + const QString lib = manager()->qtDumperLibraryName(); #if defined(Q_OS_WIN) if (m_dumperInjectionLoad) { /// Launch asynchronous remote thread to load. @@ -3929,29 +3955,20 @@ void GdbEngine::tryLoadDebuggingHelpers() void GdbEngine::tryQueryDebuggingHelpers() { -#if !X // retrieve list of dumpable classes postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken); postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper)); -#else - m_debuggingHelperState = DebuggingHelperUnavailable; -#endif } void GdbEngine::recheckDebuggingHelperAvailability() { - if (startModeAllowsDumpers()) { + if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) { // retreive list of dumpable classes postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken); postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper)); } } -bool GdbEngine::startModeAllowsDumpers() const -{ - return m_gdbAdapter->dumpersAvailable(); -} - void GdbEngine::watchPoint(const QPoint &pnt) { //qDebug() << "WATCH " << pnt; @@ -4309,7 +4326,12 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr ).arg(scriptFileName)); } } - + if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperLoadedByGdbPreload + && checkDebuggingHelpers()) { + const QString cmd = QLatin1String("set environment LD_PRELOAD ") + manager()->qtDumperLibraryName(); + postCommand(cmd); + m_debuggingHelperState = DebuggingHelperLoadTried; + } return true; } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index ab39b4101ca1d0ddae5e36149ab493bd71726f0e..6c95977dd621519e7dc9a2549413c81c2e58f22b 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -449,8 +449,9 @@ private: ////////// View & Data Stuff ////////// QMap<QString, QString> m_varToType; private: ////////// Dumper Management ////////// - - bool startModeAllowsDumpers() const; + QString qtDumperLibraryName() const; + bool checkDebuggingHelpers(); + void setDebuggingHelperState(DebuggingHelperState); void tryLoadDebuggingHelpers(); void tryQueryDebuggingHelpers(); Q_SLOT void recheckDebuggingHelperAvailability(); diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index 342b89ce3a5cfb40fa6fd7ba8e1264a9c889d2cd..9f0d4c0e832e62e5cf82602f693d057cfd815651 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -58,6 +58,15 @@ PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) engine, SLOT(readDebugeeOutput(QByteArray))); } +AbstractGdbAdapter::DumperHandling PlainGdbAdapter::dumperHandling() const +{ +#ifdef Q_OS_WIN + return DumperLoadedByGdb; +#else + return DumperLoadedByGdbPreload; +#endif +} + void PlainGdbAdapter::startAdapter() { QTC_ASSERT(state() == EngineStarting, qDebug() << state()); diff --git a/src/plugins/debugger/gdb/plaingdbadapter.h b/src/plugins/debugger/gdb/plaingdbadapter.h index 41154640223c4bc45384d19b269cb60a903e4eab..21545212af73e49ccac7ffaf350eb9087ae88d82 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.h +++ b/src/plugins/debugger/gdb/plaingdbadapter.h @@ -50,7 +50,7 @@ class PlainGdbAdapter : public AbstractGdbAdapter public: PlainGdbAdapter(GdbEngine *engine, QObject *parent = 0); - bool dumpersAvailable() const { return true; } + virtual DumperHandling dumperHandling() const; void startAdapter(); void startInferior(); diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index d49a03aaceda13984725183f19af4811dba7fdfb..4550359956a1023e721e135408499aa63e70e446 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -34,6 +34,7 @@ #include <utils/qtcassert.h> #include <utils/fancymainwindow.h> +#include <projectexplorer/toolchain.h> #include <QtCore/QFileInfo> #include <QtGui/QMessageBox> @@ -51,8 +52,9 @@ namespace Internal { // /////////////////////////////////////////////////////////////////////// -RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent) - : AbstractGdbAdapter(engine, parent) +RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent) : + AbstractGdbAdapter(engine, parent), + m_toolChainType(toolChainType) { connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(uploadProcError(QProcess::ProcessError))); @@ -62,6 +64,23 @@ RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent) this, SLOT(readUploadStandardError())); } +AbstractGdbAdapter::DumperHandling RemoteGdbAdapter::dumperHandling() const +{ + switch (m_toolChainType) { + case ProjectExplorer::ToolChain::MinGW: + case ProjectExplorer::ToolChain::MSVC: + case ProjectExplorer::ToolChain::WINCE: + case ProjectExplorer::ToolChain::WINSCW: + case ProjectExplorer::ToolChain::GCCE: + case ProjectExplorer::ToolChain::RVCT_ARMV5: + case ProjectExplorer::ToolChain::RVCT_ARMV6: + return DumperLoadedByGdb; + default: + break; + } + return DumperLoadedByGdbPreload; +} + void RemoteGdbAdapter::startAdapter() { QTC_ASSERT(state() == EngineStarting, qDebug() << state()); diff --git a/src/plugins/debugger/gdb/remotegdbadapter.h b/src/plugins/debugger/gdb/remotegdbadapter.h index 24ca66b43949c199ab90ba3a781143c14d140790..fd435caeabc210d596e5548690b7fbe6df4519ec 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.h +++ b/src/plugins/debugger/gdb/remotegdbadapter.h @@ -46,9 +46,9 @@ class RemoteGdbAdapter : public AbstractGdbAdapter Q_OBJECT public: - RemoteGdbAdapter(GdbEngine *engine, QObject *parent = 0); + RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0); - bool dumpersAvailable() const { return true; } + virtual DumperHandling dumperHandling() const; void startAdapter(); void startInferior(); @@ -67,6 +67,8 @@ private: void handleFileExecAndSymbols(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response); + const int m_toolChainType; + QProcess m_uploadProc; }; diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp index b369dad4c6d8d92597686f0f841c528013981188..19de9ffa06777a79c81b0a767c0d878d8c43b0d2 100644 --- a/src/plugins/debugger/gdb/termgdbadapter.cpp +++ b/src/plugins/debugger/gdb/termgdbadapter.cpp @@ -69,6 +69,15 @@ TermGdbAdapter::~TermGdbAdapter() m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub } +AbstractGdbAdapter::DumperHandling TermGdbAdapter::dumperHandling() const +{ +#ifdef Q_OS_WIN + return DumperLoadedByGdb; +#else + return DumperLoadedByAdapter; // Handles loading itself via LD_PRELOAD +#endif +} + void TermGdbAdapter::startAdapter() { QTC_ASSERT(state() == EngineStarting, qDebug() << state()); @@ -82,7 +91,14 @@ void TermGdbAdapter::startAdapter() // m_stubProc.blockSignals(false); m_stubProc.setWorkingDirectory(startParameters().workingDir); - m_stubProc.setEnvironment(startParameters().environment); + // Set environment + dumper preload. + QStringList environment = startParameters().environment; + if (dumperHandling() == DumperLoadedByGdbPreload + && m_engine->checkDebuggingHelpers()) { + environment.push_back(QLatin1String("LD_PRELOAD=") + m_engine->qtDumperLibraryName()); + m_engine->setDebuggingHelperState(DebuggingHelperLoadTried); + } + m_stubProc.setEnvironment(environment); // FIXME: Starting the stub implies starting the inferior. This is // fairly unclean as far as the state machine and error reporting go. if (!m_stubProc.start(startParameters().executable, diff --git a/src/plugins/debugger/gdb/termgdbadapter.h b/src/plugins/debugger/gdb/termgdbadapter.h index 1b98eed9874bc906b09d7829a2267afb117a3056..0444555f92ee0bfc9f2d4e1d633566047193cfee 100644 --- a/src/plugins/debugger/gdb/termgdbadapter.h +++ b/src/plugins/debugger/gdb/termgdbadapter.h @@ -51,7 +51,7 @@ public: TermGdbAdapter(GdbEngine *engine, QObject *parent = 0); ~TermGdbAdapter(); - bool dumpersAvailable() const { return true; } + virtual DumperHandling dumperHandling() const; void startAdapter(); void startInferior(); diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index a4e01f3258a6ab5bda1b3574b489f0eb64e9d6db..c59894ffd09c73f57f8d72d4dbe8ac1a863b4781 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -164,7 +164,8 @@ public: QIODevice::OpenMode mode = QIODevice::ReadWrite); void write(const QByteArray &data); bool isTrkAdapter() const { return true; } - bool dumpersAvailable() const { return false; } + + virtual DumperHandling dumperHandling() const { return DumperNotAvailable; } private: void startAdapter();