From 82272d9c22f362d00d00cd38eccd0f0660c33704 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 6 Jun 2011 18:17:51 +0200 Subject: [PATCH] debugger: add possibility to fake response packets to trigger error handling Change-Id: Ieeb0daef594024b72e52c1180047835193e9341d Reviewed-on: http://codereview.qt.nokia.com/340 Reviewed-by: hjk --- src/plugins/debugger/gdb/gdbengine.cpp | 98 ++++++++++++++++---------- src/plugins/debugger/gdb/gdbengine.h | 13 +++- 2 files changed, 72 insertions(+), 39 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d67230e17ac..c77f081c9d1 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -338,17 +338,6 @@ void GdbEngine::handleResponse(const QByteArray &buff) { showMessage(QString::fromLocal8Bit(buff, buff.length()), LogOutput); -#if 0 - static QTime lastTime; - qDebug() // << "#### start response handling #### " - << lastTime.msecsTo(QTime::currentTime()) << "ms," - << "buf:" << buff.left(1500) << "..." - //<< "buf:" << buff - << "size:" << buff.size(); - lastTime = QTime::currentTime(); -#else - //qDebug() << "buf:" << buff; -#endif if (buff.isEmpty() || buff == "(gdb) ") return; @@ -357,19 +346,17 @@ void GdbEngine::handleResponse(const QByteArray &buff) const char *inner; int token = -1; - // token is a sequence of numbers + // Token is a sequence of numbers. for (inner = from; inner != to; ++inner) if (*inner < '0' || *inner > '9') break; if (from != inner) { token = QByteArray(from, inner - from).toInt(); from = inner; - //qDebug() << "found token" << token; } - // next char decides kind of response + // Next char decides kind of response. const char c = *from++; - //qDebug() << "CODE:" << c; switch (c) { case '*': case '+': @@ -381,7 +368,6 @@ void GdbEngine::handleResponse(const QByteArray &buff) break; asyncClass += *from; } - //qDebug() << "ASYNCCLASS" << asyncClass; GdbMi result; while (from != to) { @@ -820,29 +806,41 @@ void GdbEngine::flushCommand(const GdbCommand &cmd0) QTC_ASSERT(gdbProc()->state() == QProcess::Running, return;) - ++currentToken(); + const int token = ++currentToken(); + GdbCommand cmd = cmd0; cmd.postTime = QTime::currentTime(); - m_cookieForToken[currentToken()] = cmd; + m_cookieForToken[token] = cmd; if (cmd.flags & ConsoleCommand) cmd.command = "-interpreter-exec console \"" + cmd.command + '"'; - cmd.command = QByteArray::number(currentToken()) + cmd.command; + cmd.command = QByteArray::number(token) + cmd.command; showMessage(_(cmd.command), LogInput); - m_gdbAdapter->write(cmd.command + "\r\n"); + if (m_scheduledTestResponses.contains(token)) { + // Fake response for test cases. + QByteArray buffer = m_scheduledTestResponses.value(token); + buffer.replace("@TOKEN@", QByteArray::number(token)); + m_scheduledTestResponses.remove(token); + showMessage(_("FAKING TEST RESPONSE (TOKEN: %2, RESPONSE: '%3')") + .arg(token).arg(_(buffer))); + QMetaObject::invokeMethod(this, "handleResponse", + Q_ARG(QByteArray, buffer)); + } else { + m_gdbAdapter->write(cmd.command + "\r\n"); - // Start Watchdog. - if (m_commandTimer.interval() <= 20000) - m_commandTimer.setInterval(commandTimeoutTime()); - // The process can die for external reason between the "-gdb-exit" was - // sent and a response could be retrieved. We don't want the watchdog - // to bark in that case since the only possible outcome is a dead - // process anyway. - if (!cmd.command.endsWith("-gdb-exit")) - m_commandTimer.start(); + // Start Watchdog. + if (m_commandTimer.interval() <= 20000) + m_commandTimer.setInterval(commandTimeoutTime()); + // The process can die for external reason between the "-gdb-exit" was + // sent and a response could be retrieved. We don't want the watchdog + // to bark in that case since the only possible outcome is a dead + // process anyway. + if (!cmd.command.endsWith("-gdb-exit")) + m_commandTimer.start(); - //if (cmd.flags & LosesChild) - // notifyInferiorIll(); + //if (cmd.flags & LosesChild) + // notifyInferiorIll(); + } } int GdbEngine::commandTimeoutTime() const @@ -894,9 +892,9 @@ void GdbEngine::commandTimeout() void GdbEngine::handleResultRecord(GdbResponse *response) { - //qDebug() << "TOKEN:" << response.token + //qDebug() << "TOKEN:" << response->token // << " ACCEPTABLE:" << m_oldestAcceptableToken; - //qDebug() << "\nRESULT" << response.token << response.toString(); + //qDebug() << "\nRESULT" << response->token << response->toString(); int token = response->token; if (token == -1) @@ -1984,10 +1982,11 @@ void GdbEngine::executeStep() showStatusMessage(tr("Step requested..."), 5000); if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0) postCommand("sal step,0x" + QByteArray::number(stackHandler()->topAddress(), 16)); - if (isReverseDebugging()) + if (isReverseDebugging()) { postCommand("reverse-step", RunRequest, CB(handleExecuteStep)); - else + } else { postCommand("-exec-step", RunRequest, CB(handleExecuteStep)); + } } void GdbEngine::handleExecuteStep(const GdbResponse &response) @@ -2050,10 +2049,14 @@ void GdbEngine::executeNext() showStatusMessage(tr("Step next requested..."), 5000); if (m_gdbAdapter->isTrkAdapter() && stackHandler()->stackSize() > 0) postCommand("sal next,0x" + QByteArray::number(stackHandler()->topAddress(), 16)); - if (isReverseDebugging()) + if (isReverseDebugging()) { postCommand("reverse-next", RunRequest, CB(handleExecuteNext)); - else + } else { + scheduleTestResponse(GdbTestNoBoundsOfCurrentFunction, + "@TOKEN@^error,msg=\"Warning:\\nCannot insert breakpoint -39.\\n" + " Error accessing memory address 0x11673fc: Input/output error.\\n\""); postCommand("-exec-next", RunRequest, CB(handleExecuteNext)); + } } void GdbEngine::handleExecuteNext(const GdbResponse &response) @@ -2071,7 +2074,8 @@ void GdbEngine::handleExecuteNext(const GdbResponse &response) } QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); QByteArray msg = response.data.findChild("msg").data(); - if (msg.startsWith("Cannot find bounds of current function")) { + if (msg.startsWith("Cannot find bounds of current function") + || msg.contains("Error accessing memory address ")) { if (!m_commandsToRunOnTemporaryBreak.isEmpty()) flushQueuedCommands(); notifyInferiorRunFailed(); @@ -4383,6 +4387,12 @@ bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck bool GdbEngine::startGdb(const QStringList &args, const QString &settingsIdHint) { + const QByteArray tests = qgetenv("QTC_DEBUGGER_TESTS"); + foreach (const QByteArray &test, tests.split(',')) + m_testCases.insert(test.toInt()); + foreach (int test, m_testCases) + showMessage(_("ENABLING TEST CASE: " + QByteArray::number(test))); + gdbProc()->disconnect(); // From any previous runs const DebuggerStartParameters &sp = startParameters(); @@ -4895,6 +4905,18 @@ bool GdbEngine::isQFatalBreakpoint(int bpnr) const return bpnr && m_qFatalBreakpointNumber == bpnr; } +void GdbEngine::scheduleTestResponse(int testCase, const QByteArray &response) +{ + if (!m_testCases.contains(testCase)) + return; + + int token = currentToken() + 1; + showMessage(_("SCHEDULING TEST RESPONSE (CASE: %1, TOKEN: %2, RESPONSE: '%3')") + .arg(testCase).arg(token).arg(_(response))); + m_scheduledTestResponses[token] = response; +} + + // // Factory // diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 05dc3bf9fb8..cf950ad8b8b 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -80,6 +80,11 @@ enum DebuggingHelperState }; +enum GdbTestCase +{ + GdbTestNoBoundsOfCurrentFunction = 1 +}; + class UpdateParameters { public: @@ -389,6 +394,9 @@ private: ////////// Gdb Command Management ////////// Q_SLOT void commandTimeout(); void setTokenBarrier(); + // Sets up an "unexpected result" for the following commeand. + void scheduleTestResponse(int testCase, const QByteArray &response); + QHash m_cookieForToken; int commandTimeoutTime() const; QTimer m_commandTimer; @@ -413,7 +421,7 @@ private: ////////// Gdb Command Management ////////// private: ////////// Gdb Output, State & Capability Handling ////////// - void handleResponse(const QByteArray &buff); + Q_SLOT void handleResponse(const QByteArray &buff); void handleStopResponse(const GdbMi &data); void handleResultRecord(GdbResponse *response); void handleStop0(const GdbMi &data); @@ -724,6 +732,9 @@ private: ////////// View & Data Stuff ////////// QString m_lastWinException; int m_qFatalBreakpointNumber; bool m_actingOnExpectedStop; + + QHash m_scheduledTestResponses; + QSet m_testCases; }; } // namespace Internal