diff --git a/debuggers/gdb/debugjob.cpp b/debuggers/gdb/debugjob.cpp --- a/debuggers/gdb/debugjob.cpp +++ b/debuggers/gdb/debugjob.cpp @@ -35,6 +35,7 @@ #include "debug.h" #include +#include #include using namespace GDBDebugger; @@ -50,6 +51,11 @@ m_session = p->createSession(); connect(m_session, &DebugSession::applicationStandardOutputLines, this, &DebugJob::stderrReceived); connect(m_session, &DebugSession::applicationStandardErrorLines, this, &DebugJob::stdoutReceived); + connect(m_session, &DebugSession::gdbInternalCommandStdout, + this, [this](const QString &output){ + this->stdoutReceived(output.split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts)); + }); + connect(m_session, &DebugSession::finished, this, &DebugJob::done ); if (launchcfg->project()) { diff --git a/debuggers/gdb/debugsession.h b/debuggers/gdb/debugsession.h --- a/debuggers/gdb/debugsession.h +++ b/debuggers/gdb/debugsession.h @@ -254,6 +254,7 @@ void ttyStderr (const QByteArray& output); void gdbInternalCommandStdout (const QString& output); void gdbUserCommandStdout (const QString& output); + void gdbInternalOutput (const QString& output); void gdbStateChanged(DBGStateFlags oldState, DBGStateFlags newState); void debuggerAbnormalExit(); diff --git a/debuggers/gdb/debugsession.cpp b/debuggers/gdb/debugsession.cpp --- a/debuggers/gdb/debugsession.cpp +++ b/debuggers/gdb/debugsession.cpp @@ -884,6 +884,8 @@ &DebugSession::gdbUserCommandStdout); connect(gdb, &GDB::internalCommandOutput, this, &DebugSession::gdbInternalCommandStdout); + connect(gdb, &GDB::debuggerInternalOutput, this, + &DebugSession::gdbInternalOutput); connect(gdb, &GDB::ready, this, &DebugSession::gdbReady); connect(gdb, &GDB::gdbExited, this, &DebugSession::gdbExited); diff --git a/debuggers/gdb/gdb.h b/debuggers/gdb/gdb.h --- a/debuggers/gdb/gdb.h +++ b/debuggers/gdb/gdb.h @@ -113,10 +113,13 @@ void userCommandOutput(const QString& s); /** Reports output of a command issued internally - by KDevelop. At the moment, stderr output from - GDB and the 'log' MI channel will be also routed here. */ + by KDevelop. */ void internalCommandOutput(const QString& s); + /** Reports debugger interal output, including stderr output from debugger + and the 'log' MI channel */ + void debuggerInternalOutput(const QString& s); + private Q_SLOTS: void readyReadStandardOutput(); void readyReadStandardError(); diff --git a/debuggers/gdb/gdb.cpp b/debuggers/gdb/gdb.cpp --- a/debuggers/gdb/gdb.cpp +++ b/debuggers/gdb/gdb.cpp @@ -192,7 +192,7 @@ void GDB::readyReadStandardError() { process_->setReadChannel(QProcess::StandardOutput); - emit internalCommandOutput(QString::fromUtf8(process_->readAll())); + emit debuggerInternalOutput(QString::fromUtf8(process_->readAll())); } void GDB::processLine(const QByteArray& line) @@ -308,17 +308,16 @@ if (s.subkind == GDBMI::StreamRecord::Target) { emit applicationOutput(s.message); - } else { + } else if (s.subkind == GDBMI::StreamRecord::Console) { if (currentCmd_ && currentCmd_->isUserCommand()) emit userCommandOutput(s.message); - else if (s.subkind == GDBMI::StreamRecord::Console) { - emit applicationOutput(s.message); - } else { + else emit internalCommandOutput(s.message); - } if (currentCmd_) currentCmd_->newOutput(s.message); + } else { + emit debuggerInternalOutput(s.message); } emit streamRecord(s); diff --git a/debuggers/gdb/gdbframestackmodel.cpp b/debuggers/gdb/gdbframestackmodel.cpp --- a/debuggers/gdb/gdbframestackmodel.cpp +++ b/debuggers/gdb/gdbframestackmodel.cpp @@ -24,6 +24,8 @@ #include +#include + using namespace KDevelop; QString getFunctionOrAddress(const GDBMI::Value &frame) @@ -59,25 +61,26 @@ { const GDBMI::Value& threads = r["threads"]; - // Traverse GDB threads in backward order -- since GDB - // reports them in backward order. We want UI to - // show thread IDs in the natural order. - // FIXME: make the code independent of whatever craziness - // gdb might have tomorrow. - - QList threadsList; - int gidx = threads.size()-1; - for (; gidx >= 0; --gidx) { - KDevelop::FrameStackModel::ThreadItem i; - const GDBMI::Value & threadMI = threads[gidx]; - i.nr = threadMI["id"].toInt(); + QList threadsList; + for (int i = 0; i!= threads.size(); ++i) { + const auto &threadMI = threads[i]; + FrameStackModel::ThreadItem threadItem; + threadItem.nr = threadMI["id"].toInt(); if (threadMI["state"].literal() == "stopped") { - i.name = getFunctionOrAddress(threads[gidx]["frame"]); + threadItem.name = getFunctionOrAddress(threadMI["frame"]); } else { - i.name = i18n("(running)"); + i18n("(running)"); } - threadsList << i; + threadsList << threadItem; } + // Sort the list by id, some old version of GDB + // reports them in backward order. We want UI to + // show thread IDs in the natural order. + std::sort(threadsList.begin(), threadsList.end(), + [](const FrameStackModel::ThreadItem &a, const FrameStackModel::ThreadItem &b){ + return a.nr < b.nr; + }); + setThreads(threadsList); if (r.hasField("current-thread-id")) { int currentThreadId = r["current-thread-id"].toInt(); diff --git a/debuggers/gdb/gdboutputwidget.cpp b/debuggers/gdb/gdboutputwidget.cpp --- a/debuggers/gdb/gdboutputwidget.cpp +++ b/debuggers/gdb/gdboutputwidget.cpp @@ -137,6 +137,9 @@ this, &GDBOutputWidget::slotInternalCommandStdout); connect(session, &DebugSession::gdbUserCommandStdout, this, &GDBOutputWidget::slotUserCommandStdout); + // debugger internal output, treat it as an internal command output + connect(session, &DebugSession::gdbInternalOutput, + this, &GDBOutputWidget::slotInternalCommandStdout); connect(session, &DebugSession::gdbStateChanged, this, &GDBOutputWidget::slotStateChanged); diff --git a/debuggers/gdb/unittests/test_gdb.cpp b/debuggers/gdb/unittests/test_gdb.cpp --- a/debuggers/gdb/unittests/test_gdb.cpp +++ b/debuggers/gdb/unittests/test_gdb.cpp @@ -437,23 +437,26 @@ TestDebugSession *session = new TestDebugSession; TestLaunchConfiguration cfg; + // breakpoint 1: line 29 KDevelop::Breakpoint * b = breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 28); QCOMPARE(breakpoints()->rowCount(), 1); session->startProgram(&cfg, m_iface); + // breakpoint 2: line 28 //insert custom command as user might do it using GDB console session->addCommand(new UserCommand(GDBMI::NonMI, "break "+debugeeFileName+":28")); - WAIT_FOR_STATE(session, DebugSession::PausedState); - QTest::qWait(100); + WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // stop at line 28 session->stepInto(); - WAIT_FOR_STATE(session, DebugSession::PausedState); + WAIT_FOR_STATE_AND_IDLE(session, DebugSession::PausedState); // stop after step QCOMPARE(breakpoints()->rowCount(), 2); b = breakpoints()->breakpoint(1); QCOMPARE(b->url(), QUrl::fromLocalFile(debugeeFileName)); QCOMPARE(b->line(), 27); session->run(); + WAIT_FOR_STATE(session, DebugSession::PausedState); // stop at line 29 + session->run(); WAIT_FOR_STATE(session, DebugSession::EndedState); }