diff options
author | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-10-06 15:50:48 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2009-10-06 15:50:48 +0200 |
commit | c70f968faca095ef55732db5dfa87b4028865605 (patch) | |
tree | b6c408bf75be6d9aa68fc7b32107f3a3a85cf8f7 | |
parent | 1110b622e2586bb1bb417cff87eca904136b4a98 (diff) | |
download | qt-creator-c70f968faca095ef55732db5dfa87b4028865605.tar.gz |
CDB: Fix step into, improve multithread dumping, exception logging
Use new call syntax of 6.11. for dumper call loading. Execute
Dumpers in a single thread (current) if at all possible (not
in some WaitFor or artificial break thread). Show one more
frame in threads view if it is FastCallReturn. Fix step into
(ignore one event), log some more exceptions. Generally log
exceptions to the debugger windows to be able to see stuff
like DLL missing, etc.
-rw-r--r-- | doc/qtcreator.qdoc | 2 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbdebugengine.cpp | 41 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbdebugengine_p.h | 1 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbdebugeventcallback.cpp | 1 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbdumperhelper.cpp | 90 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbdumperhelper.h | 21 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbexceptionutils.cpp | 12 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbstacktracecontext.cpp | 50 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbstacktracecontext.h | 7 |
9 files changed, 186 insertions, 39 deletions
diff --git a/doc/qtcreator.qdoc b/doc/qtcreator.qdoc index 126fd98c63..d5e3582218 100644 --- a/doc/qtcreator.qdoc +++ b/doc/qtcreator.qdoc @@ -1080,7 +1080,7 @@ \l{http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx}{32-bit} or \l{http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx}{64-bit} - package (Version 6.10 for the 32-bit or the 64-bit version of Qt Creator, respectively), + package (Version 6.11.1.404 for the 32-bit or the 64-bit version of Qt Creator, respectively), which is freely available for download from the \l{http://msdn.microsoft.com/en-us/default.aspx} {Microsoft Developer Network}. diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 11f37d15f1..c7f0405570 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -302,6 +302,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager, m_dumper(new CdbDumperHelper(manager, &m_cif)), m_currentThreadId(-1), m_eventThreadId(-1), + m_interrupted(false), m_watchTimer(-1), m_debugEventCallBack(engine), m_engine(engine), @@ -445,6 +446,7 @@ void CdbDebugEnginePrivate::clearForRun() m_breakEventMode = BreakEventHandle; m_eventThreadId = -1; + m_interrupted = false; cleanStackTrace(); } @@ -1026,6 +1028,9 @@ bool CdbDebugEngine::step(unsigned long executionStatus) warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr))); } if (success) { + // Oddity: Step into will first break at the calling function. Ignore + if (executionStatus == DEBUG_STATUS_STEP_INTO || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO) + m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce; startWatchTimer(); setState(InferiorRunning, Q_FUNC_INFO, __LINE__); } else { @@ -1169,7 +1174,9 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus; } - if (!DebugBreakProcess(m_hDebuggeeProcess)) { + if (DebugBreakProcess(m_hDebuggeeProcess)) { + m_interrupted = true; + } else { *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Utils::winErrorMessage(GetLastError())); return false; } @@ -1704,12 +1711,34 @@ ULONG CdbDebugEnginePrivate::updateThreadList() QList<ThreadData> threads; ULONG currentThreadId; QString errorMessage; + // When interrupting, an artifical thread with a breakpoint is created. if (!CdbStackTraceContext::getThreads(m_cif, true, &threads, ¤tThreadId, &errorMessage)) m_engine->warning(errorMessage); manager()->threadsHandler()->setThreads(threads); return currentThreadId; } +// Figure out the thread to run the dumpers in (see notes on. +// CdbDumperHelper). Avoid the artifical threads created by interrupt +// and threads that are in waitFor(). +// A stricter version could only use the thread if it is the event +// thread of a step or breakpoint hit (see CdbDebugEnginePrivate::m_interrupted). + +static inline unsigned long dumperThreadId(const QList<StackFrame> &frames, + unsigned long currentThread) +{ + if (frames.empty()) + return CdbDumperHelper::InvalidDumperCallThread; + if (frames.at(0).function == QLatin1String(CdbStackTraceContext::winFuncDebugBreakPoint)) + 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)) + return CdbDumperHelper::InvalidDumperCallThread; + return currentThread; +} + void CdbDebugEnginePrivate::updateStackTrace() { if (debugCDB) @@ -1750,11 +1779,19 @@ void CdbDebugEnginePrivate::updateStackTrace() CdbDebugEngine::tr("Thread %1: No debug information available (%2).").arg(m_currentThreadId).arg(topFunction); m_engine->warning(msg); } - + // Set up dumper with a thread (or invalid) + const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId); + if (debugCDB) + qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread; + m_dumper->setDumperCallThread(dumperThread); + // Display frames manager()->stackHandler()->setFrames(stackFrames); m_firstActivatedFrame = true; if (current >= 0) { manager()->stackHandler()->setCurrentIndex(current); + // First time : repaint + if (m_dumper->isEnabled() && m_dumper->state() != CdbDumperHelper::Initialized) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); m_engine->activateFrame(current); } manager()->watchHandler()->updateWatchers(); diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 72a154906c..73fb7d41fa 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -156,6 +156,7 @@ struct CdbDebugEnginePrivate const QSharedPointer<CdbOptions> m_options; HANDLE m_hDebuggeeProcess; HANDLE m_hDebuggeeThread; + bool m_interrupted; int m_currentThreadId; int m_eventThreadId; HandleBreakEventMode m_breakEventMode; diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp index fcebdee779..21f867ede2 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp @@ -248,6 +248,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception( if (debugCDB) 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(); return S_OK; diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index b0757784e0..9d1d8c9713 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -41,8 +41,10 @@ #include <QtCore/QRegExp> #include <QtCore/QCoreApplication> #include <QtCore/QTextStream> +#include <QtCore/QTime> enum { loadDebug = 0 }; +enum { dumpDebug = 0 }; static const char *dumperModuleNameC = "gdbmacros"; static const char *qtCoreModuleNameC = "QtCore"; @@ -158,24 +160,25 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager, // We want to call "HMODULE LoadLibraryA(LPCTSTR lpFileName)" // (void* LoadLibraryA(char*)). However, despite providing a symbol // server, the debugger refuses to recognize it as a function. - // Set up the call stack with a function of same signature (qstrdup) - // and change the call register to LoadLibraryA() before executing "g". + // Call with a prototype of 'qstrdup', as it is the same // Prepare call: Locate 'qstrdup' in the (potentially namespaced) corelib. For some // reason, the symbol is present in QtGui as well without type information. QString dummyFunc = QLatin1String("*qstrdup"); if (resolveSymbol(cif->debugSymbols, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk) return false; - QString callCmd = QLatin1String(".call "); - callCmd += dummyFunc; - callCmd += QLatin1String("(0x"); - callCmd += QString::number(nameAddress, 16); - callCmd += QLatin1Char(')'); + + QString callCmd; { + QTextStream str(&callCmd); + str.setIntegerBase(16); + str << ".call /s " << dummyFunc << " Kernel32!LoadLibraryA(0x" << nameAddress << ')'; + } + if (loadDebug) + qDebug() << "Calling" << callCmd; + if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage)) return false; - if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("r eip=Kernel32!LoadLibraryA"), errorMessage)) - return false; - // This will hit a breakpoint. - if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QString(QLatin1Char('g')), errorMessage)) + // Execute current thread. This will hit a breakpoint. + if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("~. g"), errorMessage)) return false; const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS); if (FAILED(hr)) { @@ -185,6 +188,14 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager, return true; } +// Format a "go" in a thread +static inline QString goCommand(unsigned long threadId) +{ + QString rc; + QTextStream(&rc) << '~' << threadId << " g"; + return rc; +} + // ---- Load messages static inline QString msgMethod(bool injectOrCall) { @@ -226,7 +237,9 @@ CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager, m_inBufferSize(0), m_outBufferAddress(0), m_outBufferSize(0), - m_buffer(0) + m_buffer(0), + m_dumperCallThread(0), + m_goCommand(goCommand(m_dumperCallThread)) { } @@ -324,7 +337,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess bool CdbDumperHelper::ensureInitialized(QString *errorMessage) { if (loadDebug) - qDebug() << Q_FUNC_INFO << '\n' << m_state; + qDebug() << "ensureInitialized thread: " << m_dumperCallThread << " state: " << m_state; switch (m_state) { case Disabled: @@ -372,6 +385,9 @@ bool CdbDumperHelper::ensureInitialized(QString *errorMessage) m_manager->showDebuggerOutput(LogMisc, *errorMessage); m_manager->showQtDumperLibraryWarning(*errorMessage); } + if (loadDebug) + qDebug() << Q_FUNC_INFO << '\n' << ok; + return ok; } @@ -451,7 +467,7 @@ bool CdbDumperHelper::initKnownTypes(QString *errorMessage) *errorMessage = QtDumperHelper::msgDumperOutdated(dumperVersionRequired, m_helper.dumperVersion()); return false; } - if (loadDebug) + if (loadDebug || dumpDebug) qDebug() << Q_FUNC_INFO << m_helper.toString(true); return true; } @@ -492,8 +508,11 @@ bool CdbDumperHelper::callDumper(const QString &callCmd, const QByteArray &inBuf // by using 'gN' (go not handled -> pass handling to dumper __try/__catch block) for (int i = 0; i < 10; i++) { const int oldExceptionCount = exLogger.exceptionCount(); - // Go. If an exception occurs in loop 2, let the dumper handle it. - const QString goCmd = i ? QString(QLatin1String("gN")) : QString(QLatin1Char('g')); + // Go in current thread. If an exception occurs in loop 2, + // let the dumper handle it. + QString goCmd = m_goCommand; + if (i) + goCmd = QLatin1Char('N'); if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, goCmd, errorMessage)) return false; HRESULT hr = m_cif->debugControl->WaitForEvent(0, waitTimeOutMS); @@ -556,6 +575,18 @@ static inline QString msgNotHandled(const QString &type) CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, QList<WatchData> *result, QString *errorMessage) { + if (dumpDebug) + qDebug() << ">dumpType() thread: " << m_dumperCallThread << " state: " << m_state << wd.type << QTime::currentTime().toString(); + const CdbDumperHelper::DumpResult rc = dumpTypeI(wd, dumpChildren, result, errorMessage); + if (dumpDebug) + qDebug() << "<dumpType() state: " << m_state << wd.type << " returns " << rc << *errorMessage << QTime::currentTime().toString(); + return rc; +} + +CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool dumpChildren, + QList<WatchData> *result, QString *errorMessage) +{ + errorMessage->clear(); // Check failure cache and supported types if (m_state == Disabled) { *errorMessage = QLatin1String("Dumpers are disabled"); @@ -570,6 +601,20 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool return DumpNotHandled; } + // Do we have a thread + if (m_dumperCallThread == InvalidDumperCallThread) { + *errorMessage = QString::fromLatin1("No thread to call."); + if (loadDebug) + qDebug() << *errorMessage; + return DumpNotHandled; + } + + // Delay initialization as much as possible + if (isIntOrFloatType(wd.type)) { + *errorMessage = QString::fromLatin1("Unhandled POD: " ) + wd.type; + return DumpNotHandled; + } + // Ensure types are parsed and known. if (!ensureInitialized(errorMessage)) { *errorMessage = msgDumpFailed(wd, errorMessage); @@ -722,5 +767,18 @@ bool CdbDumperHelper::runTypeSizeQuery(const QString &typeName, int *size, QStri return true; } +unsigned long CdbDumperHelper::dumperCallThread() +{ + return m_dumperCallThread; +} + +void CdbDumperHelper::setDumperCallThread(unsigned long t) +{ + if (m_dumperCallThread != t) { + m_dumperCallThread = t; + m_goCommand = goCommand(m_dumperCallThread); + } +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h index eaa7a1db7b..ca95fe4779 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.h +++ b/src/plugins/debugger/cdb/cdbdumperhelper.h @@ -55,7 +55,17 @@ struct CdbComInterfaces; * dumpType() is the main query function to obtain a list of WatchData from * WatchData item produced by the smbol context. * Call disable(), should the debuggee crash (as performing debuggee - * calls is no longer possible, then).*/ + * calls is no longer possible, then). + * + * dumperCallThread specifies the thread to use when making the calls. + * As of Debugging Tools v 6.11.1.404 (6.10.2009), calls cannot be executed + * when the current thread is in some WaitFor...() function. The call will + * then hang (regardless whether that thread or some other, non-blocking thread + * is used), and the debuggee will be in running state afterwards (causing errors + * from ReadVirtual, etc). + * The current thread can be used when stepping or a breakpoint was + * hit. When interrupting the inferior, an artifical thread is created, + * that is not usable, either. */ class CdbDumperHelper { @@ -93,6 +103,10 @@ public: inline CdbComInterfaces *comInterfaces() const { return m_cif; } + enum { InvalidDumperCallThread = 0xFFFFFFFF }; + unsigned long dumperCallThread(); + void setDumperCallThread(unsigned long t); + private: enum CallLoadResult { CallLoadOk, CallLoadError, CallLoadNoQtApp, CallLoadAlreadyLoaded }; @@ -103,6 +117,9 @@ private: bool initResolveSymbols(QString *errorMessage); bool initKnownTypes(QString *errorMessage); + inline DumpResult dumpTypeI(const WatchData &d, bool dumpChildren, + QList<WatchData> *result, QString *errorMessage); + bool getTypeSize(const QString &typeName, int *size, QString *errorMessage); bool runTypeSizeQuery(const QString &typeName, int *size, QString *errorMessage); bool callDumper(const QString &call, const QByteArray &inBuffer, const char **outputPtr, @@ -134,6 +151,8 @@ private: QStringList m_failedTypes; QtDumperHelper m_helper; + unsigned long m_dumperCallThread; + QString m_goCommand; }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp index 6404733308..4975b69724 100644 --- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp +++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp @@ -41,7 +41,11 @@ enum { debugExc = 0 }; // Special exception codes. enum { cppExceptionCode = 0xe06d7363, startupCompleteTrap = 0x406d1388, rpcServerUnavailableExceptionCode = 0x6ba, - dllNotFoundExceptionCode = 0xc0000135 }; + dllNotFoundExceptionCode = 0xc0000135, + dllInitFailed = 0xc0000142, + missingSystemFile = 0xc0000143, + appInitFailed = 0xc0000143 + }; namespace Debugger { namespace Internal { @@ -172,6 +176,12 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) case dllNotFoundExceptionCode: str << "DLL not found"; break; + case dllInitFailed: + str << "DLL failed to initialize"; + break; + case missingSystemFile: + str << "System file is missing"; + break; case EXCEPTION_ACCESS_VIOLATION: { const bool writeOperation = e->ExceptionInformation[0]; str << (writeOperation ? "write" : "read") diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 8cf72461fe..605eeb61db 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -40,6 +40,10 @@ namespace Debugger { namespace Internal { +const char *CdbStackTraceContext::winFuncFastSystemCallRet = "ntdll!KiFastSystemCallRet"; +const char *CdbStackTraceContext::winFuncDebugBreakPoint = "ntdll!DbgBreakPoint"; +const char *CdbStackTraceContext::winFuncWaitForPrefix = "kernel32!WaitFor"; + CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper) : m_dumper(dumper), m_cif(dumper->comInterfaces()), @@ -232,6 +236,7 @@ static inline bool getStoppedThreadState(const CdbComInterfaces &cif, ThreadData *t, QString *errorMessage) { + enum { MaxFrames = 2 }; ULONG currentThread; HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(¤tThread); if (FAILED(hr)) { @@ -246,29 +251,38 @@ static inline bool getStoppedThreadState(const CdbComInterfaces &cif, } } ULONG frameCount; - DEBUG_STACK_FRAME topFrame[1]; - hr = cif.debugControl->GetStackTrace(0, 0, 0, topFrame, 1, &frameCount); + // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is + // not interesting for display. + DEBUG_STACK_FRAME frames[MaxFrames]; + hr = cif.debugControl->GetStackTrace(0, 0, 0, frames, MaxFrames, &frameCount); if (FAILED(hr)) { *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetStackTrace", hr)); return false; } - - t->address = topFrame[0].InstructionOffset; + // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is + // not interesting for display. WCHAR wszBuf[MAX_PATH]; - - cif.debugSymbols->GetNameByOffsetWide(topFrame[0].InstructionOffset, wszBuf, MAX_PATH, 0, 0); - t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - ULONG ulLine; - hr = cif.debugSymbols->GetLineByOffsetWide(topFrame[0].InstructionOffset, &ulLine, wszBuf, MAX_PATH, 0, 0); - if (SUCCEEDED(hr)) { - t->line = ulLine; - // Just display base name - t->file = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); - if (!t->file.isEmpty()) { - const int slashPos = t->file.lastIndexOf(QLatin1Char('\\')); - if (slashPos != -1) - t->file.remove(0, slashPos + 1); - } + for (int frame = 0; frame < MaxFrames; frame++) { + cif.debugSymbols->GetNameByOffsetWide(frames[frame].InstructionOffset, wszBuf, MAX_PATH, 0, 0); + t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + if (frame != 0 || t->function != QLatin1String(CdbStackTraceContext::winFuncFastSystemCallRet)) { + t->address = frames[frame].InstructionOffset; + cif.debugSymbols->GetNameByOffsetWide(frames[frame].InstructionOffset, wszBuf, MAX_PATH, 0, 0); + t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + ULONG ulLine; + hr = cif.debugSymbols->GetLineByOffsetWide(frames[frame].InstructionOffset, &ulLine, wszBuf, MAX_PATH, 0, 0); + if (SUCCEEDED(hr)) { + t->line = ulLine; + // Just display base name + t->file = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + if (!t->file.isEmpty()) { + const int slashPos = t->file.lastIndexOf(QLatin1Char('\\')); + if (slashPos != -1) + t->file.remove(0, slashPos + 1); + } + } + break; + } // was not "ntdll!KiFastSystemCallRet" } return true; } diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index ff8c62d5b1..3b0e2061fc 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -63,6 +63,13 @@ class CdbStackTraceContext public: enum { maxFrames = 100 }; + // Some well known-functions + static const char *winFuncFastSystemCallRet; + // WaitFor... + static const char *winFuncWaitForPrefix; + // Dummy function used for interrupting a debuggee + static const char *winFuncDebugBreakPoint; + ~CdbStackTraceContext(); static CdbStackTraceContext *create(const QSharedPointer<CdbDumperHelper> &dumper, unsigned long threadid, |