Commit fd3d7de9 authored by hjk's avatar hjk
Browse files

debugger: implement qml->c++ cross-stepping

parent 210382f2
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment