OSDN Git Service

Debugger[New CDB]: Improve 32bit debugging on 64bit systems.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Wed, 12 Jan 2011 12:49:51 +0000 (13:49 +0100)
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>
Wed, 12 Jan 2011 12:51:33 +0000 (13:51 +0100)
- Ignore WOW64 breakpoints. Restructure code to examine stop reason
  before notifications to be able handle special stop reasons
  in a simpler way.
- Fix autodetection to look into %ProgramFiles% (x64) as well.

src/plugins/debugger/cdb/cdbengine.cpp
src/plugins/debugger/cdb/cdbengine.h
src/plugins/debugger/cdb/cdboptions.cpp
src/plugins/debugger/shared/dbgwinutils.cpp
src/plugins/debugger/shared/dbgwinutils.h

index eb30aa2..5eae14b 100644 (file)
@@ -1361,19 +1361,85 @@ static const char *cdbStatusName(unsigned long s)
     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;
 
@@ -1387,79 +1453,53 @@ void CdbEngine::handleSessionIdle(const QByteArray &message)
     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)
index 403f8e6..539a6d5 100644 (file)
@@ -152,6 +152,8 @@ private slots:
 private:
     enum SpecialStopMode { NoSpecialStop, SpecialStopSynchronizeBreakpoints };
 
+    unsigned examineStopReason(const QByteArray &messageIn, QString *message,
+                               QString *exceptionBoxMessage) const;
     bool commandsPending() const;
     void handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message);
     bool doSetupEngine(QString *errorMessage);
index ceab8ef..466c93c 100644 (file)
@@ -174,6 +174,21 @@ bool CdbOptions::equals(const CdbOptions &rhs) const
             && 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 */)
 {
@@ -182,48 +197,54 @@ bool CdbOptions::autoDetectExecutable(QString *outPath, bool *is64bitIn  /* = 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;
 }
 
index bfe38f4..42e557f 100644 (file)
@@ -292,6 +292,9 @@ void formatWindowsException(unsigned long code, quint64 address,
     case winExceptionRpcServerInvalid:
         str << "Invalid RPC server";
         break;
+    case winExceptionWX86Breakpoint:
+        str << "Win32 x86 emulation subsystem breakpoint hit";
+        break;
     case EXCEPTION_ACCESS_VIOLATION: {
             const bool writeOperation = info1;
             str << (writeOperation ? "write" : "read")
index 4920b3f..8327cfd 100644 (file)
@@ -75,7 +75,8 @@ enum { winExceptionCppException = 0xe06d7363,
        winExceptionDllEntryPointNoFound = 0xc0000139,
        winExceptionDllInitFailed = 0xc0000142,
        winExceptionMissingSystemFile = 0xc0000143,
-       winExceptionAppInitFailed = 0xc0000143
+       winExceptionAppInitFailed = 0xc0000143,
+       winExceptionWX86Breakpoint = 0x4000001f
 };
 
 // Format windows Exception