diff --git a/src/plugins/debugger/Debugger.pluginspec b/src/plugins/debugger/Debugger.pluginspec index 5e98b53131921aec7e19c17336a067b8087ac50b..5f1118132540f4a205986ce1c5bb90d85e52177e 100644 --- a/src/plugins/debugger/Debugger.pluginspec +++ b/src/plugins/debugger/Debugger.pluginspec @@ -30,6 +30,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license> <argument name="-disable-sdb">Disable Qt Script debugger engine</argument> <argument name="-disable-tcf">Disable Tcf debugger engine</argument> <argument name="-debug" parameter="process-id">Attach to Process-Id</argument> - <argument name="-winexception" parameter="exception-code">Exception code</argument> + <argument name="-wincrashevent" parameter="event-handle">Event handle used for attaching to crashed processes</argument> </argumentList> </plugin> diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 7b606a9e0ea9bec8a70d7fb1f732ffc81c70ebd9..c6ae43bacff96749c64ef09b33a232ce573cc3e6 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -526,15 +526,16 @@ void CdbDebugEnginePrivate::clearDisplay() m_debuggerManagerAccess->registerHandler()->removeAll(); } -bool CdbDebugEngine::startDebugger() +bool CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) { m_d->clearDisplay(); const DebuggerStartMode mode = m_d->m_debuggerManager->startMode(); - const QSharedPointer<DebuggerStartParameters> sp = m_d->m_debuggerManager->startParameters(); // Figure out dumper. @TODO: same in gdb... const QString dumperLibName = QDir::toNativeSeparators(m_d->m_debuggerManagerAccess->qtDumperLibraryName()); - bool dumperEnabled = mode != AttachCore && !dumperLibName.isEmpty() + bool dumperEnabled = mode != AttachCore + && mode != AttachCrashedExternal + && !dumperLibName.isEmpty() && m_d->m_debuggerManagerAccess->qtDumperLibraryEnabled(); if (dumperEnabled) { const QFileInfo fi(dumperLibName); @@ -552,8 +553,9 @@ bool CdbDebugEngine::startDebugger() m_d->clearForRun(); switch (mode) { case AttachExternal: - rc = startAttachDebugger(sp->attachPID, &errorMessage); - needWatchTimer = true; + case AttachCrashedExternal: + rc = startAttachDebugger(sp->attachPID, mode, &errorMessage); + needWatchTimer = true; // Fetch away module load, etc. even if crashed break; case StartInternal: case StartExternal: @@ -585,7 +587,7 @@ bool CdbDebugEngine::startDebugger() return rc; } -bool CdbDebugEngine::startAttachDebugger(qint64 pid, QString *errorMessage) +bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage) { // Need to attrach invasively, otherwise, no notification signals // for for CreateProcess/ExitProcess occur. @@ -597,7 +599,7 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, QString *errorMessage) *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr)); return false; } else { - m_d->m_mode = AttachExternal; + m_d->m_mode = sm; } return true; } @@ -679,6 +681,17 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 m_engine->executeDebuggerCommand(QLatin1String("bc")); if (m_debuggerManagerAccess->breakHandler()->hasPendingBreakpoints()) m_engine->attemptBreakpointSynchronization(); + // Attaching to crashed: This handshake (signalling an event) is required for + // the exception to be delivered to the debugger + if (m_mode == AttachCrashedExternal) { + const QString crashParameter = m_debuggerManager->startParameters()->crashParameter; + if (!crashParameter.isEmpty()) { + ULONG64 evtNr = crashParameter.toULongLong(); + const HRESULT hr = m_cif.debugControl->SetNotifyEventHandle(evtNr); + if (FAILED(hr)) + m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(msgComFailed("SetNotifyEventHandle", hr))); + } + } if (debugCDB) qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl); } @@ -707,7 +720,8 @@ void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em) Action action; switch (em) { case EndDebuggingAuto: - action = m_mode == AttachExternal ? Detach : Terminate; + action = (m_mode == AttachExternal || m_mode == AttachCrashedExternal) ? + Detach : Terminate; break; case EndDebuggingDetach: action = Detach; @@ -1417,7 +1431,7 @@ void CdbDebugEngine::slotConsoleStubStarted() qDebug() << Q_FUNC_INFO << appPid; // Attach to console process QString errorMessage; - if (startAttachDebugger(appPid, &errorMessage)) { + if (startAttachDebugger(appPid, AttachExternal, &errorMessage)) { startWatchTimer(); m_d->m_debuggerManagerAccess->notifyInferiorPidChanged(appPid); m_d->m_debuggerManagerAccess->notifyInferiorRunning(); @@ -1436,6 +1450,12 @@ void CdbDebugEngine::slotConsoleStubTerminated() exitDebugger(); } +void CdbDebugEngine::slotAttachedCrashed() +{ + m_d->m_debuggerManagerAccess->showDebuggerOutput("A","A"); + m_d->handleDebugEvent(); +} + void CdbDebugEngine::warning(const QString &w) { static const QString prefix = QLatin1String("warning:"); diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 7c0caff2c20cd13f1e34dab9c4b029d270345f01..ade64c7d9fcb28790b49fbc0862f865a831afe20 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -61,7 +61,7 @@ public: virtual void shutdown(); virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - virtual bool startDebugger(); + virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters); virtual void exitDebugger(); virtual void detachDebugger(); virtual void updateWatchModel(); @@ -107,10 +107,11 @@ private slots: void slotConsoleStubStarted(); void slotConsoleStubError(const QString &msg); void slotConsoleStubTerminated(); + void slotAttachedCrashed(); void warning(const QString &w); private: - bool startAttachDebugger(qint64 pid, QString *errorMessage); + bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage); bool startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage); void startWatchTimer(); void killWatchTimer(); diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index b2a19fe8b1e15cfe3ac849e989374423ed444388..90af18e6855c608a6093bec18dda46dc7ad7a5b1 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -192,6 +192,7 @@ void DebuggerStartParameters::clear() buildDir.clear(); attachPID = -1; useTerminal = false; + crashParameter.clear(); remoteChannel.clear(); remoteArchitecture.clear(); serverStartScript.clear(); @@ -892,6 +893,7 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl, const QSh QString settingsIdHint; switch (startMode()) { case AttachExternal: + case AttachCrashedExternal: m_engine = determineDebuggerEngine(m_startParameters->attachPID, &errorMessage); break; case AttachTcf: @@ -919,7 +921,7 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl, const QSh setBusyCursor(false); setStatus(DebuggerProcessStartingUp); - if (!m_engine->startDebugger()) { + if (!m_engine->startDebugger(m_startParameters)) { setStatus(DebuggerProcessNotReady); debuggingFinished(); return; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 884bfeb708bdfaa5e7d6ffe0b124f17ddb93fe5b..bc022d9a40bd1c4fb0a01df15b098e37fce2db06 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -118,12 +118,13 @@ enum DebuggerStatus enum DebuggerStartMode { - StartInternal, // Start current start project's binary - StartExternal, // Start binary found in file system - AttachExternal, // Attach to running process - AttachTcf, // Attach to a running Target Communication Framework agent - AttachCore, // Attach to a core file - StartRemote // Start and attach to a remote process + StartInternal, // Start current start project's binary + StartExternal, // Start binary found in file system + AttachExternal, // Attach to running process by process id + AttachCrashedExternal, // Attach to crashed process by process id + AttachTcf, // Attach to a running Target Communication Framework agent + AttachCore, // Attach to a core file + StartRemote // Start and attach to a remote process }; struct DebuggerStartParameters { @@ -138,6 +139,7 @@ struct DebuggerStartParameters { QString buildDir; qint64 attachPID; bool useTerminal; + QString crashParameter; // for AttachCrashedExternal // for remote debugging QString remoteChannel; QString remoteArchitecture; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 6ca88c951fae72c7a924ea8e6e48078e703f0066..4c09fe9d1d0442061e3dc14308653d3cd735cb9e 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -404,7 +404,7 @@ DebuggerPlugin::DebuggerPlugin() m_gdbRunningContext(0), m_cmdLineEnabledEngines(AllEngineTypes), m_cmdLineAttachPid(0), - m_cmdLineWinException(0), + m_cmdLineWinCrashEvent(0), m_toggleLockedAction(0) {} @@ -465,15 +465,16 @@ bool DebuggerPlugin::parseArgument(QStringList::const_iterator &it, } return true; } - // -winexception <exception code>, passed in by Windows System - if (*it == QLatin1String("-winexception")) { + // -wincrashevent <event-handle>. A handle used for + // a handshake when attaching to a crashed Windows process. + if (*it == QLatin1String("-wincrashevent")) { ++it; if (it == cend) { *errorMessage = msgParameterMissing(*it); return false; } bool ok; - m_cmdLineWinException = it->toULong(&ok); + m_cmdLineWinCrashEvent = it->toULongLong(&ok); if (!ok) { *errorMessage = msgInvalidNumericParameter(option, *it); return false; @@ -515,8 +516,12 @@ bool DebuggerPlugin::parseArguments(const QStringList &args, QString *errorMessa bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { - if (!parseArguments(arguments, errorMessage)) - return false; + // Do not fail the whole plugin if something goes wrong here + if (!parseArguments(arguments, errorMessage)) { + *errorMessage = tr("Error evaluating command line arguments: %1").arg(*errorMessage); + qWarning("%s\n", qPrintable(*errorMessage)); + errorMessage->clear(); + } m_manager = new DebuggerManager; const QList<Core::IOptionsPage *> engineOptionPages = m_manager->initializeEngines(m_cmdLineEnabledEngines); @@ -915,11 +920,9 @@ void DebuggerPlugin::extensionsInitialized() void DebuggerPlugin::attachCmdLinePid() { - const QString msg = m_cmdLineWinException ? - tr("Attaching to PID %1 (exception code %2).").arg(m_cmdLineAttachPid).arg(m_cmdLineWinException) : - tr("Attaching to PID %1.").arg(m_cmdLineAttachPid); - m_manager->showStatusMessage(msg); - attachExternalApplication(m_cmdLineAttachPid); + m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_cmdLineAttachPid)); + const QString crashParameter = m_cmdLineWinCrashEvent ? QString::number(m_cmdLineWinCrashEvent) : QString(); + attachExternalApplication(m_cmdLineAttachPid, crashParameter); } /*! Activates the previous mode when the current mode is the debug mode. */ @@ -1215,7 +1218,7 @@ void DebuggerPlugin::attachExternalApplication() attachExternalApplication(dlg.attachPID()); } -void DebuggerPlugin::attachExternalApplication(qint64 pid) +void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashParameter) { if (pid == 0) { QMessageBox::warning(m_manager->mainWindow(), tr("Warning"), tr("Cannot attach to PID 0")); @@ -1223,9 +1226,11 @@ void DebuggerPlugin::attachExternalApplication(qint64 pid) } const QSharedPointer<DebuggerStartParameters> sp(new DebuggerStartParameters); sp->attachPID = pid; + sp->crashParameter = crashParameter; + const DebuggerStartMode dsm = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal; QSharedPointer<RunConfiguration> rc = activeRunConfiguration(); if (RunControl *runControl = m_debuggerRunner - ->run(rc, ProjectExplorer::Constants::DEBUGMODE, sp, AttachExternal)) + ->run(rc, ProjectExplorer::Constants::DEBUGMODE, sp, dsm)) runControl->start(); } diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index 082a01e0160f9903bf12d56ff14b00b1ea089e53..7fdf3b08996880ef678c66a2aeae0aec65b59025 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -115,7 +115,7 @@ private: inline bool parseArgument(QStringList::const_iterator &it, const QStringList::const_iterator& end, QString *errorMessage); - void attachExternalApplication(qint64 pid); + void attachExternalApplication(qint64 pid, const QString &crashParameter = QString()); friend class DebuggerManager; friend class GdbOptionPage; @@ -131,8 +131,8 @@ private: int m_gdbRunningContext; unsigned m_cmdLineEnabledEngines; quint64 m_cmdLineAttachPid; - // Exception that crashed an app passed on by Windows - unsigned long m_cmdLineWinException; + // Event handle for attaching to crashed Windows processes. + quint64 m_cmdLineWinCrashEvent; QAction *m_toggleLockedAction; QAction *m_startExternalAction; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8f578bfead8c787e5528c4d854ead62f7c228b84..c890742dd1b4c0d97e9ae510e3318aca10c5004e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1327,7 +1327,7 @@ void GdbEngine::exitDebugger() qDebug() << "STATUS ON EXITDEBUGGER:" << q->status()); interruptInferior(); } - if (q->startMode() == AttachExternal) + if (q->startMode() == AttachExternal || q->startMode() == AttachCrashedExternal) postCommand(_("detach")); else postCommand(_("kill")); @@ -1355,7 +1355,7 @@ int GdbEngine::currentFrame() const return qq->stackHandler()->currentIndex(); } -bool GdbEngine::startDebugger() +bool GdbEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) { debugMessage(DebuggerSettings::instance()->dump()); QStringList gdbArgs; @@ -1369,9 +1369,7 @@ bool GdbEngine::startDebugger() gdbArgs.prepend(_("mi")); gdbArgs.prepend(_("-i")); - const QSharedPointer<DebuggerStartParameters> sp = q->startParameters(); - - if (q->startMode() == AttachCore || q->startMode() == AttachExternal) { + if (q->startMode() == AttachCore || q->startMode() == AttachExternal || q->startMode() == AttachCrashedExternal) { // nothing to do } else if (q->startMode() == StartRemote) { // Start the remote server @@ -1510,7 +1508,7 @@ bool GdbEngine::startDebugger() } } - if (q->startMode() == AttachExternal) { + if (q->startMode() == AttachExternal || q->startMode() == AttachCrashedExternal) { postCommand(_("attach %1").arg(sp->attachPID), CB(handleAttach)); qq->breakHandler()->removeAllBreakpoints(); } else if (q->startMode() == AttachCore) { diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 35c5b45350b23d97369bcba296d600d5c930160a..40d6708ae750afdc940404dc9c47192153b22d41 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -97,7 +97,7 @@ private: void shutdown(); void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - bool startDebugger(); + bool startDebugger(const QSharedPointer<DebuggerStartParameters> &sp); void exitDebugger(); void detachDebugger(); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 6c0fdda97e4a78a05626372ed26245ceab573d35..b8bcff5cd84c76c08b93216d6c37bb2d8f538815 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -32,6 +32,7 @@ #include <QtCore/QObject> #include <QtCore/QList> +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE class QPoint; @@ -46,6 +47,7 @@ namespace Debugger { namespace Internal { class Symbol; +struct DebuggerStartParameters; class IDebuggerEngine : public QObject { @@ -54,7 +56,7 @@ public: virtual void shutdown() = 0; virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos) = 0; - virtual bool startDebugger() = 0; + virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0; virtual void exitDebugger() = 0; virtual void detachDebugger() {} virtual void updateWatchModel() = 0; diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index 652e3e8d7b55b7385a6ac58eb986bba03f048ae9..874b18674342cc85e2812b17b5865b3f3e68dcd2 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -219,12 +219,12 @@ void ScriptEngine::exitDebugger() qq->notifyInferiorExited(); } -bool ScriptEngine::startDebugger() +bool ScriptEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) { m_stopped = false; m_stopOnNextLine = false; m_scriptEngine->abortEvaluation(); - const QSharedPointer<DebuggerStartParameters> sp = q->startParameters(); + QFileInfo fi(sp->executable); m_scriptFileName = fi.absoluteFilePath(); QFile scriptFile(m_scriptFileName); diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h index ce4f6cb588a4d80ac18afb1030a513824d70c95c..a6b1e8bf95764ecf00ec1088747c68ff3efb7c68 100644 --- a/src/plugins/debugger/script/scriptengine.h +++ b/src/plugins/debugger/script/scriptengine.h @@ -76,7 +76,8 @@ private: void shutdown(); void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - bool startDebugger(); + bool startDebugger(const QSharedPointer<DebuggerStartParameters> &sp); + void exitDebugger(); void continueInferior(); diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp index c6bbf7426fe52ee4a27b4543c0fc8063c53e6443..38e36b7c6766dc59f132acae2d64f56b67cb7ba4 100644 --- a/src/plugins/debugger/tcf/tcfengine.cpp +++ b/src/plugins/debugger/tcf/tcfengine.cpp @@ -221,10 +221,9 @@ void TcfEngine::exitDebugger() qq->notifyInferiorExited(); } -bool TcfEngine::startDebugger() +bool TcfEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) { qq->notifyInferiorRunningRequested(); - const QSharedPointer<DebuggerStartParameters> sp = qq->startParameters(); const int pos = sp->remoteChannel.indexOf(QLatin1Char(':')); const QString host = sp->remoteChannel.left(pos); const quint16 port = sp->remoteChannel.mid(pos + 1).toInt(); diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h index f9cfc00ec5b6524ea5b7b9d26ee08ba7a1afbf26..027c2e48e025eec09874bc084aae0d3c067006be 100644 --- a/src/plugins/debugger/tcf/tcfengine.h +++ b/src/plugins/debugger/tcf/tcfengine.h @@ -82,7 +82,7 @@ private: void shutdown(); void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - bool startDebugger(); + bool startDebugger(const QSharedPointer<DebuggerStartParameters> &sp); void exitDebugger(); void continueInferior();