Commit 72388379 authored by Peifeng Yu's avatar Peifeng Yu
Browse files

Associate MIVariable with MIDebugSession

Summary:
Resolving a FIXME in MIVariable, make MIVariable use per session map.
This also helps lldb plugin, which has to enumerate the map to update variables,
otherwise it would also update variables for other sessions.

Test Plan: gdb unit tests and lldb unit tests (on peifeng/lldb-plugin branch)

Reviewers: #kdevelop, apol

Reviewed By: #kdevelop, apol

Subscribers: kdevelop-devel

Differential Revision: https://phabricator.kde.org/D2132
parent dd97537a
......@@ -30,6 +30,7 @@
#include "debuglog.h"
#include "midebugger.h"
#include "mivariable.h"
#include "mi/mi.h"
#include "mi/micommand.h"
#include "mi/micommandqueue.h"
......@@ -114,6 +115,27 @@ IDebugSession::DebuggerState MIDebugSession::state() const
return m_sessionState;
}
QMap<QString, MIVariable*> & MIDebugSession::variableMapping()
{
return m_allVariables;
}
MIVariable* MIDebugSession::findVariableByVarobjName(const QString &varobjName)
{
if (m_allVariables.count(varobjName) == 0)
return nullptr;
return m_allVariables[varobjName];
}
void MIDebugSession::markAllVariableDead()
{
for (auto i = m_allVariables.begin(), e = m_allVariables.end(); i != e; ++i)
{
i.value()->markAsDead();
}
m_allVariables.clear();
}
bool MIDebugSession::restartAvaliable() const
{
if (debuggerStateIsOn(s_attached) || debuggerStateIsOn(s_core)) {
......
......@@ -35,6 +35,8 @@
#include "mi/mi.h"
#include "mi/micommand.h"
#include <QMap>
#include <memory>
class IExecutePlugin;
......@@ -50,6 +52,7 @@ class CommandQueue;
}
class MIDebugger;
class MIVariable;
class STTY;
class MIDebugSession : public KDevelop::IDebugSession
{
......@@ -211,6 +214,10 @@ public:
void (Handler::* handler_method)(const MI::ResultRecord&),
MI::CommandFlags flags = 0);
QMap<QString, MIVariable*> & variableMapping();
MIVariable* findVariableByVarobjName(const QString &varobjName);
void markAllVariableDead();
protected Q_SLOTS:
virtual void slotDebuggerReady();
virtual void slotDebuggerExited(bool abnormal, const QString &msg);
......@@ -327,6 +334,9 @@ protected:
bool m_hasCrashed;
bool m_sourceInitFile;
// Map from GDB varobj name to MIVariable.
QMap<QString, MIVariable*> m_allVariables;
};
template<class Handler>
......
......@@ -21,6 +21,7 @@
#include "mivariable.h"
#include "debuglog.h"
#include "midebugsession.h"
#include "mi/micommand.h"
......@@ -31,24 +32,20 @@ using namespace KDevelop;
using namespace KDevMI;
using namespace KDevMI::MI;
QMap<QString, MIVariable*> MIVariable::allVariables_;
static bool hasStartedSession()
bool MIVariable::sessionIsAlive() const
{
if (!ICore::self()->debugController()) return false; //happens on shutdown
IDebugSession *session = ICore::self()->debugController()->currentSession();
if (!session)
if (!debugSession)
return false;
IDebugSession::DebuggerState s = session->state();
IDebugSession::DebuggerState s = debugSession->state();
return s != IDebugSession::NotStartedState
&& s != IDebugSession::EndedState;
}
MIVariable::MIVariable(TreeModel* model, TreeItem* parent,
MIVariable::MIVariable(MIDebugSession *session, TreeModel* model, TreeItem* parent,
const QString& expression, const QString& display)
: Variable(model, parent, expression, display)
, debugSession(session)
{
}
......@@ -58,33 +55,29 @@ MIVariable::~MIVariable()
{
// Delete only top-level variable objects.
if (topLevel()) {
if (hasStartedSession()) {
IDebugSession* is = ICore::self()->debugController()->currentSession();
MIDebugSession * s = static_cast<MIDebugSession *>(is);
s->addCommand(VarDelete, QString("\"%1\"").arg(varobj_));
if (sessionIsAlive()) {
debugSession->addCommand(VarDelete, QString("\"%1\"").arg(varobj_));
}
}
allVariables_.remove(varobj_);
if (debugSession)
debugSession->variableMapping().remove(varobj_);
}
}
MIVariable* MIVariable::findByVarobjName(const QString& varobjName)
{
if (allVariables_.count(varobjName) == 0)
return 0;
return allVariables_[varobjName];
}
void MIVariable::setVarobj(const QString& v)
{
if (!debugSession) {
qCDebug(DEBUGGERCOMMON) << "WARNING: MIVariable::setVarobj called when its session died";
return;
}
if (!varobj_.isEmpty()) {
// this should not happen
// but apperently it does when attachMaybe is called a second time before
// the first -var-create call returned
allVariables_.remove(varobj_);
debugSession->variableMapping().remove(varobj_);
}
varobj_ = v;
allVariables_[varobj_] = this;
debugSession->variableMapping()[varobj_] = this;
}
......@@ -153,23 +146,20 @@ void MIVariable::attachMaybe(QObject *callback, const char *callbackMethod)
if (!varobj_.isEmpty())
return;
if (hasStartedSession()) {
IDebugSession* is = ICore::self()->debugController()->currentSession();
MIDebugSession * s = static_cast<MIDebugSession *>(is);
s->addCommand(VarCreate,
QString("var%1 @ %2").arg(nextId++).arg(enquotedExpression()),
new CreateVarobjHandler(this, callback, callbackMethod));
// Try find a current session and attach to it
if (!ICore::self()->debugController()) return; //happens on shutdown
debugSession = static_cast<MIDebugSession*>(ICore::self()->debugController()->currentSession());
if (sessionIsAlive()) {
debugSession->addCommand(VarCreate,
QString("var%1 @ %2").arg(nextId++).arg(enquotedExpression()),
new CreateVarobjHandler(this, callback, callbackMethod));
}
}
void MIVariable::markAllDead()
void MIVariable::markAsDead()
{
QMap<QString, MIVariable*>::iterator i, e;
for (i = allVariables_.begin(), e = allVariables_.end(); i != e; ++i)
{
i.value()->varobj_.clear();
}
allVariables_.clear();
varobj_.clear();
}
class FetchMoreChildrenHandler : public MICommandHandler
......@@ -247,13 +237,12 @@ void MIVariable::fetchMoreChildren()
int c = childItems.size();
// FIXME: should not even try this if app is not started.
// Probably need to disable open, or something
if (hasStartedSession()) {
IDebugSession* is = ICore::self()->debugController()->currentSession();
MIDebugSession * s = static_cast<MIDebugSession *>(is);
s->addCommand(VarListChildren,
QString("--all-values \"%1\" %2 %3")
.arg(varobj_).arg( c ).arg( c + fetchStep ), // fetch from .. to ..
new FetchMoreChildrenHandler(this, s));
if (sessionIsAlive()) {
debugSession->addCommand(VarListChildren,
QString("--all-values \"%1\" %2 %3")
// fetch from .. to ..
.arg(varobj_).arg(c).arg(c + fetchStep),
new FetchMoreChildrenHandler(this, debugSession));
}
}
......@@ -298,19 +287,18 @@ void MIVariable::handleUpdate(const Value& var)
const Value& child = children[i];
const QString& exp = child["exp"].literal();
IDebugSession* is = ICore::self()->debugController()->currentSession();
MIDebugSession * s = static_cast<MIDebugSession *>(is);
KDevelop::Variable* xvar = s->variableController()->
createVariable(model(), this, exp);
MIVariable* var = static_cast<MIVariable*>(xvar);
var->setTopLevel(false);
var->setVarobj(child["name"].literal());
bool hasMore = child["numchild"].toInt() != 0 || ( child.hasField("dynamic") && child["dynamic"].toInt()!=0 );
var->setHasMoreInitial(hasMore);
appendChild(var);
var->setType(child["type"].literal());
var->setValue(child["value"].literal());
var->setChanged(true);
if (debugSession) {
auto xvar = debugSession->variableController()->createVariable(model(), this, exp);
auto var = static_cast<MIVariable*>(xvar);
var->setTopLevel(false);
var->setVarobj(child["name"].literal());
bool hasMore = child["numchild"].toInt() != 0 || ( child.hasField("dynamic") && child["dynamic"].toInt()!=0 );
var->setHasMoreInitial(hasMore);
appendChild(var);
var->setType(child["type"].literal());
var->setValue(child["value"].literal());
var->setChanged(true);
}
}
}
......@@ -365,12 +353,10 @@ void MIVariable::formatChanged()
}
else
{
if (hasStartedSession()) {
IDebugSession* is = ICore::self()->debugController()->currentSession();
MIDebugSession * s = static_cast<MIDebugSession *>(is);
s->addCommand(VarSetFormat,
QString(" \"%1\" %2 ").arg(varobj_).arg(format2str(format())),
new SetFormatHandler(this));
if (sessionIsAlive()) {
debugSession->addCommand(VarSetFormat,
QString(" \"%1\" %2 ").arg(varobj_).arg(format2str(format())),
new SetFormatHandler(this));
}
}
}
......@@ -27,16 +27,17 @@
#include <debugger/variable/variablecollection.h>
#include <QMap>
#include <QPointer>
class CreateVarobjHandler;
class FetchMoreChildrenHandler;
namespace KDevMI {
class MIDebugSession;
class MIVariable : public KDevelop::Variable
{
public:
MIVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
MIVariable(MIDebugSession *session, KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
const QString& expression, const QString& display = "");
~MIVariable();
......@@ -46,11 +47,9 @@ public:
const QString& varobj() const;
void handleUpdate(const MI::Value& var);
static MIVariable *findByVarobjName(const QString& varobjName);
/* Called when debugger dies. Clears the association between varobj names
and Variable instances. */
static void markAllDead();
void markAsDead();
bool canSetFormat() const override { return true; }
......@@ -62,17 +61,19 @@ private: // Variable overrides
private: // Internal
friend class ::CreateVarobjHandler;
friend class ::FetchMoreChildrenHandler;
QString enquotedExpression() const;
bool sessionIsAlive() const;
void setVarobj(const QString& v);
QString varobj_;
QPointer<MIDebugSession> debugSession;
// How many children should be fetched in one
// increment.
static const int fetchStep = 5;
/* Map from GDB varobj name to GdbVariable.
FIXME: eventually, should be per-session map. */
static QMap<QString, MIVariable*> allVariables_;
};
} // end of KDevMI
......
......@@ -98,7 +98,7 @@ void MIVariableController::handleVarUpdate(const ResultRecord& r)
for (int i = 0; i < changed.size(); ++i)
{
const Value& var = changed[i];
MIVariable* v = MIVariable::findByVarobjName(var["name"].literal());
MIVariable* v = debugSession()->findVariableByVarobjName(var["name"].literal());
// v can be NULL here if we've already removed locals after step,
// but the corresponding -var-delete command is still in the queue.
if (v) {
......@@ -239,7 +239,7 @@ void MIVariableController::addWatchpoint(const ResultRecord& r)
Variable* MIVariableController::createVariable(TreeModel* model, TreeItem* parent,
const QString& expression, const QString& display)
{
return new MIVariable(model, parent, expression, display);
return new MIVariable(debugSession(), model, parent, expression, display);
}
void MIVariableController::handleEvent(IDebugSession::event_t event)
......@@ -250,6 +250,6 @@ void MIVariableController::handleEvent(IDebugSession::event_t event)
void MIVariableController::stateChanged(IDebugSession::DebuggerState state)
{
if (state == IDebugSession::EndedState) {
MIVariable::markAllDead();
debugSession()->markAllVariableDead();
}
}
......@@ -22,11 +22,13 @@
#include "gdbvariable.h"
#include "debugsession.h"
using namespace KDevelop;
using namespace KDevMI::GDB;
GdbVariable::GdbVariable(TreeModel *model, TreeItem *parent,
GdbVariable::GdbVariable(DebugSession *session, TreeModel *model, TreeItem *parent,
const QString& expression, const QString& display)
: MIVariable(model, parent, expression, display)
: MIVariable(session, model, parent, expression, display)
{
}
......@@ -31,13 +31,13 @@ class TreeItem;
}
namespace KDevMI { namespace GDB {
class DebugSession;
class GdbVariable : public KDevMI::MIVariable
{
Q_OBJECT
public:
GdbVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
GdbVariable(DebugSession *session, KDevelop::TreeModel* model, KDevelop::TreeItem* parent,
const QString& expression, const QString& display = "");
};
......
......@@ -1261,7 +1261,7 @@ void GdbTest::testVariablesStopDebugger()
void GdbTest::testVariablesStartSecondSession()
{
TestDebugSession *session = new TestDebugSession;
QPointer<TestDebugSession> session = new TestDebugSession;
session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
TestLaunchConfiguration cfg;
......@@ -1270,15 +1270,15 @@ void GdbTest::testVariablesStartSecondSession()
QVERIFY(session->startDebugging(&cfg, m_iface));
WAIT_FOR_STATE(session, DebugSession::PausedState);
session = new TestDebugSession;
session->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
QPointer<TestDebugSession> session2 = new TestDebugSession;
session2->variableController()->setAutoUpdate(KDevelop::IVariableController::UpdateLocals);
breakpoints()->addCodeBreakpoint(QUrl::fromLocalFile(debugeeFileName), 38);
QVERIFY(session->startDebugging(&cfg, m_iface));
WAIT_FOR_STATE(session, DebugSession::PausedState);
QVERIFY(session2->startDebugging(&cfg, m_iface));
WAIT_FOR_STATE(session2, DebugSession::PausedState);
session->run();
WAIT_FOR_STATE(session, DebugSession::EndedState);
session2->run();
WAIT_FOR_STATE(session2, DebugSession::EndedState);
}
void GdbTest::testVariablesSwitchFrame()
......
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