diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 1086adf8e559a1112f1dd686fe1fe85bb264db43..181ed4e06039bb141c28916546002ff3eb62a06c 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -37,6 +37,7 @@ #include "cdbassembler.h" #include "cdboptionspage.h" #include "cdboptions.h" +#include "cdbexceptionutils.h" #include "debuggeragents.h" #include "debuggeractions.h" @@ -305,12 +306,14 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager, m_dumper(new CdbDumperHelper(manager, &m_cif)), m_currentThreadId(-1), m_eventThreadId(-1), - m_interrupted(false), + m_interruptArticifialThreadId(-1), + m_interrupted(false), m_watchTimer(-1), m_debugEventCallBack(engine), m_engine(engine), m_currentStackTrace(0), m_firstActivatedFrame(true), + m_inferiorStartupComplete(false), m_mode(AttachCore) { } @@ -447,7 +450,7 @@ void CdbDebugEnginePrivate::clearForRun() qDebug() << Q_FUNC_INFO; m_breakEventMode = BreakEventHandle; - m_eventThreadId = -1; + m_eventThreadId = m_interruptArticifialThreadId = -1; m_interrupted = false; cleanStackTrace(); } @@ -619,6 +622,8 @@ void CdbDebugEnginePrivate::checkVersion() void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) { + if (debugCDBExecution) + qDebug() << "startDebugger" << *sp; setState(AdapterStarting, Q_FUNC_INFO, __LINE__); m_d->checkVersion(); if (m_d->m_hDebuggeeProcess) { @@ -627,6 +632,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> emit startFailed(); } m_d->clearDisplay(); + m_d->m_inferiorStartupComplete = false; setState(AdapterStarted, Q_FUNC_INFO, __LINE__); setState(InferiorPreparing, Q_FUNC_INFO, __LINE__); @@ -699,10 +705,11 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QStri { // Need to attrach invasively, otherwise, no notification signals // for for CreateProcess/ExitProcess occur. - const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS; + // As of version 6.11, the initial breakpoint suppression has no effect (see notifyException). + const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS|DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags); if (debugCDB) - qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl); + qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl); if (FAILED(hr)) { *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr)); return false; @@ -771,7 +778,7 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString * } void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle) -{ +{ m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__); setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle)); ULONG currentThreadId; @@ -782,8 +789,11 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 } // Clear any saved breakpoints and set initial breakpoints m_engine->executeDebuggerCommand(QLatin1String("bc")); - if (manager()->breakHandler()->hasPendingBreakpoints()) + if (manager()->breakHandler()->hasPendingBreakpoints()) { + if (debugCDBExecution) + qDebug() << "processCreatedAttached: Syncing breakpoints"; 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) { @@ -796,8 +806,8 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 } } m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__); - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl); + if (debugCDBExecution) + qDebug() << "<processCreatedAttached" << executionStatusString(m_cif.debugControl); } void CdbDebugEngine::processTerminated(unsigned long exitCode) @@ -1018,8 +1028,8 @@ static inline QString msgStepFailed(unsigned long executionStatus, int threadId, // its reverse equivalents in the case of single threads. bool CdbDebugEngine::step(unsigned long executionStatus) { - if (debugCDB) - qDebug() << Q_FUNC_INFO << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId; + if (debugCDBExecution) + qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId; // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404): // The constants exist, but invoking the calls leads to E_NOINTERFACE. @@ -1029,6 +1039,12 @@ bool CdbDebugEngine::step(unsigned long executionStatus) return false; } + // Do not step the artifical thread created to interrupt the debuggee. + if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) { + warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId)); + return false; + } + // SetExecutionStatus() continues the thread that triggered the // stop event (~# p). This can be confusing if the user is looking // at the stack trace of another thread and wants to step that one. If that @@ -1067,6 +1083,8 @@ bool CdbDebugEngine::step(unsigned long executionStatus) } else { setState(InferiorStopped, Q_FUNC_INFO, __LINE__); } + if (debugCDBExecution) + qDebug() << "<step samethread" << sameThread << "succeeded" << success; return success; } @@ -1092,8 +1110,8 @@ void CdbDebugEngine::nextIExec() void CdbDebugEngine::stepOutExec() { - if (debugCDB) - qDebug() << Q_FUNC_INFO; + if (debugCDBExecution) + qDebug() << "stepOutExec"; // emulate gdb 'exec-finish' (exec until return of current function) // by running up to address of the above stack frame (mostly works). const StackHandler* sh = manager()->stackHandler(); @@ -1142,8 +1160,8 @@ void CdbDebugEngine::continueInferior() // Continue process without notifications bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */) { - if (debugCDB) - qDebug() << Q_FUNC_INFO; + if (debugCDBExecution) + qDebug() << "continueInferiorProcess"; const HRESULT hr = m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_GO); if (FAILED(hr)) { const QString errorMessage = msgComFailed("SetExecutionStatus", hr); @@ -1198,11 +1216,12 @@ bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage) bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) { + // Interrupt the interferior process without notifications - if (debugCDB) { + if (debugCDBExecution) { ULONG executionStatus; getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage); - qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus; + qDebug() << "interruptInterferiorProcess ex=" << executionStatus; } if (DebugBreakProcess(m_hDebuggeeProcess)) { @@ -1218,6 +1237,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) arg(getInterruptTimeOutSecs(m_cif.debugControl)).arg(msgComFailed("SetInterrupt", hr)); return false; } + m_interrupted = true; #endif return true; } @@ -1646,10 +1666,27 @@ void CdbDebugEngine::warning(const QString &w) qWarning("%s\n", qPrintable(w)); } -void CdbDebugEnginePrivate::notifyCrashed() +void CdbDebugEnginePrivate::notifyException(long code, bool fatal) { + if (debugCDBExecution) + qDebug() << "notifyException code" << code << " fatal=" << fatal; + // Suppress the initial breakpoint that occurs when + // attaching (If a breakpoint is encountered before startup + // is complete). + switch (code) { + case winExceptionStartupCompleteTrap: + m_inferiorStartupComplete = true; + break; + case EXCEPTION_BREAKPOINT: + if (!m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) { + manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Ignoring initial breakpoint...")); + m_breakEventMode = BreakEventIgnoreOnce; + } + break; + } // Cannot go over crash point to execute calls. - m_dumper->disable(); + if (fatal) + m_dumper->disable(); } static int threadIndexById(const ThreadsHandler *threadsHandler, int id) @@ -1664,10 +1701,10 @@ static int threadIndexById(const ThreadsHandler *threadsHandler, int id) void CdbDebugEnginePrivate::handleDebugEvent() { - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << m_hDebuggeeProcess << m_breakEventMode - << executionStatusString(m_cif.debugControl); - + if (debugCDBExecution) + qDebug() << "handleDebugEvent mode " << m_breakEventMode + << executionStatusString(m_cif.debugControl) << " interrupt" << m_interrupted + << " startupcomplete" << m_inferiorStartupComplete; // restore mode and do special handling const HandleBreakEventMode mode = m_breakEventMode; m_breakEventMode = BreakEventHandle; @@ -1679,9 +1716,27 @@ void CdbDebugEnginePrivate::handleDebugEvent() if (m_engine->state() != InferiorStopping) m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__); m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__); - m_eventThreadId = m_currentThreadId = updateThreadList(); - manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId)); + m_eventThreadId = updateThreadList(); + m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1; + // Get thread to stop and its index. If avoidable, do not use + // the artifical thread that is created when interrupting, + // use the oldest thread 0 instead. ThreadsHandler *threadsHandler = manager()->threadsHandler(); + m_currentThreadId = m_interrupted ? 0 : m_eventThreadId; + int currentThreadIndex = -1; + m_currentThreadId = -1; + if (m_interrupted) { + m_currentThreadId = 0; + currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); + } + if (!m_interrupted || currentThreadIndex == -1) { + m_currentThreadId = m_eventThreadId; + currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); + } + const QString msg = m_interrupted ? + CdbDebugEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) : + CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId); + manager()->showDebuggerOutput(LogMisc, msg); const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId); if (threadIndex != -1) threadsHandler->setCurrentThread(threadIndex); @@ -1690,8 +1745,10 @@ void CdbDebugEnginePrivate::handleDebugEvent() break; case BreakEventIgnoreOnce: m_engine->startWatchTimer(); + m_interrupted = false; break; case BreakEventSyncBreakPoints: { + m_interrupted = false; // Temp stop to sync breakpoints QString errorMessage; attemptBreakpointSynchronization(&errorMessage); @@ -1764,9 +1821,12 @@ static inline unsigned long dumperThreadId(const QList<StackFrame> &frames, return CdbDumperHelper::InvalidDumperCallThread; const int waitCheckDepth = qMin(frames.size(), 5); static const QString waitForPrefix = QLatin1String(CdbStackTraceContext::winFuncWaitForPrefix); - for (int f = 0; f < waitCheckDepth; f++) - if (frames.at(f).function.startsWith(waitForPrefix)) + static const QString msgWaitForPrefix = QLatin1String(CdbStackTraceContext::winFuncMsgWaitForPrefix); + for (int f = 0; f < waitCheckDepth; f++) { + const QString &function = frames.at(f).function; + if (function.startsWith(waitForPrefix) || function.startsWith(msgWaitForPrefix)) return CdbDumperHelper::InvalidDumperCallThread; + } return currentThread; } @@ -1812,7 +1872,7 @@ void CdbDebugEnginePrivate::updateStackTrace() } // Set up dumper with a thread (or invalid) const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId); - if (debugCDB) + if (debugCDBExecution) qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread; m_dumper->setDumperCallThread(dumperThread); // Display frames @@ -1824,6 +1884,10 @@ void CdbDebugEnginePrivate::updateStackTrace() if (m_dumper->isEnabled() && m_dumper->state() != CdbDumperHelper::Initialized) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); m_engine->activateFrame(current); + } else { + // Clean out variables + manager()->watchHandler()->beginCycle(); + manager()->watchHandler()->endCycle(); } manager()->watchHandler()->updateWatchers(); } diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index b0a01d378961428133fded48999b46a1b5d024f2..e52ddadef5c78ff11844e2486bc26915928386fd 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -135,7 +135,7 @@ struct CdbDebugEnginePrivate bool executeContinueCommand(const QString &command); bool attemptBreakpointSynchronization(QString *errorMessage); - void notifyCrashed(); + void notifyException(long code, bool fatal); enum EndInferiorAction { DetachInferior, TerminateInferior }; bool endInferior(EndInferiorAction a, QString *errorMessage); @@ -157,9 +157,10 @@ struct CdbDebugEnginePrivate const QSharedPointer<CdbOptions> m_options; HANDLE m_hDebuggeeProcess; HANDLE m_hDebuggeeThread; - bool m_interrupted; + bool m_interrupted; int m_currentThreadId; int m_eventThreadId; + int m_interruptArticifialThreadId; HandleBreakEventMode m_breakEventMode; int m_watchTimer; @@ -175,6 +176,7 @@ struct CdbDebugEnginePrivate EditorToolTipCache m_editorToolTipCache; bool m_firstActivatedFrame; + bool m_inferiorStartupComplete; DebuggerStartMode m_mode; Utils::ConsoleProcess m_consoleStubProc; @@ -192,6 +194,7 @@ QString msgDebugEngineComResult(HRESULT hr); QString msgComFailed(const char *func, HRESULT hr); enum { debugCDB = 0 }; +enum { debugCDBExecution = 0 }; enum { debugCDBWatchHandling = 0 }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp index 21f867ede22f7678add22ed44b961ebb8113f867..26c24b2058ba22fc3afd99809c46f5d35670d46a 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp @@ -35,6 +35,7 @@ #include <QtCore/QDebug> #include <QtCore/QTextStream> +#include <QtCore/QCoreApplication> namespace Debugger { namespace Internal { @@ -249,8 +250,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception( qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg; m_pEngine->manager()->showApplicationOutput(msg); m_pEngine->manager()->showDebuggerOutput(LogMisc, msg); - if (fatal) - m_pEngine->m_d->notifyCrashed(); + m_pEngine->m_d->notifyException(Exception->ExceptionCode, fatal); return S_OK; } @@ -373,8 +373,11 @@ STDMETHODIMP CdbDebugEventCallback::SystemError( } // -----------ExceptionLoggerEventCallback -CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *manager) : +CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, + bool skipNonFatalExceptions, + DebuggerManager *manager) : m_logChannel(logChannel), + m_skipNonFatalExceptions(skipNonFatalExceptions), m_manager(manager) { } @@ -391,15 +394,18 @@ STDMETHODIMP CdbExceptionLoggerEventCallback::Exception( __in ULONG /* FirstChance */ ) { - m_exceptionCodes.push_back(Exception->ExceptionCode); - m_exceptionMessages.push_back(QString()); - { - QTextStream str(&m_exceptionMessages.back()); - formatException(Exception, str); + const bool recordException = !m_skipNonFatalExceptions || isFatalException(Exception->ExceptionCode); + QString message; + formatException(Exception, QTextStream(&message)); + if (recordException) { + m_exceptionCodes.push_back(Exception->ExceptionCode); + m_exceptionMessages.push_back(message); } if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << m_exceptionMessages.back(); - m_manager->showDebuggerOutput(m_logChannel, m_exceptionMessages.back()); + qDebug() << Q_FUNC_INFO << '\n' << message; + m_manager->showDebuggerOutput(m_logChannel, message); + if (recordException) + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); return S_OK; } diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h index b9de88e1745650a667a22c2ba794aae4f1f69937..4250cd5b24c03d106c0284542552522fb9c0bb28 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.h @@ -242,7 +242,9 @@ private: class CdbExceptionLoggerEventCallback : public CdbDebugEventCallbackBase { public: - CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *access); + CdbExceptionLoggerEventCallback(int logChannel, + bool skipNonFatalExceptions, + DebuggerManager *access); STDMETHOD(GetInterestMask)( THIS_ @@ -261,6 +263,7 @@ public: private: const int m_logChannel; + const bool m_skipNonFatalExceptions; DebuggerManager *m_manager; QList<ULONG> m_exceptionCodes; QStringList m_exceptionMessages; diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index a188d2c1f2b82a6428a1fe767ab54cba2a5c06a3..753c54be845d7b7d3cc42f89e07f709b74c23280 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -144,13 +144,14 @@ static bool createDebuggeeAscIIString(CdbComInterfaces *cif, // make sense for Qt apps. static bool debuggeeLoadLibrary(DebuggerManager *manager, CdbComInterfaces *cif, + unsigned long threadId, const QString &moduleName, QString *errorMessage) { if (loadDebug > 1) qDebug() << Q_FUNC_INFO << moduleName; - // Try to ignore the breakpoints - CdbExceptionLoggerEventCallback exLogger(LogWarning, manager); + // Try to ignore the breakpoints, skip stray startup-complete trap exceptions + CdbExceptionLoggerEventCallback exLogger(LogWarning, true, manager); EventCallbackRedirector eventRedir(cif->debugClient, &exLogger); // Make a call to LoadLibraryA. First, reserve memory in debugger // and copy name over. @@ -178,7 +179,9 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager, if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage)) return false; // Execute current thread. This will hit a breakpoint. - if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("~. g"), errorMessage)) + QString goCmd; + QTextStream(&goCmd) << '~' << threadId << " g"; + if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, goCmd, errorMessage)) return false; const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS); if (FAILED(hr)) { @@ -329,7 +332,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty()) return CallLoadNoQtApp; // Try to load - if (!debuggeeLoadLibrary(m_manager, m_cif, m_library, errorMessage)) + if (!debuggeeLoadLibrary(m_manager, m_cif, m_dumperCallThread, m_library, errorMessage)) return CallLoadError; return CallLoadOk; } @@ -495,7 +498,8 @@ CdbDumperHelper::CallResult bool ignoreAccessViolation, QString *errorMessage) { *outDataPtr = 0; - CdbExceptionLoggerEventCallback exLogger(LogWarning, m_manager); + // Skip stray startup-complete trap exceptions. + CdbExceptionLoggerEventCallback exLogger(LogWarning, true, m_manager); EventCallbackRedirector eventRedir(m_cif->debugClient, &exLogger); // write input buffer if (!inBuffer.isEmpty()) { @@ -576,7 +580,7 @@ static inline QString msgNotHandled(const QString &type) CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, QList<WatchData> *result, QString *errorMessage) { - if (dumpDebug) + if (dumpDebug || debugCDBExecution) qDebug() << ">dumpType() thread: " << m_dumperCallThread << " state: " << m_state << wd.type << QTime::currentTime().toString(); const CdbDumperHelper::DumpResult rc = dumpTypeI(wd, dumpChildren, result, errorMessage); if (dumpDebug) diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp index 4975b697243adfcf0dc2424d33a80408be7298f0..2c9b49d413e1a2e3bdf409a2763efc0b5837a4c5 100644 --- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp +++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp @@ -38,15 +38,6 @@ enum { debugExc = 0 }; -// Special exception codes. -enum { cppExceptionCode = 0xe06d7363, startupCompleteTrap = 0x406d1388, - rpcServerUnavailableExceptionCode = 0x6ba, - dllNotFoundExceptionCode = 0xc0000135, - dllInitFailed = 0xc0000142, - missingSystemFile = 0xc0000143, - appInitFailed = 0xc0000143 - }; - namespace Debugger { namespace Internal { @@ -167,19 +158,19 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) str << "\nException at 0x" << e->ExceptionAddress << ", code: 0x" << e->ExceptionCode << ": "; switch (e->ExceptionCode) { - case cppExceptionCode: + case winExceptionCppException: str << "C++ exception"; break; - case startupCompleteTrap: + case winExceptionStartupCompleteTrap: str << "Startup complete"; break; - case dllNotFoundExceptionCode: + case winExceptionDllNotFound: str << "DLL not found"; break; - case dllInitFailed: + case winExceptionDllInitFailed: str << "DLL failed to initialize"; break; - case missingSystemFile: + case winExceptionMissingSystemFile: str << "System file is missing"; break; case EXCEPTION_ACCESS_VIOLATION: { @@ -260,7 +251,7 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) { formatException(e, str); - if (e->ExceptionCode == cppExceptionCode) { + if (e->ExceptionCode == winExceptionCppException) { QString errorMessage; ULONG currentThreadId = 0; dumper->comInterfaces()->debugSystemObjects->GetCurrentThreadId(¤tThreadId); @@ -278,10 +269,10 @@ bool isFatalException(LONG code) switch (code) { case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: - case startupCompleteTrap: // Mysterious exception at start of application - case rpcServerUnavailableExceptionCode: - case dllNotFoundExceptionCode: - case cppExceptionCode: + case winExceptionStartupCompleteTrap: // Mysterious exception at start of application + case winExceptionRpcServerUnavailable: + case winExceptionDllNotFound: + case winExceptionCppException: return false; default: break; diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.h b/src/plugins/debugger/cdb/cdbexceptionutils.h index 98af74706fa9411177cfe36ee707fd94d61e85a6..b54447580f34c9e3b0fc592e39fcd85e3681dec4 100644 --- a/src/plugins/debugger/cdb/cdbexceptionutils.h +++ b/src/plugins/debugger/cdb/cdbexceptionutils.h @@ -42,6 +42,17 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { +// Special exception codes. +enum { winExceptionCppException = 0xe06d7363, + winExceptionStartupCompleteTrap = 0x406d1388, + winExceptionRpcServerUnavailable = 0x6ba, + winExceptionDllNotFound = 0xc0000135, + winExceptionDllInitFailed = 0xc0000142, + winExceptionMissingSystemFile = 0xc0000143, + winExceptionAppInitFailed = 0xc0000143 +}; + + class CdbDumperHelper; // Utility class that blocks out exception handling (breaking) diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 93ab11d75efb31956cad1e7bbaa844aaa51090f5..d97a968768c2cf2c6fa29285256e1780339244e8 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -134,7 +134,7 @@ static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0) const bool missing = wd->isTypeNeeded() || wd->type.isEmpty(); if (missing) { static const QString unknownType = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Type>"); - wd->setType(source ? source->type : unknownType); + wd->setType(source ? source->type : unknownType, false); } return missing; } diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 605eeb61dbfd4c05d6519b39305ca49ffbf77a62..0a338f9fdcc79a0bf46de4e2b53ec4cfc016aa1b 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -43,6 +43,7 @@ namespace Internal { const char *CdbStackTraceContext::winFuncFastSystemCallRet = "ntdll!KiFastSystemCallRet"; const char *CdbStackTraceContext::winFuncDebugBreakPoint = "ntdll!DbgBreakPoint"; const char *CdbStackTraceContext::winFuncWaitForPrefix = "kernel32!WaitFor"; +const char *CdbStackTraceContext::winFuncMsgWaitForPrefix = "kernel32!MsgWaitForMultipleObjects"; CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper) : m_dumper(dumper), diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index 3b0e2061fc89c31310ecd38fae2952464c6e0bff..ac9cb030b06b3f6f3ad9659708e462a2a617066b 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -67,6 +67,8 @@ public: static const char *winFuncFastSystemCallRet; // WaitFor... static const char *winFuncWaitForPrefix; + static const char *winFuncMsgWaitForPrefix; + // Dummy function used for interrupting a debuggee static const char *winFuncDebugBreakPoint; diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index ea3924ddd26853b982c1fbd41d966cd7e2473036..166902112eb370d3905fa8db2c784a112847f8be 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -1406,10 +1406,14 @@ void DebuggerManager::modulesDockToggled(bool on) void DebuggerManager::showDebuggerOutput(int channel, const QString &msg) { - if (d->m_outputWindow) + if (d->m_outputWindow) { emit emitShowOutput(channel, msg); - else + if (channel == LogError) + ensureLogVisible(); + } else { qDebug() << "OUTPUT: " << channel << msg; + + } } void DebuggerManager::showDebuggerInput(int channel, const QString &msg) @@ -1761,6 +1765,13 @@ bool DebuggerManager::checkDebugConfiguration(int toolChain, return success; } +void DebuggerManager::ensureLogVisible() +{ + QAction *action = d->m_outputDock->toggleViewAction(); + if (!action->isChecked()) + action->trigger(); +} + QDebug operator<<(QDebug d, DebuggerState state) { return d << stateName(state) << '(' << int(state) << ')'; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index ddd692b43167fa6156764d4a07a69c840c2855f1..2d84c9383cc1ae9a7b730d0d83ff91487cc016ce 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -234,6 +234,8 @@ public slots: public slots: // FIXME void showDebuggerOutput(const QString &msg) { showDebuggerOutput(LogDebug, msg); } + void ensureLogVisible(); + //private slots: // FIXME void showDebuggerOutput(int channel, const QString &msg); void showDebuggerInput(int channel, const QString &msg); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 04e3bee8f739c9bcb52f06a261d2970c12b5a680..1cf41e932350e5576a1d5d0e524f540eb64bf2ad 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -177,7 +177,7 @@ void WatchData::setValueToolTip(const QString &tooltip) valuetooltip = tooltip; } -void WatchData::setType(const QString &str) +void WatchData::setType(const QString &str, bool guessChildrenFromType) { type = str.trimmed(); bool changed = true; @@ -202,7 +202,8 @@ void WatchData::setType(const QString &str) changed = false; } setTypeUnneeded(); - switch (guessChildren(type)) { + if (guessChildrenFromType) { + switch (guessChildren(type)) { case HasChildren: setHasChildren(true); break; @@ -212,6 +213,7 @@ void WatchData::setType(const QString &str) case HasPossiblyChildren: setHasChildren(true); // FIXME: bold assumption break; + } } } @@ -1091,7 +1093,10 @@ void WatchHandler::cleanup() void WatchHandler::insertData(const WatchData &data) { MODEL_DEBUG("INSERTDATA: " << data.toString()); - QTC_ASSERT(data.isValid(), return); + if (!data.isValid()) { + qWarning("%s:%d: Attempt to insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString())); + return; + } if (data.isSomethingNeeded()) { m_manager->updateWatchData(data); } else { @@ -1117,7 +1122,11 @@ void WatchHandler::insertBulkData(const QList<WatchData> &list) foreach (const WatchData &data, list) { // we insert everything, including incomplete stuff // to reduce the number of row add operations in the model. - hash[parentName(data.iname)].append(data); + if (data.isValid()) { + hash[parentName(data.iname)].append(data); + } else { + qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString())); + } } foreach (const QString &parentIName, hash.keys()) { WatchModel *model = modelForIName(parentIName); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index eb2797f3e0ee130c376277712e18d28af8378024..dc426f4e22de74d5f28256a0cbfc1c55b74f6b79 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -78,7 +78,7 @@ public: }; void setValue(const QString &); - void setType(const QString &); + void setType(const QString &, bool guessChildrenFromType = true); void setValueToolTip(const QString &); void setError(const QString &); void setAddress(const QString &address);