forked from qt-creator/qt-creator
debugger: implement qml->c++ cross-stepping
This commit is contained in:
@@ -244,8 +244,8 @@ public:
|
||||
bool isMasterEngine() const;
|
||||
DebuggerEngine *masterEngine() const;
|
||||
|
||||
virtual bool prepareForQmlBreak(bool /*on*/) { return false; }
|
||||
virtual void handlePrepareForQmlBreak() {}
|
||||
virtual bool setupQmlStep(bool /*on*/) { return false; }
|
||||
virtual void readyToExecuteQmlStep() {}
|
||||
|
||||
signals:
|
||||
void stateChanged(const DebuggerState &state);
|
||||
|
||||
@@ -80,10 +80,6 @@ void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &respon
|
||||
if (m_engine->m_gdbVersion < 70000)
|
||||
m_engine->postCommand("info target", CB(handleInfoTarget));
|
||||
}
|
||||
//if (m_engine->isSlaveEngine())
|
||||
//m_engine->postCommand("qmlb", GdbEngine::ConsoleCommand);
|
||||
//m_engine->postCommand("rbreak QScript::FunctionWrapper::proxyCall");
|
||||
// m_engine->postCommand("-break-insert -f 'myns::QScript::FunctionWrapper::proxyCall'");
|
||||
m_engine->handleInferiorPrepared();
|
||||
} else {
|
||||
QByteArray ba = response.data.findChild("msg").data();
|
||||
@@ -105,15 +101,15 @@ void AbstractPlainGdbAdapter::runEngine()
|
||||
fileName = symbols.fileName();
|
||||
}
|
||||
m_engine->postCommand("maint print msymbols " + fileName.toLocal8Bit(),
|
||||
CB(handleNamespaceExtraction1), fileName);
|
||||
//m_engine->postCommand("print QString", CB(handleNamespaceExtraction));
|
||||
CB(handleNamespaceExtraction), fileName);
|
||||
}
|
||||
|
||||
void AbstractPlainGdbAdapter::handleNamespaceExtraction1(const GdbResponse &response)
|
||||
void AbstractPlainGdbAdapter::handleNamespaceExtraction(const GdbResponse &response)
|
||||
{
|
||||
QFile file(response.cookie.toString());
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QByteArray ba = file.readAll();
|
||||
file.remove();
|
||||
int pos = ba.indexOf("7QString9fromAscii");
|
||||
int pos1 = pos - 1;
|
||||
while (pos1 > 0 && ba.at(pos1) != 'N' && ba.at(pos1) > '@')
|
||||
@@ -122,75 +118,7 @@ void AbstractPlainGdbAdapter::handleNamespaceExtraction1(const GdbResponse &resp
|
||||
const QByteArray ns = ba.mid(pos1, pos - pos1);
|
||||
if (!ns.isEmpty())
|
||||
m_engine->setQtNamespace(ns + "::");
|
||||
if (m_engine->isSlaveEngine()) {
|
||||
for (int i = 1; i <= 8; ++i) {
|
||||
m_engine->postCommand("-break-insert -f '" + m_engine->qtNamespace()
|
||||
+ "QScript::qScriptBreaker" + QByteArray::number(i) + "'",
|
||||
CB(handleFindScriptBreaker), i);
|
||||
}
|
||||
} else {
|
||||
doRunEngine();
|
||||
}
|
||||
file.remove();
|
||||
}
|
||||
|
||||
void AbstractPlainGdbAdapter::handleNamespaceExtraction(const GdbResponse &response)
|
||||
{
|
||||
if (response.resultClass == GdbResultDone) {
|
||||
// $1 = {void (myns::QString * const, const char *)} 0x8058e2c <QString>"}
|
||||
const QByteArray ba = response.data.findChild("consolestreamoutput").data();
|
||||
const int posQString = ba.indexOf("QString");
|
||||
const int posNs = ba.lastIndexOf('(', posQString) + 1;
|
||||
const QByteArray ns = ba.mid(posNs, posQString - posNs);
|
||||
if (!ns.isEmpty())
|
||||
m_engine->setQtNamespace(ns);
|
||||
}
|
||||
if (m_engine->isSlaveEngine()) {
|
||||
for (int i = 1; i <= 8; ++i) {
|
||||
m_engine->postCommand("-break-insert -f '" + m_engine->qtNamespace()
|
||||
+ "QScript::qScriptBreaker" + QByteArray::number(i) + "'",
|
||||
CB(handleFindScriptBreaker), i);
|
||||
}
|
||||
} else {
|
||||
doRunEngine();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractPlainGdbAdapter::handleFindScriptBreaker(const GdbResponse &response)
|
||||
{
|
||||
//QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
||||
if (response.resultClass == GdbResultDone) {
|
||||
const int qmlBpType = response.cookie.toInt();
|
||||
// 20^done,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
|
||||
// addr="<PENDING>",pending="'myns::QScript::qScriptBreaker'"
|
||||
const GdbMi bkpt = response.data.findChild("bkpt");
|
||||
const GdbMi number = bkpt.findChild("number");
|
||||
const int bpnr = number.data().toInt();
|
||||
m_engine->addQmlBreakpointNumber(qmlBpType, bpnr);
|
||||
//m_engine->postCommand("disable " + number.data());
|
||||
switch (qmlBpType) {
|
||||
case 5:
|
||||
m_engine->postCommand("enable " + number.data());
|
||||
m_engine->postCommand("command " + number.data() +
|
||||
//"\necho \"STEP NOW\"\nfinish\nend")
|
||||
"\nup"
|
||||
"\necho \"YYY\""
|
||||
"\ntbreak"
|
||||
"\ncommands"
|
||||
"\necho \"XXX\""
|
||||
"\nstep"
|
||||
"\nend"
|
||||
"\ncontinue"
|
||||
"\nend");
|
||||
break;
|
||||
default:
|
||||
//m_engine->postCommand("command " + number.data() +
|
||||
// "\nfinish\nend");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (response.cookie.toInt() == 8)
|
||||
doRunEngine();
|
||||
doRunEngine();
|
||||
}
|
||||
|
||||
void AbstractPlainGdbAdapter::doRunEngine()
|
||||
|
||||
@@ -53,7 +53,6 @@ public:
|
||||
protected:
|
||||
void handleInfoTarget(const GdbResponse &response);
|
||||
void handleNamespaceExtraction(const GdbResponse &response);
|
||||
void handleNamespaceExtraction1(const GdbResponse &response);
|
||||
|
||||
private:
|
||||
virtual QByteArray execFilePath() const = 0;
|
||||
@@ -62,7 +61,6 @@ private:
|
||||
virtual QString fromLocalEncoding(const QByteArray &ba) const = 0;
|
||||
void handleExecRun(const GdbResponse &response);
|
||||
void handleFileExecAndSymbols(const GdbResponse &response);
|
||||
void handleFindScriptBreaker(const GdbResponse &response);
|
||||
void doRunEngine();
|
||||
};
|
||||
|
||||
|
||||
@@ -1178,7 +1178,10 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
if (fullName.isEmpty())
|
||||
fullName = QString::fromUtf8(frame.findChild("file").data());
|
||||
|
||||
if (bkptno && frame.isValid()) {
|
||||
const bool isSpecialQmlBreakpoint =
|
||||
m_qmlBreakpointNumbers.keys().contains(bkptno);
|
||||
|
||||
if (bkptno && frame.isValid() && !isSpecialQmlBreakpoint) {
|
||||
// Use opportunity to update the breakpoint marker position.
|
||||
BreakHandler *handler = breakHandler();
|
||||
BreakpointId id = handler->findBreakpointByNumber(bkptno);
|
||||
@@ -1194,7 +1197,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
|
||||
// Quickly set the location marker.
|
||||
if (lineNumber && !debuggerCore()->boolSetting(OperateByInstruction)
|
||||
&& QFileInfo(fullName).exists())
|
||||
&& QFileInfo(fullName).exists() && !isSpecialQmlBreakpoint)
|
||||
gotoLocation(Location(fullName, lineNumber));
|
||||
|
||||
if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
|
||||
@@ -1263,6 +1266,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
}
|
||||
*/
|
||||
|
||||
if (isSpecialQmlBreakpoint)
|
||||
return;
|
||||
|
||||
handleStop0(data);
|
||||
}
|
||||
|
||||
@@ -4534,27 +4540,36 @@ void GdbEngine::handleRemoteSetupFailed(const QString &message)
|
||||
m_gdbAdapter->handleRemoteSetupFailed(message);
|
||||
}
|
||||
|
||||
bool GdbEngine::prepareForQmlBreak(bool on)
|
||||
bool GdbEngine::setupQmlStep(bool on)
|
||||
{
|
||||
QTC_ASSERT(isSlaveEngine(), return false);
|
||||
Q_UNUSED(on);
|
||||
postCommand("tbreak '" + qtNamespace() + "QScript::FunctionWrapper::proxyCall'\n"
|
||||
"commands\n"
|
||||
"set $d=(void*)((FunctionWrapper*)callee)->data->function\n"
|
||||
"tbreak *$d\ncontinue\nend",
|
||||
NeedsStop, CB(handleSetQmlStepBreakpoint));
|
||||
m_preparedForQmlBreak = on;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GdbEngine::handleQmlBreakpoint(const GdbResponse &response)
|
||||
void GdbEngine::handleSetQmlStepBreakpoint(const GdbResponse &response)
|
||||
{
|
||||
//QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
||||
if (response.resultClass == GdbResultDone) {
|
||||
qDebug() << "RESPONSE: " << response.toString();
|
||||
// 20^done,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",
|
||||
// addr="<PENDING>",pending="'myns::QScript::qScriptBreaker'"}
|
||||
const GdbMi bkpt = response.data.findChild("bkpt");
|
||||
const GdbMi number = bkpt.findChild("number");
|
||||
const int bpnr = number.data().toInt();
|
||||
m_qmlBreakpointNumbers[1] = bpnr;
|
||||
//postCommand("disable " + number.data());
|
||||
//postCommand("enable " + number.data());
|
||||
}
|
||||
QTC_ASSERT(masterEngine(), return);
|
||||
masterEngine()->handlePrepareForQmlBreak();
|
||||
masterEngine()->readyToExecuteQmlStep();
|
||||
}
|
||||
|
||||
void GdbEngine::addQmlBreakpointNumber(int type, int nr)
|
||||
{
|
||||
qDebug() << "ADD SPECIAL QML BREAKPOINT, TYPE: " << type << "NR: " << nr;
|
||||
m_qmlBreakpointNumbers[type] = nr;
|
||||
}
|
||||
|
||||
//
|
||||
// Factory
|
||||
|
||||
@@ -553,12 +553,10 @@ private: ////////// View & Data Stuff //////////
|
||||
//
|
||||
// Qml
|
||||
//
|
||||
void addQmlBreakpointNumber(int type /* 1-8 */, int nr);
|
||||
QHash<int, int> m_qmlBreakpointNumbers;
|
||||
bool m_preparedForQmlBreak;
|
||||
bool prepareForQmlBreak(bool on);
|
||||
void handleQmlBreakpoint(const GdbResponse &response);
|
||||
|
||||
bool setupQmlStep(bool on);
|
||||
void handleSetQmlStepBreakpoint(const GdbResponse &response);
|
||||
|
||||
// HACK:
|
||||
StackFrame m_targetFrame;
|
||||
|
||||
@@ -220,16 +220,16 @@ void QmlCppEngine::executeStep()
|
||||
{
|
||||
if (d->m_activeEngine == d->m_qmlEngine) {
|
||||
QTC_ASSERT(d->m_cppEngine->state() == InferiorRunOk, /**/);
|
||||
d->m_cppEngine->prepareForQmlBreak(true);
|
||||
if (d->m_cppEngine->setupQmlStep(true))
|
||||
return; // Wait for callback to readyToExecuteQmlStep()
|
||||
}
|
||||
notifyInferiorRunRequested();
|
||||
d->m_activeEngine->executeStep();
|
||||
readyToExecuteQmlStep();
|
||||
}
|
||||
|
||||
void QmlCppEngine::handlePrepareForQmlBreak()
|
||||
void QmlCppEngine::readyToExecuteQmlStep()
|
||||
{
|
||||
notifyInferiorRunRequested();
|
||||
d->m_activeEngine->executeStep();
|
||||
d->m_qmlEngine->executeStep();
|
||||
}
|
||||
|
||||
void QmlCppEngine::executeStepOut()
|
||||
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
void setState(DebuggerState newState, bool forced = false);
|
||||
void slaveEngineStateChanged(DebuggerEngine *slaveEngine, DebuggerState state);
|
||||
|
||||
virtual void handlePrepareForQmlBreak();
|
||||
void readyToExecuteQmlStep();
|
||||
|
||||
private:
|
||||
QScopedPointer<QmlCppEnginePrivate> d;
|
||||
|
||||
Reference in New Issue
Block a user