Enabled the use of Debugger-specific watch/locals models.

- Modified WatchModel to handle storage of an hierarchy
  of WatchItems.
- Factored out code for asynchronous population to
  AsyncWatchModel and added a mixin for convenient
  handling
- Added base class for synchronous models.
- Implement simple, synchronous models for CDB, greatly
  simplifying code and finally getting manual
  expansion right.
Signed-off-by: hjk <qtc-committer@nokia.com>
This commit is contained in:
Friedemann Kleint
2009-07-10 14:36:28 +02:00
parent b0227ce496
commit abf5e3ddc3
29 changed files with 1798 additions and 697 deletions

View File

@@ -30,7 +30,6 @@
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "cdbstacktracecontext.h"
#include "cdbstackframecontext.h"
#include "cdbsymbolgroupcontext.h"
#include "cdbbreakpoint.h"
#include "cdbmodules.h"
@@ -47,6 +46,7 @@
#include "moduleshandler.h"
#include "disassemblerhandler.h"
#include "watchutils.h"
#include "cdbwatchmodels.h"
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
@@ -301,7 +301,9 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent,
m_debuggerManagerAccess(parent->engineInterface()),
m_currentStackTrace(0),
m_firstActivatedFrame(true),
m_mode(AttachCore)
m_mode(AttachCore),
m_localsModel(0),
m_watchModel(0)
{
}
@@ -390,6 +392,15 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
m_cif.debugDataSpaces->Release();
}
void CdbDebugEnginePrivate::saveLocalsViewState()
{
if (m_localsModel && m_localsModel->symbolGroupContext()) {
const int oldFrame = m_debuggerManagerAccess->stackHandler()->currentIndex();
if (oldFrame != -1)
m_debuggerManagerAccess->watchHandler()->saveLocalsViewState(oldFrame);
}
}
void CdbDebugEnginePrivate::clearForRun()
{
if (debugCDB)
@@ -403,6 +414,10 @@ void CdbDebugEnginePrivate::clearForRun()
void CdbDebugEnginePrivate::cleanStackTrace()
{
if (m_localsModel) {
saveLocalsViewState();
m_localsModel->setSymbolGroupContext(0);
}
if (m_currentStackTrace) {
delete m_currentStackTrace;
m_currentStackTrace = 0;
@@ -465,14 +480,19 @@ QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &functio
QString errorMessage;
QString rc;
// Find the frame of the function if there is any
CdbStackFrameContext *frame = 0;
const QString iname = QLatin1String("local.") + exp;
if (m_d->m_currentStackTrace && !function.isEmpty()) {
const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
if (frameIndex != -1)
frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
if (frameIndex != -1) {
// Are we at the current frame?
if (frameIndex == m_d->m_debuggerManagerAccess->stackHandler()->currentIndex()) {
if (const WatchData *wd = m_d->m_localsModel->findItemByIName(iname, m_d->m_localsModel->root()))
return wd->toToolTip(); }
// Nope, try to retrieve via another symbol group
if (m_d->m_currentStackTrace->editorToolTip(frameIndex, iname, &rc, &errorMessage))
return rc;
}
}
if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
return rc;
// No function/symbol context found, try to evaluate in current context.
// Do not append type as this will mostly be 'long long' for integers, etc.
QString type;
@@ -770,67 +790,6 @@ void CdbDebugEngine::detachDebugger()
m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
}
CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const
{
if (!m_currentStackTrace) {
*errorMessage = QLatin1String(msgNoStackTraceC);
return 0;
}
if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage))
return sg;
return 0;
}
void CdbDebugEngine::evaluateWatcher(WatchData *wd)
{
if (debugCDBWatchHandling)
qDebug() << Q_FUNC_INFO << wd->exp;
QString errorMessage;
QString value;
QString type;
if (evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
wd->setValue(value);
wd->setType(type);
} else {
wd->setValue(errorMessage);
wd->setTypeUnneeded();
}
wd->setHasChildren(false);
}
void CdbDebugEngine::updateWatchData(const WatchData &incomplete)
{
// Watch item was edited while running
if (m_d->isDebuggeeRunning())
return;
if (debugCDBWatchHandling)
qDebug() << Q_FUNC_INFO << "\n " << incomplete.toString();
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
if (incomplete.iname.startsWith(QLatin1String("watch."))) {
WatchData watchData = incomplete;
evaluateWatcher(&watchData);
watchHandler->insertData(watchData);
return;
}
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
bool success = false;
QString errorMessage;
do {
CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
if (!sg)
break;
if (!sg->completeData(incomplete, watchHandler, &errorMessage))
break;
success = true;
} while (false);
if (!success)
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
}
void CdbDebugEngine::stepExec()
{
if (debugCDB)
@@ -1037,18 +996,14 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
bool success = false;
do {
QString newValue;
CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage);
if (!sg)
if (frameIndex < 0 || !m_d->m_currentStackTrace) {
errorMessage = tr("No current stack trace.");
break;
if (!sg->assignValue(expr, value, &newValue, &errorMessage))
break;
// Update view
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
if (WatchData *fwd = watchHandler->findItem(expr)) {
fwd->setValue(newValue);
watchHandler->insertData(*fwd);
watchHandler->updateWatchers();
}
// Assign in stack and update view
if (!m_d->m_currentStackTrace->assignValue(frameIndex, expr, value, &newValue, &errorMessage))
break;
m_d->m_localsModel->setValueByExpression(expr, newValue);
success = true;
} while (false);
if (!success) {
@@ -1078,6 +1033,11 @@ bool CdbDebugEnginePrivate::executeDebuggerCommand(CIDebugControl *ctrl, const Q
return true;
}
bool CdbDebugEngine::isDebuggeeHalted() const
{
return m_d->m_hDebuggeeProcess && !m_d->isDebuggeeRunning();
}
bool CdbDebugEngine::evaluateExpression(const QString &expression,
QString *value,
QString *type,
@@ -1132,21 +1092,21 @@ void CdbDebugEngine::activateFrame(int frameIndex)
bool success = false;
do {
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
const int oldIndex = stackHandler->currentIndex();
if (frameIndex >= stackHandler->stackSize()) {
errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
break;
}
if (oldIndex != frameIndex)
if (oldIndex != frameIndex) {
m_d->saveLocalsViewState();
stackHandler->setCurrentIndex(frameIndex);
}
const StackFrame &frame = stackHandler->currentFrame();
if (!frame.isUsable()) {
m_d->m_localsModel->setSymbolGroupContext(0);
// Clean out model
watchHandler->beginCycle();
watchHandler->endCycle();
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
arg(QLatin1String(Q_FUNC_INFO), frame.file);
break;
@@ -1155,10 +1115,18 @@ void CdbDebugEngine::activateFrame(int frameIndex)
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
watchHandler->beginCycle();
if (CdbStackFrameContext *sgc = m_d->getStackFrameContext(frameIndex, &errorMessage))
success = sgc->populateModelInitially(watchHandler, &errorMessage);
watchHandler->endCycle();
m_d->m_localsModel->setUseDumpers(m_d->m_dumper->isEnabled() && theDebuggerBoolSetting(UseDebuggingHelpers));
CdbSymbolGroupContext *ctx = 0;
if (m_d->m_currentStackTrace) {
ctx = m_d->m_currentStackTrace->symbolGroupAt(frameIndex, &errorMessage);
success = ctx != 0;
} else {
errorMessage = QLatin1String(msgNoStackTraceC);
}
m_d->m_localsModel->setSymbolGroupContext(ctx);
m_d->m_debuggerManagerAccess->watchHandler()->restoreLocalsViewState(frameIndex);
} else {
success = true;
}
} while (false);
if (!success)
@@ -1222,7 +1190,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
m_cif.debugSymbols,
m_debuggerManagerAccess->breakHandler(),
errorMessage, &warnings);
if (const int warningsCount = warnings.size())
if (const int warningsCount = warnings.size())
for (int w = 0; w < warningsCount; w++)
m_engine->warning(warnings.at(w));
return ok;
@@ -1500,7 +1468,8 @@ void CdbDebugEnginePrivate::updateStackTrace()
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
m_engine->activateFrame(current);
}
m_debuggerManagerAccess->watchHandler()->updateWatchers();
// Update watchers
m_watchModel->refresh();
}
void CdbDebugEnginePrivate::updateModules()
@@ -1512,8 +1481,6 @@ void CdbDebugEnginePrivate::updateModules()
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
}
static const char *dumperPrefixC = "dumper";
void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
{
if (debugCDB>2)
@@ -1586,6 +1553,37 @@ bool CdbDebugEnginePrivate::setSymbolPaths(const QStringList &s, QString *errorM
return true;
}
void CdbDebugEngine::insertWatcher(const WatchData &wd)
{
// Make sure engine is active
if (m_d->m_watchModel && m_d->m_watchModel == m_d->m_debuggerManagerAccess->watchHandler()->model(WatchersWatch))
m_d->m_watchModel->addWatcher(wd);
}
WatchModel *CdbDebugEngine::watchModel(int type) const
{
switch (type) {
case LocalsWatch:
if (!m_d->m_localsModel) {
m_d->m_localsModel = new CdbLocalsModel(m_d->m_dumper, m_d->m_debuggerManagerAccess->watchHandler(), LocalsWatch, const_cast<CdbDebugEngine*>(this));
connect(m_d->m_localsModel, SIGNAL(error(QString)), this, SLOT(warning(QString)));
}
return m_d->m_localsModel;
case WatchersWatch:
if (!m_d->m_watchModel) {
CdbDebugEngine* nonConstThis = const_cast<CdbDebugEngine*>(this);
WatchHandler *wh = m_d->m_debuggerManagerAccess->watchHandler();
m_d->m_watchModel = new CdbWatchModel(nonConstThis, m_d->m_dumper, wh, WatchersWatch, nonConstThis);
connect(m_d->m_watchModel, SIGNAL(error(QString)), this, SLOT(warning(QString)));
connect(wh, SIGNAL(watcherInserted(WatchData)), this, SLOT(insertWatcher(WatchData)));
}
return m_d->m_watchModel;
default:
break;
}
return 0;
}
} // namespace Internal
} // namespace Debugger