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