return "unknown";
}
-void CdbEngine::handleSessionIdle(const QByteArray &message)
+/* Examine how to react to a stop. */
+enum StopActionFlags
+{
+ // Report options
+ StopReportLog = 0x1,
+ StopReportStatusMessage = 0x2,
+ StopReportParseError = 0x2,
+ StopShowExceptionMessageBox = 0x4,
+ // Notify stop or just continue
+ StopNotifyStop = 0x8,
+ StopIgnoreContinue = 0x10
+};
+
+unsigned CdbEngine::examineStopReason(const QByteArray &messageIn,
+ QString *message,
+ QString *exceptionBoxMessage) const
+{
+ // Report stop reason (GDBMI)
+ GdbMi stopReason;
+ stopReason.fromString(messageIn);
+ if (debug)
+ qDebug("%s", stopReason.toString(true, 4).constData());
+ const QByteArray reason = stopReason.findChild("reason").data();
+ if (reason.isEmpty()) {
+ *message = tr("Malformed stop response received.");
+ return StopReportParseError|StopNotifyStop;
+ }
+ const int threadId = stopReason.findChild("threadId").data().toInt();
+ if (reason == "breakpoint") {
+ const int number = stopReason.findChild("breakpointId").data().toInt();
+ const BreakpointId id = breakHandler()->findBreakpointByNumber(number);
+ if (id && breakHandler()->type(id) == Watchpoint) {
+ *message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
+ } else {
+ *message = msgBreakpointTriggered(id, number, QString::number(threadId));
+ }
+ return StopReportStatusMessage|StopNotifyStop;
+ }
+ if (reason == "exception") {
+ WinException exception;
+ exception.fromGdbMI(stopReason);
+#ifdef Q_OS_WIN
+ // It is possible to hit on a startup trap while stepping (if something
+ // pulls DLLs. Avoid showing a 'stopped' Message box.
+ if (exception.exceptionCode == winExceptionStartupCompleteTrap)
+ return StopNotifyStop;
+ const QString description = exception.toString();
+ // WOW 64 breakpoint: just report in log and continue
+ if (exception.exceptionCode == winExceptionWX86Breakpoint) {
+ *message = description;
+ return StopIgnoreContinue|StopReportLog;
+ }
+ if (isDebuggerWinException(exception.exceptionCode)) {
+ *message = msgInterrupted();
+ return StopReportStatusMessage|StopNotifyStop;
+ }
+#endif
+ *exceptionBoxMessage = msgStoppedByException(description, QString::number(threadId));
+ *message = description;
+ return StopShowExceptionMessageBox|StopReportStatusMessage|StopNotifyStop;
+ }
+ *message = msgStopped(QLatin1String(reason));
+ return StopReportStatusMessage|StopNotifyStop;
+}
+
+void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
{
if (!m_hasDebuggee)
return;
if (debug)
qDebug("CdbEngine::handleSessionIdle %dms '%s' in state '%s', special mode %d",
- elapsedLogTime(), message.constData(),
+ elapsedLogTime(), messageBA.constData(),
stateName(state()), m_specialStopMode);
// Switch source level debugging
syncOperateByInstruction(m_operateByInstructionPending);
+ // Engine-special stop reasons: Breakpoints and setup
const SpecialStopMode specialStopMode = m_specialStopMode;
m_specialStopMode = NoSpecialStop;
case NoSpecialStop:
break;
}
- switch(state()) { // Temporary stop at beginning
- case EngineSetupRequested:
+
+ if (state() == EngineSetupRequested) { // Temporary stop at beginning
if (debug)
qDebug("notifyEngineSetupOk");
notifyEngineSetupOk();
return;
- case InferiorSetupRequested:
- return;
- case InferiorStopRequested:
- case InferiorRunOk:
- break; // Proper stop of inferior handled below.
-
- default:
- qWarning("WARNING: CdbEngine::handleSessionAccessible called in state %s", stateName(state()));
- return;
}
- // Handle stop.
- if (state() == InferiorStopRequested) {
- if (debug)
- qDebug("notifyInferiorStopOk");
- notifyInferiorStopOk();
- } else {
- if (debug)
- qDebug("notifyInferiorSpontaneousStop");
- notifyInferiorSpontaneousStop();
- }
- // Start sequence to get all relevant data. Hack: Avoid module reload?
- unsigned sequence = CommandListStack|CommandListThreads;
- if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
- sequence |= CommandListRegisters;
- if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
- sequence |= CommandListModules;
- postCommandSequence(sequence);
- // Report stop reason (GDBMI)
- GdbMi stopReason;
- stopReason.fromString(message);
- if (debug)
- qDebug("%s", stopReason.toString(true, 4).constData());
- const QByteArray reason = stopReason.findChild("reason").data();
- if (reason.isEmpty()) {
- showStatusMessage(tr("Malformed stop response received."), LogError);
+
+ // Further examine stop and report to user
+ QString message;
+ QString exceptionBoxMessage;
+ const unsigned stopFlags = examineStopReason(messageBA, &message, &exceptionBoxMessage);
+ // Do the non-blocking log reporting
+ if (stopFlags & StopReportLog)
+ showMessage(message, LogMisc);
+ if (stopFlags & StopReportStatusMessage)
+ showStatusMessage(message);
+ if (stopFlags & StopReportParseError)
+ showMessage(message, LogError);
+ // Ignore things like WOW64
+ if (stopFlags & StopIgnoreContinue) {
+ postCommand("g", 0);
return;
}
- const int threadId = stopReason.findChild("threadId").data().toInt();
- if (reason == "breakpoint") {
- const int number = stopReason.findChild("breakpointId").data().toInt();
- const BreakpointId id = breakHandler()->findBreakpointByNumber(number);
- if (id && breakHandler()->type(id) == Watchpoint) {
- showStatusMessage(msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId)));
+ // Notify about state and send off command sequence to get stack, etc.
+ if (stopFlags & StopNotifyStop) {
+ if (state() == InferiorStopRequested) {
+ if (debug)
+ qDebug("notifyInferiorStopOk");
+ notifyInferiorStopOk();
} else {
- showStatusMessage(msgBreakpointTriggered(id, number, QString::number(threadId)));
- }
- return;
- }
- if (reason == "exception") {
- WinException exception;
- exception.fromGdbMI(stopReason);
-#ifdef Q_OS_WIN
- // It is possible to hit on a startup trap while stepping (if something
- // pulls DLLs. Avoid showing a 'stopped' Message box.
- if (exception.exceptionCode == winExceptionStartupCompleteTrap)
- return;
- if (isDebuggerWinException(exception.exceptionCode)) {
- showStatusMessage(msgInterrupted());
- return;
+ if (debug)
+ qDebug("notifyInferiorSpontaneousStop");
+ notifyInferiorSpontaneousStop();
}
-#endif
- const QString description = exception.toString();
- showStatusMessage(msgStoppedByException(description, QString::number(threadId)));
- showStoppedByExceptionMessageBox(description);
- return;
- }
- showStatusMessage(msgStopped(QLatin1String(reason)));
+ // Start sequence to get all relevant data.
+ unsigned sequence = CommandListStack|CommandListThreads;
+ if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
+ sequence |= CommandListRegisters;
+ if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
+ sequence |= CommandListModules;
+ postCommandSequence(sequence);
+ }
+ // After the sequence has been sent off and CDB is pondering the commands,
+ // pop up a message box for exceptions.
+ if (stopFlags & StopShowExceptionMessageBox)
+ showStoppedByExceptionMessageBox(exceptionBoxMessage);
}
void CdbEngine::handleSessionAccessible(unsigned long cdbExState)
&& breakEvents == rhs.breakEvents;
}
+// Check the CDB executable and accumulate the list of checked paths
+// for reporting.
+static QString checkCdbExecutable(const QString &programDir, const QString &postfix,
+ QStringList *checkedDirectories = 0)
+{
+ QString executable = programDir;
+ executable += QLatin1String("/Debugging Tools For Windows");
+ executable += postfix;
+ if (checkedDirectories)
+ checkedDirectories->push_back(QDir::toNativeSeparators(executable));
+ executable += QLatin1String("/cdb.exe");
+ const QFileInfo fi(executable);
+ return fi.isFile() && fi.isExecutable() ? fi.absoluteFilePath() : QString();
+}
+
bool CdbOptions::autoDetectExecutable(QString *outPath, bool *is64bitIn /* = 0 */,
QStringList *checkedDirectories /* = 0 */)
{
static const char *postFixes[] = {" (x64)", " 64-bit", " (x86)", " (x32)" };
enum { first32bitIndex = 2 };
+ outPath->clear();
if (checkedDirectories)
checkedDirectories->clear();
- outPath->clear();
- const QByteArray programDirB = qgetenv("ProgramFiles");
- if (programDirB.isEmpty())
+ const QString programDir = QString::fromLocal8Bit(qgetenv("ProgramFiles"));
+ if (programDir.isEmpty())
return false;
- const QString programDir = QString::fromLocal8Bit(programDirB) + QLatin1Char('/');
- const QString installDir = QLatin1String("Debugging Tools For Windows");
- const QString executable = QLatin1String("/cdb.exe");
-
- QString path = programDir + installDir;
- if (checkedDirectories)
- checkedDirectories->push_back(path);
- const QFileInfo fi(path + executable);
- // Plain system installation
- if (fi.isFile() && fi.isExecutable()) {
- *outPath = fi.absoluteFilePath();
- if (is64bitIn)
#ifdef Q_OS_WIN
- *is64bitIn = Utils::winIs64BitSystem();
+ const bool systemIs64Bit = Utils::winIs64BitSystem();
#else
- *is64bitIn = false;
+ const bool systemIs64Bit = false;
#endif
+ // Plain system installation. 32/64 Bit matches the system.
+ *outPath = checkCdbExecutable(programDir, QString(), checkedDirectories);
+ if (!outPath->isEmpty()) {
+ if (is64bitIn)
+ *is64bitIn = systemIs64Bit;
return true;
}
// Try the post fixes
- const int rootLength = path.size();
for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
- path.truncate(rootLength);
- path += QLatin1String(postFixes[i]);
- if (checkedDirectories)
- checkedDirectories->push_back(path);
- const QFileInfo fi2(path + executable);
- if (fi2.isFile() && fi2.isExecutable()) {
+ *outPath = checkCdbExecutable(programDir, QLatin1String(postFixes[i]), checkedDirectories);
+ if (!outPath->isEmpty()) {
if (is64bitIn)
*is64bitIn = i < first32bitIndex;
- *outPath = fi2.absoluteFilePath();
return true;
}
}
+ // A 32bit-compile running on a 64bit system sees the 64 bit installation
+ // as "$ProgramFiles (x64)/Debugging Tools..." and (untested), a 64 bit-
+ // compile running on a 64bit system sees the 32 bit installation as
+ // "$ProgramFiles (x86)/Debugging Tools..." (assuming this works at all)
+#ifdef Q_OS_WIN64
+ *outPath = checkCdbExecutable(programDir + QLatin1String(" (x32)"), QString(), checkedDirectories);
+ if (!outPath->isEmpty()) {
+ if (is64bitIn)
+ *is64bitIn = false;
+ return true;
+ }
+#else
+ *outPath = checkCdbExecutable(programDir + QLatin1String(" (x64)"), QString(), checkedDirectories);
+ if (!outPath->isEmpty()) {
+ if (is64bitIn)
+ *is64bitIn = true;
+ return true;
+ }
+#endif
return false;
}