Commit 6a681b77 authored by Niko Sams's avatar Niko Sams
Browse files

Fix Internal Debugger Error when clicking step into too fast

Always wait for a gdb reply (^done or ^running) before sending
the next command. *stopped is not a reply, as ^done will follow
and everything will get out of sync.
Also remove a workaround for handling attach response, as this
had apperently the same problem.

BUG: 274390
parent f8fa5194
......@@ -44,7 +44,7 @@
using namespace GDBDebugger;
GDB::GDB(QObject* parent)
: QObject(parent), process_(0), sawPrompt_(false), currentCmd_(0)
: QObject(parent), process_(0), sawPrompt_(false), currentCmd_(0), receivedReply_(false), isRunning_(false)
{
}
......@@ -120,6 +120,9 @@ void GDB::execute(GDBCommand* command)
QString commandText = currentCmd_->cmdToSend();
kDebug(9012) << "SEND:" << commandText;
isRunning_ = false;
receivedReply_ = false;
process_->write(commandText.toLatin1(),
commandText.length());
......@@ -184,7 +187,7 @@ void GDB::readyReadStandardError()
void GDB::processLine(const QByteArray& line)
{
kDebug(9012) << "GDB output: " << line << "\n";
kDebug(9012) << "GDB output: " << line;
if(!currentCmd_)
{
kDebug(9012) << "No current command\n";
......@@ -224,8 +227,7 @@ void GDB::processLine(const QByteArray& line)
}
else
{
bool ready_for_next_command = false;
#ifndef DEBUG_NO_TRY
try
{
......@@ -250,26 +252,19 @@ void GDB::processLine(const QByteArray& line)
if (result.reason == "stopped")
{
//stopped is *not* a reply, wait for ^running or ^done (running before stopped, done after stopped)
isRunning_ = false;
emit programStopped(result);
ready_for_next_command = true;
}
else if (result.reason == "running")
{
receivedReply_ = true;
isRunning_ = true;
emit programRunning();
}
/* In theory, commands that run inferior and asynchronous,
and we get back gdb prompt, and can send further
commands. As of Dec 2007, this actually does not work,
and fully async operation of GDB is only being designed.
So, if we see "running", assume we can't yet send
commands. */
ready_for_next_command = (result.reason != "running");
if (currentCmd_ && currentCmd_->type() == GDBMI::TargetAttach && result.reason == "stopped") {
//when attaching don't send next command when we get *stopped response, as ^done will follow
ready_for_next_command = false;
else
{
receivedReply_ = true;
}
if (result.reason == "done")
......@@ -328,14 +323,12 @@ void GDB::processLine(const QByteArray& line)
"The MI response is: %2", e.what(),
QString::fromLatin1(line)),
i18n("Internal debugger error"));
delete currentCmd_;
currentCmd_ = 0;
ready_for_next_command = true;
isRunning_ = false;
receivedReply_ = true;
}
#endif
if (ready_for_next_command)
if (receivedReply_ && !isRunning_)
{
delete currentCmd_;
currentCmd_ = 0;
......
......@@ -140,6 +140,9 @@ private:
/** The unprocessed output from gdb. Output is
processed as soon as we see newline. */
QByteArray buffer_;
bool receivedReply_;
bool isRunning_;
};
}
......
/*
Copyright 2011 Niko Sams <niko.sams@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QDebug>
#include <qt4/QtCore/QString>
#include <qt4/QtCore/qpointer.h>
int main(int argc, char **argv) {
for(int i=0; i<10; ++i) {
QString x("foobar");
x += QString::number(i);
qDebug() << x;
}
return 0;
}
......@@ -1237,6 +1237,23 @@ void GdbTest::testInsertAndRemoveBreakpointWhileRunning()
WAIT_FOR_STATE(session, DebugSession::EndedState);
}
//Bug 274390
void GdbTest::testCommandOrderFastStepping()
{
TestDebugSession *session = new TestDebugSession;
TestLaunchConfiguration cfg(KUrl(QDir::currentPath()+"/unittests/debugeeqt"));
breakpoints()->addCodeBreakpoint("main");
QVERIFY(session->startProgram(&cfg));
for(int i=0; i<20; i++) {
session->stepInto();
}
WAIT_FOR_STATE(session, DebugSession::PausedState);
session->run();
WAIT_FOR_STATE(session, DebugSession::EndedState);
}
void GdbTest::waitForState(GDBDebugger::DebugSession *session, DebugSession::DebuggerState state,
const char *file, int line)
......
......@@ -71,6 +71,7 @@ private Q_SLOTS:
void testSegfaultDebugee();
void testSwitchFrameGdbConsole();
void testInsertAndRemoveBreakpointWhileRunning();
void testCommandOrderFastStepping();
private:
KDevelop::TestCore* m_core;
void waitForState(GDBDebugger::DebugSession *session, KDevelop::IDebugSession::DebuggerState state, const char *file, int line);
......
Supports Markdown
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