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.
Disable Qt Script debugger engine
Disable Tcf debugger engine
Attach to Process-Id
- Exception code
+ Event handle used for attaching to crashed processes
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 &sp)
{
m_d->clearDisplay();
const DebuggerStartMode mode = m_d->m_debuggerManager->startMode();
- const QSharedPointer 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 &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 , passed in by Windows System
- if (*it == QLatin1String("-winexception")) {
+ // -wincrashevent . 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 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 sp(new DebuggerStartParameters);
sp->attachPID = pid;
+ sp->crashParameter = crashParameter;
+ const DebuggerStartMode dsm = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal;
QSharedPointer 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 &sp)
{
debugMessage(DebuggerSettings::instance()->dump());
QStringList gdbArgs;
@@ -1369,9 +1369,7 @@ bool GdbEngine::startDebugger()
gdbArgs.prepend(_("mi"));
gdbArgs.prepend(_("-i"));
- const QSharedPointer 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 &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
#include
+#include
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 &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 &sp)
{
m_stopped = false;
m_stopOnNextLine = false;
m_scriptEngine->abortEvaluation();
- const QSharedPointer 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 &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 &sp)
{
qq->notifyInferiorRunningRequested();
- const QSharedPointer 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 &sp);
void exitDebugger();
void continueInferior();