Debugger[New CDB]: Add support for "Select Widget to Watch".

in stopped state. Add helper for executing calls
to ExtensionContext including recording of output in
OutputCallback. Extend symbol resolution to return addresses
as well since QApplication::widgetAt() is ambiguous and needs
to be called by address. Add 'widgetat' extension command
to return the widget.
This commit is contained in:
Friedemann Kleint
2011-01-18 11:40:45 +01:00
parent a471f54240
commit 11c6ca71ac
13 changed files with 329 additions and 37 deletions

View File

@@ -353,7 +353,9 @@ CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
m_hasDebuggee(false),
m_elapsedLogTime(0),
m_sourceStepInto(false),
m_wX86BreakpointCount(0)
m_wX86BreakpointCount(0),
m_watchPointX(0),
m_watchPointY(0)
{
Utils::SavedAction *assemblerAction = theAssemblerAction();
m_operateByInstructionPending = assemblerAction->isChecked();
@@ -1443,6 +1445,12 @@ unsigned CdbEngine::examineStopReason(const QByteArray &messageIn,
*message = tr("Malformed stop response received.");
return StopReportParseError|StopNotifyStop;
}
// Additional stop messages occurring for debuggee function calls (widgetAt, etc). Just log.
if (state() == InferiorStopOk) {
*message = QString::fromLatin1("Ignored stop notification from function call (%1).").
arg(QString::fromAscii(reason));
return StopReportLog;
}
const int threadId = stopReason.findChild("threadId").data().toInt();
if (reason == "breakpoint") {
const int number = stopReason.findChild("breakpointId").data().toInt();
@@ -1511,6 +1519,9 @@ void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
attemptBreakpointSynchronization();
doContinueInferior();
return;
case SpecialStopGetWidgetAt:
postWidgetAtCommand();
return;
case NoSpecialStop:
break;
}
@@ -2112,5 +2123,67 @@ void CdbEngine::postCommandSequence(unsigned mask)
}
}
void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
{
bool success = false;
QString message;
do {
if (!reply->success) {
message = QString::fromAscii(reply->errorMessage);
break;
}
// Should be "namespace::QWidget:0x555"
QString watchExp = QString::fromAscii(reply->reply);
const int sepPos = watchExp.lastIndexOf(QLatin1Char(':'));
if (sepPos == -1) {
message = QString::fromAscii("Invalid output: %1").arg(watchExp);
break;
}
// 0x000 -> nothing found
if (!watchExp.mid(sepPos + 1).toULongLong(0, 0)) {
message = QString::fromAscii("No widget could be found at %1, %2.").arg(m_watchPointX).arg(m_watchPointY);
break;
}
// Turn into watch expression: "*(namespace::QWidget*)0x555"
watchExp.replace(sepPos, 1, QLatin1String("*)"));
watchExp.insert(0, QLatin1String("*("));
watchHandler()->watchExpression(watchExp);
success = true;
} while (false);
if (!success)
showMessage(message, LogWarning);
m_watchPointX = m_watchPointY = 0;
}
void CdbEngine::watchPoint(const QPoint &p)
{
m_watchPointX = p.x();
m_watchPointY = p.y();
switch (state()) {
case InferiorStopOk:
postWidgetAtCommand();
break;
case InferiorRunOk:
// "Select Widget to Watch" from a running application is currently not
// supported. It could be implemented via SpecialStopGetWidgetAt-mode,
// but requires some work as not to confuse the engine by state-change notifications
// emitted by the debuggee function call.
showMessage(tr("\"Select Widget to Watch\": Please stop the application first."), LogWarning);
break;
default:
showMessage(tr("\"Select Widget to Watch\": Not supported in state '%1'.").
arg(QString::fromAscii(stateName(state()))), LogWarning);
break;
}
}
void CdbEngine::postWidgetAtCommand()
{
QByteArray arguments = QByteArray::number(m_watchPointX);
arguments.append(' ');
arguments.append(QByteArray::number(m_watchPointY));
postExtensionCommand("widgetat", arguments, 0, &CdbEngine::handleWidgetAt, 0);
}
} // namespace Internal
} // namespace Debugger

View File

@@ -89,6 +89,7 @@ public:
virtual void updateWatchData(const WatchData &data,
const WatchUpdateFlags & flags = WatchUpdateFlags());
virtual unsigned debuggerCapabilities() const;
virtual void watchPoint(const QPoint &);
virtual void setRegisterValue(int regnr, const QString &value);
virtual void executeStep();
@@ -150,7 +151,12 @@ private slots:
void operateByInstructionTriggered(bool);
private:
enum SpecialStopMode { NoSpecialStop, SpecialStopSynchronizeBreakpoints };
enum SpecialStopMode
{
NoSpecialStop,
SpecialStopSynchronizeBreakpoints,
SpecialStopGetWidgetAt
};
unsigned examineStopReason(const QByteArray &messageIn, QString *message,
QString *exceptionBoxMessage);
@@ -166,6 +172,7 @@ private:
inline bool isCdbProcessRunning() const { return m_process.state() != QProcess::NotRunning; }
bool canInterruptInferior() const;
void syncOperateByInstruction(bool operateByInstruction);
void postWidgetAtCommand();
// Builtin commands
void dummyHandler(const CdbBuiltinCommandPtr &);
@@ -182,6 +189,7 @@ private:
void handleRegisters(const CdbExtensionCommandPtr &reply);
void handleModules(const CdbExtensionCommandPtr &reply);
void handleMemory(const CdbExtensionCommandPtr &);
void handleWidgetAt(const CdbExtensionCommandPtr &);
QString normalizeFileName(const QString &f);
void updateLocalVariable(const QByteArray &iname);
@@ -215,6 +223,8 @@ private:
QByteArray m_extensionMessageBuffer;
bool m_sourceStepInto;
unsigned m_wX86BreakpointCount;
int m_watchPointX;
int m_watchPointY;
};
} // namespace Internal