Debugger[New CDB]:Introduce watches infrastructure.

- Move the 'current module' into the Node
- Split symbol group hierarchy into LocalsSymbolGroup
  tied to frame/thread and a separate, scopeless
  WatchesSymbolGroup
- Add infrastructure for removing symbols from a SymbolGroup,
  doing the index bookkeeping.
- Add method to synchronize watches to  WatchesSymbolGroup
  (iname/name map).
- Introduce watches commands for adding and dumping.
- Extend locals command to get watches as well.
- Add a dummy 'ErrorSymbolGroupNode' to use in case
  insertion fails.
This commit is contained in:
Friedemann Kleint
2011-01-14 16:50:31 +01:00
parent 7968853f1a
commit 3a87af8ada
13 changed files with 944 additions and 251 deletions

View File

@@ -85,6 +85,7 @@ Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
enum { debug = 0 };
enum { debugLocals = 0 };
enum { debugWatches = 0 };
enum { debugBreakpoints = 0 };
#if 0
@@ -703,16 +704,35 @@ void CdbEngine::detachDebugger()
postCommand(".detach", 0);
}
static inline bool isWatchIName(const QByteArray &iname)
{
return iname.startsWith("watch");
}
void CdbEngine::updateWatchData(const WatchData &dataIn,
const WatchUpdateFlags & flags)
{
if (debug)
qDebug("CdbEngine::updateWatchData() %dms %s incr=%d: %s",
elapsedLogTime(), stateName(state()),
if (debug || debugLocals || debugWatches)
qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
elapsedLogTime(), m_accessible, stateName(state()),
flags.tryIncremental,
qPrintable(dataIn.toString()));
if (!dataIn.hasChildren) {
if (!m_accessible) // Add watch data while running?
return;
// New watch item?
if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
QByteArray args;
ByteArrayInputStream str(args);
str << dataIn.iname << " \"" << dataIn.exp << '"';
postExtensionCommand("addwatch", args, 0,
&CdbEngine::handleAddWatch, 0,
qVariantFromValue(dataIn));
return;
}
if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
WatchData data = dataIn;
data.setAllUnneeded();
watchHandler()->insertData(data);
@@ -721,6 +741,22 @@ void CdbEngine::updateWatchData(const WatchData &dataIn,
updateLocalVariable(dataIn.iname);
}
void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
{
WatchData item = qvariant_cast<WatchData>(reply->cookie);
if (debugWatches)
qDebug() << "handleAddWatch ok=" << reply->success << item.iname;
if (reply->success) {
updateLocalVariable(item.iname);
} else {
item.setError(tr("Unable to add expression"));
watchHandler()->insertData(item);
showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
arg(QString::fromAscii(item.iname), QString::fromAscii(item.exp),
reply->errorMessage), LogError);
}
}
void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
{
if (debuggerCore()->boolSetting(VerboseLog))
@@ -737,22 +773,28 @@ void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
void CdbEngine::updateLocalVariable(const QByteArray &iname)
{
const int stackFrame = stackHandler()->currentIndex();
if (stackFrame >= 0) {
QByteArray localsArguments;
ByteArrayInputStream str(localsArguments);
addLocalsOptions(str);
str << blankSeparator << stackFrame << ' ' << iname;
postExtensionCommand("locals", localsArguments, 0, &CdbEngine::handleLocals);
} else {
qWarning("Internal error; no stack frame in updateLocalVariable");
const bool isWatch = isWatchIName(iname);
if (debugWatches)
qDebug() << "updateLocalVariable watch=" << isWatch << iname;
QByteArray localsArguments;
ByteArrayInputStream str(localsArguments);
addLocalsOptions(str);
if (!isWatch) {
const int stackFrame = stackHandler()->currentIndex();
if (stackFrame < 0) {
qWarning("Internal error; no stack frame in updateLocalVariable");
return;
}
str << blankSeparator << stackFrame;
}
str << blankSeparator << iname;
postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, &CdbEngine::handleLocals);
}
unsigned CdbEngine::debuggerCapabilities() const
{
return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
|WatchpointCapability|JumpToLineCapability
|WatchpointCapability|JumpToLineCapability|AddWatcherCapability
|BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw().
}
@@ -1052,6 +1094,8 @@ void CdbEngine::activateFrame(int index)
void CdbEngine::updateLocals()
{
typedef QHash<QByteArray, int> WatcherHash;
const int frameIndex = stackHandler()->currentIndex();
if (frameIndex < 0) {
watchHandler()->beginCycle();
@@ -1094,6 +1138,16 @@ void CdbEngine::updateLocals()
}
}
}
// Perform watches synchronization
str << blankSeparator << "-W";
const WatcherHash watcherHash = WatchHandler::watcherNames();
if (!watcherHash.isEmpty()) {
const WatcherHash::const_iterator cend = watcherHash.constEnd();
for (WatcherHash::const_iterator it = watcherHash.constBegin(); it != cend; ++it) {
str << blankSeparator << "-w " << it.value() << " \"" << it.key() << '"';
}
}
// Required arguments: frame
str << blankSeparator << frameIndex;
watchHandler()->beginCycle();