From 09380afe90ff64119425371c8bf83fc1e8612c38 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Tue, 26 May 2009 16:27:24 +0200 Subject: [PATCH] Get attaching to a crashed Windows process right (CDB). Handle the 2nd parameter correctly as a event id to be used for a handshake. Introduce a special mode when attaching to crashed processes. Code cleanup, pass StartParameters along to startDebugger. --- src/plugins/debugger/Debugger.pluginspec | 2 +- src/plugins/debugger/cdb/cdbdebugengine.cpp | 38 +++++++++++++++----- src/plugins/debugger/cdb/cdbdebugengine.h | 5 +-- src/plugins/debugger/debuggermanager.cpp | 4 ++- src/plugins/debugger/debuggermanager.h | 14 ++++---- src/plugins/debugger/debuggerplugin.cpp | 31 +++++++++------- src/plugins/debugger/debuggerplugin.h | 6 ++-- src/plugins/debugger/gdb/gdbengine.cpp | 10 +++--- src/plugins/debugger/gdb/gdbengine.h | 2 +- src/plugins/debugger/idebuggerengine.h | 4 ++- src/plugins/debugger/script/scriptengine.cpp | 4 +-- src/plugins/debugger/script/scriptengine.h | 3 +- src/plugins/debugger/tcf/tcfengine.cpp | 3 +- src/plugins/debugger/tcf/tcfengine.h | 2 +- 14 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/plugins/debugger/Debugger.pluginspec b/src/plugins/debugger/Debugger.pluginspec index 5e98b531319..5f111813254 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 7b606a9e0ea..c6ae43bacff 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 7c0caff2c20..ade64c7d9fc 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 b2a19fe8b1e..90af18e6855 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 884bfeb708b..bc022d9a40b 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 6ca88c951fa..4c09fe9d1d0 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 082a01e0160..7fdf3b08996 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 8f578bfead8..c890742dd1b 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 35c5b45350b..40d6708ae75 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 6c0fdda97e4..b8bcff5cd84 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 652e3e8d7b5..874b1867434 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 ce4f6cb588a..a6b1e8bf957 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 c6bbf7426fe..38e36b7c676 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 f9cfc00ec5b..027c2e48e02 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(); -- GitLab