summaryrefslogtreecommitdiff
path: root/src/plugins/debugger
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2018-07-31 12:30:48 +0200
committerhjk <hjk@qt.io>2018-08-17 12:35:15 +0000
commit3b5ecac238b87615b44b27375cef0b4f1d4637e4 (patch)
tree7ef6ab68b1d92564bfdd7181e4cd6c14130a544c /src/plugins/debugger
parentd6911fd10c0d16740e267147bb829ac0aa1b7413 (diff)
downloadqt-creator-3b5ecac238b87615b44b27375cef0b4f1d4637e4.tar.gz
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger sessions side-by-side. The combined C++-and-QML engine has been removed, instead a combined setup creates now two individual engines, under a single DebuggerRunTool but mostly independent with no combined state machine. This requires a few more clicks in some cases, but makes it easier to direct e.g. interrupt requests to the interesting engine. Care has been taken to not change the UX of the single debugger session use case if possible. The fat debug button operates as-before in that case, i.e. switches to Interrupt if the single active runconfiguration runs in the debugger etc. Most views are made per-engine, running an engine creates a new Perspective, which is destroyed when the run control dies. The snapshot view remains global and becomes primary source of information on a "current engine" that receives all menu and otherwise global input. There is a new global "Breakpoint Preset" view containing all "static" breakpoint data. When an engine starts up it "claims" breakpoint it believes it can handle, but operates on a copy of the static data. The markers of the static version are suppressed as long as an engine controls a breakpoint (that inclusive all resolved locations), but are re-instatet once the engine quits. The old Breakpoint class that already contained this split per-instance was split into a new Breakpoint and a GlobalBreakpoint class, with a per-engine model for Breakpoints, and a singleton model containing GlobalBreakpoints. There is a new CppDebuggerEngine intermediate level serving as base for C++ (or, rather, "compiled") binary debugging, i.e. {Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine base that are not applicable to non-binary debuggers. Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/debugger')
-rw-r--r--src/plugins/debugger/analyzer/analyzermanager.h6
-rw-r--r--src/plugins/debugger/breakhandler.cpp2291
-rw-r--r--src/plugins/debugger/breakhandler.h367
-rw-r--r--src/plugins/debugger/breakpoint.cpp313
-rw-r--r--src/plugins/debugger/breakpoint.h85
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp485
-rw-r--r--src/plugins/debugger/cdb/cdbengine.h26
-rw-r--r--src/plugins/debugger/cdb/cdbparsehelpers.cpp123
-rw-r--r--src/plugins/debugger/cdb/cdbparsehelpers.h13
-rw-r--r--src/plugins/debugger/debugger.pro2
-rw-r--r--src/plugins/debugger/debugger.qbs2
-rw-r--r--src/plugins/debugger/debuggeractions.cpp9
-rw-r--r--src/plugins/debugger/debuggeractions.h2
-rw-r--r--src/plugins/debugger/debuggerconstants.h4
-rw-r--r--src/plugins/debugger/debuggercore.h33
-rw-r--r--src/plugins/debugger/debuggerengine.cpp1943
-rw-r--r--src/plugins/debugger/debuggerengine.h224
-rw-r--r--src/plugins/debugger/debuggericons.cpp9
-rw-r--r--src/plugins/debugger/debuggericons.h3
-rw-r--r--src/plugins/debugger/debuggerinternalconstants.h20
-rw-r--r--src/plugins/debugger/debuggermainwindow.cpp567
-rw-r--r--src/plugins/debugger/debuggermainwindow.h122
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp2125
-rw-r--r--src/plugins/debugger/debuggerprotocol.h14
-rw-r--r--src/plugins/debugger/debuggerruncontrol.cpp200
-rw-r--r--src/plugins/debugger/debuggerruncontrol.h17
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.cpp3
-rw-r--r--src/plugins/debugger/disassembleragent.cpp30
-rw-r--r--src/plugins/debugger/disassembleragent.h3
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp672
-rw-r--r--src/plugins/debugger/gdb/gdbengine.h44
-rw-r--r--src/plugins/debugger/lldb/lldbengine.cpp140
-rw-r--r--src/plugins/debugger/lldb/lldbengine.h19
-rw-r--r--src/plugins/debugger/logwindow.cpp239
-rw-r--r--src/plugins/debugger/logwindow.h34
-rw-r--r--src/plugins/debugger/pdb/pdbengine.cpp80
-rw-r--r--src/plugins/debugger/pdb/pdbengine.h9
-rw-r--r--src/plugins/debugger/qml/qml.pri2
-rw-r--r--src/plugins/debugger/qml/qmlengine.cpp333
-rw-r--r--src/plugins/debugger/qml/qmlengine.h15
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.cpp7
-rw-r--r--src/plugins/debugger/qml/qmlinspectoragent.h1
-rw-r--r--src/plugins/debugger/registerhandler.cpp2
-rw-r--r--src/plugins/debugger/snapshothandler.cpp358
-rw-r--r--src/plugins/debugger/snapshothandler.h50
-rw-r--r--src/plugins/debugger/snapshotwindow.cpp108
-rw-r--r--src/plugins/debugger/snapshotwindow.h52
-rw-r--r--src/plugins/debugger/sourcefileshandler.cpp2
-rw-r--r--src/plugins/debugger/terminal.cpp17
-rw-r--r--src/plugins/debugger/terminal.h3
-rw-r--r--src/plugins/debugger/threadshandler.cpp2
-rw-r--r--src/plugins/debugger/watchhandler.cpp21
-rw-r--r--src/plugins/debugger/watchhandler.h7
53 files changed, 5850 insertions, 5408 deletions
diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h
index 20c7e741c4..ebdaced8b0 100644
--- a/src/plugins/debugger/analyzer/analyzermanager.h
+++ b/src/plugins/debugger/analyzer/analyzermanager.h
@@ -32,9 +32,8 @@
#include <projectexplorer/runconfiguration.h>
-#include <QWidget>
-
#include <QCoreApplication>
+#include <QWidget>
#include <functional>
@@ -63,14 +62,11 @@ DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName);
// Register a tool for a given start mode.
DEBUGGER_EXPORT void registerPerspective(Utils::Perspective *perspective);
-DEBUGGER_EXPORT void destroyDynamicPerspective(const QByteArray &perspectiveId);
-DEBUGGER_EXPORT void setPerspectiveEnabled(const QByteArray &perspectiveId, bool enable);
DEBUGGER_EXPORT void enableMainWindow(bool on);
DEBUGGER_EXPORT QWidget *mainWindow();
DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId);
-DEBUGGER_EXPORT QByteArray currentPerspective();
// Convenience functions.
DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000);
diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp
index d926159ff6..4972f7f616 100644
--- a/src/plugins/debugger/breakhandler.cpp
+++ b/src/plugins/debugger/breakhandler.cpp
@@ -30,7 +30,9 @@
#include "debuggerengine.h"
#include "debuggericons.h"
#include "debuggerinternalconstants.h"
+#include "disassembleragent.h"
#include "simplifytype.h"
+#include "snapshothandler.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/coreplugin.h>
@@ -38,7 +40,6 @@
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
-#include <extensionsystem/invoker.h>
#include <texteditor/textmark.h>
#include <texteditor/texteditor.h>
@@ -73,126 +74,131 @@ using namespace Utils;
namespace Debugger {
namespace Internal {
-class LocationItem : public TypedTreeItem<TreeItem, BreakpointItem>
-{
-public:
- QVariant data(int column, int role) const final
- {
- if (role == Qt::DecorationRole && column == 0) {
- return params.enabled ? Icons::BREAKPOINT.icon()
- : Icons::BREAKPOINT_DISABLED.icon();
- }
-
- if (role == Qt::DisplayRole) {
- switch (column) {
- case BreakpointNumberColumn:
- return params.id.toString();
- case BreakpointFunctionColumn:
- return params.functionName;
- case BreakpointAddressColumn:
- if (params.address)
- return QString::fromLatin1("0x%1").arg(params.address, 0, 16);
- }
- }
- return QVariant();
- }
-
- BreakpointResponse params;
-};
+static BreakpointManager *theBreakpointManager = nullptr;
-class BreakpointMarker;
+//
+// BreakpointMarker
+//
-class BreakpointItem : public QObject, public TypedTreeItem<LocationItem>
+// The red blob on the left side in the cpp editor.
+class BreakpointMarker : public TextEditor::TextMark
{
- Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
-
public:
- ~BreakpointItem() override;
+ BreakpointMarker(const Breakpoint &bp, const FileName &fileName, int lineNumber)
+ : TextMark(fileName, lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_bp(bp)
+ {
+ setColor(Theme::Debugger_Breakpoint_TextMarkColor);
+ setDefaultToolTip(QApplication::translate("BreakHandler", "Breakpoint"));
+ setPriority(TextEditor::TextMark::NormalPriority);
+ setIcon(bp->icon());
+ setToolTip(bp->toolTip());
+ }
- QVariant data(int column, int role) const override;
+ void updateLineNumber(int lineNumber) final
+ {
+ TextMark::updateLineNumber(lineNumber);
+ QTC_ASSERT(m_bp, return);
+ m_bp->setLineNumber(lineNumber);
+ }
- QIcon icon() const;
+ void updateFileName(const FileName &fileName) final
+ {
+ TextMark::updateFileName(fileName);
+ QTC_ASSERT(m_bp, return);
+ m_bp->setFileName(fileName.toString());
+ }
- void removeBreakpoint();
- void updateLineNumberFromMarker(int lineNumber);
- void updateFileNameFromMarker(const QString &fileName);
- void changeLineNumberFromMarker(int lineNumber);
- bool isLocatedAt(const QString &fileName, int lineNumber, bool useMarkerPosition) const;
+ bool isDraggable() const final { return true; }
- void setMarkerFileAndLine(const QString &fileName, int lineNumber);
+ void dragToLine(int line) final
+ {
+ QTC_ASSERT(m_bp, return);
+ GlobalBreakpoint gbp = m_bp->globalBreakpoint();
+ if (!gbp)
+ return;
+ BreakpointParameters params = gbp->m_params;
+ params.lineNumber = line;
+ gbp->deleteBreakpoint();
+ BreakpointManager::createBreakpoint(params);
+ }
- void insertSubBreakpoint(const BreakpointResponse &params);
- QString markerFileName() const;
- int markerLineNumber() const;
+ bool isClickable() const final { return true; }
- bool needsChange() const;
+ void clicked() final
+ {
+ QTC_ASSERT(m_bp, return);
+ m_bp->deleteGlobalOrThisBreakpoint();
+ }
-private:
- friend class BreakHandler;
- friend class Breakpoint;
- BreakpointItem(BreakHandler *handler);
-
- void destroyMarker();
- void updateMarker();
- void updateMarkerIcon();
- void scheduleSynchronization();
-
- QString toToolTip() const;
- void setState(BreakpointState state);
- void deleteThis();
- bool isEngineRunning() const;
-
- BreakHandler * const m_handler;
- const BreakpointModelId m_id;
- BreakpointParameters m_params;
- BreakpointState m_state; // Current state of breakpoint.
- DebuggerEngine *m_engine; // Engine currently handling the breakpoint.
- BreakpointResponse m_response;
- BreakpointMarker *m_marker;
+public:
+ Breakpoint m_bp;
};
-//
-// BreakpointMarker
-//
-
// The red blob on the left side in the cpp editor.
-class BreakpointMarker : public TextEditor::TextMark
+class GlobalBreakpointMarker : public TextEditor::TextMark
{
public:
- BreakpointMarker(BreakpointItem *b, const FileName &fileName, int lineNumber)
- : TextMark(fileName, lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_bp(b)
+ GlobalBreakpointMarker(GlobalBreakpoint gbp, const FileName &fileName, int lineNumber)
+ : TextMark(fileName, lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_gbp(gbp)
{
setColor(Theme::Debugger_Breakpoint_TextMarkColor);
setDefaultToolTip(QApplication::translate("BreakHandler", "Breakpoint"));
setPriority(TextEditor::TextMark::NormalPriority);
- setIcon(b->icon());
+ setIcon(m_gbp->icon());
}
- void removedFromEditor() override
+ void removedFromEditor() final
{
- if (m_bp)
- m_bp->removeBreakpoint();
+ QTC_ASSERT(m_gbp, return);
+ m_gbp->removeBreakpointFromModel();
}
- void updateLineNumber(int lineNumber) override
+ void updateLineNumber(int lineNumber) final
{
TextMark::updateLineNumber(lineNumber);
- m_bp->updateLineNumberFromMarker(lineNumber);
+ QTC_ASSERT(m_gbp, return);
+
+ // Ignore updates to the "real" line number while the debugger is
+ // running, as this can be triggered by moving the breakpoint to
+ // the next line that generated code.
+
+ m_gbp->m_params.lineNumber = lineNumber;
+ m_gbp->updateMarker();
+ m_gbp->update();
}
- void updateFileName(const FileName &fileName) override
+ void updateFileName(const FileName &fileName) final
{
TextMark::updateFileName(fileName);
- m_bp->updateFileNameFromMarker(fileName.toString());
+ QTC_ASSERT(m_gbp, return);
+ m_gbp->m_params.fileName = fileName.toString();
+ m_gbp->update();
}
- bool isDraggable() const override { return true; }
- void dragToLine(int line) override { m_bp->changeLineNumberFromMarker(line); }
- bool isClickable() const override { return true; }
- void clicked() override { m_bp->removeBreakpoint(); }
+ bool isDraggable() const final { return true; }
+
+ void dragToLine(int line) final
+ {
+ QTC_ASSERT(m_gbp, return);
+ QTC_ASSERT(BreakpointManager::globalBreakpoints().contains(m_gbp), return);
+ BreakpointParameters params = m_gbp->m_params;
+ params.lineNumber = line;
+ GlobalBreakpoint gbp = m_gbp;
+ m_gbp = GlobalBreakpoint();
+ gbp->deleteBreakpoint();
+ m_gbp = BreakpointManager::createBreakpoint(params);
+ }
+
+ bool isClickable() const final { return true; }
+
+ void clicked() final
+ {
+ QTC_ASSERT(m_gbp, return);
+ m_gbp->removeBreakpointFromModel();
+ }
public:
- BreakpointItem *m_bp;
+ GlobalBreakpoint m_gbp;
};
static QString stateToString(BreakpointState state)
@@ -200,13 +206,13 @@ static QString stateToString(BreakpointState state)
switch (state) {
case BreakpointNew:
return BreakHandler::tr("New");
- case BreakpointInsertRequested:
+ case BreakpointInsertionRequested:
return BreakHandler::tr("Insertion requested");
- case BreakpointInsertProceeding:
+ case BreakpointInsertionProceeding:
return BreakHandler::tr("Insertion proceeding");
- case BreakpointChangeRequested:
+ case BreakpointUpdateRequested:
return BreakHandler::tr("Change requested");
- case BreakpointChangeProceeding:
+ case BreakpointUpdateProceeding:
return BreakHandler::tr("Change proceeding");
case BreakpointInserted:
return BreakHandler::tr("Breakpoint inserted");
@@ -304,7 +310,7 @@ class BreakpointDialog : public QDialog
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
public:
- explicit BreakpointDialog(Breakpoint b, QWidget *parent = nullptr);
+ explicit BreakpointDialog(const DebuggerEngine *engine, QWidget *parent = nullptr);
bool showDialog(BreakpointParameters *data, BreakpointParts *parts);
void setParameters(const BreakpointParameters &data);
@@ -361,7 +367,7 @@ private:
QDialogButtonBox *m_buttonBox;
};
-BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
+BreakpointDialog::BreakpointDialog(const DebuggerEngine *engine, QWidget *parent)
: QDialog(parent), m_enabledParts(~0), m_previousType(UnknownBreakpointType),
m_firstTypeChange(true)
{
@@ -491,15 +497,13 @@ BreakpointDialog::BreakpointDialog(Breakpoint b, QWidget *parent)
m_buttonBox = new QDialogButtonBox(this);
m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
- if (b) {
- if (DebuggerEngine *engine = b.engine()) {
- if (!engine->hasCapability(BreakConditionCapability))
- m_enabledParts &= ~ConditionPart;
- if (!engine->hasCapability(BreakModuleCapability))
- m_enabledParts &= ~ModulePart;
- if (!engine->hasCapability(TracePointCapability))
- m_enabledParts &= ~TracePointPart;
- }
+ if (engine) {
+ if (!engine->hasCapability(BreakConditionCapability))
+ m_enabledParts &= ~ConditionPart;
+ if (!engine->hasCapability(BreakModuleCapability))
+ m_enabledParts &= ~ModulePart;
+ if (!engine->hasCapability(TracePointCapability))
+ m_enabledParts &= ~TracePointPart;
}
auto basicLayout = new QFormLayout(groupBoxBasic);
@@ -850,7 +854,7 @@ class MultiBreakPointsDialog : public QDialog
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
public:
- MultiBreakPointsDialog(QWidget *parent = nullptr);
+ MultiBreakPointsDialog(bool canUseConditions, QWidget *parent);
QString condition() const { return m_lineEditCondition->text(); }
int ignoreCount() const { return m_spinBoxIgnoreCount->value(); }
@@ -869,7 +873,7 @@ private:
QDialogButtonBox *m_buttonBox;
};
-MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) :
+MultiBreakPointsDialog::MultiBreakPointsDialog(bool canUseConditions, QWidget *parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -885,7 +889,7 @@ MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) :
m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
auto formLayout = new QFormLayout;
- if (currentEngine()->hasCapability(BreakConditionCapability))
+ if (canUseConditions)
formLayout->addRow(tr("&Condition:"), m_lineEditCondition);
formLayout->addRow(tr("&Ignore count:"), m_spinBoxIgnoreCount);
formLayout->addRow(tr("&Thread specification:"), m_lineEditThreadSpec);
@@ -898,16 +902,14 @@ MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) :
connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
-BreakHandler::BreakHandler()
- : m_syncTimerId(-1)
+BreakHandler::BreakHandler(DebuggerEngine *engine)
+ : m_engine(engine)
{
- qRegisterMetaType<BreakpointModelId>();
-
#if USE_BREAK_MODEL_TEST
new ModelTest(this, 0);
#endif
- setHeader(QStringList({tr("Number"), tr("Function"), tr("File"), tr("Line"), tr("Address"),
- tr("Condition"), tr("Ignore"), tr("Threads")}));
+ setHeader({tr("Number"), tr("Function"), tr("File"), tr("Line"), tr("Address"),
+ tr("Condition"), tr("Ignore"), tr("Threads")});
}
static inline bool fileNameMatch(const QString &f1, const QString &f2)
@@ -917,7 +919,13 @@ static inline bool fileNameMatch(const QString &f1, const QString &f2)
return f1 == f2;
}
-static bool isSimilarTo(const BreakpointParameters &params, const BreakpointResponse &needle)
+bool BreakpointParameters::isLocatedAt(const QString &file, int line, const QString &markerFile) const
+{
+ return lineNumber == line
+ && (fileNameMatch(fileName, file) || fileNameMatch(fileName, markerFile));
+}
+
+static bool isSimilarTo(const BreakpointParameters &params, const BreakpointParameters &needle)
{
// Clear miss.
if (needle.type != UnknownBreakpointType && params.type != UnknownBreakpointType
@@ -949,48 +957,18 @@ static bool isSimilarTo(const BreakpointParameters &params, const BreakpointResp
return false;
}
-Breakpoint BreakHandler::findSimilarBreakpoint(const BreakpointResponse &needle) const
-{
- // Search a breakpoint we might refer to.
- return Breakpoint(findItemAtLevel<1>([needle](BreakpointItem *b) {
- if (b->m_response.id.isValid() && b->m_response.id.majorPart() == needle.id.majorPart())
- return true;
- return isSimilarTo(b->m_params, needle);
- }));
-}
-
-Breakpoint BreakHandler::findBreakpointByResponseId(const BreakpointResponseId &id) const
-{
- return Breakpoint(findItemAtLevel<1>([id](BreakpointItem *b) {
- return b->m_response.id.majorPart() == id.majorPart();
- }));
-}
-
-Breakpoint BreakHandler::findBreakpointByFunction(const QString &functionName) const
+Breakpoint BreakHandler::findBreakpointByResponseId(const QString &id) const
{
- return Breakpoint(findItemAtLevel<1>([functionName](BreakpointItem *b) {
- return b->m_params.functionName == functionName;
- }));
-}
-
-Breakpoint BreakHandler::findBreakpointByAddress(quint64 address) const
-{
- return Breakpoint(findItemAtLevel<1>([address](BreakpointItem *b) {
- return b->m_params.address == address;
- }));
-}
-
-Breakpoint BreakHandler::findBreakpointByFileAndLine(const QString &fileName,
- int lineNumber, bool useMarkerPosition)
-{
- return Breakpoint(findItemAtLevel<1>([=](BreakpointItem *b) {
- return b->isLocatedAt(fileName, lineNumber, useMarkerPosition);
- }));
+ return findItemAtLevel<1>([id](const Breakpoint bp) {
+ return bp && bp->responseId() == id;
+ });
}
-Breakpoint BreakHandler::breakpointById(BreakpointModelId id) const
+SubBreakpoint BreakHandler::findSubBreakpointByResponseId(const QString &id) const
{
- return Breakpoint(findItemAtLevel<1>([id](BreakpointItem *b) { return b->m_id == id; }));
+ return findItemAtLevel<2>([id](const SubBreakpoint sub) {
+ return sub && sub->responseId == id;
+ });
}
QVariant BreakHandler::data(const QModelIndex &idx, int role) const
@@ -998,150 +976,57 @@ QVariant BreakHandler::data(const QModelIndex &idx, int role) const
if (role == BaseTreeView::ItemDelegateRole)
return QVariant::fromValue(new LeftElideDelegate);
- return BreakModel::data(idx, role);
-}
-
-void BreakHandler::deletionHelper(BreakpointModelId id)
-{
- Breakpoint b = breakpointById(id);
- QTC_ASSERT(b, return);
- destroyItem(b.b);
+ return BreakHandlerModel::data(idx, role);
}
Breakpoint BreakHandler::findWatchpoint(const BreakpointParameters &params) const
{
- return Breakpoint(findItemAtLevel<1>([params](BreakpointItem *b) {
- return b->m_params.isWatchpoint()
- && b->m_params.address == params.address
- && b->m_params.size == params.size
- && b->m_params.expression == params.expression
- && b->m_params.bitpos == params.bitpos;
- }));
+ return findItemAtLevel<1>([params](const Breakpoint &bp) {
+ return bp->m_parameters.isWatchpoint()
+ && bp->m_parameters.address == params.address
+ && bp->m_parameters.size == params.size
+ && bp->m_parameters.expression == params.expression
+ && bp->m_parameters.bitpos == params.bitpos;
+ });
}
-void BreakHandler::saveBreakpoints()
+Breakpoint BreakHandler::findBreakpointByIndex(const QModelIndex &index) const
{
- QList<QVariant> list;
- forItemsAtLevel<1>([&list](BreakpointItem *b) {
- const BreakpointParameters &params = b->m_params;
- QMap<QString, QVariant> map;
- if (params.type != BreakpointByFileAndLine)
- map.insert("type", params.type);
- if (!params.fileName.isEmpty())
- map.insert("filename", params.fileName);
- if (params.lineNumber)
- map.insert("linenumber", params.lineNumber);
- if (!params.functionName.isEmpty())
- map.insert("funcname", params.functionName);
- if (params.address)
- map.insert("address", params.address);
- if (!params.condition.isEmpty())
- map.insert("condition", params.condition);
- if (params.ignoreCount)
- map.insert("ignorecount", params.ignoreCount);
- if (params.threadSpec >= 0)
- map.insert("threadspec", params.threadSpec);
- if (!params.enabled)
- map.insert("disabled", "1");
- if (params.oneShot)
- map.insert("oneshot", "1");
- if (params.pathUsage != BreakpointPathUsageEngineDefault)
- map.insert("usefullpath", QString::number(params.pathUsage));
- if (params.tracepoint)
- map.insert("tracepoint", "1");
- if (!params.module.isEmpty())
- map.insert("module", params.module);
- if (!params.command.isEmpty())
- map.insert("command", params.command);
- if (!params.expression.isEmpty())
- map.insert("expression", params.expression);
- if (!params.message.isEmpty())
- map.insert("message", params.message);
- list.append(map);
- });
- setSessionValue("Breakpoints", list);
+ return itemForIndexAtLevel<1>(index);
}
-void BreakHandler::loadBreakpoints()
+SubBreakpoint BreakHandler::findSubBreakpointByIndex(const QModelIndex &index) const
{
- const QVariant value = sessionValue("Breakpoints");
- const QList<QVariant> list = value.toList();
- for (const QVariant &var : list) {
- const QMap<QString, QVariant> map = var.toMap();
- BreakpointParameters params(BreakpointByFileAndLine);
- QVariant v = map.value("filename");
- if (v.isValid())
- params.fileName = v.toString();
- v = map.value("linenumber");
- if (v.isValid())
- params.lineNumber = v.toString().toInt();
- v = map.value("condition");
- if (v.isValid())
- params.condition = v.toString();
- v = map.value("address");
- if (v.isValid())
- params.address = v.toString().toULongLong();
- v = map.value("ignorecount");
- if (v.isValid())
- params.ignoreCount = v.toString().toInt();
- v = map.value("threadspec");
- if (v.isValid())
- params.threadSpec = v.toString().toInt();
- v = map.value("funcname");
- if (v.isValid())
- params.functionName = v.toString();
- v = map.value("disabled");
- if (v.isValid())
- params.enabled = !v.toInt();
- v = map.value("oneshot");
- if (v.isValid())
- params.oneShot = v.toInt();
- v = map.value("usefullpath");
- if (v.isValid())
- params.pathUsage = static_cast<BreakpointPathUsage>(v.toInt());
- v = map.value("tracepoint");
- if (v.isValid())
- params.tracepoint = bool(v.toInt());
- v = map.value("type");
- if (v.isValid() && v.toInt() != UnknownBreakpointType)
- params.type = BreakpointType(v.toInt());
- v = map.value("module");
- if (v.isValid())
- params.module = v.toString();
- v = map.value("command");
- if (v.isValid())
- params.command = v.toString();
- v = map.value("expression");
- if (v.isValid())
- params.expression = v.toString();
- v = map.value("message");
- if (v.isValid())
- params.message = v.toString();
- if (params.isValid())
- appendBreakpointInternal(params);
- else
- qWarning("Not restoring invalid breakpoint: %s", qPrintable(params.toString()));
- }
+ return itemForIndexAtLevel<2>(index);
}
-void BreakHandler::updateMarkers()
+Breakpoint BreakHandler::findBreakpointByModelId(int modelId) const
{
- forItemsAtLevel<1>([](BreakpointItem *b) { b->updateMarker(); });
+ return findItemAtLevel<1>([modelId](const Breakpoint &bp) {
+ QTC_ASSERT(bp, return false);
+ return bp->modelId() == modelId;
+ });
}
-Breakpoint BreakHandler::findBreakpointByIndex(const QModelIndex &index) const
+Breakpoints BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const
{
- return Breakpoint(itemForIndexAtLevel<1>(index));
+ QSet<Breakpoint> items;
+ for (const QModelIndex &index : list) {
+ if (Breakpoint bp = findBreakpointByIndex(index))
+ items.insert(bp);
+ }
+ return items.toList();
}
-Breakpoints BreakHandler::findBreakpointsByIndex(const QList<QModelIndex> &list) const
+SubBreakpoints BreakHandler::findSubBreakpointsByIndex(const QList<QModelIndex> &list) const
{
- QSet<Breakpoint> ids;
+ QSet<SubBreakpoint> items;
for (const QModelIndex &index : list) {
- if (Breakpoint b = findBreakpointByIndex(index))
- ids.insert(b);
+ if (SubBreakpoint sbp = findSubBreakpointByIndex(index))
+ items.insert(sbp);
}
- return ids.toList();
+ return items.toList();
+
}
QString BreakHandler::displayFromThreadSpec(int spec)
@@ -1160,29 +1045,13 @@ const QString empty(QLatin1Char('-'));
QVariant BreakpointItem::data(int column, int role) const
{
- bool orig = false;
- switch (m_state) {
- case BreakpointInsertRequested:
- case BreakpointInsertProceeding:
- case BreakpointChangeRequested:
- case BreakpointChangeProceeding:
- case BreakpointInserted:
- case BreakpointRemoveRequested:
- case BreakpointRemoveProceeding:
- break;
- case BreakpointNew:
- case BreakpointDead:
- orig = true;
- break;
- };
-
if (role == Qt::ForegroundRole) {
static const QVariant gray(QColor(140, 140, 140));
switch (m_state) {
- case BreakpointInsertRequested:
- case BreakpointInsertProceeding:
- case BreakpointChangeRequested:
- case BreakpointChangeProceeding:
+ case BreakpointInsertionRequested:
+ case BreakpointInsertionProceeding:
+ case BreakpointUpdateRequested:
+ case BreakpointUpdateProceeding:
case BreakpointRemoveRequested:
case BreakpointRemoveProceeding:
return gray;
@@ -1196,31 +1065,29 @@ QVariant BreakpointItem::data(int column, int role) const
switch (column) {
case BreakpointNumberColumn:
if (role == Qt::DisplayRole)
- return m_id.toString();
+ return m_displayName.isEmpty() ? m_responseId : m_displayName;
if (role == Qt::DecorationRole)
return icon();
break;
case BreakpointFunctionColumn:
if (role == Qt::DisplayRole) {
- if (!m_response.functionName.isEmpty())
- return simplifyType(m_response.functionName);
- if (!m_params.functionName.isEmpty())
- return m_params.functionName;
- if (m_params.type == BreakpointAtMain
- || m_params.type == BreakpointAtThrow
- || m_params.type == BreakpointAtCatch
- || m_params.type == BreakpointAtFork
- || m_params.type == BreakpointAtExec
- //|| m_params.type == BreakpointAtVFork
- || m_params.type == BreakpointAtSysCall)
- return typeToString(m_params.type);
- if (m_params.type == WatchpointAtAddress) {
- quint64 address = m_response.address ? m_response.address : m_params.address;
+ if (!m_parameters.functionName.isEmpty())
+ return simplifyType(m_parameters.functionName);
+ if (m_parameters.type == BreakpointAtMain
+ || m_parameters.type == BreakpointAtThrow
+ || m_parameters.type == BreakpointAtCatch
+ || m_parameters.type == BreakpointAtFork
+ || m_parameters.type == BreakpointAtExec
+ //|| m_response.type == BreakpointAtVFork
+ || m_parameters.type == BreakpointAtSysCall)
+ return typeToString(m_parameters.type);
+ if (m_parameters.type == WatchpointAtAddress) {
+ quint64 address = m_parameters.address ? m_parameters.address : m_parameters.address;
return BreakHandler::tr("Data at 0x%1").arg(address, 0, 16);
}
- if (m_params.type == WatchpointAtExpression) {
- QString expression = !m_response.expression.isEmpty()
- ? m_response.expression : m_params.expression;
+ if (m_parameters.type == WatchpointAtExpression) {
+ QString expression = !m_parameters.expression.isEmpty()
+ ? m_parameters.expression : m_parameters.expression;
return BreakHandler::tr("Data at %1").arg(expression);
}
return empty;
@@ -1229,10 +1096,8 @@ QVariant BreakpointItem::data(int column, int role) const
case BreakpointFileColumn:
if (role == Qt::DisplayRole) {
QString str;
- if (!m_response.fileName.isEmpty())
- str = m_response.fileName;
- if (str.isEmpty() && !m_params.fileName.isEmpty())
- str = m_params.fileName;
+ if (!m_parameters.fileName.isEmpty())
+ str = m_parameters.fileName;
if (str.isEmpty()) {
QString s = FileName::fromString(str).fileName();
if (!s.isEmpty())
@@ -1248,238 +1113,164 @@ QVariant BreakpointItem::data(int column, int role) const
break;
case BreakpointLineColumn:
if (role == Qt::DisplayRole) {
- if (m_response.lineNumber > 0)
- return m_response.lineNumber;
- if (m_params.lineNumber > 0)
- return m_params.lineNumber;
+ if (m_parameters.lineNumber > 0)
+ return m_parameters.lineNumber;
return empty;
}
if (role == Qt::UserRole + 1)
- return m_params.lineNumber;
+ return m_parameters.lineNumber;
break;
case BreakpointAddressColumn:
if (role == Qt::DisplayRole) {
- const quint64 address = orig ? m_params.address : m_response.address;
- if (address)
- return QString("0x%1").arg(address, 0, 16);
+ if (m_parameters.address)
+ return QString("0x%1").arg(m_parameters.address, 0, 16);
return QVariant();
}
break;
case BreakpointConditionColumn:
if (role == Qt::DisplayRole)
- return orig ? m_params.condition : m_response.condition;
+ return m_parameters.condition;
if (role == Qt::ToolTipRole)
return BreakHandler::tr("Breakpoint will only be hit if this condition is met.");
if (role == Qt::UserRole + 1)
- return m_params.condition;
+ return m_parameters.condition;
break;
case BreakpointIgnoreColumn:
if (role == Qt::DisplayRole) {
- const int ignoreCount =
- orig ? m_params.ignoreCount : m_response.ignoreCount;
+ const int ignoreCount = m_parameters.ignoreCount;
return ignoreCount ? QVariant(ignoreCount) : QVariant(QString());
}
if (role == Qt::ToolTipRole)
return BreakHandler::tr("Breakpoint will only be hit after being ignored so many times.");
if (role == Qt::UserRole + 1)
- return m_params.ignoreCount;
+ return m_parameters.ignoreCount;
break;
case BreakpointThreadsColumn:
if (role == Qt::DisplayRole)
- return BreakHandler::displayFromThreadSpec(orig ? m_params.threadSpec : m_response.threadSpec);
+ return BreakHandler::displayFromThreadSpec(m_parameters.threadSpec);
if (role == Qt::ToolTipRole)
return BreakHandler::tr("Breakpoint will only be hit in the specified thread(s).");
if (role == Qt::UserRole + 1)
- return BreakHandler::displayFromThreadSpec(m_params.threadSpec);
+ return BreakHandler::displayFromThreadSpec(m_parameters.threadSpec);
break;
}
if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInBreakpointsView))
- return toToolTip();
+ return toolTip();
return QVariant();
}
-#define PROPERTY(type, getter, setter) \
-\
-type Breakpoint::getter() const \
-{ \
- return parameters().getter; \
-} \
-\
-void Breakpoint::setter(const type &value) \
-{ \
- QTC_ASSERT(b, return); \
- if (b->m_params.getter == value) \
- return; \
- b->m_params.getter = value; \
- if (b->m_state != BreakpointNew) { \
- b->m_state = BreakpointChangeRequested; \
- b->scheduleSynchronization(); \
- } \
-}
-
-PROPERTY(BreakpointPathUsage, pathUsage, setPathUsage)
-PROPERTY(QString, fileName, setFileName)
-PROPERTY(QString, functionName, setFunctionName)
-PROPERTY(BreakpointType, type, setType)
-PROPERTY(int, threadSpec, setThreadSpec)
-PROPERTY(QString, condition, setCondition)
-PROPERTY(QString, command, setCommand)
-PROPERTY(quint64, address, setAddress)
-PROPERTY(QString, expression, setExpression)
-PROPERTY(QString, message, setMessage)
-PROPERTY(int, ignoreCount, setIgnoreCount)
-
-void BreakpointItem::scheduleSynchronization()
+void BreakpointItem::addToCommand(DebuggerCommand *cmd) const
{
- m_handler->scheduleSynchronization();
+ cmd->arg("modelid", modelId());
+ cmd->arg("id", m_responseId);
+ cmd->arg("type", m_requestedParameters.type);
+ cmd->arg("ignorecount", m_requestedParameters.ignoreCount);
+ cmd->arg("condition", toHex(m_requestedParameters.condition));
+ cmd->arg("command", toHex(m_requestedParameters.command));
+ cmd->arg("function", m_requestedParameters.functionName);
+ cmd->arg("oneshot", m_requestedParameters.oneShot);
+ cmd->arg("enabled", m_requestedParameters.enabled);
+ cmd->arg("file", m_requestedParameters.fileName);
+ cmd->arg("line", m_requestedParameters.lineNumber);
+ cmd->arg("address", m_requestedParameters.address);
+ cmd->arg("expression", m_requestedParameters.expression);
}
-const BreakpointParameters &Breakpoint::parameters() const
+void BreakpointItem::updateFromGdbOutput(const GdbMi &bkpt)
{
- static BreakpointParameters p;
- QTC_ASSERT(b, return p);
- return b->m_params;
+ m_parameters.updateFromGdbOutput(bkpt);
+ adjustMarker();
}
-void Breakpoint::addToCommand(DebuggerCommand *cmd) const
+int BreakpointItem::modelId() const
{
- cmd->arg("modelid", id().toString());
- cmd->arg("id", int(response().id.majorPart()));
- cmd->arg("type", type());
- cmd->arg("ignorecount", ignoreCount());
- cmd->arg("condition", toHex(condition()));
- cmd->arg("command", toHex(command()));
- cmd->arg("function", functionName());
- cmd->arg("oneshot", isOneShot());
- cmd->arg("enabled", isEnabled());
- cmd->arg("file", fileName());
- cmd->arg("line", lineNumber());
- cmd->arg("address", address());
- cmd->arg("expression", expression());
+ return m_globalBreakpoint ? m_globalBreakpoint->modelId() : 0;
}
-BreakpointState Breakpoint::state() const
+void BreakpointItem::setPending(bool pending)
{
- QTC_ASSERT(b, return BreakpointState());
- return b->m_state;
+ m_parameters.pending = pending;
+ adjustMarker();
}
-int Breakpoint::lineNumber() const { return parameters().lineNumber; }
-
-bool Breakpoint::isEnabled() const { return parameters().enabled; }
-
-bool Breakpoint::isWatchpoint() const { return parameters().isWatchpoint(); }
-
-bool Breakpoint::isTracepoint() const { return parameters().isTracepoint(); }
-
-QIcon Breakpoint::icon() const { return b ? b->icon() : QIcon(); }
-
-DebuggerEngine *Breakpoint::engine() const
+void BreakHandler::removeAlienBreakpoint(const QString &rid)
{
- return b ? b->m_engine : nullptr;
+ Breakpoint bp = findBreakpointByResponseId(rid);
+ destroyItem(bp);
}
-const BreakpointResponse &Breakpoint::response() const
+void BreakHandler::requestBreakpointInsertion(const Breakpoint &bp)
{
- static BreakpointResponse r;
- return b ? b->m_response : r;
+ bp->gotoState(BreakpointInsertionRequested, BreakpointNew);
+ QTimer::singleShot(0, m_engine, [this, bp] { m_engine->insertBreakpoint(bp); });
}
-bool Breakpoint::isOneShot() const { return parameters().oneShot; }
-
-void Breakpoint::removeAlienBreakpoint()
+void BreakHandler::requestBreakpointUpdate(const Breakpoint &bp)
{
- b->m_state = BreakpointRemoveProceeding;
- b->deleteThis();
+ bp->gotoState(BreakpointUpdateRequested, BreakpointInserted);
+ QTimer::singleShot(0, m_engine, [this, bp] { m_engine->updateBreakpoint(bp); });
}
-void Breakpoint::removeBreakpoint() const
+void BreakHandler::requestBreakpointRemoval(const Breakpoint &bp)
{
- if (b)
- b->removeBreakpoint();
+ bp->gotoState(BreakpointRemoveRequested, BreakpointInserted);
+ QTimer::singleShot(0, m_engine, [this, bp] { m_engine->removeBreakpoint(bp); });
}
-Breakpoint::Breakpoint(BreakpointItem *b)
- : b(b)
-{}
-
-void Breakpoint::setEnabled(bool on) const
+void BreakHandler::requestBreakpointEnabling(const Breakpoint &bp, bool enabled)
{
- QTC_ASSERT(b, return);
- if (b->m_params.enabled == on)
- return;
- b->m_params.enabled = on;
- b->updateMarkerIcon();
- b->update();
- if (b->m_engine) {
- b->m_state = BreakpointChangeRequested;
- b->scheduleSynchronization();
+ if (bp->m_parameters.enabled != enabled) {
+ bp->m_requestedParameters.enabled = enabled;
+ bp->updateMarkerIcon();
+ bp->update();
+ requestBreakpointUpdate(bp);
}
}
-void Breakpoint::setMarkerFileAndLine(const QString &fileName, int lineNumber)
+void BreakHandler::requestSubBreakpointEnabling(const SubBreakpoint &sbp, bool enabled)
{
- if (b)
- b->setMarkerFileAndLine(fileName, lineNumber);
-}
-
-void Breakpoint::setTracepoint(bool on)
-{
- if (b->m_params.tracepoint == on)
- return;
- b->m_params.tracepoint = on;
- b->updateMarkerIcon();
-
- if (b->m_engine) {
- b->m_state = BreakpointChangeRequested;
- b->scheduleSynchronization();
+ if (sbp->params.enabled != enabled) {
+ sbp->params.enabled = enabled;
+ sbp->breakpoint()->update();
+ QTimer::singleShot(0, m_engine, [this, sbp, enabled] {
+ m_engine->enableSubBreakpoint(sbp, enabled);
+ });
}
}
void BreakpointItem::setMarkerFileAndLine(const QString &fileName, int lineNumber)
{
- if (m_response.fileName == fileName && m_response.lineNumber == lineNumber)
+ if (m_parameters.fileName == fileName && m_parameters.lineNumber == lineNumber)
return;
- m_response.fileName = fileName;
- m_response.lineNumber = lineNumber;
+ m_parameters.fileName = fileName;
+ m_parameters.lineNumber = lineNumber;
destroyMarker();
updateMarker();
update();
}
-void Breakpoint::setEngine(DebuggerEngine *value)
-{
- QTC_ASSERT(b->m_state == BreakpointNew, qDebug() << "STATE: " << b->m_state << b->m_id);
- QTC_ASSERT(!b->m_engine, qDebug() << "NO ENGINE" << b->m_id; return);
- b->m_engine = value;
- b->m_state = BreakpointInsertRequested;
- b->m_response = BreakpointResponse();
- b->updateMarker();
- //b->scheduleSynchronization();
-}
-
static bool isAllowedTransition(BreakpointState from, BreakpointState to)
{
switch (from) {
case BreakpointNew:
- return to == BreakpointInsertRequested
+ return to == BreakpointInsertionRequested
|| to == BreakpointDead;
- case BreakpointInsertRequested:
- return to == BreakpointInsertProceeding;
- case BreakpointInsertProceeding:
+ case BreakpointInsertionRequested:
+ return to == BreakpointInsertionProceeding;
+ case BreakpointInsertionProceeding:
return to == BreakpointInserted
|| to == BreakpointDead
- || to == BreakpointChangeRequested
+ || to == BreakpointUpdateRequested
|| to == BreakpointRemoveRequested;
- case BreakpointChangeRequested:
- return to == BreakpointChangeProceeding;
- case BreakpointChangeProceeding:
+ case BreakpointUpdateRequested:
+ return to == BreakpointUpdateProceeding;
+ case BreakpointUpdateProceeding:
return to == BreakpointInserted
|| to == BreakpointDead;
case BreakpointInserted:
- return to == BreakpointChangeRequested
+ return to == BreakpointUpdateRequested
|| to == BreakpointRemoveRequested;
case BreakpointRemoveRequested:
return to == BreakpointRemoveProceeding;
@@ -1492,12 +1283,23 @@ static bool isAllowedTransition(BreakpointState from, BreakpointState to)
return false;
}
-bool BreakpointItem::isEngineRunning() const
+void BreakpointItem::gotoState(BreakpointState target, BreakpointState assumedCurrent)
{
- if (!m_engine)
- return false;
- const DebuggerState state = m_engine->state();
- return state != DebuggerFinished && state != DebuggerNotReady;
+ QTC_ASSERT(m_state == assumedCurrent, qDebug() << m_state);
+ setState(target);
+}
+
+void BreakHandler::updateDisassemblerMarker(const Breakpoint &bp)
+{
+ return m_engine->disassemblerAgent()->updateBreakpointMarker(bp);
+}
+
+void BreakHandler::removeDisassemblerMarker(const Breakpoint &bp)
+{
+ m_engine->disassemblerAgent()->removeBreakpointMarker(bp);
+ bp->destroyMarker();
+ if (GlobalBreakpoint gbp = bp->globalBreakpoint())
+ gbp->updateMarker();
}
void BreakpointItem::setState(BreakpointState state)
@@ -1510,7 +1312,7 @@ void BreakpointItem::setState(BreakpointState state)
}
if (m_state == state) {
- qDebug() << "STATE UNCHANGED: " << m_id << m_state;
+ qDebug() << "STATE UNCHANGED: " << responseId() << m_state;
return;
}
@@ -1524,379 +1326,209 @@ void BreakpointItem::setState(BreakpointState state)
update();
}
-void BreakpointItem::deleteThis()
+const GlobalBreakpoint BreakpointItem::globalBreakpoint() const
{
- setState(BreakpointDead);
- destroyMarker();
-
- // This is called from b directly. So delay deletion of b.
- ExtensionSystem::InvokerBase invoker;
- invoker.addArgument(m_id);
- invoker.setConnectionType(Qt::QueuedConnection);
- invoker.invoke(m_handler, "deletionHelper");
- QTC_CHECK(invoker.wasSuccessful());
+ return m_globalBreakpoint;
}
-void Breakpoint::gotoState(BreakpointState target, BreakpointState assumedCurrent)
+void BreakpointItem::setParameters(const BreakpointParameters &value)
{
- QTC_ASSERT(b, return);
- QTC_ASSERT(b->m_state == assumedCurrent, qDebug() << b->m_state);
- b->setState(target);
+ m_parameters = value;
+ adjustMarker();
}
-void Breakpoint::notifyBreakpointChangeAfterInsertNeeded()
+void BreakpointItem::setEnabled(bool on)
{
- gotoState(BreakpointChangeRequested, BreakpointInsertProceeding);
+ m_parameters.enabled = on;
+ adjustMarker();
}
-void Breakpoint::notifyBreakpointInsertProceeding()
+void BreakHandler::setBreakpointEnabled(const Breakpoint &bp, bool on)
{
- gotoState(BreakpointInsertProceeding, BreakpointInsertRequested);
+ bp->setEnabled(on);
+ requestBreakpointUpdate(bp);
}
-void Breakpoint::notifyBreakpointInsertOk()
+void DebuggerEngine::notifyBreakpointInsertProceeding(const Breakpoint &bp)
{
- gotoState(BreakpointInserted, BreakpointInsertProceeding);
- if (b->m_engine)
- b->m_engine->updateBreakpointMarker(*this);
+ QTC_ASSERT(bp, return);
+ bp->gotoState(BreakpointInsertionProceeding, BreakpointInsertionRequested);
}
-void Breakpoint::notifyBreakpointInsertFailed()
+void DebuggerEngine::notifyBreakpointInsertOk(const Breakpoint &bp)
{
- gotoState(BreakpointDead, BreakpointInsertProceeding);
+ QTC_ASSERT(bp, return);
+ bp->adjustMarker();
+ bp->gotoState(BreakpointInserted, BreakpointInsertionProceeding);
+ breakHandler()->updateDisassemblerMarker(bp);
+ bp->updateMarker();
}
-void Breakpoint::notifyBreakpointRemoveProceeding()
+void DebuggerEngine::notifyBreakpointInsertFailed(const Breakpoint &bp)
{
- gotoState(BreakpointRemoveProceeding, BreakpointRemoveRequested);
+ QTC_ASSERT(bp, return);
+ bp->gotoState(BreakpointDead, BreakpointInsertionProceeding);
}
-void Breakpoint::notifyBreakpointRemoveOk()
+void DebuggerEngine::notifyBreakpointRemoveProceeding(const Breakpoint &bp)
{
- QTC_ASSERT(b, return);
- QTC_ASSERT(b->m_state == BreakpointRemoveProceeding, qDebug() << b->m_state);
- if (b->m_engine)
- b->m_engine->removeBreakpointMarker(*this);
- b->deleteThis();
+ QTC_ASSERT(bp, return);
+ bp->gotoState(BreakpointRemoveProceeding, BreakpointRemoveRequested);
}
-void Breakpoint::notifyBreakpointRemoveFailed()
+void DebuggerEngine::notifyBreakpointRemoveOk(const Breakpoint &bp)
{
- QTC_ASSERT(b, return);
- QTC_ASSERT(b->m_state == BreakpointRemoveProceeding, qDebug() << b->m_state);
- if (b->m_engine)
- b->m_engine->removeBreakpointMarker(*this);
- b->deleteThis();
+ QTC_ASSERT(bp, return);
+ QTC_ASSERT(bp->state() == BreakpointRemoveProceeding, qDebug() << bp->state());
+ breakHandler()->removeDisassemblerMarker(bp);
+ breakHandler()->destroyItem(bp);
}
-void Breakpoint::notifyBreakpointChangeProceeding()
+void DebuggerEngine::notifyBreakpointRemoveFailed(const Breakpoint &bp)
{
- gotoState(BreakpointChangeProceeding, BreakpointChangeRequested);
+ QTC_ASSERT(bp, return);
+ QTC_ASSERT(bp->m_state == BreakpointRemoveProceeding, qDebug() << bp->m_state);
+ breakHandler()->removeDisassemblerMarker(bp);
+ breakHandler()->destroyItem(bp);
}
-void Breakpoint::notifyBreakpointChangeOk()
+void DebuggerEngine::notifyBreakpointChangeProceeding(const Breakpoint &bp)
{
- gotoState(BreakpointInserted, BreakpointChangeProceeding);
+ bp->gotoState(BreakpointUpdateProceeding, BreakpointUpdateRequested);
}
-void Breakpoint::notifyBreakpointChangeFailed()
+void DebuggerEngine::notifyBreakpointChangeOk(const Breakpoint &bp)
{
- gotoState(BreakpointDead, BreakpointChangeProceeding);
+ bp->gotoState(BreakpointInserted, BreakpointUpdateProceeding);
}
-void Breakpoint::notifyBreakpointReleased()
+void DebuggerEngine::notifyBreakpointChangeFailed(const Breakpoint &bp)
{
- QTC_ASSERT(b, return);
- b->removeChildren();
- //QTC_ASSERT(b->m_state == BreakpointChangeProceeding, qDebug() << b->m_state);
- b->m_state = BreakpointNew;
- b->m_engine = nullptr;
- b->m_response = BreakpointResponse();
- b->destroyMarker();
- b->updateMarker();
- if (b->m_params.type == WatchpointAtAddress
- || b->m_params.type == WatchpointAtExpression
- || b->m_params.type == BreakpointByAddress)
- b->m_params.enabled = false;
- else
- b->m_params.address = 0;
- b->update();
+ bp->gotoState(BreakpointDead, BreakpointUpdateProceeding);
}
-void Breakpoint::notifyBreakpointAdjusted(const BreakpointParameters &params)
+void DebuggerEngine::notifyBreakpointNeedsReinsertion(const Breakpoint &bp)
{
- QTC_ASSERT(b, return);
- QTC_ASSERT(b->m_state == BreakpointInserted, qDebug() << b->m_state);
- b->m_params = params;
- //if (b->needsChange())
- // b->setState(BreakpointChangeRequested);
+ QTC_ASSERT(bp, return);
+ QTC_ASSERT(bp->m_state == BreakpointUpdateProceeding, qDebug() << bp->m_state);
+ bp->m_state = BreakpointInsertionRequested;
}
-void Breakpoint::notifyBreakpointNeedsReinsertion()
+void BreakHandler::handleAlienBreakpoint(const QString &responseId, const BreakpointParameters &params)
{
- QTC_ASSERT(b, return);
- QTC_ASSERT(b->m_state == BreakpointChangeProceeding, qDebug() << b->m_state);
- b->m_state = BreakpointInsertRequested;
-}
-
-void BreakpointItem::removeBreakpoint()
-{
- switch (m_state) {
- case BreakpointRemoveRequested:
- break;
- case BreakpointInserted:
- case BreakpointInsertProceeding:
- setState(BreakpointRemoveRequested);
- scheduleSynchronization();
- break;
- case BreakpointNew:
- deleteThis();
- break;
- default:
- qWarning("Warning: Cannot remove breakpoint %s in state '%s'.",
- qPrintable(m_id.toString()), qPrintable(stateToString(m_state)));
- m_state = BreakpointRemoveRequested;
- break;
- }
-}
-
-void BreakHandler::appendBreakpoint(const BreakpointParameters &params)
-{
- appendBreakpointInternal(params);
- scheduleSynchronization();
-}
-
-void BreakHandler::appendBreakpointInternal(const BreakpointParameters &params)
-{
- if (!params.isValid()) {
- qWarning("Not adding invalid breakpoint: %s", qPrintable(params.toString()));
- return;
- }
-
- auto b = new BreakpointItem(this);
- b->m_params = params;
- b->updateMarker();
- rootItem()->appendChild(b);
-}
+ // Search a breakpoint we might refer to.
+ Breakpoint bp = findItemAtLevel<1>([params, responseId](const Breakpoint &bp) {
+ if (bp && !bp->responseId().isEmpty() && bp->responseId() == responseId)
+ return true;
+ return bp && isSimilarTo(bp->m_parameters, params);
+ });
-void BreakHandler::handleAlienBreakpoint(const BreakpointResponse &response, DebuggerEngine *engine)
-{
- Breakpoint b = findSimilarBreakpoint(response);
- if (b) {
- if (response.id.isMinor())
- b.insertSubBreakpoint(response);
- else
- b.setResponse(response);
+ if (bp) {
+ // FIXME: x.y looks rather gdb specific.
+ if (bp->responseId().contains('.')) {
+ SubBreakpoint loc = bp->findOrCreateSubBreakpoint(bp->responseId());
+ QTC_ASSERT(loc, return);
+ loc->setParameters(params);
+ } else {
+ bp->setParameters(params);
+ }
} else {
- auto b = new BreakpointItem(this);
- b->m_params = response;
- b->m_response = response;
- b->m_state = BreakpointInserted;
- b->m_engine = engine;
- b->updateMarker();
- rootItem()->appendChild(b);
+ bp = new BreakpointItem(nullptr);
+ bp->setState(BreakpointInserted);
+ bp->setParameters(params);
+ rootItem()->appendChild(bp);
+ // This has no global breakpoint, so there's nothing to update here.
}
}
-void Breakpoint::insertSubBreakpoint(const BreakpointResponse &params)
-{
- QTC_ASSERT(b, return);
- b->insertSubBreakpoint(params);
-}
-
-void BreakpointItem::insertSubBreakpoint(const BreakpointResponse &params)
+SubBreakpoint BreakpointItem::findOrCreateSubBreakpoint(const QString &responseId)
{
- QTC_ASSERT(params.id.isMinor(), return);
+ const QString minorPart = responseId.section('.', 1);
- int minorPart = params.id.minorPart();
-
- LocationItem *l = findFirstLevelChild([minorPart](LocationItem *l) {
- return l->params.id.minorPart() == minorPart;
+ SubBreakpoint loc = findFirstLevelChild([&](const SubBreakpoint &l) {
+ return l->responseId == responseId;
});
- if (l) {
+ if (loc) {
// This modifies an existing sub-breakpoint.
- l->params = params;
- l->update();
+ loc->update();
} else {
// This is a new sub-breakpoint.
- l = new LocationItem;
- l->params = params;
- appendChild(l);
+ loc = new SubBreakpointItem;
+ loc->responseId = responseId;
+ appendChild(loc);
expand();
}
+ return loc;
}
-void BreakHandler::saveSessionData()
-{
- saveBreakpoints();
-}
-
-void BreakHandler::loadSessionData()
-{
- clear();
- loadBreakpoints();
-}
-
-void BreakHandler::breakByFunction(const QString &functionName)
-{
- // One breakpoint per function is enough for now. This does not handle
- // combinations of multiple conditions and ignore counts, though.
- bool found = findItemAtLevel<1>([functionName](BreakpointItem *b) {
- const BreakpointParameters &params = b->m_params;
- return params.functionName == functionName
- && params.condition.isEmpty()
- && params.ignoreCount == 0;
- });
- if (found)
- return;
-
- BreakpointParameters params(BreakpointByFunction);
- params.functionName = functionName;
- appendBreakpoint(params);
-}
-
-void BreakHandler::scheduleSynchronization()
+bool BreakHandler::tryClaimBreakpoint(const GlobalBreakpoint &gbp)
{
- if (m_syncTimerId == -1)
- m_syncTimerId = startTimer(10);
-}
-
-void BreakHandler::timerEvent(QTimerEvent *event)
-{
- QTC_ASSERT(event->timerId() == m_syncTimerId, return);
- killTimer(m_syncTimerId);
- m_syncTimerId = -1;
- saveBreakpoints(); // FIXME: remove?
- Internal::synchronizeBreakpoints();
-}
+ const Breakpoints bps = breakpoints();
+ if (Utils::anyOf(bps, [gbp](const Breakpoint &bp) { return bp->globalBreakpoint() == gbp; }))
+ return false;
-void Breakpoint::gotoLocation() const
-{
- if (DebuggerEngine *engine = currentEngine()) {
- if (b->m_params.type == BreakpointByAddress) {
- engine->gotoLocation(b->m_params.address);
- } else {
- // Don't use gotoLocation unconditionally as this ends up in
- // disassembly if OperateByInstruction is on. But fallback
- // to disassembly if we can't open the file.
- const QString file = QDir::cleanPath(b->markerFileName());
- if (IEditor *editor = EditorManager::openEditor(file))
- editor->gotoLine(b->markerLineNumber(), 0);
- else
- engine->openDisassemblerView(Location(b->m_response.address));
- }
+ if (!m_engine->acceptsBreakpoint(gbp->parameters())) {
+ m_engine->showMessage(QString("BREAKPOINT %1 IS NOT ACCEPTED BY ENGINE %2")
+ .arg(gbp->displayName()).arg(objectName()));
+ return false;
}
-}
-void BreakpointItem::updateFileNameFromMarker(const QString &fileName)
-{
- m_params.fileName = fileName;
- update();
-}
+ m_engine->showMessage(QString("TAKING OWNERSHIP OF BREAKPOINT %1").arg(gbp->displayName()));
-void BreakpointItem::updateLineNumberFromMarker(int lineNumber)
-{
- // Ignore updates to the "real" line number while the debugger is
- // running, as this can be triggered by moving the breakpoint to
- // the next line that generated code.
- if (m_params.lineNumber == lineNumber)
- ; // Nothing
- else if (isEngineRunning())
- m_params.lineNumber += lineNumber - m_response.lineNumber;
- else
- m_params.lineNumber = lineNumber;
- updateMarker();
- update();
-}
+ Breakpoint bp(new BreakpointItem(gbp));
+ rootItem()->appendChild(bp);
-void BreakpointItem::changeLineNumberFromMarker(int lineNumber)
-{
- m_params.lineNumber = lineNumber;
-
- // We need to delay this as it is called from a marker which will be destroyed.
- ExtensionSystem::InvokerBase invoker;
- invoker.addArgument(m_id);
- invoker.setConnectionType(Qt::QueuedConnection);
- invoker.invoke(m_handler, "changeLineNumberFromMarkerHelper");
- QTC_CHECK(invoker.wasSuccessful());
-}
+ gbp->updateMarker();
+ requestBreakpointInsertion(bp);
-void BreakHandler::changeLineNumberFromMarkerHelper(BreakpointModelId id)
-{
- Breakpoint b = breakpointById(id);
- QTC_ASSERT(b, return);
- BreakpointParameters params = b.parameters();
- destroyItem(b.b);
- appendBreakpoint(params);
-}
-
-const Breakpoints BreakHandler::allBreakpoints() const
-{
- Breakpoints items;
- forItemsAtLevel<1>([&items](BreakpointItem *b) { items.append(Breakpoint(b)); });
- return items;
+ return true;
}
-const Breakpoints BreakHandler::unclaimedBreakpoints() const
+void BreakHandler::gotoLocation(const Breakpoint &bp) const
{
- return engineBreakpoints(nullptr);
+ QTC_ASSERT(bp, return);
+ QTC_ASSERT(m_engine, return);
+ if (bp->m_parameters.type == BreakpointByAddress) {
+ m_engine->gotoLocation(bp->m_parameters.address);
+ } else {
+ // Don't use gotoLocation unconditionally as this ends up in
+ // disassembly if OperateByInstruction is on. But fallback
+ // to disassembly if we can't open the file.
+ const QString file = QDir::cleanPath(bp->markerFileName());
+ if (IEditor *editor = EditorManager::openEditor(file))
+ editor->gotoLine(bp->markerLineNumber(), 0);
+ else
+ m_engine->openDisassemblerView(Location(bp->m_parameters.address));
+ }
}
-const Breakpoints BreakHandler::engineBreakpoints(DebuggerEngine *engine) const
+const Breakpoints BreakHandler::breakpoints() const
{
- Breakpoints items;
- forItemsAtLevel<1>([&items, engine](BreakpointItem *b) {
- if (b->m_engine == engine)
- items.append(Breakpoint(b));
- });
+ QList<Breakpoint> items;
+ forItemsAtLevel<1>([&items](Breakpoint bp) { if (bp) items.append(bp); });
return items;
}
-QStringList BreakHandler::engineBreakpointPaths(DebuggerEngine *engine) const
+void BreakpointItem::adjustMarker()
{
- QSet<QString> set;
- forItemsAtLevel<1>([&set, engine](BreakpointItem *b) {
- if (b->m_engine == engine) {
- if (b->m_params.type == BreakpointByFileAndLine)
- set.insert(QFileInfo(b->m_params.fileName).dir().path());
- }
- });
- return set.toList();
+ destroyMarker();
+ updateMarker();
}
-void Breakpoint::setResponse(const BreakpointResponse &response)
+void BreakpointItem::deleteBreakpoint()
{
- QTC_ASSERT(b, return);
- b->m_response = response;
- b->destroyMarker();
- b->updateMarker();
- // Take over corrected values from response.
- if ((b->m_params.type == BreakpointByFileAndLine
- || b->m_params.type == BreakpointByFunction)
- && !response.module.isEmpty())
- b->m_params.module = response.module;
-}
+ QTC_ASSERT(!globalBreakpoint(), return); // Use deleteBreakpoint(GlobalBreakpoint gbp) instead.
-bool Internal::Breakpoint::needsChange() const
-{
- return b && b->needsChange();
+ for (QPointer<DebuggerEngine> engine : EngineManager::engines())
+ engine->breakHandler()->requestBreakpointRemoval(this);
}
-void Breakpoint::changeBreakpointData(const BreakpointParameters &params)
+void BreakpointItem::deleteGlobalOrThisBreakpoint()
{
- if (!b)
- return;
- if (params == b->m_params)
- return;
- b->m_params = params;
- if (b->m_engine)
- b->m_engine->updateBreakpointMarker(*this);
- b->destroyMarker();
- b->updateMarker();
- b->update();
- if (b->needsChange() && b->m_engine && b->m_state != BreakpointNew) {
- b->setState(BreakpointChangeRequested);
- b->m_handler->scheduleSynchronization();
+ if (GlobalBreakpoint gbp = globalBreakpoint()) {
+ gbp->deleteBreakpoint();
+ } else {
+ deleteBreakpoint();
}
}
@@ -1904,7 +1536,7 @@ bool BreakHandler::setData(const QModelIndex &idx, const QVariant &value, int ro
{
if (role == BaseTreeView::ItemActivatedRole) {
if (Breakpoint bp = findBreakpointByIndex(idx))
- bp.gotoLocation();
+ gotoLocation(bp);
return true;
}
@@ -1917,36 +1549,44 @@ bool BreakHandler::setData(const QModelIndex &idx, const QVariant &value, int ro
if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
if (kev->key() == Qt::Key_Delete) {
QModelIndexList si = ev.currentOrSelectedRows();
- const Breakpoints ids = findBreakpointsByIndex(si);
+ const Breakpoints bps = findBreakpointsByIndex(si);
+ for (Breakpoint bp : bps) {
+ if (GlobalBreakpoint gbp = bp->globalBreakpoint())
+ gbp->deleteBreakpoint();
+ else
+ bp->deleteBreakpoint();
+ }
// int row = qMin(rowCount() - ids.size() - 1, idx.row());
- deleteBreakpoints(ids);
// setCurrentIndex(index(row, 0)); FIXME
return true;
}
if (kev->key() == Qt::Key_Space) {
const QModelIndexList selectedIds = ev.selectedRows();
if (!selectedIds.isEmpty()) {
- const Breakpoints items = findBreakpointsByIndex(selectedIds);
- const bool isEnabled = items.isEmpty() || items.at(0).isEnabled();
- setBreakpointsEnabled(items, !isEnabled);
-// FIXME
-// for (const QModelIndex &id : selectedIds)
-// update(id);
+ const Breakpoints bps = findBreakpointsByIndex(selectedIds);
+ const SubBreakpoints sbps = findSubBreakpointsByIndex(selectedIds);
+ const bool isEnabled = (bps.isEmpty() && sbps.isEmpty())
+ || (!bps.isEmpty() && bps.at(0)->isEnabled())
+ || (!sbps.isEmpty() && sbps.at(0)->params.enabled);
+ for (Breakpoint bp : bps)
+ requestBreakpointEnabling(bp, !isEnabled);
+ for (SubBreakpoint sbp : sbps)
+ requestSubBreakpointEnabling(sbp, !isEnabled);
return true;
}
}
}
if (ev.as<QMouseEvent>(QEvent::MouseButtonDblClick)) {
- if (Breakpoint b = findBreakpointByIndex(idx)) {
+ if (Breakpoint bp = findBreakpointByIndex(idx)) {
if (idx.column() >= BreakpointAddressColumn)
- editBreakpoints({b}, ev.view());
+ editBreakpoints({bp}, ev.view());
else
- b.gotoLocation();
- } else if (LocationItem *l = itemForIndexAtLevel<2>(idx)) {
- Breakpoint(l->parent()).gotoLocation();
+ gotoLocation(bp);
+ } else if (SubBreakpoint loc = itemForIndexAtLevel<2>(idx)) {
+ gotoLocation(loc->breakpoint());
} else {
- addBreakpoint();
+ BreakpointManager::executeAddBreakpointDialog();
}
return true;
}
@@ -1960,17 +1600,16 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
const QModelIndexList selectedIndices = ev.selectedRows();
const Breakpoints selectedBreakpoints = findBreakpointsByIndex(selectedIndices);
- const bool breakpointsEnabled = selectedBreakpoints.isEmpty() || selectedBreakpoints.at(0).isEnabled();
+ const bool breakpointsEnabled = selectedBreakpoints.isEmpty() || selectedBreakpoints.at(0)->isEnabled();
- QList<LocationItem *> selectedLocations;
+ QList<SubBreakpointItem *> selectedLocations;
bool handlesIndividualLocations = false;
for (const QModelIndex &index : selectedIndices) {
- if (LocationItem *location = itemForIndexAtLevel<2>(index)) {
+ if (SubBreakpointItem *location = itemForIndexAtLevel<2>(index)) {
if (selectedLocations.contains(location))
continue;
selectedLocations.append(location);
- DebuggerEngine *engine = location->parent()->m_engine;
- if (engine && engine->hasCapability(BreakIndividualLocationsCapability))
+ if (m_engine->hasCapability(BreakIndividualLocationsCapability))
handlesIndividualLocations = true;
}
}
@@ -1978,11 +1617,19 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
auto menu = new QMenu;
- addAction(menu, tr("Add Breakpoint..."), true, [this] { addBreakpoint(); });
+ addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog);
addAction(menu, tr("Delete Selected Breakpoints"),
!selectedBreakpoints.isEmpty(),
- [this, selectedBreakpoints] { deleteBreakpoints(selectedBreakpoints); });
+ [selectedBreakpoints] {
+ for (Breakpoint bp : selectedBreakpoints) {
+ if (GlobalBreakpoint gbp = bp->globalBreakpoint()) {
+ gbp->deleteBreakpoint();
+ } else {
+ bp->deleteBreakpoint();
+ }
+ }
+ });
addAction(menu, tr("Edit Selected Breakpoints..."),
!selectedBreakpoints.isEmpty(),
@@ -2006,7 +1653,8 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
: breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"),
!selectedBreakpoints.isEmpty(),
[this, selectedBreakpoints, breakpointsEnabled] {
- setBreakpointsEnabled(selectedBreakpoints, !breakpointsEnabled);
+ for (Breakpoint bp : selectedBreakpoints)
+ requestBreakpointEnabling(bp, !breakpointsEnabled);
}
);
@@ -2015,14 +1663,9 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
? locationsEnabled ? tr("Disable Selected Locations") : tr("Enable Selected Locations")
: locationsEnabled ? tr("Disable Location") : tr("Enable Location"),
!selectedLocations.isEmpty() && handlesIndividualLocations,
- [selectedLocations, locationsEnabled] {
- for (LocationItem *location : selectedLocations) {
- location->params.enabled = !locationsEnabled;
- location->update();
- BreakpointItem *bp = location->parent();
- if (bp->m_engine)
- bp->m_engine->enableSubBreakpoint(location->params.id.toString(), !locationsEnabled);
- }
+ [this, selectedLocations, locationsEnabled] {
+ for (const SubBreakpoint &sbp : selectedLocations)
+ requestSubBreakpointEnabling(sbp, !locationsEnabled);
}
);
@@ -2030,13 +1673,12 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
addAction(menu, tr("Delete All Breakpoints"),
rowCount() > 0,
- [this] { deleteAllBreakpoints(); });
+ &BreakpointManager::executeDeleteAllBreakpointsDialog);
// Delete by file: Find indices of breakpoints of the same file.
- BreakpointItem *item = itemForIndexAtLevel<1>(ev.index());
- Breakpoints breakpointsInFile;
+ QList<Breakpoint> breakpointsInFile;
QString file;
- if (item) {
+ if (Breakpoint bp = itemForIndexAtLevel<1>(ev.index())) {
const QModelIndex index = ev.index().sibling(ev.index().row(), BreakpointFileColumn);
if (!file.isEmpty()) {
for (int i = 0; i != rowCount(); ++i)
@@ -2047,18 +1689,15 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file),
tr("Delete Breakpoints of File"),
breakpointsInFile.size() > 1,
- [this, breakpointsInFile] { deleteBreakpoints(breakpointsInFile); });
+ [breakpointsInFile] {
+ for (Breakpoint bp : breakpointsInFile)
+ bp->deleteGlobalOrThisBreakpoint();
+ });
menu->addSeparator();
- addAction(menu, tr("Synchronize Breakpoints"),
- Internal::hasSnapshots(),
- [] { Internal::synchronizeBreakpoints(); });
-
- menu->addSeparator();
menu->addAction(action(UseToolTipsInBreakpointsView));
- if (currentEngine()->hasCapability(MemoryAddressCapability))
- menu->addAction(action(UseAddressInBreakpointsView));
+ menu->addAction(action(UseAddressInBreakpointsView));
menu->addSeparator();
menu->addAction(action(SettingsDialog));
@@ -2067,58 +1706,55 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
return true;
}
-void BreakHandler::setBreakpointsEnabled(const Breakpoints &bps, bool enabled)
-{
- for (Breakpoint b : bps)
- b.setEnabled(enabled);
-}
-
-void BreakHandler::deleteAllBreakpoints()
+void BreakHandler::removeBreakpoint(const Breakpoint &bp)
{
- QDialogButtonBox::StandardButton pressed =
- CheckableMessageBox::doNotAskAgainQuestion(ICore::dialogParent(),
- tr("Remove All Breakpoints"),
- tr("Are you sure you want to remove all breakpoints "
- "from all files in the current session?"),
- ICore::settings(),
- "RemoveAllBreakpoints");
- if (pressed == QDialogButtonBox::Yes)
- deleteBreakpoints(breakHandler()->allBreakpoints());
-}
-
-void BreakHandler::deleteBreakpoints(const Breakpoints &bps)
-{
- for (Breakpoint bp : bps)
- bp.removeBreakpoint();
+ QTC_ASSERT(bp, return);
+ switch (bp->m_state) {
+ case BreakpointRemoveRequested:
+ break;
+ case BreakpointInserted:
+ case BreakpointInsertionProceeding:
+ bp->setState(BreakpointRemoveRequested);
+ requestBreakpointRemoval(bp);
+ break;
+ case BreakpointNew:
+ bp->setState(BreakpointDead);
+ bp->destroyMarker();
+ destroyItem(bp);
+ break;
+ default:
+ qWarning("Warning: Cannot remove breakpoint %s in state '%s'.",
+ qPrintable(bp->responseId()), qPrintable(stateToString(bp->m_state)));
+ bp->m_state = BreakpointRemoveRequested;
+ break;
+ }
}
-void BreakHandler::editBreakpoint(Breakpoint bp, QWidget *parent)
+void BreakHandler::editBreakpoint(const Breakpoint &bp, QWidget *parent)
{
- BreakpointParameters data = bp.parameters();
+ QTC_ASSERT(bp, return);
+ BreakpointParameters params = bp->requestedParameters();
BreakpointParts parts = NoParts;
- BreakpointDialog dialog(bp, parent);
- if (!dialog.showDialog(&data, &parts))
+ BreakpointDialog dialog(m_engine, parent);
+ if (!dialog.showDialog(&params, &parts))
return;
- bp.changeBreakpointData(data);
-}
-
-void BreakHandler::addBreakpoint()
-{
- BreakpointParameters data(BreakpointByFileAndLine);
- BreakpointParts parts = NoParts;
- BreakpointDialog dialog(Breakpoint(), ICore::dialogParent());
- dialog.setWindowTitle(tr("Add Breakpoint"));
- if (dialog.showDialog(&data, &parts))
- appendBreakpoint(data);
+ if (params != bp->requestedParameters()) {
+ bp->setParameters(params);
+ updateDisassemblerMarker(bp);
+ bp->updateMarker();
+ bp->update();
+ if (bp->needsChange() && bp->m_state != BreakpointNew)
+ requestBreakpointUpdate(bp);
+ }
}
void BreakHandler::editBreakpoints(const Breakpoints &bps, QWidget *parent)
{
QTC_ASSERT(!bps.isEmpty(), return);
- const Breakpoint bp = bps.at(0);
+ Breakpoint bp = bps.at(0);
if (bps.size() == 1) {
editBreakpoint(bp, parent);
@@ -2129,10 +1765,12 @@ void BreakHandler::editBreakpoints(const Breakpoints &bps, QWidget *parent)
if (!bp)
return;
- MultiBreakPointsDialog dialog;
- dialog.setCondition(bp.condition());
- dialog.setIgnoreCount(bp.ignoreCount());
- dialog.setThreadSpec(bp.threadSpec());
+ const bool canUseConditions = m_engine->hasCapability(BreakConditionCapability);
+
+ MultiBreakPointsDialog dialog(canUseConditions, parent);
+ dialog.setCondition(bp->condition());
+ dialog.setIgnoreCount(bp->ignoreCount());
+ dialog.setThreadSpec(bp->threadSpec());
if (dialog.exec() == QDialog::Rejected)
return;
@@ -2143,9 +1781,11 @@ void BreakHandler::editBreakpoints(const Breakpoints &bps, QWidget *parent)
for (Breakpoint bp : bps) {
if (bp) {
- bp.setCondition(newCondition);
- bp.setIgnoreCount(newIgnoreCount);
- bp.setThreadSpec(newThreadSpec);
+ bp->m_parameters.condition = newCondition;
+ bp->m_parameters.ignoreCount = newIgnoreCount;
+ bp->m_parameters.threadSpec = newThreadSpec;
+ if (bp->m_state != BreakpointNew)
+ requestBreakpointUpdate(bp);
}
}
}
@@ -2156,13 +1796,12 @@ void BreakHandler::editBreakpoints(const Breakpoints &bps, QWidget *parent)
//
//////////////////////////////////////////////////////////////////
-// Ok to be not thread-safe. The order does not matter and only the gui
-// produces authoritative ids.
-static int currentId = 0;
-
-BreakpointItem::BreakpointItem(BreakHandler *handler)
- : m_handler(handler), m_id(++currentId), m_state(BreakpointNew), m_engine(nullptr), m_marker(nullptr)
-{}
+BreakpointItem::BreakpointItem(const GlobalBreakpoint &gbp)
+ : m_globalBreakpoint(gbp)
+{
+ if (gbp)
+ m_requestedParameters = gbp->parameters();
+}
BreakpointItem::~BreakpointItem()
{
@@ -2173,7 +1812,6 @@ void BreakpointItem::destroyMarker()
{
if (m_marker) {
BreakpointMarker *m = m_marker;
- m->m_bp = nullptr;
m_marker = nullptr;
delete m;
}
@@ -2182,27 +1820,27 @@ void BreakpointItem::destroyMarker()
QString BreakpointItem::markerFileName() const
{
// Some heuristics to find a "good" file name.
- if (!m_params.fileName.isEmpty()) {
- QFileInfo fi(m_params.fileName);
+ if (!m_parameters.fileName.isEmpty()) {
+ QFileInfo fi(m_parameters.fileName);
if (fi.exists())
return fi.absoluteFilePath();
}
- if (!m_response.fileName.isEmpty()) {
- QFileInfo fi(m_response.fileName);
- if (fi.exists())
- return fi.absoluteFilePath();
- }
- if (m_response.fileName.endsWith(m_params.fileName))
- return m_response.fileName;
- if (m_params.fileName.endsWith(m_response.fileName))
- return m_params.fileName;
- return m_response.fileName.size() > m_params.fileName.size()
- ? m_response.fileName : m_params.fileName;
+ const QString origFileName = requestedParameters().fileName;
+ if (m_parameters.fileName.endsWith(origFileName))
+ return m_parameters.fileName;
+ if (origFileName.endsWith(m_parameters.fileName))
+ return origFileName;
+ return m_parameters.fileName.size() > origFileName ? m_parameters.fileName : origFileName;
}
int BreakpointItem::markerLineNumber() const
{
- return m_response.lineNumber ? m_response.lineNumber : m_params.lineNumber;
+ return m_parameters.lineNumber;
+}
+
+const BreakpointParameters &BreakpointItem::requestedParameters() const
+{
+ return m_requestedParameters;
}
static void formatAddress(QTextStream &str, quint64 address)
@@ -2217,17 +1855,18 @@ static void formatAddress(QTextStream &str, quint64 address)
bool BreakpointItem::needsChange() const
{
- if (!m_params.conditionsMatch(m_response.condition))
+ const BreakpointParameters &oparams = requestedParameters();
+ if (!oparams.conditionsMatch(m_parameters.condition))
return true;
- if (m_params.ignoreCount != m_response.ignoreCount)
+ if (oparams.ignoreCount != m_parameters.ignoreCount)
return true;
- if (m_params.enabled != m_response.enabled)
+ if (oparams.enabled != m_parameters.enabled)
return true;
- if (m_params.threadSpec != m_response.threadSpec)
+ if (oparams.threadSpec != m_parameters.threadSpec)
return true;
- if (m_params.command != m_response.command)
+ if (oparams.command != m_parameters.command)
return true;
- if (m_params.type == BreakpointByFileAndLine && m_params.lineNumber != m_response.lineNumber)
+ if (oparams.type == BreakpointByFileAndLine && oparams.lineNumber != m_parameters.lineNumber)
return true;
// FIXME: Too strict, functions may have parameter lists, or not.
// if (m_params.type == BreakpointByFunction && m_params.functionName != m_response.functionName)
@@ -2237,15 +1876,6 @@ bool BreakpointItem::needsChange() const
return false;
}
-bool BreakpointItem::isLocatedAt
- (const QString &fileName, int lineNumber, bool useMarkerPosition) const
-{
- int line = useMarkerPosition ? m_response.lineNumber : m_params.lineNumber;
- return lineNumber == line
- && (fileNameMatch(fileName, m_response.fileName)
- || fileNameMatch(fileName, markerFileName()));
-}
-
void BreakpointItem::updateMarkerIcon()
{
if (m_marker) {
@@ -2264,141 +1894,118 @@ void BreakpointItem::updateMarker()
if (!m_marker && !file.isEmpty() && line > 0)
m_marker = new BreakpointMarker(this, file, line);
- if (m_marker) {
- QString toolTip;
- auto addToToolTipText = [&toolTip](const QString &info, const QString &label) {
- if (info.isEmpty())
- return;
- if (!toolTip.isEmpty())
- toolTip += ' ';
- toolTip += label + ": '" + info + '\'';
- };
- addToToolTipText(m_params.condition, tr("Breakpoint Condition"));
- addToToolTipText(m_params.command, tr("Debugger Command"));
- m_marker->setToolTip(toolTip);
- }
+ if (m_marker)
+ m_marker->setToolTip(toolTip());
}
QIcon BreakpointItem::icon() const
{
// FIXME: This seems to be called on each cursor blink as soon as the
// cursor is near a line with a breakpoint marker (+/- 2 lines or so).
- if (m_params.isTracepoint())
+ if (m_parameters.isTracepoint())
return Icons::TRACEPOINT.icon();
- if (m_params.type == WatchpointAtAddress)
+ if (m_parameters.type == WatchpointAtAddress)
return Icons::WATCHPOINT.icon();
- if (m_params.type == WatchpointAtExpression)
+ if (m_parameters.type == WatchpointAtExpression)
return Icons::WATCHPOINT.icon();
- if (!m_params.enabled)
+ if (!m_parameters.enabled)
return Icons::BREAKPOINT_DISABLED.icon();
- if (m_state == BreakpointInserted && !m_response.pending)
+ if (m_state == BreakpointInserted && !m_parameters.pending)
return Icons::BREAKPOINT.icon();
return Icons::BREAKPOINT_PENDING.icon();
}
-QString BreakpointItem::toToolTip() const
+QString BreakpointItem::toolTip() const
{
QString rc;
QTextStream str(&rc);
- str << "<html><body><table>"
- //<< "<tr><td>" << tr("ID:") << "</td><td>" << m_id << "</td></tr>"
+ str << "<html><body><b>" << tr("Breakpoint") << "</b>"
+ << "<table>"
+ << "<tr><td>" << tr("Internal ID:")
+ << "</td><td>" << m_responseId << "</td></tr>"
<< "<tr><td>" << tr("State:")
- << "</td><td>" << (m_params.enabled ? tr("Enabled") : tr("Disabled"));
- if (m_response.pending)
- str << tr(", pending");
- str << ", " << m_state << " (" << stateToString(m_state) << ")</td></tr>";
- if (m_engine) {
- str << "<tr><td>" << tr("Engine:")
- << "</td><td>" << m_engine->objectName() << "</td></tr>";
- }
- if (!m_response.pending) {
- str << "<tr><td>" << tr("Breakpoint Number:")
- << "</td><td>" << m_response.id.toString() << "</td></tr>";
- }
+ << "</td><td>" << (requestedParameters().enabled ? tr("Enabled") : tr("Disabled"));
+ if (m_parameters.pending)
+ str << ", " << tr("pending");
+ str << ", " << stateToString(m_state) << "</td></tr>";
str << "<tr><td>" << tr("Breakpoint Type:")
- << "</td><td>" << typeToString(m_params.type) << "</td></tr>"
+ << "</td><td>" << typeToString(m_requestedParameters.type) << "</td></tr>"
<< "<tr><td>" << tr("Marker File:")
<< "</td><td>" << QDir::toNativeSeparators(markerFileName()) << "</td></tr>"
<< "<tr><td>" << tr("Marker Line:")
<< "</td><td>" << markerLineNumber() << "</td></tr>"
<< "<tr><td>" << tr("Hit Count:")
- << "</td><td>" << m_response.hitCount << "</td></tr>"
- << "</table><br><hr><table>"
+ << "</td><td>" << m_parameters.hitCount << "</td></tr>"
+ << "</table><br><table>"
<< "<tr><th>" << tr("Property")
<< "</th><th>" << tr("Requested")
- << "</th><th>" << tr("Obtained") << "</th></tr>"
- << "<tr><td>" << tr("Internal Number:")
- << "</td><td>&mdash;</td><td>" << m_response.id.toString() << "</td></tr>";
- if (m_params.type == BreakpointByFunction) {
+ << "</th><th>" << tr("Obtained") << "</th></tr>";
+ if (!m_displayName.isEmpty()) {
+ str << "<tr><td>" << tr("Display Name:")
+ << "</td><td>&mdash;</td><td>" << m_displayName << "</td></tr>";
+ }
+ if (m_parameters.type == BreakpointByFunction) {
str << "<tr><td>" << tr("Function Name:")
- << "</td><td>" << m_params.functionName
- << "</td><td>" << m_response.functionName
+ << "</td><td>" << m_requestedParameters.functionName
+ << "</td><td>" << m_parameters.functionName
<< "</td></tr>";
}
- if (m_params.type == BreakpointByFileAndLine) {
- str << "<tr><td>" << tr("File Name:")
- << "</td><td>" << QDir::toNativeSeparators(m_params.fileName)
- << "</td><td>" << QDir::toNativeSeparators(m_response.fileName)
- << "</td></tr>"
- << "<tr><td>" << tr("Line Number:")
- << "</td><td>" << m_params.lineNumber
- << "</td><td>" << m_response.lineNumber << "</td></tr>"
- << "<tr><td>" << tr("Corrected Line Number:")
- << "</td><td>-"
- << "</td><td>" << m_response.correctedLineNumber << "</td></tr>";
+ if (m_parameters.type == BreakpointByFileAndLine) {
+ str << "<tr><td>" << tr("File Name:")
+ << "</td><td>" << QDir::toNativeSeparators(m_requestedParameters.fileName)
+ << "</td><td>" << QDir::toNativeSeparators(m_parameters.fileName)
+ << "</td></tr>"
+ << "<tr><td>" << tr("Line Number:")
+ << "</td><td>" << m_requestedParameters.lineNumber
+ << "</td><td>" << m_parameters.lineNumber << "</td></tr>";
}
- if (m_params.type == BreakpointByFunction || m_params.type == BreakpointByFileAndLine) {
+ if (m_requestedParameters.type == BreakpointByFunction || m_parameters.type == BreakpointByFileAndLine) {
str << "<tr><td>" << tr("Module:")
- << "</td><td>" << m_params.module
- << "</td><td>" << m_response.module
+ << "</td><td>" << m_requestedParameters.module
+ << "</td><td>" << m_parameters.module
<< "</td></tr>";
}
str << "<tr><td>" << tr("Breakpoint Address:")
<< "</td><td>";
- formatAddress(str, m_params.address);
+ formatAddress(str, m_requestedParameters.address);
str << "</td><td>";
- formatAddress(str, m_response.address);
+ formatAddress(str, m_parameters.address);
str << "</td></tr>";
- if (m_response.multiple) {
- str << "<tr><td>" << tr("Multiple Addresses:")
- << "</td><td>"
- << "</td></tr>";
- }
- if (!m_params.command.isEmpty() || !m_response.command.isEmpty()) {
+ if (!m_requestedParameters.command.isEmpty() || !m_parameters.command.isEmpty()) {
str << "<tr><td>" << tr("Command:")
- << "</td><td>" << m_params.command
- << "</td><td>" << m_response.command
+ << "</td><td>" << m_requestedParameters.command
+ << "</td><td>" << m_parameters.command
<< "</td></tr>";
}
- if (!m_params.message.isEmpty() || !m_response.message.isEmpty()) {
+ if (!m_requestedParameters.message.isEmpty() || !m_parameters.message.isEmpty()) {
str << "<tr><td>" << tr("Message:")
- << "</td><td>" << m_params.message
- << "</td><td>" << m_response.message
+ << "</td><td>" << m_requestedParameters.message
+ << "</td><td>" << m_parameters.message
<< "</td></tr>";
}
- if (!m_params.condition.isEmpty() || !m_response.condition.isEmpty()) {
+ if (!m_requestedParameters.condition.isEmpty() || !m_parameters.condition.isEmpty()) {
str << "<tr><td>" << tr("Condition:")
- << "</td><td>" << m_params.condition
- << "</td><td>" << m_response.condition
+ << "</td><td>" << m_requestedParameters.condition
+ << "</td><td>" << m_parameters.condition
<< "</td></tr>";
}
- if (m_params.ignoreCount || m_response.ignoreCount) {
+ if (m_requestedParameters.ignoreCount || m_parameters.ignoreCount) {
str << "<tr><td>" << tr("Ignore Count:") << "</td><td>";
- if (m_params.ignoreCount)
- str << m_params.ignoreCount;
+ if (m_requestedParameters.ignoreCount)
+ str << m_parameters.ignoreCount;
str << "</td><td>";
- if (m_response.ignoreCount)
- str << m_response.ignoreCount;
+ if (m_parameters.ignoreCount)
+ str << m_parameters.ignoreCount;
str << "</td></tr>";
}
- if (m_params.threadSpec >= 0 || m_response.threadSpec >= 0) {
+ if (m_requestedParameters.threadSpec >= 0 || m_parameters.threadSpec >= 0) {
str << "<tr><td>" << tr("Thread Specification:")
<< "</td><td>";
- if (m_params.threadSpec >= 0)
- str << m_params.threadSpec;
+ if (m_requestedParameters.threadSpec >= 0)
+ str << m_requestedParameters.threadSpec;
str << "</td><td>";
- if (m_response.threadSpec >= 0)
- str << m_response.threadSpec;
+ if (m_parameters.threadSpec >= 0)
+ str << m_parameters.threadSpec;
str << "</td></tr>";
}
str << "</table></body></html>";
@@ -2415,7 +2022,7 @@ void BreakHandler::setWatchpointAtAddress(quint64 address, unsigned size)
// removeBreakpoint(index);
return;
}
- appendBreakpoint(params);
+ BreakpointManager::createBreakpointForEngine(params, m_engine);
}
void BreakHandler::setWatchpointAtExpression(const QString &exp)
@@ -2427,69 +2034,747 @@ void BreakHandler::setWatchpointAtExpression(const QString &exp)
// removeBreakpoint(index);
return;
}
- appendBreakpoint(params);
+ BreakpointManager::createBreakpointForEngine(params, m_engine);
+}
+
+void BreakHandler::releaseAllBreakpoints()
+{
+ for (Breakpoint bp : breakpoints()) {
+ bp->removeChildren();
+ bp->destroyMarker();
+ if (GlobalBreakpoint gbp = bp->globalBreakpoint())
+ gbp->updateMarker();
+ }
+ clear();
+ // The now-unclaimed breakpoints are globally visible again.
+}
+
+QString BreakpointItem::msgWatchpointByExpressionTriggered(const QString &expr) const
+{
+ return tr("Internal data breakpoint %1 at %2 triggered.")
+ .arg(responseId()).arg(expr);
+}
+
+QString BreakpointItem::msgWatchpointByExpressionTriggered(const QString &expr,
+ const QString &threadId) const
+{
+ return tr("Internal data breakpoint %1 at %2 in thread %3 triggered.")
+ .arg(responseId()).arg(expr).arg(threadId);
+}
+
+QString BreakpointItem::msgWatchpointByAddressTriggered(quint64 address) const
+{
+ return tr("Internal data breakpoint %1 at 0x%2 triggered.")
+ .arg(responseId()).arg(address, 0, 16);
+}
+
+QString BreakpointItem::msgWatchpointByAddressTriggered(quint64 address,
+ const QString &threadId) const
+{
+ return tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.")
+ .arg(responseId()).arg(address, 0, 16).arg(threadId);
+}
+
+QString BreakpointItem::msgBreakpointTriggered(const QString &threadId) const
+{
+ return tr("Stopped at breakpoint %1 in thread %2.")
+ .arg(responseId()).arg(threadId);
+}
+
+
+QVariant SubBreakpointItem::data(int column, int role) const
+{
+ if (role == Qt::DecorationRole && column == 0) {
+ return params.enabled ? Icons::BREAKPOINT.icon()
+ : Icons::BREAKPOINT_DISABLED.icon();
+ }
+
+ if (role == Qt::DisplayRole) {
+ switch (column) {
+ case BreakpointNumberColumn:
+ return displayName.isEmpty() ? responseId : displayName;
+ case BreakpointFunctionColumn:
+ return params.functionName;
+ case BreakpointAddressColumn:
+ if (params.address)
+ return QString::fromLatin1("0x%1").arg(params.address, 0, 16);
+ }
+ }
+ return QVariant();
+}
+
+
+//
+// GlobalBreakpointItem
+//
+
+// Ok to be not thread-safe. The order does not matter and only the gui
+// produces authoritative ids.
+static int currentId = 0;
+
+GlobalBreakpointItem::GlobalBreakpointItem()
+ : m_modelId(++currentId)
+{
+}
+
+GlobalBreakpointItem::~GlobalBreakpointItem()
+{}
+
+QVariant GlobalBreakpointItem::data(int column, int role) const
+{
+
+ switch (column) {
+ case BreakpointNumberColumn:
+ if (role == Qt::DisplayRole) {
+ if (auto engine = usingEngine())
+ return engine->runParameters().displayName;
+
+
+ return QString("-");
+ }
+ if (role == Qt::DecorationRole)
+ return icon();
+ break;
+ case BreakpointFunctionColumn:
+ if (role == Qt::DisplayRole) {
+ if (!m_params.functionName.isEmpty())
+ return m_params.functionName;
+ if (m_params.type == BreakpointAtMain
+ || m_params.type == BreakpointAtThrow
+ || m_params.type == BreakpointAtCatch
+ || m_params.type == BreakpointAtFork
+ || m_params.type == BreakpointAtExec
+ //|| m_params.type == BreakpointAtVFork
+ || m_params.type == BreakpointAtSysCall)
+ return typeToString(m_params.type);
+ if (m_params.type == WatchpointAtAddress)
+ return BreakHandler::tr("Data at 0x%1").arg(m_params.address, 0, 16);
+ if (m_params.type == WatchpointAtExpression)
+ return BreakHandler::tr("Data at %1").arg(m_params.expression);
+ return empty;
+ }
+ break;
+ case BreakpointFileColumn:
+ if (role == Qt::DisplayRole) {
+ QString str = m_params.fileName;
+ if (!str.isEmpty())
+ return QDir::toNativeSeparators(str);
+ return empty;
+ }
+ break;
+ case BreakpointLineColumn:
+ if (role == Qt::DisplayRole) {
+ if (m_params.lineNumber > 0)
+ return m_params.lineNumber;
+ return empty;
+ }
+ if (role == Qt::UserRole + 1)
+ return m_params.lineNumber;
+ break;
+ case BreakpointAddressColumn:
+ if (role == Qt::DisplayRole) {
+ const quint64 address = m_params.address;
+ if (address)
+ return QString("0x%1").arg(address, 0, 16);
+ return QVariant();
+ }
+ break;
+ case BreakpointConditionColumn:
+ if (role == Qt::DisplayRole)
+ return m_params.condition;
+ if (role == Qt::ToolTipRole)
+ return BreakHandler::tr("Breakpoint will only be hit if this condition is met.");
+ if (role == Qt::UserRole + 1)
+ return m_params.condition;
+ break;
+ case BreakpointIgnoreColumn:
+ if (role == Qt::DisplayRole) {
+ const int ignoreCount = m_params.ignoreCount;
+ return ignoreCount ? QVariant(ignoreCount) : QVariant(QString());
+ }
+ if (role == Qt::ToolTipRole)
+ return BreakHandler::tr("Breakpoint will only be hit after being ignored so many times.");
+ if (role == Qt::UserRole + 1)
+ return m_params.ignoreCount;
+ break;
+ case BreakpointThreadsColumn:
+ if (role == Qt::DisplayRole)
+ return BreakHandler::displayFromThreadSpec(m_params.threadSpec);
+ if (role == Qt::ToolTipRole)
+ return BreakHandler::tr("Breakpoint will only be hit in the specified thread(s).");
+ if (role == Qt::UserRole + 1)
+ return BreakHandler::displayFromThreadSpec(m_params.threadSpec);
+ break;
+ }
+
+ if (role == Qt::ToolTipRole && boolSetting(UseToolTipsInBreakpointsView))
+ return toolTip();
+
+ return QVariant();
+}
+
+QIcon GlobalBreakpointItem::icon() const
+{
+ // FIXME: This seems to be called on each cursor blink as soon as the
+ // cursor is near a line with a breakpoint marker (+/- 2 lines or so).
+ if (m_params.isTracepoint())
+ return Icons::TRACEPOINT.icon();
+ if (m_params.type == WatchpointAtAddress)
+ return Icons::WATCHPOINT.icon();
+ if (m_params.type == WatchpointAtExpression)
+ return Icons::WATCHPOINT.icon();
+ if (!m_params.enabled)
+ return Icons::BREAKPOINT_DISABLED.icon();
+
+ return Icons::BREAKPOINT_PENDING.icon();
+}
+
+QPointer<DebuggerEngine> GlobalBreakpointItem::usingEngine() const
+{
+ for (QPointer<DebuggerEngine> engine : EngineManager::engines()) {
+ for (Breakpoint bp : engine->breakHandler()->breakpoints()) {
+ if (bp->globalBreakpoint() == this)
+ return engine;
+ }
+ }
+ return nullptr;
+}
+
+int GlobalBreakpointItem::modelId() const
+{
+ return m_modelId;
+}
+
+QString GlobalBreakpointItem::displayName() const
+{
+ return QString::number(m_modelId);
+}
+
+void GlobalBreakpointItem::deleteBreakpoint()
+{
+ for (QPointer<DebuggerEngine> engine : EngineManager::engines()) {
+ BreakHandler *handler = engine->breakHandler();
+ for (Breakpoint bp : handler->breakpoints()) {
+ if (bp->globalBreakpoint() == this)
+ handler->removeBreakpoint(bp);
+ }
+ }
+ removeBreakpointFromModel();
+}
+
+void GlobalBreakpointItem::removeBreakpointFromModel()
+{
+ delete m_marker;
+ m_marker = nullptr;
+ theBreakpointManager->destroyItem(this);
+}
+
+QString GlobalBreakpointItem::markerFileName() const
+{
+ // Some heuristics to find a "good" file name.
+ if (!m_params.fileName.isEmpty()) {
+ QFileInfo fi(m_params.fileName);
+ if (fi.exists())
+ return fi.absoluteFilePath();
+ }
+ return m_params.fileName;
+}
+
+int GlobalBreakpointItem::markerLineNumber() const
+{
+ return m_params.lineNumber;
+}
+
+void GlobalBreakpointItem::updateMarkerIcon()
+{
+ if (m_marker) {
+ m_marker->setIcon(icon());
+ m_marker->updateMarker();
+ }
+}
+
+void GlobalBreakpointItem::updateMarker()
+{
+ if (usingEngine() != nullptr) {
+ // Don't show markers that are claimed by engines.
+ // FIXME: Apart, perhaps, when the engine's reported location does not match?
+ destroyMarker();
+ return;
+ }
+
+ const FileName file = FileName::fromString(m_params.fileName);
+ const int line = m_params.lineNumber;
+ if (m_marker && (file != m_marker->fileName() || line != m_marker->lineNumber()))
+ destroyMarker();
+
+ if (!m_marker && !file.isEmpty() && line > 0)
+ m_marker = new GlobalBreakpointMarker(this, file, line);
+
+ if (m_marker)
+ m_marker->setToolTip(toolTip());
+}
+
+void GlobalBreakpointItem::setEnabled(bool enabled)
+{
+ QTC_CHECK(m_params.enabled != enabled);
+ m_params.enabled = enabled;
+ updateMarkerIcon();
+ update();
+
+ for (QPointer<DebuggerEngine> engine : EngineManager::engines()) {
+ for (Breakpoint bp : engine->breakHandler()->breakpoints()) {
+ if (bp->globalBreakpoint() == this)
+ bp->setEnabled(enabled);
+ }
+ }
+}
+
+void GlobalBreakpointItem::destroyMarker()
+{
+ delete m_marker;
+ m_marker = nullptr;
+}
+
+QString GlobalBreakpointItem::toolTip() const
+{
+ QString rc;
+ QTextStream str(&rc);
+ str << "<html><body><b>" << BreakpointItem::tr("Unclaimed Breakpoint") << "</b>"
+ << "<table>"
+ //<< "<tr><td>" << tr("ID:") << "</td><td>" << m_id << "</td></tr>"
+ << "<tr><td>" << BreakpointItem::tr("State:")
+ << "</td><td>" << (m_params.enabled ? BreakpointItem::tr("Enabled") : BreakpointItem::tr("Disabled"))
+ << "<tr><td>" << BreakpointItem::tr("Breakpoint Type:")
+ << "</td><td>" << typeToString(m_params.type) << "</td></tr>";
+ if (m_params.type == BreakpointByFunction) {
+ str << "<tr><td>" << BreakpointItem::tr("Function Name:")
+ << "</td><td>" << m_params.functionName
+ << "</td></tr>";
+ }
+ if (m_params.type == BreakpointByFileAndLine) {
+ str << "<tr><td>" << BreakpointItem::tr("File Name:")
+ << "</td><td>" << QDir::toNativeSeparators(m_params.fileName)
+ << "</td></tr>"
+ << "<tr><td>" << BreakpointItem::tr("Line Number:")
+ << "</td><td>" << m_params.lineNumber;
+ }
+ if (m_params.type == BreakpointByFunction || m_params.type == BreakpointByFileAndLine) {
+ str << "<tr><td>" << BreakpointItem::tr("Module:")
+ << "</td><td>" << m_params.module
+ << "</td></tr>";
+ }
+ str << "<tr><td>" << BreakpointItem::tr("Breakpoint Address:") << "</td><td>";
+ formatAddress(str, m_params.address);
+ str << "</td></tr>";
+ if (!m_params.command.isEmpty())
+ str << "<tr><td>" << BreakpointItem::tr("Command:") << "</td><td>" << m_params.command << "</td></tr>";
+ if (!m_params.message.isEmpty())
+ str << "<tr><td>" << BreakpointItem::tr("Message:") << "</td><td>" << m_params.message << "</td></tr>";
+ if (!m_params.condition.isEmpty())
+ str << "<tr><td>" << BreakpointItem::tr("Condition:") << "</td><td>" << m_params.condition << "</td></tr>";
+ if (m_params.ignoreCount)
+ str << "<tr><td>" << BreakpointItem::tr("Ignore Count:") << "</td><td>" << m_params.ignoreCount << "</td></tr>";
+ if (m_params.threadSpec >= 0)
+ str << "<tr><td>" << BreakpointItem::tr("Thread Specification:") << "</td><td>" << m_params.threadSpec << "</td></tr>";
+
+ str << "</table></body></html><hr>";
+ return rc;
+}
+
+//
+// BreakpointManager
+//
+
+BreakpointManager::BreakpointManager()
+{
+ theBreakpointManager = this;
+ setHeader({tr("Debuggee"), tr("Function"), tr("File"), tr("Line"), tr("Address"),
+ tr("Condition"), tr("Ignore"), tr("Threads")});
+}
+
+QAbstractItemModel *BreakpointManager::model()
+{
+ return theBreakpointManager;
+}
+
+const GlobalBreakpoints BreakpointManager::globalBreakpoints()
+{
+ GlobalBreakpoints items;
+ theBreakpointManager->forItemsAtLevel<1>([&items](GlobalBreakpointItem *b) { items.append(b); });
+ return items;
+}
+
+GlobalBreakpoint BreakpointManager::findSimilarBreakpoint(const BreakpointParameters &needle)
+{
+ // Search a breakpoint we might refer to.
+ return theBreakpointManager->findItemAtLevel<1>([needle](const GlobalBreakpoint &gbp) {
+ return gbp && isSimilarTo(gbp->m_params, needle);
+ });
+}
+
+void BreakpointManager::claimBreakpointsForEngine(DebuggerEngine *engine)
+{
+ theBreakpointManager->forItemsAtLevel<1>([&](GlobalBreakpoint gbp) {
+ engine->breakHandler()->tryClaimBreakpoint(gbp);
+ gbp->updateMarker();
+ });
+}
+
+GlobalBreakpoint BreakpointManager::createBreakpointHelper(const BreakpointParameters &params)
+{
+ GlobalBreakpoint gbp = new GlobalBreakpointItem;
+ gbp->m_params = params;
+ gbp->updateMarker();
+ theBreakpointManager->rootItem()->appendChild(gbp);
+ return gbp;
+}
+
+GlobalBreakpoint BreakpointManager::findBreakpointByIndex(const QModelIndex &index)
+{
+ return theBreakpointManager->itemForIndexAtLevel<1>(index);
+}
+
+GlobalBreakpoints BreakpointManager::findBreakpointsByIndex(const QList<QModelIndex> &list)
+{
+ QSet<GlobalBreakpoint> items;
+ for (const QModelIndex &index : list) {
+ if (GlobalBreakpoint gbp = findBreakpointByIndex(index))
+ items.insert(gbp);
+ }
+ return items.toList();
}
-bool Breakpoint::isValid() const
+GlobalBreakpoint BreakpointManager::createBreakpoint(const BreakpointParameters &params)
{
- return b && b->m_id.isValid();
+ GlobalBreakpoint gbp = createBreakpointHelper(params);
+ for (QPointer<DebuggerEngine> engine : EngineManager::engines())
+ engine->breakHandler()->tryClaimBreakpoint(gbp);
+ return gbp;
}
-uint Breakpoint::hash() const
+void BreakpointManager::createBreakpointForEngine(const BreakpointParameters &params, DebuggerEngine *engine)
{
- return b ? 0 : qHash(b->m_id);
+ GlobalBreakpoint gbp = createBreakpointHelper(params);
+ engine->breakHandler()->tryClaimBreakpoint(gbp);
+}
+
+void BreakpointManager::toggleBreakpoint(const ContextData &location, const QString &tracePointMessage)
+{
+ QTC_ASSERT(location.isValid(), return);
+ GlobalBreakpoint gbp = findBreakpointByLocation(location);
+
+ if (gbp) {
+ gbp->deleteBreakpoint();
+ } else {
+ BreakpointParameters data;
+ if (location.type == LocationByFile) {
+ data.type = BreakpointByFileAndLine;
+ if (boolSetting(BreakpointsFullPathByDefault))
+ data.pathUsage = BreakpointUseFullPath;
+ data.tracepoint = !tracePointMessage.isEmpty();
+ data.message = tracePointMessage;
+ data.fileName = location.fileName;
+ data.lineNumber = location.lineNumber;
+ } else if (location.type == LocationByAddress) {
+ data.type = BreakpointByAddress;
+ data.tracepoint = !tracePointMessage.isEmpty();
+ data.message = tracePointMessage;
+ data.address = location.address;
+ }
+ BreakpointManager::createBreakpoint(data);
+ }
+}
+
+GlobalBreakpoint BreakpointManager::findBreakpointByLocation(const ContextData &location)
+{
+ return theBreakpointManager->findItemAtLevel<1>([&location](GlobalBreakpoint bp) {
+ if (location.type == LocationByFile)
+ return bp->m_params.isLocatedAt(location.fileName, location.lineNumber, QString());
+ if (location.type == LocationByAddress)
+ return bp->m_params.address == location.address;
+ return false;
+ });
+ return {};
+}
+
+void BreakpointManager::executeAddBreakpointDialog()
+{
+ BreakpointParameters data(BreakpointByFileAndLine);
+ BreakpointParts parts = NoParts;
+ BreakpointDialog dialog(nullptr, ICore::dialogParent());
+ dialog.setWindowTitle(tr("Add Breakpoint"));
+ if (dialog.showDialog(&data, &parts))
+ BreakpointManager::createBreakpoint(data);
+}
+
+QVariant BreakpointManager::data(const QModelIndex &idx, int role) const
+{
+ if (role == BaseTreeView::ItemDelegateRole)
+ return QVariant::fromValue(new LeftElideDelegate);
+
+ return BreakpointManagerModel::data(idx, role);
+}
+
+bool BreakpointManager::setData(const QModelIndex &idx, const QVariant &value, int role)
+{
+ if (role == BaseTreeView::ItemActivatedRole) {
+ if (GlobalBreakpoint bp = findBreakpointByIndex(idx))
+ gotoLocation(bp);
+ return true;
+ }
+
+ if (role == BaseTreeView::ItemViewEventRole) {
+ ItemViewEvent ev = value.value<ItemViewEvent>();
+
+ if (ev.as<QContextMenuEvent>())
+ return contextMenuEvent(ev);
+
+ if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
+ if (kev->key() == Qt::Key_Delete) {
+ QModelIndexList si = ev.currentOrSelectedRows();
+ const GlobalBreakpoints gbps = findBreakpointsByIndex(si);
+ for (GlobalBreakpoint gbp : gbps)
+ gbp->deleteBreakpoint();
+// int row = qMin(rowCount() - ids.size() - 1, idx.row());
+// setCurrentIndex(index(row, 0)); FIXME
+ return true;
+ }
+// if (kev->key() == Qt::Key_Space) {
+// const QModelIndexList selectedIds = ev.selectedRows();
+// if (!selectedIds.isEmpty()) {
+// const GlobalBreakpoints gbps = findBreakpointsByIndex(selectedIds);
+// const bool isEnabled = gbps.isEmpty() || gbps.at(0)->isEnabled();
+// for (GlobalBreakpoint gbp : gbps)
+// gbp->m_parameters.enabled = isEnabled;
+// scheduleSynchronization();
+// return true;
+// }
+// }
+ }
+
+ if (ev.as<QMouseEvent>(QEvent::MouseButtonDblClick)) {
+ if (GlobalBreakpoint gbp = findBreakpointByIndex(idx)) {
+// if (idx.column() >= BreakpointAddressColumn)
+// editBreakpoints({gbp}, ev.view());
+// else
+ gotoLocation(gbp);
+ } else {
+ BreakpointManager::executeAddBreakpointDialog();
+ }
+ return true;
+ }
+ }
+
+ return false;
}
-BreakpointModelId Breakpoint::id() const
+bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev)
{
- return b ? b->m_id : BreakpointModelId();
+ const QModelIndexList selectedIndices = ev.selectedRows();
+
+ const GlobalBreakpoints selectedBreakpoints = findBreakpointsByIndex(selectedIndices);
+ const bool breakpointsEnabled = selectedBreakpoints.isEmpty() || selectedBreakpoints.at(0)->isEnabled();
+
+// QList<LocationItem *> selectedLocations;
+// const bool locationsEnabled = selectedLocations.isEmpty() || selectedLocations.at(0)->params.enabled;
+
+ auto menu = new QMenu;
+
+ addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog);
+
+ addAction(menu, tr("Delete Selected Breakpoints"),
+ !selectedBreakpoints.isEmpty(),
+ [selectedBreakpoints] {
+ for (GlobalBreakpoint gbp : selectedBreakpoints)
+ gbp->deleteBreakpoint();
+ });
+
+// addAction(menu, tr("Edit Selected Breakpoints..."),
+// !selectedBreakpoints.isEmpty(),
+// [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); });
+
+ addAction(menu,
+ selectedBreakpoints.size() > 1
+ ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints")
+ : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"),
+ !selectedBreakpoints.isEmpty(),
+ [selectedBreakpoints, breakpointsEnabled] {
+ for (GlobalBreakpoint gbp : selectedBreakpoints)
+ gbp->setEnabled(!breakpointsEnabled);
+ }
+ );
+
+ menu->addSeparator();
+
+ addAction(menu, tr("Delete All Breakpoints"),
+ rowCount() > 0,
+ &BreakpointManager::executeDeleteAllBreakpointsDialog);
+
+ // Delete by file: Find indices of breakpoints of the same file.
+ GlobalBreakpoints breakpointsInFile;
+ QString file;
+ if (GlobalBreakpoint gbp = itemForIndexAtLevel<1>(ev.index())) {
+ if (!file.isEmpty()) {
+ for (int i = 0; i != rowCount(); ++i)
+ if (gbp->markerFileName() == file)
+ breakpointsInFile.append(gbp);
+ }
+ }
+ addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file),
+ tr("Delete Breakpoints of File"),
+ breakpointsInFile.size() > 1,
+ [breakpointsInFile] {
+ for (GlobalBreakpoint gbp : breakpointsInFile)
+ gbp->deleteBreakpoint();
+ });
+
+ menu->addSeparator();
+
+ menu->addAction(action(UseToolTipsInBreakpointsView));
+ menu->addAction(action(UseAddressInBreakpointsView));
+ menu->addSeparator();
+ menu->addAction(action(SettingsDialog));
+
+ menu->popup(ev.globalPos());
+
+ return true;
}
-QString Breakpoint::msgWatchpointByExpressionTriggered(const int number, const QString &expr) const
+void BreakpointManager::gotoLocation(const GlobalBreakpoint &gbp) const
{
- return id()
- ? tr("Data breakpoint %1 (%2) at %3 triggered.")
- .arg(id().toString()).arg(number).arg(expr)
- : tr("Internal data breakpoint %1 at %2 triggered.")
- .arg(number).arg(expr);
+ QTC_ASSERT(gbp, return);
+ const QString file = QDir::cleanPath(gbp->markerFileName());
+ if (IEditor *editor = EditorManager::openEditor(file))
+ editor->gotoLine(gbp->markerLineNumber(), 0);
}
-QString Breakpoint::msgWatchpointByExpressionTriggered(const int number, const QString &expr,
- const QString &threadId) const
+void BreakpointManager::executeDeleteAllBreakpointsDialog()
{
- return id()
- ? tr("Data breakpoint %1 (%2) at %3 in thread %4 triggered.")
- .arg(id().toString()).arg(number).arg(expr).arg(threadId)
- : tr("Internal data breakpoint %1 at %2 in thread %3 triggered.")
- .arg(number).arg(expr).arg(threadId);
+ QDialogButtonBox::StandardButton pressed =
+ CheckableMessageBox::doNotAskAgainQuestion(ICore::dialogParent(),
+ tr("Remove All Breakpoints"),
+ tr("Are you sure you want to remove all breakpoints "
+ "from all files in the current session?"),
+ ICore::settings(),
+ "RemoveAllBreakpoints");
+ if (pressed != QDialogButtonBox::Yes)
+ return;
+
+ for (GlobalBreakpoint gbp : globalBreakpoints())
+ gbp->deleteBreakpoint();
}
-QString Breakpoint::msgWatchpointByAddressTriggered(const int number, quint64 address) const
+void BreakpointManager::saveSessionData()
{
- return id()
- ? tr("Data breakpoint %1 (%2) at 0x%3 triggered.")
- .arg(id().toString()).arg(number).arg(address, 0, 16)
- : tr("Internal data breakpoint %1 at 0x%2 triggered.")
- .arg(number).arg(address, 0, 16);
+ QList<QVariant> list;
+ theBreakpointManager->forItemsAtLevel<1>([&list](const GlobalBreakpoint &bp) {
+ const BreakpointParameters &params = bp->m_params;
+ QMap<QString, QVariant> map;
+ if (params.type != BreakpointByFileAndLine)
+ map.insert("type", params.type);
+ if (!params.fileName.isEmpty())
+ map.insert("filename", params.fileName);
+ if (params.lineNumber)
+ map.insert("linenumber", params.lineNumber);
+ if (!params.functionName.isEmpty())
+ map.insert("funcname", params.functionName);
+ if (params.address)
+ map.insert("address", params.address);
+ if (!params.condition.isEmpty())
+ map.insert("condition", params.condition);
+ if (params.ignoreCount)
+ map.insert("ignorecount", params.ignoreCount);
+ if (params.threadSpec >= 0)
+ map.insert("threadspec", params.threadSpec);
+ if (!params.enabled)
+ map.insert("disabled", "1");
+ if (params.oneShot)
+ map.insert("oneshot", "1");
+ if (params.pathUsage != BreakpointPathUsageEngineDefault)
+ map.insert("usefullpath", QString::number(params.pathUsage));
+ if (params.tracepoint)
+ map.insert("tracepoint", "1");
+ if (!params.module.isEmpty())
+ map.insert("module", params.module);
+ if (!params.command.isEmpty())
+ map.insert("command", params.command);
+ if (!params.expression.isEmpty())
+ map.insert("expression", params.expression);
+ if (!params.message.isEmpty())
+ map.insert("message", params.message);
+ list.append(map);
+ });
+ setSessionValue("Breakpoints", list);
}
-QString Breakpoint::msgWatchpointByAddressTriggered(
- const int number, quint64 address, const QString &threadId) const
+void BreakpointManager::aboutToUnloadSession()
{
- return id()
- ? tr("Data breakpoint %1 (%2) at 0x%3 in thread %4 triggered.")
- .arg(id().toString()).arg(number).arg(address, 0, 16).arg(threadId)
- : tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.")
- .arg(id().toString()).arg(number).arg(address, 0, 16).arg(threadId);
+ saveSessionData();
+ theBreakpointManager->clear();
}
-QString Breakpoint::msgBreakpointTriggered(const int number, const QString &threadId) const
+void BreakpointManager::loadSessionData()
{
- return id()
- ? tr("Stopped at breakpoint %1 (%2) in thread %3.")
- .arg(id().toString()).arg(number).arg(threadId)
- : tr("Stopped at internal breakpoint %1 in thread %2.")
- .arg(number).arg(threadId);
+ theBreakpointManager->clear();
+
+ const QVariant value = sessionValue("Breakpoints");
+ const QList<QVariant> list = value.toList();
+ for (const QVariant &var : list) {
+ const QMap<QString, QVariant> map = var.toMap();
+ BreakpointParameters params(BreakpointByFileAndLine);
+ QVariant v = map.value("filename");
+ if (v.isValid())
+ params.fileName = v.toString();
+ v = map.value("linenumber");
+ if (v.isValid())
+ params.lineNumber = v.toString().toInt();
+ v = map.value("condition");
+ if (v.isValid())
+ params.condition = v.toString();
+ v = map.value("address");
+ if (v.isValid())
+ params.address = v.toString().toULongLong();
+ v = map.value("ignorecount");
+ if (v.isValid())
+ params.ignoreCount = v.toString().toInt();
+ v = map.value("threadspec");
+ if (v.isValid())
+ params.threadSpec = v.toString().toInt();
+ v = map.value("funcname");
+ if (v.isValid())
+ params.functionName = v.toString();
+ v = map.value("disabled");
+ if (v.isValid())
+ params.enabled = !v.toInt();
+ v = map.value("oneshot");
+ if (v.isValid())
+ params.oneShot = v.toInt();
+ v = map.value("usefullpath");
+ if (v.isValid())
+ params.pathUsage = static_cast<BreakpointPathUsage>(v.toInt());
+ v = map.value("tracepoint");
+ if (v.isValid())
+ params.tracepoint = bool(v.toInt());
+ v = map.value("type");
+ if (v.isValid() && v.toInt() != UnknownBreakpointType)
+ params.type = BreakpointType(v.toInt());
+ v = map.value("module");
+ if (v.isValid())
+ params.module = v.toString();
+ v = map.value("command");
+ if (v.isValid())
+ params.command = v.toString();
+ v = map.value("expression");
+ if (v.isValid())
+ params.expression = v.toString();
+ v = map.value("message");
+ if (v.isValid())
+ params.message = v.toString();
+ if (params.isValid())
+ BreakpointManager::createBreakpoint(params);
+ else
+ qWarning("Not restoring invalid breakpoint: %s", qPrintable(params.toString()));
+ }
}
} // namespace Internal
diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h
index 09461ba081..91a47649b1 100644
--- a/src/plugins/debugger/breakhandler.h
+++ b/src/plugins/debugger/breakhandler.h
@@ -28,6 +28,7 @@
#include "breakpoint.h"
#include "debuggerprotocol.h"
+#include <utils/fileutils.h>
#include <utils/treemodel.h>
#include <QCoreApplication>
@@ -38,203 +39,295 @@ namespace Utils { class ItemViewEvent; }
namespace Debugger {
namespace Internal {
-class LocationItem;
class BreakpointItem;
+class BreakpointMarker;
class BreakHandler;
class DebuggerCommand;
class DebuggerEngine;
+class BreakpointManager;
+class GlobalBreakpointMarker;
-// Non-owning "deletion-safe" wrapper around a BreakpointItem *
-class Breakpoint
+class SubBreakpointItem : public QObject, public Utils::TypedTreeItem<Utils::TreeItem, BreakpointItem>
+{
+public:
+ QVariant data(int column, int role) const final;
+
+ BreakpointItem *breakpoint() const { return Utils::TypedTreeItem<Utils::TreeItem, BreakpointItem>::parent(); }
+ void setParameters(const BreakpointParameters &pars) { params = pars; }
+ BreakpointParameters params;
+ QString responseId; //!< Breakpoint number assigned by the debugger engine.
+ QString displayName; //!< Breakpoint number assigned by the debugger engine.
+};
+
+using SubBreakpoint = QPointer<SubBreakpointItem>;
+
+class GlobalBreakpointItem : public QObject, public Utils::TreeItem
{
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
public:
- Breakpoint() = default;
+ explicit GlobalBreakpointItem();
+ ~GlobalBreakpointItem() override;
+
+ QVariant data(int column, int role) const override;
+ QIcon icon() const;
- bool isValid() const;
- operator const void *() const { return isValid() ? this : nullptr; }
- bool operator!() const { return !isValid(); }
+ void deleteBreakpoint();
+ void removeBreakpointFromModel();
- uint hash() const;
+ void updateLineNumber(int lineNumber);
+ void updateFileName(const Utils::FileName &fileName);
- const BreakpointParameters &parameters() const;
- void addToCommand(DebuggerCommand *cmd) const;
+ bool isLocatedAt(const QString &fileName, int lineNumber, bool useMarkerPosition) const;
+
+ QString displayName() const;
+ QString markerFileName() const;
+ QString toolTip() const;
+ int markerLineNumber() const;
+ int modelId() const;
+
+ bool isEnabled() const { return m_params.enabled; }
+ void setEnabled(bool enabled);
+
+ const BreakpointParameters &parameters() const { return m_params; }
+
+private:
+ friend class BreakHandler;
+ friend class BreakpointManager;
+ friend class BreakpointMarker;
+ friend class GlobalBreakpointMarker;
+
+ void updateMarker();
+ void updateMarkerIcon();
+ void destroyMarker();
+ void scheduleSynchronization();
+ QPointer<DebuggerEngine> usingEngine() const;
- BreakpointModelId id() const;
- bool isLocatedAt(const QString &fileName, int lineNumber,
- bool useMarkerPosition) const;
+ bool isEngineRunning() const;
+
+ const int m_modelId;
+ BreakpointParameters m_params;
+ GlobalBreakpointMarker *m_marker = nullptr; // The primary marker set by the user.
+};
+
+using GlobalBreakpoint = QPointer<GlobalBreakpointItem>;
+using GlobalBreakpoints = QList<GlobalBreakpoint>;
+
+class BreakpointItem : public QObject, public Utils::TypedTreeItem<SubBreakpointItem>
+{
+ Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
+
+public:
+ explicit BreakpointItem(const GlobalBreakpoint &gbp);
+ ~BreakpointItem() final;
+
+ QVariant data(int column, int role) const final;
QIcon icon() const;
- BreakpointState state() const;
- void setEngine(DebuggerEngine *engine);
-
- // State transitions.
- void notifyBreakpointChangeAfterInsertNeeded();
- void notifyBreakpointInsertProceeding();
- void notifyBreakpointInsertOk();
- void notifyBreakpointInsertFailed();
- void notifyBreakpointChangeOk();
- void notifyBreakpointChangeProceeding();
- void notifyBreakpointChangeFailed();
- void notifyBreakpointPending();
- void notifyBreakpointRemoveProceeding();
- void notifyBreakpointRemoveOk();
- void notifyBreakpointRemoveFailed();
- void notifyBreakpointReleased();
- void notifyBreakpointNeedsReinsertion();
- void notifyBreakpointAdjusted(const BreakpointParameters &params);
-
- void update();
-
- void gotoLocation() const;
-
- // Getter retrieves property value.
- // Setter sets property value and triggers update if changed.
- // Only use setters when it is safe to assume that the breakpoint still
- // exist. That's not the case if the event loop could run after you
- // obtained the BreakpointItem pointer.
- BreakpointPathUsage pathUsage() const;
- void setPathUsage(const BreakpointPathUsage &u);
- QString condition() const;
- void setCondition(const QString &condition);
- int ignoreCount() const;
- void setIgnoreCount(const int &count);
- int threadSpec() const;
- void setThreadSpec(const int &spec);
- QString fileName() const;
- void setFileName(const QString &fileName);
- QString functionName() const;
- void setFunctionName(const QString &functionName);
- QString expression() const;
- void setExpression(const QString &expression);
- QString message() const;
- QString command() const;
- void setCommand(const QString &command);
- void setMessage(const QString &m);
- BreakpointType type() const;
- void setType(const BreakpointType &type);
- quint64 address() const;
- void setAddress(const quint64 &address);
- int lineNumber() const;
- void changeBreakpointData(const BreakpointParameters &data);
- bool isEnabled() const;
- void setEnabled(bool on) const;
- void updateFileNameFromMarker(const QString &fileName);
- void updateLineNumberFromMarker(int lineNumber);
- void changeLineNumberFromMarker(int lineNumber);
+
void setMarkerFileAndLine(const QString &fileName, int lineNumber);
- bool isWatchpoint() const;
- bool isTracepoint() const;
- void setTracepoint(bool on);
- DebuggerEngine *engine() const;
- const BreakpointResponse &response() const;
- void setResponse(const BreakpointResponse &data);
bool needsChange() const;
- bool needsChildren() const;
- bool isOneShot() const;
- void insertSubBreakpoint(const BreakpointResponse &data);
- void removeAlienBreakpoint();
- void removeBreakpoint() const;
+ SubBreakpoint findOrCreateSubBreakpoint(const QString &responseId);
+ QString markerFileName() const;
+ int markerLineNumber() const;
- QString msgWatchpointByAddressTriggered(int number, quint64 address) const;
- QString msgWatchpointByAddressTriggered(
- int number, quint64 address, const QString &threadId) const;
- QString msgWatchpointByExpressionTriggered(int number, const QString &expr) const;
- QString msgWatchpointByExpressionTriggered(
- int number, const QString &expr, const QString &threadId) const;
- QString msgBreakpointTriggered(int number, const QString &threadId) const;
+ const BreakpointParameters &requestedParameters() const;
+ void addToCommand(DebuggerCommand *cmd) const;
+ void updateFromGdbOutput(const GdbMi &bkpt);
+
+ int modelId() const;
+ QString responseId() const { return m_responseId; }
+ QString displayName() const { return m_displayName; }
+ QString toolTip() const;
+ QString shortToolTip() const;
+ BreakpointState state() const { return m_state; }
+ BreakpointType type() const { return m_parameters.type; }
+ BreakpointPathUsage pathUsage() const;
+ const BreakpointParameters parameters() const { return m_parameters; }
+
+ QString condition() const { return m_parameters.condition; }
+ int ignoreCount() const { return m_parameters.ignoreCount; }
+ int threadSpec() const { return m_parameters.threadSpec; }
+ QString fileName() const { return m_parameters.fileName; }
+ QString functionName() const { return m_parameters.functionName; }
+ QString expression() const { return m_parameters.expression; }
+ QString message() const { return m_parameters.message; }
+ QString command() const { return m_parameters.command; }
+ quint64 address() const { return m_parameters.address; }
+ int lineNumber() const { return m_parameters.lineNumber; }
+ bool isEnabled() const { return m_parameters.enabled; }
+ bool isWatchpoint() const { return m_parameters.isWatchpoint(); }
+ bool isTracepoint() const { return m_parameters.isTracepoint(); }
+ bool isOneShot() const { return m_parameters.oneShot; }
+ bool isPending() const { return m_parameters.pending; }
+
+ void setLineNumber(int lineNumber) { m_parameters.lineNumber = lineNumber; }
+ void setFileName(const QString &fileName) { m_parameters.fileName = fileName; }
+ void setFunctionName(const QString &functionName) { m_parameters.functionName = functionName; }
+ void setPending(bool pending);
+ void setResponseId(const QString &str) { m_responseId = str; }
+ void setDisplayName(const QString &name) { m_displayName = name; }
+ void setParameters(const BreakpointParameters &value);
+ void setAddress(quint64 address) { m_parameters.address = address; }
+ void setEnabled(bool on);
+ void setHitCount(int hitCount) { m_parameters.hitCount = hitCount; }
+ void setThreadSpec(int threadSpec) { m_parameters.threadSpec = threadSpec; }
+ void setIgnoreCount(int count) { m_parameters.ignoreCount = count; }
+ void setCommand(const QString &command) { m_parameters.command = command; }
+ void setCondition(const QString &condition) { m_parameters.condition = condition; }
+
+ QString msgWatchpointByAddressTriggered(quint64 address) const;
+ QString msgWatchpointByAddressTriggered(quint64 address, const QString &threadId) const;
+ QString msgWatchpointByExpressionTriggered(const QString &expr) const;
+ QString msgWatchpointByExpressionTriggered(const QString &expr, const QString &threadId) const;
+ QString msgBreakpointTriggered(const QString &threadId) const;
+
+ friend class BreakpointManager;
+ friend class BreakHandler;
+ friend class DebuggerEngine;
-private:
- void gotoState(BreakpointState target, BreakpointState assumedCurrent);
+ void adjustMarker();
- friend class BreakHandler;
- explicit Breakpoint(BreakpointItem *b);
+ void deleteBreakpoint();
+ void deleteGlobalOrThisBreakpoint();
+
+ void updateLineNumber(int lineNumber);
+ void updateFileName(const Utils::FileName &fileName);
- QPointer<BreakpointItem> b;
+ const GlobalBreakpoint globalBreakpoint() const;
+ void gotoState(BreakpointState target, BreakpointState assumedCurrent);
+
+private:
+ void destroyMarker();
+ void updateMarker();
+ void updateMarkerIcon();
+ void setState(BreakpointState state);
+
+ const GlobalBreakpoint m_globalBreakpoint; // Origin, or null for aliens.
+ BreakpointParameters m_requestedParameters; // May differ from global value over lifetime of breakpoint.
+ BreakpointParameters m_parameters;
+ BreakpointState m_state = BreakpointNew; // Current state of breakpoint.
+ BreakpointMarker *m_marker = nullptr;
+ QString m_responseId; //!< Breakpoint number or id assigne by or used in the debugger backend.
+ QString m_displayName;
};
-inline uint qHash(const Debugger::Internal::Breakpoint &b) { return b.hash(); }
+using Breakpoint = QPointer<BreakpointItem>;
+using Breakpoints = const QList<Breakpoint>;
+using SubBreakpoints = const QList<SubBreakpoint>;
-using Breakpoints = QList<Breakpoint>;
+using BreakHandlerModel = Utils::TreeModel<Utils::TypedTreeItem<BreakpointItem>, BreakpointItem, SubBreakpointItem>;
+using BreakpointManagerModel = Utils::TreeModel<Utils::TypedTreeItem<GlobalBreakpointItem>, GlobalBreakpointItem>;
-using BreakModel = Utils::TreeModel<Utils::TypedTreeItem<BreakpointItem>, BreakpointItem, LocationItem>;
+inline uint qHash(const Debugger::Internal::SubBreakpoint &b) { return qHash(b.data()); }
+inline uint qHash(const Debugger::Internal::Breakpoint &b) { return qHash(b.data()); }
+inline uint qHash(const Debugger::Internal::GlobalBreakpoint &b) { return qHash(b.data()); }
-class BreakHandler : public BreakModel
+class BreakHandler : public BreakHandlerModel
{
Q_OBJECT
public:
- BreakHandler();
+ explicit BreakHandler(DebuggerEngine *engine);
+
+ QAbstractItemModel *model() { return this; }
+ const Breakpoints breakpoints() const;
void loadSessionData();
void saveSessionData();
- QAbstractItemModel *model() { return this; }
+ bool tryClaimBreakpoint(const GlobalBreakpoint &gbp);
+ void releaseAllBreakpoints();
- // The only way to add a new breakpoint.
- void appendBreakpoint(const BreakpointParameters &data);
- void handleAlienBreakpoint(const BreakpointResponse &response, DebuggerEngine *engine);
+ void handleAlienBreakpoint(const QString &responseId, const BreakpointParameters &response);
+ void removeAlienBreakpoint(const QString &responseId);
+ void requestBreakpointInsertion(const Breakpoint &bp);
+ void requestBreakpointUpdate(const Breakpoint &bp);
+ void requestBreakpointRemoval(const Breakpoint &bp);
+ void requestBreakpointEnabling(const Breakpoint &bp, bool enabled);
+ void requestSubBreakpointEnabling(const SubBreakpoint &sbp, bool enabled);
- const Breakpoints allBreakpoints() const;
- const Breakpoints engineBreakpoints(DebuggerEngine *engine) const;
- const Breakpoints unclaimedBreakpoints() const;
- QStringList engineBreakpointPaths(DebuggerEngine *engine) const;
+ void removeBreakpoint(const Breakpoint &bp);
+ void editBreakpoint(const Breakpoint &bp, QWidget *parent);
- // Find a breakpoint matching approximately the data in needle.
- Breakpoint findSimilarBreakpoint(const BreakpointResponse &needle) const;
- Breakpoint findBreakpointByResponseId(const BreakpointResponseId &resultId) const;
+ Breakpoint findBreakpointByResponseId(const QString &responseId) const;
+ SubBreakpoint findSubBreakpointByResponseId(const QString &responseId) const;
Breakpoint findWatchpoint(const BreakpointParameters &data) const;
- Breakpoint findBreakpointByFunction(const QString &functionName) const;
- Breakpoint findBreakpointByIndex(const QModelIndex &index) const;
- Breakpoints findBreakpointsByIndex(const QList<QModelIndex> &list) const;
- void updateMarkers();
+ Breakpoint findBreakpointByModelId(int modelId) const;
- Breakpoint findBreakpointByFileAndLine(const QString &fileName,
- int lineNumber, bool useMarkerPosition = true);
- Breakpoint findBreakpointByAddress(quint64 address) const;
-
- void breakByFunction(const QString &functionName);
static QString displayFromThreadSpec(int spec);
static int threadSpecFromDisplay(const QString &str);
// Convenience.
void setWatchpointAtAddress(quint64 address, unsigned size);
void setWatchpointAtExpression(const QString &exp);
+ void setBreakpointEnabled(const Breakpoint &bp, bool on);
- Breakpoint breakpointById(BreakpointModelId id) const;
- void editBreakpoint(Breakpoint bp, QWidget *parent);
+ void updateDisassemblerMarker(const Breakpoint &bp);
+ void removeDisassemblerMarker(const Breakpoint &bp);
private:
- QVariant data(const QModelIndex &idx, int role) const override;
- bool setData(const QModelIndex &idx, const QVariant &value, int role) override;
- void timerEvent(QTimerEvent *event) override;
+ Breakpoint findBreakpointByIndex(const QModelIndex &index) const;
+ Breakpoints findBreakpointsByIndex(const QList<QModelIndex> &list) const;
+ SubBreakpoint findSubBreakpointByIndex(const QModelIndex &index) const;
+ SubBreakpoints findSubBreakpointsByIndex(const QList<QModelIndex> &list) const;
+ void editBreakpoints(const Breakpoints &bps, QWidget *parent);
+
+ void gotoState(Breakpoint bp, BreakpointState target, BreakpointState assumedCurrent);
+ void gotoLocation(const Breakpoint &bp) const;
+
+ QVariant data(const QModelIndex &idx, int role) const final;
+ bool setData(const QModelIndex &idx, const QVariant &value, int role) final;
bool contextMenuEvent(const Utils::ItemViewEvent &ev);
friend class BreakpointItem;
- friend class Breakpoint;
- void loadBreakpoints();
- void saveBreakpoints();
+ DebuggerEngine * const m_engine;
+};
- void appendBreakpointInternal(const BreakpointParameters &data);
- void deleteBreakpoints(const Breakpoints &bps);
- void deleteAllBreakpoints();
- void setBreakpointsEnabled(const Breakpoints &bps, bool enabled);
- void addBreakpoint();
- void editBreakpoints(const Breakpoints &bps, QWidget *parent);
+class BreakpointManager : public BreakpointManagerModel
+{
+ Q_OBJECT
- Q_SLOT void changeLineNumberFromMarkerHelper(Debugger::Internal::BreakpointModelId id);
- Q_SLOT void deletionHelper(Debugger::Internal::BreakpointModelId id);
+public:
+ BreakpointManager();
- void scheduleSynchronization();
+ static QAbstractItemModel *model();
+
+ static const GlobalBreakpoints globalBreakpoints();
+ static void loadSessionData();
+ static void saveSessionData();
+ static void aboutToUnloadSession();
+
+ static GlobalBreakpoint createBreakpoint(const BreakpointParameters &data);
- int m_syncTimerId;
+ static GlobalBreakpoint findBreakpointByLocation(const ContextData &location);
+ // Find a breakpoint matching approximately the data in needle.
+ static GlobalBreakpoint findSimilarBreakpoint(const BreakpointParameters &needle);
+ static GlobalBreakpoint findWatchpoint(const BreakpointParameters &data);
+ static GlobalBreakpoint findBreakpointByFunction(const QString &functionName);
+
+ static void claimBreakpointsForEngine(DebuggerEngine *engine);
+ static void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString());
+ static void createBreakpointForEngine(const BreakpointParameters &data, DebuggerEngine *engine);
+
+ static void executeAddBreakpointDialog();
+ static void executeDeleteAllBreakpointsDialog();
+
+private:
+ static GlobalBreakpoint createBreakpointHelper(const BreakpointParameters &data);
+ static GlobalBreakpoint findBreakpointByIndex(const QModelIndex &index);
+ static GlobalBreakpoints findBreakpointsByIndex(const QList<QModelIndex> &list);
+
+ QVariant data(const QModelIndex &idx, int role) const final;
+ bool setData(const QModelIndex &idx, const QVariant &value, int role) final;
+
+ bool contextMenuEvent(const Utils::ItemViewEvent &ev);
+ void gotoLocation(const GlobalBreakpoint &gbp) const;
};
} // namespace Internal
} // namespace Debugger
-Q_DECLARE_METATYPE(Debugger::Internal::Breakpoint)
diff --git a/src/plugins/debugger/breakpoint.cpp b/src/plugins/debugger/breakpoint.cpp
index be1287d1d5..dc1e43559f 100644
--- a/src/plugins/debugger/breakpoint.cpp
+++ b/src/plugins/debugger/breakpoint.cpp
@@ -25,90 +25,21 @@
#include "breakpoint.h"
+#include "debuggeractions.h"
+#include "debuggercore.h"
+#include "debuggerprotocol.h"
+
+#include <projectexplorer/abi.h>
#include <utils/qtcassert.h>
#include <QDebug>
#include <QFileInfo>
+#include <QDir>
namespace Debugger {
namespace Internal {
/*!
- \class Debugger::Internal::BreakpointIdBase
-
- Convenience base class for BreakpointModelId and
- BreakpointResponseId.
-*/
-
-QDebug operator<<(QDebug d, const BreakpointIdBase &id)
-{
- d << qPrintable(id.toString());
- return d;
-}
-
-QString BreakpointIdBase::toString() const
-{
- if (!isValid())
- return QLatin1String("<invalid bkpt>");
- if (isMinor())
- return QString("%1.%2").arg(m_majorPart).arg(m_minorPart);
- return QString::number(m_majorPart);
-}
-
-
-/*!
- \class Debugger::Internal::BreakpointModelId
-
- This identifies a breakpoint in the \c BreakHandler. The
- major parts are strictly increasing over time.
-
- The minor part identifies a multiple breakpoint
- set for example by gdb in constructors.
-*/
-
-
-BreakpointModelId::BreakpointModelId(const QString &ba)
-{
- int pos = ba.indexOf('\'');
- if (pos == -1) {
- m_majorPart = ba.toUShort();
- m_minorPart = 0;
- } else {
- m_majorPart = ba.left(pos).toUShort();
- m_minorPart = ba.mid(pos + 1).toUShort();
- }
-}
-
-/*!
- \class Debugger::Internal::BreakpointResponseId
-
- This is what the external debuggers use to identify a breakpoint.
- It is only valid for one debugger run.
-
- In gdb, the breakpoint number is used, which is constant
- during a session. CDB's breakpoint numbers vary if breakpoints
- are deleted, so, the ID is used.
-*/
-
-BreakpointResponseId::BreakpointResponseId(const QString &ba)
-{
- int pos = ba.indexOf('.');
- if (pos == -1) {
- m_majorPart = ba.toInt();
- m_minorPart = 0;
- } else {
- m_majorPart = ba.left(pos).toInt();
- m_minorPart = ba.mid(pos + 1).toInt();
- }
-}
-
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointParameters
-//
-//////////////////////////////////////////////////////////////////
-
-/*!
\class Debugger::Internal::BreakpointParameters
Data type holding the parameters of a breakpoint.
@@ -215,25 +146,32 @@ void BreakpointParameters::updateLocation(const QString &location)
}
}
+bool BreakpointParameters::isQmlFileAndLineBreakpoint() const
+{
+ if (type != BreakpointByFileAndLine)
+ return false;
+
+ QString qmlExtensionString = QString::fromLocal8Bit(qgetenv("QTC_QMLDEBUGGER_FILEEXTENSIONS"));
+ if (qmlExtensionString.isEmpty())
+ qmlExtensionString = ".qml;.js";
+
+ const auto qmlFileExtensions = qmlExtensionString.splitRef(';', QString::SkipEmptyParts);
+ for (QStringRef extension : qmlFileExtensions) {
+ if (fileName.endsWith(extension, Qt::CaseInsensitive))
+ return true;
+ }
+ return false;
+}
+
bool BreakpointParameters::isCppBreakpoint() const
{
// Qml specific breakpoint types.
- if (type == BreakpointAtJavaScriptThrow
- || type == BreakpointOnQmlSignalEmit)
+ if (type == BreakpointAtJavaScriptThrow || type == BreakpointOnQmlSignalEmit)
return false;
// Qml is currently only file.
- if (type == BreakpointByFileAndLine) {
- auto qmlExtensionString = QString::fromLocal8Bit(qgetenv("QTC_QMLDEBUGGER_FILEEXTENSIONS"));
- if (qmlExtensionString.isEmpty())
- qmlExtensionString = ".qml;.js";
-
- const auto qmlFileExtensions = qmlExtensionString.splitRef(';', QString::SkipEmptyParts);
- for (QStringRef extension : qmlFileExtensions) {
- if (fileName.endsWith(extension, Qt::CaseInsensitive))
- return false;
- }
- }
+ if (type == BreakpointByFileAndLine)
+ return !isQmlFileAndLineBreakpoint();
return true;
}
@@ -283,55 +221,176 @@ QString BreakpointParameters::toString() const
ts << " Command: " << command;
if (!message.isEmpty())
ts << " Message: " << message;
- return result;
-}
-
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointResponse
-//
-//////////////////////////////////////////////////////////////////
-
-/*!
- \class Debugger::Internal::BreakpointResponse
-
- This is what debuggers produce in response to the attempt to
- insert a breakpoint. The data might differ from the requested bits.
-*/
-
-BreakpointResponse::BreakpointResponse()
-{
- pending = true;
- hitCount = 0;
- multiple = false;
- correctedLineNumber = 0;
-}
-QString BreakpointResponse::toString() const
-{
- QString result = BreakpointParameters::toString();
- QTextStream ts(&result);
- ts << " Number: " << id.toString();
if (pending)
ts << " [pending]";
if (!functionName.isEmpty())
ts << " Function: " << functionName;
- if (multiple)
- ts << " Multiple: " << multiple;
- if (correctedLineNumber)
- ts << " CorrectedLineNumber: " << correctedLineNumber;
ts << " Hit: " << hitCount << " times";
ts << ' ';
- return result + BreakpointParameters::toString();
+
+ return result;
}
-void BreakpointResponse::fromParameters(const BreakpointParameters &p)
+static QString cleanupFullName(const QString &fileName)
{
- BreakpointParameters::operator=(p);
- id = BreakpointResponseId();
- multiple = false;
- correctedLineNumber = 0;
- hitCount = 0;
+ QString cleanFilePath = fileName;
+
+ // Gdb running on windows often delivers "fullnames" which
+ // (a) have no drive letter and (b) are not normalized.
+ if (ProjectExplorer::Abi::hostAbi().os() == ProjectExplorer::Abi::WindowsOS) {
+ if (fileName.isEmpty())
+ return QString();
+ QFileInfo fi(fileName);
+ if (fi.isReadable())
+ cleanFilePath = QDir::cleanPath(fi.absoluteFilePath());
+ }
+
+// if (!boolSetting(AutoEnrichParameters))
+// return cleanFilePath;
+
+// const QString sysroot = runParameters().sysRoot;
+// if (QFileInfo(cleanFilePath).isReadable())
+// return cleanFilePath;
+// if (!sysroot.isEmpty() && fileName.startsWith('/')) {
+// cleanFilePath = sysroot + fileName;
+// if (QFileInfo(cleanFilePath).isReadable())
+// return cleanFilePath;
+// }
+// if (m_baseNameToFullName.isEmpty()) {
+// QString debugSource = sysroot + "/usr/src/debug";
+// if (QFileInfo(debugSource).isDir()) {
+// QDirIterator it(debugSource, QDirIterator::Subdirectories);
+// while (it.hasNext()) {
+// it.next();
+// QString name = it.fileName();
+// if (!name.startsWith('.')) {
+// QString path = it.filePath();
+// m_baseNameToFullName.insert(name, path);
+// }
+// }
+// }
+// }
+
+// cleanFilePath.clear();
+// const QString base = FileName::fromString(fileName).fileName();
+
+// QMap<QString, QString>::const_iterator jt = m_baseNameToFullName.constFind(base);
+// while (jt != m_baseNameToFullName.constEnd() && jt.key() == base) {
+// // FIXME: Use some heuristics to find the "best" match.
+// return jt.value();
+// //++jt;
+// }
+
+ return cleanFilePath;
+}
+void BreakpointParameters::updateFromGdbOutput(const GdbMi &bkpt)
+{
+ QTC_ASSERT(bkpt.isValid(), return);
+
+ QString originalLocation;
+ QString file;
+ QString fullName;
+ QString internalId;
+
+ enabled = true;
+ pending = false;
+ condition.clear();
+ for (const GdbMi &child : bkpt.children()) {
+ if (child.hasName("number")) {
+ // Handled on caller side.
+ } else if (child.hasName("func")) {
+ functionName = child.data();
+ } else if (child.hasName("addr")) {
+ // <MULTIPLE> happens in constructors, inline functions, and
+ // at other places like 'foreach' lines. In this case there are
+ // fields named "addr" in the response and/or the address
+ // is called <MULTIPLE>.
+ //qDebug() << "ADDR: " << child.data() << (child.data() == "<MULTIPLE>");
+ if (child.data().startsWith("0x"))
+ address = child.toAddress();
+ } else if (child.hasName("file")) {
+ file = child.data();
+ } else if (child.hasName("fullname")) {
+ fullName = child.data();
+ } else if (child.hasName("line")) {
+ lineNumber = child.toInt();
+ } else if (child.hasName("cond")) {
+ // gdb 6.3 likes to "rewrite" conditions. Just accept that fact.
+ condition = child.data();
+ } else if (child.hasName("enabled")) {
+ enabled = (child.data() == "y");
+ } else if (child.hasName("disp")) {
+ oneShot = child.data() == "del";
+ } else if (child.hasName("pending")) {
+ // Any content here would be interesting only if we did accept
+ // spontaneously appearing breakpoints (user using gdb commands).
+ if (file.isEmpty())
+ file = child.data();
+ pending = true;
+ } else if (child.hasName("at")) {
+ // Happens with gdb 6.4 symbianelf.
+ QString ba = child.data();
+ if (ba.startsWith('<') && ba.endsWith('>'))
+ ba = ba.mid(1, ba.size() - 2);
+ functionName = ba;
+ } else if (child.hasName("thread")) {
+ threadSpec = child.toInt();
+ } else if (child.hasName("type")) {
+ // "breakpoint", "hw breakpoint", "tracepoint", "hw watchpoint"
+ // {bkpt={number="2",type="hw watchpoint",disp="keep",enabled="y",
+ // what="*0xbfffed48",times="0",original-location="*0xbfffed48"}}
+ if (child.data().contains("tracepoint")) {
+ tracepoint = true;
+ } else if (child.data() == "hw watchpoint" || child.data() == "watchpoint") {
+ QString what = bkpt["what"].data();
+ if (what.startsWith("*0x")) {
+ type = WatchpointAtAddress;
+ address = what.mid(1).toULongLong(0, 0);
+ } else {
+ type = WatchpointAtExpression;
+ expression = what;
+ }
+ } else if (child.data() == "breakpoint") {
+ QString catchType = bkpt["catch-type"].data();
+ if (catchType == "throw")
+ type = BreakpointAtThrow;
+ else if (catchType == "catch")
+ type = BreakpointAtCatch;
+ else if (catchType == "fork")
+ type = BreakpointAtFork;
+ else if (catchType == "exec")
+ type = BreakpointAtExec;
+ else if (catchType == "syscall")
+ type = BreakpointAtSysCall;
+ }
+ } else if (child.hasName("times")) {
+ hitCount = child.toInt();
+ } else if (child.hasName("original-location")) {
+ originalLocation = child.data();
+ }
+ // This field is not present. Contents needs to be parsed from
+ // the plain "ignore"
+ //else if (child.hasName("ignore"))
+ // ignoreCount = child.data();
+ }
+
+ QString name;
+ if (!fullName.isEmpty()) {
+ name = cleanupFullName(fullName);
+ fileName = name;
+ //if (data->markerFileName().isEmpty())
+ // data->setMarkerFileName(name);
+ } else {
+ name = file;
+ // Use fullName() once we have a mapping which is more complete than
+ // gdb's own. No point in assigning markerFileName for now.
+ }
+ if (!name.isEmpty())
+ fileName = name;
+
+ if (fileName.isEmpty())
+ updateLocation(originalLocation);
}
} // namespace Internal
diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h
index 45c9a11205..26e118b8bb 100644
--- a/src/plugins/debugger/breakpoint.h
+++ b/src/plugins/debugger/breakpoint.h
@@ -31,52 +31,7 @@
namespace Debugger {
namespace Internal {
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointIds
-//
-//////////////////////////////////////////////////////////////////
-
-class BreakpointIdBase
-{
-public:
- BreakpointIdBase() = default;
-
- bool isValid() const { return m_majorPart != 0; }
- bool isMajor() const { return m_majorPart != 0 && m_minorPart == 0; }
- bool isMinor() const { return m_majorPart != 0 && m_minorPart != 0; }
- bool operator!() const { return !isValid(); }
- operator const void*() const { return isValid() ? this : nullptr; }
- quint32 toInternalId() const { return m_majorPart | (m_minorPart << 16); }
- QString toString() const;
- bool operator==(const BreakpointIdBase &id) const
- { return m_majorPart == id.m_majorPart && m_minorPart == id.m_minorPart; }
- quint16 majorPart() const { return m_majorPart; }
- quint16 minorPart() const { return m_minorPart; }
-
-protected:
- quint16 m_majorPart = 0;
- quint16 m_minorPart = 0;
-};
-
-class BreakpointModelId : public BreakpointIdBase
-{
-public:
- BreakpointModelId() { m_majorPart = m_minorPart = 0; }
- explicit BreakpointModelId(quint16 ma) { m_majorPart = ma; m_minorPart = 0; }
- BreakpointModelId(quint16 ma, quint16 mi) { m_majorPart = ma; m_minorPart = mi; }
- explicit BreakpointModelId(const QString &ba); // "21.2"
-};
-
-class BreakpointResponseId : public BreakpointIdBase
-{
-public:
- BreakpointResponseId() { m_majorPart = m_minorPart = 0; }
- explicit BreakpointResponseId(quint16 ma) { m_majorPart = ma; m_minorPart = 0; }
- BreakpointResponseId(quint16 ma, quint16 mi) { m_majorPart = ma; m_minorPart = mi; }
- explicit BreakpointResponseId(const QString &ba); // "21.2"
-};
-
+class GdbMi;
//////////////////////////////////////////////////////////////////
//
@@ -86,7 +41,7 @@ public:
//! \enum Debugger::Internal::BreakpointType
-// Note: Keep synchronized with similar definitions in bridge.py
+// Note: Keep synchronized with similar definitions in dumper.py
enum BreakpointType
{
UnknownBreakpointType,
@@ -110,11 +65,11 @@ enum BreakpointType
enum BreakpointState
{
BreakpointNew,
- BreakpointInsertRequested, //!< Inferior was told about bp, not ack'ed.
- BreakpointInsertProceeding,
- BreakpointChangeRequested,
- BreakpointChangeProceeding,
+ BreakpointInsertionRequested, //!< Inferior was told about bp, not ack'ed.
+ BreakpointInsertionProceeding,
BreakpointInserted,
+ BreakpointUpdateRequested,
+ BreakpointUpdateProceeding,
BreakpointRemoveRequested,
BreakpointRemoveProceeding,
BreakpointDead
@@ -185,12 +140,15 @@ public:
bool conditionsMatch(const QString &other) const;
bool isWatchpoint() const
{ return type == WatchpointAtAddress || type == WatchpointAtExpression; }
+ bool isLocatedAt(const QString &fileName, int lineNumber, const QString &markerFileName) const;
// Enough for now.
bool isBreakpoint() const { return !isWatchpoint() && !isTracepoint(); }
bool isTracepoint() const { return tracepoint; }
bool isCppBreakpoint() const;
+ bool isQmlFileAndLineBreakpoint() const;
QString toString() const;
void updateLocation(const QString &location); // file.cpp:42
+ void updateFromGdbOutput(const GdbMi &bkpt);
bool operator==(const BreakpointParameters &p) const { return equals(p); }
bool operator!=(const BreakpointParameters &p) const { return !equals(p); }
@@ -214,31 +172,10 @@ public:
QString message; //!< message
bool tracepoint;
bool oneShot; //!< Should this breakpoint trigger only once?
-};
-
-class BreakpointResponse : public BreakpointParameters
-{
-public:
- BreakpointResponse();
- QString toString() const;
-
-public:
- void fromParameters(const BreakpointParameters &p);
- BreakpointResponseId id; //!< Breakpoint number assigned by the debugger engine.
- bool pending; //!< Breakpoint not fully resolved.
- int hitCount; //!< Number of times this has been hit.
- bool multiple; //!< Happens in constructors/gdb.
- int correctedLineNumber; //!< Line number as seen by gdb.
+ bool pending = true; //!< Breakpoint not fully resolved.
+ int hitCount = 0; //!< Number of times this has been hit.
};
-inline uint qHash(const Debugger::Internal::BreakpointModelId &id)
-{
- return id.toInternalId();
-}
-
} // namespace Internal
} // namespace Debugger
-
-Q_DECLARE_METATYPE(Debugger::Internal::BreakpointModelId)
-Q_DECLARE_METATYPE(Debugger::Internal::BreakpointResponseId)
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 55dbc5c8fb..d9ca62d7d1 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -182,6 +182,7 @@ CdbEngine::CdbEngine() :
m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT ".")
{
setObjectName("CdbEngine");
+ setDebuggerName("CDB");
DisplayFormats stringFormats;
stringFormats.append(SimpleFormat);
@@ -225,7 +226,7 @@ void CdbEngine::init()
m_stopMode = NoStopRequested;
m_nextCommandToken = 0;
m_currentBuiltinResponseToken = -1;
- m_operateByInstruction = true;
+ m_operateByInstruction = action(OperateByInstruction)->isChecked();
m_hasDebuggee = false;
m_sourceStepInto = false;
m_watchPointX = m_watchPointY = 0;
@@ -238,8 +239,6 @@ void CdbEngine::init()
m_currentBuiltinResponse.clear();
m_extensionMessageBuffer.clear();
m_pendingBreakpointMap.clear();
- m_insertSubBreakpointMap.clear();
- m_pendingSubBreakpointMap.clear();
m_interrupCallbacks.clear();
m_symbolAddressCache.clear();
m_coreStopReason.reset();
@@ -526,15 +525,17 @@ void CdbEngine::handleInitialSessionIdle()
operateByInstructionTriggered(action(OperateByInstruction)->isChecked());
// QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
// (attemptBreakpointSynchronization() will be directly called then)
- attemptBreakpointSynchronization();
if (rp.breakOnMain) {
- const BreakpointParameters bp(BreakpointAtMain);
- BreakpointModelId id(quint16(-1));
- QString function = cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true);
- runCommand({function, BuiltinCommand,
- [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); }});
+ // FIXME:
+// const BreakpointParameters bp(BreakpointAtMain);
+// BreakpointModelId id(quint16(-1));
+// QString function = cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true);
+// runCommand({function, BuiltinCommand,
+// [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); }});
}
+ // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
+ BreakpointManager::claimBreakpointsForEngine(this);
runCommand({".symopt+0x8000"}); // disable searching public symbol table - improving the symbol lookup speed
runCommand({"sxn 0x4000001f", NoFlags}); // Do not break on WowX86 exceptions.
runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints.
@@ -608,7 +609,7 @@ void CdbEngine::runEngine()
runCommand({"sxe " + breakEvent, NoFlags});
// Break functions: each function must be fully qualified,
// else the debugger will slow down considerably.
- const auto cb = [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); };
+ const auto cb = [this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); };
if (boolSetting(CdbBreakOnCrtDbgReport)) {
Abi::OSFlavor flavor = runParameters().toolChainAbi.osFlavor();
// CrtDebugReport can not be safely resolved for vc 19
@@ -853,13 +854,8 @@ void CdbEngine::doInterruptInferior(const InterruptCallback &callback)
showMessage(QString("Interrupting process %1...").arg(inferiorPid()), LogMisc);
QTC_ASSERT(!m_signalOperation, notifyInferiorStopFailed(); return);
- if (DebuggerRunTool *rt = runTool()) {
- IDevice::ConstPtr device = rt->device();
- if (!device)
- device = runParameters().inferior.device;
- if (device)
- m_signalOperation = device->signalOperation();
- }
+ QTC_ASSERT(device(), notifyInferiorRunFailed(); return);
+ m_signalOperation = device()->signalOperation();
QTC_ASSERT(m_signalOperation, notifyInferiorStopFailed(); return;);
connect(m_signalOperation.data(), &DeviceProcessSignalOperation::finished,
this, &CdbEngine::handleDoInterruptInferior);
@@ -881,8 +877,8 @@ void CdbEngine::executeRunToLine(const ContextData &data)
bp.lineNumber = data.lineNumber;
}
- runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), BuiltinCommand,
- [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }});
+ runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, {}, true), BuiltinCommand,
+ [this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); }});
continueInferior();
}
@@ -891,8 +887,8 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
// Add one-shot breakpoint
BreakpointParameters bp(BreakpointByFunction);
bp.functionName = functionName;
- runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), BuiltinCommand,
- [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }});
+ runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, {}, true), BuiltinCommand,
+ [this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); }});
continueInferior();
}
@@ -1014,10 +1010,9 @@ void CdbEngine::handleThreads(const DebuggerResponse &response)
}
}
-void CdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
+void CdbEngine::executeDebuggerCommand(const QString &command)
{
- if (languages & CppLanguage)
- runCommand({command, NoFlags});
+ runCommand({command, NoFlags});
}
// Post command to the cdb process
@@ -1465,8 +1460,7 @@ void CdbEngine::fetchMemory(MemoryAgent *agent, quint64 address, quint64 length)
StringInputStream str(args);
str << address << ' ' << length;
cmd.args = args;
- cmd.callback = [this, agent = QPointer<MemoryAgent>(agent), address, length]
- (const DebuggerResponse &response) {
+ cmd.callback = [&](const DebuggerResponse &response) {
if (!agent)
return;
if (response.resultClass == ResultDone) {
@@ -1507,7 +1501,8 @@ void CdbEngine::requestModuleSymbols(const QString &moduleName)
void CdbEngine::reloadRegisters()
{
- QTC_ASSERT(threadsHandler()->currentThreadIndex() >= 0, return);
+ if (!(threadsHandler()->currentThreadIndex() >= 0))
+ return;
runCommand({"registers", ExtensionCommand, CB(handleRegistersExt)});
}
@@ -1680,19 +1675,18 @@ enum StopActionFlags
StopShutdownInProgress = 0x80 // Shutdown in progress
};
-static inline QString msgTracePointTriggered(BreakpointModelId id, const int number,
+static inline QString msgTracePointTriggered(const Breakpoint &, const QString &displayName,
const QString &threadId)
{
- return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
- .arg(id.toString()).arg(number).arg(threadId);
+ return CdbEngine::tr("Trace point %1 in thread %2 triggered.")
+ .arg(displayName).arg(threadId);
}
-static inline QString msgCheckingConditionalBreakPoint(BreakpointModelId id, const int number,
- const QString &condition,
+static inline QString msgCheckingConditionalBreakPoint(const Breakpoint &bp, const QString &displayName,
const QString &threadId)
{
- return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression \"%4\".")
- .arg(id.toString()).arg(number).arg(threadId, condition);
+ return CdbEngine::tr("Conditional breakpoint %1 in thread %2 triggered, examining expression \"%3\".")
+ .arg(displayName).arg(threadId, bp->condition());
}
unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
@@ -1722,52 +1716,55 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
if (reason == "breakpoint") {
// Note: Internal breakpoints (run to line) are reported with id=0.
// Step out creates temporary breakpoints with id 10000.
- int number = 0;
- BreakpointModelId id = cdbIdToBreakpointModelId(stopReason["breakpointId"]);
- Breakpoint bp = breakHandler()->breakpointById(id);
+
+ const QString responseId = stopReason["breakpointId"].data();
+ QString displayName;
+ Breakpoint bp = breakHandler()->findBreakpointByResponseId(responseId);
+ if (!bp) {
+ if (const SubBreakpoint sub = breakHandler()->findSubBreakpointByResponseId(responseId)) {
+ bp = sub->breakpoint();
+ displayName = sub->displayName;
+ }
+ } else {
+ displayName = bp->displayName();
+ }
if (bp) {
- if (bp.engine() == this) {
- const BreakpointResponse parameters = bp.response();
- if (!parameters.message.isEmpty()) {
- showMessage(parameters.message + '\n', AppOutput);
- showMessage(parameters.message, LogMisc);
- }
- // Trace point? Just report.
- number = parameters.id.majorPart();
- if (parameters.tracepoint) {
- *message = msgTracePointTriggered(id, number, QString::number(threadId));
- return StopReportLog|StopIgnoreContinue;
- }
- // Trigger evaluation of BP expression unless we are already in the response.
- if (!conditionalBreakPointTriggered && !parameters.condition.isEmpty()) {
- *message = msgCheckingConditionalBreakPoint(id, number, parameters.condition,
- QString::number(threadId));
- QString args = parameters.condition;
- if (args.contains(' ') && !args.startsWith('"')) {
- args.prepend('"');
- args.append('"');
- }
- DebuggerCommand cmd("expression", ExtensionCommand);
- cmd.args = args;
- cmd.callback = [this, id, stopReason](const DebuggerResponse &response) {
- handleExpression(response, id, stopReason);
- };
- runCommand(cmd);
-
- return StopReportLog;
+ if (!bp->message().isEmpty()) {
+ showMessage(bp->message() + '\n', AppOutput);
+ showMessage(bp->message(), LogMisc);
+ }
+ // Trace point? Just report.
+ if (bp->isTracepoint()) {
+ *message = msgTracePointTriggered(bp, displayName, QString::number(threadId));
+ return StopReportLog|StopIgnoreContinue;
+ }
+ // Trigger evaluation of BP expression unless we are already in the response.
+ if (!conditionalBreakPointTriggered && !bp->condition().isEmpty()) {
+ *message = msgCheckingConditionalBreakPoint(bp, displayName, QString::number(threadId));
+ QString args = bp->condition();
+ if (args.contains(' ') && !args.startsWith('"')) {
+ args.prepend('"');
+ args.append('"');
}
- } else {
- bp = Breakpoint();
+ DebuggerCommand cmd("expression", ExtensionCommand);
+ cmd.args = args;
+ cmd.callback = [this, bp, stopReason](const DebuggerResponse &response) {
+ handleExpression(response, bp, stopReason);
+ };
+ runCommand(cmd);
+
+ return StopReportLog;
}
+
+ QString tid = QString::number(threadId);
+ if (bp->type() == WatchpointAtAddress)
+ *message = bp->msgWatchpointByAddressTriggered(bp->address(), tid);
+ else if (bp->type() == WatchpointAtExpression)
+ *message = bp->msgWatchpointByExpressionTriggered(bp->expression(), tid);
+ else
+ *message = bp->msgBreakpointTriggered(tid);
+ rc |= StopReportStatusMessage|StopNotifyStop;
}
- QString tid = QString::number(threadId);
- if (bp.type() == WatchpointAtAddress)
- *message = bp.msgWatchpointByAddressTriggered(number, bp.address(), tid);
- else if (bp.type() == WatchpointAtExpression)
- *message = bp.msgWatchpointByExpressionTriggered(number, bp.expression(), tid);
- else
- *message = bp.msgBreakpointTriggered(number, tid);
- rc |= StopReportStatusMessage|StopNotifyStop;
return rc;
}
if (reason == "exception") {
@@ -1881,11 +1878,11 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
showMessage(stopReason["threaderror"].data(), LogError);
}
// Fire off remaining commands asynchronously
- if (!m_pendingBreakpointMap.isEmpty() && !m_pendingSubBreakpointMap.isEmpty())
+ if (!m_pendingBreakpointMap.isEmpty())
listBreakpoints();
- if (Internal::isRegistersWindowVisible())
+ if (isRegistersWindowVisible())
reloadRegisters();
- if (Internal::isModulesWindowVisible())
+ if (isModulesWindowVisible())
reloadModules();
}
// After the sequence has been sent off and CDB is pondering the commands,
@@ -1894,7 +1891,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
showStoppedByExceptionMessageBox(exceptionBoxMessage);
}
-void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const BreakpointModelId &bpId)
+void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const Breakpoint &bp)
{
const QStringList reply = response.data.data().split('\n');
if (reply.isEmpty())
@@ -1913,16 +1910,19 @@ void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const Breakp
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::operator QString (__cdecl*)(void) (000007f6`be2f27b0)
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::<helper_func_vectorcall> (000007f6`be2f27d0)
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::operator QString (__vectorcall*)(void) (000007f6`be2f2850)
- // Ambiguous symbol error at '`untitled2!C:\dev\src\tmp\untitled2\main.cpp:18`'
+ // Ambiguous symbol error at '`untitled2!C:\dev\src\tmp\unttitled2\main.cpp:18`'
// ^ Extra character error in 'bu1004 `untitled2!C:\dev\src\tmp\untitled2\main.cpp:18`'
- if (!bpId.isValid())
+ // Happens regularly for Run to Line and Jump to Line.
+ if (!bp)
return;
- Breakpoint bp = breakHandler()->breakpointById(bpId);
+
// add break point for every match
+ const int parentResponseId = bp->responseId().toInt();
quint16 subBreakPointID = 0;
+ const QLatin1String matchPrefix("Matched: ");
for (auto line = reply.constBegin(), end = reply.constEnd(); line != end; ++line) {
- if (!line->startsWith("Matched: "))
+ if (!line->startsWith(matchPrefix))
continue;
const int addressStartPos = line->lastIndexOf('(') + 1;
const int addressEndPos = line->indexOf(')', addressStartPos);
@@ -1936,16 +1936,25 @@ void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const Breakp
if (!ok)
continue;
- BreakpointModelId id(bpId.majorPart(), ++subBreakPointID);
- BreakpointResponse res = bp.response();
- res.type = BreakpointByAddress;
- res.address = address;
- m_insertSubBreakpointMap.insert(id, res);
+ ++subBreakPointID;
+ const QString responseId(QString::number(parentResponseId + subBreakPointID));
+ SubBreakpoint sub = bp->findOrCreateSubBreakpoint(responseId);
+ sub->responseId = responseId;
+ sub->params = bp->parameters();
+ sub->params.type = BreakpointByAddress;
+ sub->params.address = address;
+ QString functionName(line->mid(matchPrefix.size(),
+ addressStartPos - 1 - matchPrefix.size()));
+ const int functionStart = functionName.indexOf('!') + 1;
+ const int functionOffset = functionName.lastIndexOf('+');
+ if (functionOffset > 0)
+ functionName.truncate(functionOffset);
+ if (functionStart > 0)
+ functionName = functionName.mid(functionStart);
+ sub->params.functionName = functionName;
+ sub->displayName = bp->displayName() + '.' + QString::number(subBreakPointID);
+ runCommand({cdbAddBreakpointCommand(sub->params, m_sourcePathMappings, sub->responseId, false), NoFlags});
}
- if (subBreakPointID == 0)
- return;
-
- attemptBreakpointSynchronization();
}
void CdbEngine::handleCheckWow64(const DebuggerResponse &response, const GdbMi &stack)
@@ -2413,10 +2422,10 @@ bool CdbEngine::stateAcceptsBreakpointChanges() const
return false;
}
-bool CdbEngine::acceptsBreakpoint(Breakpoint bp) const
+bool CdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
- if (bp.parameters().isCppBreakpoint()) {
- switch (bp.type()) {
+ if (bp.isCppBreakpoint()) {
+ switch (bp.type) {
case UnknownBreakpointType:
case LastBreakpointType:
case BreakpointAtFork:
@@ -2490,139 +2499,90 @@ unsigned BreakpointCorrectionContext::fixLineNumber(const QString &fileName,
return correctedLine;
}
-void CdbEngine::attemptBreakpointSynchronization()
+void CdbEngine::insertBreakpoint(const Breakpoint &bp)
+{
+ BreakpointParameters parameters = bp->requestedParameters();
+ const auto handleBreakInsertCB = [this, bp](const DebuggerResponse &r) { handleBreakInsert(r, bp); };
+ BreakpointParameters response = parameters;
+ auto responseId = QString::number(breakPointIdToCdbId(bp));
+ QScopedPointer<BreakpointCorrectionContext> lineCorrection(
+ new BreakpointCorrectionContext(m_codeModelSnapshot, CppTools::CppModelManager::instance()->workingCopy()));
+ if (!m_autoBreakPointCorrection
+ && parameters.type == BreakpointByFileAndLine
+ && boolSetting(CdbBreakPointCorrection)) {
+ response.lineNumber = int(lineCorrection->fixLineNumber(
+ parameters.fileName, unsigned(parameters.lineNumber)));
+ QString cmd = cdbAddBreakpointCommand(response, m_sourcePathMappings, responseId, false);
+ runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
+ } else {
+ QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, responseId, false);
+ runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
+ }
+ if (!parameters.enabled)
+ runCommand({"bd " + responseId, NoFlags});
+ // Ensure enabled/disabled is correct in handler and line number is there.
+ bp->setParameters(response);
+ bp->setResponseId(responseId);
+ bp->setDisplayName(QString::number(bp->modelId()));
+ notifyBreakpointInsertProceeding(bp);
+ notifyBreakpointInsertOk(bp);
+ m_pendingBreakpointMap.insert(bp);
+ if (debugBreakpoints)
+ qDebug("Adding %d %s\n", bp->modelId(), qPrintable(response.toString()));
+ listBreakpoints();
+}
+
+void CdbEngine::removeBreakpoint(const Breakpoint &bp)
{
- if (debug)
- qDebug("attemptBreakpointSynchronization in %s", qPrintable(stateName(state())));
- // Check if there is anything to be done at all.
- BreakHandler *handler = breakHandler();
- // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
- for (Breakpoint bp : handler->unclaimedBreakpoints())
- if (acceptsBreakpoint(bp))
- bp.setEngine(this);
-
- // Quick check: is there a need to change something? - Populate module cache
- bool changed = !m_insertSubBreakpointMap.isEmpty();
- const Breakpoints bps = handler->engineBreakpoints(this);
- if (!changed) {
- for (Breakpoint bp : bps) {
- switch (bp.state()) {
- case BreakpointInsertRequested:
- case BreakpointRemoveRequested:
- case BreakpointChangeRequested:
- changed = true;
- break;
- case BreakpointInserted: {
- // Collect the new modules matching the files.
- // In the future, that information should be obtained from the build system.
- const BreakpointParameters &data = bp.parameters();
- if (data.type == BreakpointByFileAndLine && !data.module.isEmpty())
- m_fileNameModuleHash.insert(data.fileName, data.module);
- }
- break;
- default:
- break;
- }
- }
- }
+ runCommand({cdbClearBreakpointCommand(bp), NoFlags});
+ notifyBreakpointRemoveProceeding(bp);
+ notifyBreakpointRemoveOk(bp);
+ m_pendingBreakpointMap.remove(bp);
+}
- if (debugBreakpoints)
- qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d",
- elapsedLogTime(), m_accessible, qPrintable(stateName(state())), bps.size(), changed);
- if (!changed)
- return;
+static QString enableBreakpointCommand(const QString &responseId, bool on)
+{
+ const QString command(on ? QString("be") : QString("bd"));
+ return command + ' ' + responseId;
+}
- // Add/Change breakpoints and store pending ones in map, since
- // Breakhandler::setResponse() on pending breakpoints clears the pending flag.
- // handleBreakPoints will the complete that information and set it on the break handler.
- bool addedChanged = false;
- QScopedPointer<BreakpointCorrectionContext> lineCorrection;
- for (Breakpoint bp : bps) {
- BreakpointParameters parameters = bp.parameters();
- BreakpointModelId id = bp.id();
- const auto handleBreakInsertCB = [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); };
- BreakpointResponse response;
- response.fromParameters(parameters);
- response.id = BreakpointResponseId(id.majorPart(), id.minorPart());
- // If we encountered that file and have a module for it: Add it.
- if (parameters.type == BreakpointByFileAndLine && parameters.module.isEmpty()) {
- const QHash<QString, QString>::const_iterator it = m_fileNameModuleHash.constFind(parameters.fileName);
- if (it != m_fileNameModuleHash.constEnd())
- parameters.module = it.value();
- }
- switch (bp.state()) {
- case BreakpointInsertRequested:
- if (!m_autoBreakPointCorrection
- && parameters.type == BreakpointByFileAndLine
- && boolSetting(CdbBreakPointCorrection)) {
- if (lineCorrection.isNull())
- lineCorrection.reset(new BreakpointCorrectionContext(m_codeModelSnapshot,
- CppTools::CppModelManager::instance()->workingCopy()));
- response.lineNumber = int(lineCorrection->fixLineNumber(
- parameters.fileName, unsigned(parameters.lineNumber)));
- QString cmd = cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false);
- runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
- } else {
- QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false);
- runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
- }
- if (!parameters.enabled)
- runCommand({"bd " + QString::number(breakPointIdToCdbId(id)), NoFlags});
- bp.notifyBreakpointInsertProceeding();
- bp.notifyBreakpointInsertOk();
- m_pendingBreakpointMap.insert(id, response);
- addedChanged = true;
- // Ensure enabled/disabled is correct in handler and line number is there.
- bp.setResponse(response);
- if (debugBreakpoints)
- qDebug("Adding %d %s\n", id.toInternalId(),
- qPrintable(response.toString()));
- break;
- case BreakpointChangeRequested:
- bp.notifyBreakpointChangeProceeding();
- if (debugBreakpoints)
- qDebug("Changing %d:\n %s\nTo %s\n", id.toInternalId(),
- qPrintable(bp.response().toString()),
- qPrintable(parameters.toString()));
- if (parameters.enabled != bp.response().enabled) {
- // Change enabled/disabled breakpoints without triggering update.
- if (parameters.enabled)
- runCommand({"be " + QString::number(breakPointIdToCdbId(id)), NoFlags});
- else
- runCommand({"bd " + QString::number(breakPointIdToCdbId(id)), NoFlags});
- response.pending = false;
- response.enabled = parameters.enabled;
- bp.setResponse(response);
- } else {
- // Delete and re-add, triggering update
- addedChanged = true;
- runCommand({cdbClearBreakpointCommand(id), NoFlags});
- QString cmd(cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false));
- runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
- m_pendingBreakpointMap.insert(id, response);
- }
- bp.notifyBreakpointChangeOk();
- break;
- case BreakpointRemoveRequested:
- runCommand({cdbClearBreakpointCommand(id), NoFlags});
- bp.notifyBreakpointRemoveProceeding();
- bp.notifyBreakpointRemoveOk();
- m_pendingBreakpointMap.remove(id);
- break;
- default:
- break;
- }
- }
- foreach (BreakpointModelId id, m_insertSubBreakpointMap.keys()) {
- addedChanged = true;
- const BreakpointResponse &response = m_insertSubBreakpointMap.value(id);
- runCommand({cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false), NoFlags});
- m_insertSubBreakpointMap.remove(id);
- m_pendingSubBreakpointMap.insert(id, response);
- }
- // List breakpoints and send responses
- if (addedChanged)
+void CdbEngine::updateBreakpoint(const Breakpoint &bp)
+{
+ BreakpointParameters parameters = bp->requestedParameters();
+ const auto handleBreakInsertCB = [this, bp](const DebuggerResponse &r) { handleBreakInsert(r, bp); };
+ BreakpointParameters response = parameters;
+ auto responseId = QString::number(breakPointIdToCdbId(bp));
+ notifyBreakpointChangeProceeding(bp);
+ if (debugBreakpoints)
+ qDebug("Changing %d:\n %s\nTo %s\n", bp->modelId(),
+ qPrintable(bp->parameters().toString()),
+ qPrintable(parameters.toString()));
+ if (parameters.enabled != bp->isEnabled()) {
+ // Change enabled/disabled breakpoints without triggering update.
+ bp->forFirstLevelChildren([this, parameters](SubBreakpointItem *sbp){
+ breakHandler()->requestSubBreakpointEnabling({sbp}, parameters.enabled);
+ });
+ if (!bp->hasChildren())
+ runCommand({enableBreakpointCommand(bp->responseId(), parameters.enabled), NoFlags});
+ response.pending = false;
+ response.enabled = parameters.enabled;
+ bp->setParameters(response);
+ } else {
+ // Delete and re-add, triggering update
+ runCommand({cdbClearBreakpointCommand(bp), NoFlags});
+ QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, responseId, false);
+ runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
+ m_pendingBreakpointMap.insert(bp);
listBreakpoints();
+ }
+ notifyBreakpointChangeOk(bp);
+}
+
+void CdbEngine::enableSubBreakpoint(const SubBreakpoint &sbp, bool on)
+{
+ runCommand({enableBreakpointCommand(sbp->responseId, on), NoFlags});
+ if (on && !sbp->breakpoint()->isEnabled())
+ sbp->breakpoint()->setEnabled(true);
}
// Pass a file name through source mapping and normalize upper/lower case (for the editor
@@ -2852,7 +2812,7 @@ void CdbEngine::handleStackTrace(const DebuggerResponse &response)
}
}
-void CdbEngine::handleExpression(const DebuggerResponse &response, BreakpointModelId id, const GdbMi &stopReason)
+void CdbEngine::handleExpression(const DebuggerResponse &response, const Breakpoint &bp, const GdbMi &stopReason)
{
int value = 0;
if (response.resultClass == ResultDone)
@@ -2862,9 +2822,9 @@ void CdbEngine::handleExpression(const DebuggerResponse &response, BreakpointMod
// Is this a conditional breakpoint?
const QString message = value ?
tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
- arg(value).arg(id.toString()) :
+ arg(value).arg(bp->displayName()) :
tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
- arg(id.toString());
+ arg(bp->displayName());
showMessage(message, LogMisc);
// Stop if evaluation is true, else continue
if (value)
@@ -2905,10 +2865,9 @@ void CdbEngine::handleWidgetAt(const DebuggerResponse &response)
m_watchPointX = m_watchPointY = 0;
}
-static inline void formatCdbBreakPointResponse(BreakpointModelId id, const BreakpointResponse &r,
- QTextStream &str)
+static void formatCdbBreakPointResponse(int modelId, const QString &responseId, const BreakpointParameters &r, QTextStream &str)
{
- str << "Obtained breakpoint " << id << " (#" << r.id.majorPart() << ')';
+ str << "Obtained breakpoint " << modelId << " (#" << responseId << ')';
if (r.pending) {
str << ", pending";
} else {
@@ -2946,46 +2905,62 @@ void CdbEngine::handleBreakPoints(const DebuggerResponse &response)
QTextStream str(&message);
BreakHandler *handler = breakHandler();
foreach (const GdbMi &breakPointG, response.data.children()) {
- BreakpointResponse reportedResponse;
+ // Might not be valid if there is not id
+ const QString responseId = breakPointG["id"].data();
+ BreakpointParameters reportedResponse;
parseBreakPoint(breakPointG, &reportedResponse);
if (debugBreakpoints)
- qDebug(" Parsed %d: pending=%d %s\n", reportedResponse.id.majorPart(),
+ qDebug(" Parsed %s: pending=%d %s\n", qPrintable(responseId),
reportedResponse.pending,
qPrintable(reportedResponse.toString()));
- if (reportedResponse.id.isValid() && !reportedResponse.pending) {
- Breakpoint bp = handler->findBreakpointByResponseId(reportedResponse.id);
+ if (!responseId.isEmpty() && !reportedResponse.pending) {
+ Breakpoint bp = handler->findBreakpointByResponseId(responseId);
if (!bp && reportedResponse.type == BreakpointByFunction)
continue; // Breakpoints from options, CrtDbgReport() and others.
- QTC_ASSERT(bp, continue);
- const auto it = m_pendingBreakpointMap.find(bp.id());
- const auto subIt = m_pendingSubBreakpointMap.find(
- BreakpointModelId(reportedResponse.id.majorPart(),
- reportedResponse.id.minorPart()));
- if (it != m_pendingBreakpointMap.end() || subIt != m_pendingSubBreakpointMap.end()) {
+
+ if (bp) {
+ if (!bp->isPending())
+ continue;
+ QTC_ASSERT(m_pendingBreakpointMap.contains(bp), continue);
// Complete the response and set on handler.
- BreakpointResponse currentResponse = it != m_pendingBreakpointMap.end()
- ? it.value()
- : subIt.value();
- currentResponse.id = reportedResponse.id;
+ BreakpointParameters currentResponse = bp->parameters();
currentResponse.address = reportedResponse.address;
currentResponse.module = reportedResponse.module;
currentResponse.pending = reportedResponse.pending;
currentResponse.enabled = reportedResponse.enabled;
currentResponse.fileName = reportedResponse.fileName;
currentResponse.lineNumber = reportedResponse.lineNumber;
- formatCdbBreakPointResponse(bp.id(), currentResponse, str);
+ formatCdbBreakPointResponse(bp->modelId(), responseId, currentResponse, str);
if (debugBreakpoints)
- qDebug(" Setting for %d: %s\n", currentResponse.id.majorPart(),
+ qDebug(" Setting for %s: %s\n", qPrintable(responseId),
qPrintable(currentResponse.toString()));
- if (it != m_pendingBreakpointMap.end()) {
- bp.setResponse(currentResponse);
- m_pendingBreakpointMap.erase(it);
- }
- if (subIt != m_pendingSubBreakpointMap.end()) {
- bp.insertSubBreakpoint(currentResponse);
- m_pendingSubBreakpointMap.erase(subIt);
- }
+ bp->setParameters(currentResponse);
+ m_pendingBreakpointMap.remove(bp);
+ continue;
+ }
+ SubBreakpoint sub = handler->findSubBreakpointByResponseId(responseId);
+ if (sub) {
+ BreakpointParameters currentResponse = sub->params;
+ currentResponse.address = reportedResponse.address;
+ currentResponse.module = reportedResponse.module;
+ currentResponse.pending = reportedResponse.pending;
+ currentResponse.enabled = reportedResponse.enabled;
+ currentResponse.fileName = reportedResponse.fileName;
+ currentResponse.lineNumber = reportedResponse.lineNumber;
+ Breakpoint bp = sub->breakpoint();
+ QTC_ASSERT(bp, continue);
+ formatCdbBreakPointResponse(bp->modelId(), responseId, currentResponse, str);
+ m_pendingBreakpointMap.remove(bp);
+ if (bp->isPending() && !reportedResponse.pending)
+ bp->setPending(false);
+ if (debugBreakpoints)
+ qDebug(" Setting for %s: %s\n", qPrintable(responseId),
+ qPrintable(currentResponse.toString()));
+// SubBreakpointItem *loc = bp->findOrCreateSubBreakpoint(reportedResponse.responseId);
+ sub->setParameters(currentResponse);
+ continue;
}
+ QTC_ASSERT(false, qDebug() << "bp not found in either of the pending maps");
} // not pending reported
} // foreach
if (m_pendingBreakpointMap.empty())
diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h
index 2ef4c3c876..cfc822c658 100644
--- a/src/plugins/debugger/cdb/cdbengine.h
+++ b/src/plugins/debugger/cdb/cdbengine.h
@@ -52,12 +52,8 @@ public:
explicit CdbEngine();
~CdbEngine() override;
- // Factory function that returns 0 if the debug engine library cannot be found.
-
bool canHandleToolTip(const DebuggerToolTipContext &context) const override;
- DebuggerEngine *cppEngine() override { return this; }
-
void setupEngine() override;
void runEngine() override;
void shutdownInferior() override;
@@ -81,14 +77,18 @@ public:
void executeRunToFunction(const QString &functionName) override;
void executeJumpToLine(const ContextData &data) override;
void assignValueInDebugger(WatchItem *w, const QString &expr, const QVariant &value) override;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override;
+ void executeDebuggerCommand(const QString &command) override;
void activateFrame(int index) override;
void selectThread(ThreadId threadId) override;
bool stateAcceptsBreakpointChanges() const override;
- bool acceptsBreakpoint(Breakpoint bp) const override;
- void attemptBreakpointSynchronization() override;
+ bool acceptsBreakpoint(const BreakpointParameters &params) const override;
+
+ void insertBreakpoint(const Breakpoint &bp) override;
+ void removeBreakpoint(const Breakpoint &bp) override;
+ void updateBreakpoint(const Breakpoint &bp) override;
+ void enableSubBreakpoint(const SubBreakpoint &sbp, bool on) override;
void fetchDisassembler(DisassemblerAgent *agent) override;
void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
@@ -119,8 +119,7 @@ private:
void handleDoInterruptInferior(const QString &errorMessage);
- using PendingBreakPointMap = QHash<BreakpointModelId, BreakpointResponse>;
- using SourcePathMapping = QPair<QString, QString>;
+ typedef QPair<QString, QString> SourcePathMapping;
struct NormalizedSourceFileName // Struct for caching mapped/normalized source files.
{
NormalizedSourceFileName(const QString &fn = QString(), bool e = false) : fileName(fn), exists(e) {}
@@ -176,10 +175,10 @@ private:
void handleStackTrace(const DebuggerResponse &);
void handleRegisters(const DebuggerResponse &);
void handleJumpToLineAddressResolution(const DebuggerResponse &response, const ContextData &context);
- void handleExpression(const DebuggerResponse &command, BreakpointModelId id, const GdbMi &stopReason);
+ void handleExpression(const DebuggerResponse &command, const Breakpoint &bp, const GdbMi &stopReason);
void handleResolveSymbol(const DebuggerResponse &command, const QString &symbol, DisassemblerAgent *agent);
void handleResolveSymbolHelper(const QList<quint64> &addresses, DisassemblerAgent *agent);
- void handleBreakInsert(const DebuggerResponse &response, const BreakpointModelId &bpId);
+ void handleBreakInsert(const DebuggerResponse &response, const Breakpoint &bp);
void handleCheckWow64(const DebuggerResponse &response, const GdbMi &stack);
void ensureUsing32BitStackInWow64(const DebuggerResponse &response, const GdbMi &stack);
void handleSwitchWow64Stack(const DebuggerResponse &response);
@@ -232,11 +231,8 @@ private:
bool m_sourceStepInto = false;
int m_watchPointX = 0;
int m_watchPointY = 0;
- PendingBreakPointMap m_pendingBreakpointMap;
- PendingBreakPointMap m_insertSubBreakpointMap;
- PendingBreakPointMap m_pendingSubBreakpointMap;
+ QSet<Breakpoint> m_pendingBreakpointMap;
bool m_autoBreakPointCorrection = false;
- QHash<QString, QString> m_fileNameModuleHash;
QMultiHash<QString, quint64> m_symbolAddressCache;
bool m_ignoreCdbOutput = false;
QList<InterruptCallback> m_interrupCallbacks;
diff --git a/src/plugins/debugger/cdb/cdbparsehelpers.cpp b/src/plugins/debugger/cdb/cdbparsehelpers.cpp
index fccd1c0086..415d9c2de7 100644
--- a/src/plugins/debugger/cdb/cdbparsehelpers.cpp
+++ b/src/plugins/debugger/cdb/cdbparsehelpers.cpp
@@ -27,6 +27,7 @@
#include "stringinputstream.h"
+#include <debugger/breakhandler.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/disassemblerlines.h>
#include <debugger/shared/hostutils.h>
@@ -77,14 +78,14 @@ QString cdbSourcePathMapping(QString fileName,
// Determine file name to be used for breakpoints. Convert to native and, unless short path
// is set, perform reverse lookup in the source path mappings.
-static inline QString cdbBreakPointFileName(const BreakpointParameters &bp,
+static inline QString cdbBreakPointFileName(const BreakpointParameters &params,
const QList<QPair<QString, QString> > &sourcePathMapping)
{
- if (bp.fileName.isEmpty())
- return bp.fileName;
- if (bp.pathUsage == BreakpointUseShortPath)
- return Utils::FileName::fromString(bp.fileName).fileName();
- return cdbSourcePathMapping(QDir::toNativeSeparators(bp.fileName), sourcePathMapping, SourceToDebugger);
+ if (params.fileName.isEmpty())
+ return params.fileName;
+ if (params.pathUsage == BreakpointUseShortPath)
+ return Utils::FileName::fromString(params.fileName).fileName();
+ return cdbSourcePathMapping(QDir::toNativeSeparators(params.fileName), sourcePathMapping, SourceToDebugger);
}
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
@@ -127,69 +128,46 @@ static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
return p;
}
-int breakPointIdToCdbId(const BreakpointModelId &id)
+int breakPointIdToCdbId(const Breakpoint &bp)
{
- return cdbBreakPointStartId + id.majorPart() * cdbBreakPointIdMinorPart + id.minorPart();
+// return cdbBreakPointStartId + bp.majorPart() * cdbBreakPointIdMinorPart + bp.minorPart();
+ if (!bp->responseId().isEmpty())
+ return bp->responseId().toInt();
+ return cdbBreakPointStartId + bp->modelId() * cdbBreakPointIdMinorPart;
}
-template <class ModelId>
-inline ModelId cdbIdToBreakpointId(const int &id)
-{
- if (id >= cdbBreakPointStartId) {
- int major = (id - cdbBreakPointStartId) / cdbBreakPointIdMinorPart;
- int minor = id % cdbBreakPointIdMinorPart;
- if (minor)
- return ModelId(major, minor);
- else
- return ModelId(major);
- }
- return ModelId();
-}
-
-template <class ModelId>
-inline ModelId cdbIdToBreakpointId(const GdbMi &data)
-{
- if (data.isValid()) { // Might not be valid if there is not id
- bool ok;
- const int id = data.data().toInt(&ok);
- if (ok)
- return cdbIdToBreakpointId<ModelId>(id);
- }
- return ModelId();
-}
-
-BreakpointModelId cdbIdToBreakpointModelId(const GdbMi &id)
-{
- return cdbIdToBreakpointId<BreakpointModelId>(id);
-}
-
-BreakpointResponseId cdbIdToBreakpointResponseId(const GdbMi &id)
-{
- return cdbIdToBreakpointId<BreakpointResponseId>(id);
-}
+//static int cdbIdToBreakpointModel(int cdbid)
+//{
+// if (cdbid >= cdbBreakPointStartId) {
+// int major = (cdbid - cdbBreakPointStartId) / cdbBreakPointIdMinorPart;
+// int minor = cdbid % cdbBreakPointIdMinorPart;
+// (void) minor;
+// return major;
+// }
+// return 0;
+//}
QString cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
const QList<QPair<QString, QString> > &sourcePathMapping,
- BreakpointModelId id /* = BreakpointId() */,
+ const QString &responseId,
bool oneshot)
{
- const BreakpointParameters bp = fixWinMSVCBreakpoint(bpIn);
+ const BreakpointParameters params = fixWinMSVCBreakpoint(bpIn);
QString rc;
StringInputStream str(rc);
- if (bp.threadSpec >= 0)
- str << '~' << bp.threadSpec << ' ';
+ if (params.threadSpec >= 0)
+ str << '~' << params.threadSpec << ' ';
// Currently use 'bu' so that the offset expression (including file name)
// is kept when reporting back breakpoints (which is otherwise discarded
// when resolving).
- str << (bp.type == WatchpointAtAddress ? "ba" : "bu");
- if (id.isValid())
- str << breakPointIdToCdbId(id);
- str << ' ';
+ str << (params.type == WatchpointAtAddress ? "ba" : "bu")
+ << responseId
+ << ' ';
if (oneshot)
str << "/1 ";
- switch (bp.type) {
+ switch (params.type) {
case BreakpointAtFork:
case BreakpointAtExec:
case WatchpointAtExpression:
@@ -204,39 +182,41 @@ QString cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
QTC_ASSERT(false, return QString());
break;
case BreakpointByAddress:
- str << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
+ str << hex << hexPrefixOn << params.address << hexPrefixOff << dec;
break;
case BreakpointByFunction:
- if (!bp.module.isEmpty())
- str << bp.module << '!';
- str << bp.functionName;
+ if (!params.module.isEmpty())
+ str << params.module << '!';
+ str << params.functionName;
break;
case BreakpointByFileAndLine:
str << '`';
- if (!bp.module.isEmpty())
- str << bp.module << '!';
- str << cdbBreakPointFileName(bp, sourcePathMapping) << ':' << bp.lineNumber << '`';
+ if (!params.module.isEmpty())
+ str << params.module << '!';
+ str << cdbBreakPointFileName(params, sourcePathMapping) << ':' << params.lineNumber << '`';
break;
case WatchpointAtAddress: { // Read/write, no space here
- const unsigned size = bp.size ? bp.size : 1;
- str << 'r' << size << ' ' << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
+ const unsigned size = params.size ? params.size : 1;
+ str << 'r' << size << ' ' << hex << hexPrefixOn << params.address << hexPrefixOff << dec;
}
break;
}
- if (bp.ignoreCount)
- str << " 0n" << (bp.ignoreCount + 1);
+ if (params.ignoreCount)
+ str << " 0n" << (params.ignoreCount + 1);
// Condition currently unsupported.
- if (!bp.command.isEmpty())
- str << " \"" << bp.command << '"';
+ if (!params.command.isEmpty())
+ str << " \"" << params.command << '"';
return rc;
}
-QString cdbClearBreakpointCommand(const BreakpointModelId &id)
+QString cdbClearBreakpointCommand(const Breakpoint &bp)
{
- const int firstBreakPoint = breakPointIdToCdbId(id);
- if (id.isMinor())
- return "bc " + QString::number(firstBreakPoint);
+// FIME: Check
+// const int firstBreakPoint = breakPointIdToCdbId(id);
+// if (id.isMinor())
+// return "bc " + QString::number(firstBreakPoint);
// If this is a major break point we also want to delete all sub break points
+ const int firstBreakPoint = cdbBreakPointStartId + bp->modelId() * cdbBreakPointIdMinorPart;
const int lastBreakPoint = firstBreakPoint + cdbBreakPointIdMinorPart - 1;
return "bc " + QString::number(firstBreakPoint) + '-' + QString::number(lastBreakPoint);
}
@@ -270,14 +250,11 @@ static inline bool gdbmiChildToBool(const GdbMi &parent, const char *childName,
// Parse extension command listing breakpoints.
// Note that not all fields are returned, since file, line, function are encoded
// in the expression (that is in addition deleted on resolving for a bp-type breakpoint).
-void parseBreakPoint(const GdbMi &gdbmi, BreakpointResponse *r,
+void parseBreakPoint(const GdbMi &gdbmi, BreakpointParameters *r,
QString *expression /* = 0 */)
{
gdbmiChildToBool(gdbmi, "enabled", &(r->enabled));
gdbmiChildToBool(gdbmi, "deferred", &(r->pending));
- r->id = BreakpointResponseId();
- // Might not be valid if there is not id
- r->id = cdbIdToBreakpointResponseId(gdbmi["id"]);
const GdbMi moduleG = gdbmi["module"];
if (moduleG.isValid())
r->module = moduleG.data();
diff --git a/src/plugins/debugger/cdb/cdbparsehelpers.h b/src/plugins/debugger/cdb/cdbparsehelpers.h
index f9973c4de8..73b480b69e 100644
--- a/src/plugins/debugger/cdb/cdbparsehelpers.h
+++ b/src/plugins/debugger/cdb/cdbparsehelpers.h
@@ -25,7 +25,7 @@
#pragma once
-#include <debugger/breakpoint.h>
+#include <debugger/breakhandler.h>
#include <QPair>
@@ -36,7 +36,6 @@ QT_END_NAMESPACE
namespace Debugger {
namespace Internal {
-class BreakpointData;
class BreakpointParameters;
struct ThreadData;
class Register;
@@ -54,19 +53,17 @@ QString cdbSourcePathMapping(QString fileName,
enum { cdbBreakPointStartId = 100000,
cdbBreakPointIdMinorPart = 100};
-int breakPointIdToCdbId(const BreakpointModelId &id);
-BreakpointModelId cdbIdToBreakpointModelId(const GdbMi &id);
-BreakpointResponseId cdbIdToBreakpointResponseId(const GdbMi &id);
+int breakPointIdToCdbId(const Breakpoint &bp);
// Convert breakpoint in CDB syntax (applying source path mappings using native paths).
QString cdbAddBreakpointCommand(const BreakpointParameters &d,
const QList<QPair<QString, QString> > &sourcePathMapping,
- BreakpointModelId id = BreakpointModelId(quint16(-1)), bool oneshot = false);
-QString cdbClearBreakpointCommand(const BreakpointModelId &id);
+ const QString &responseId = QString(), bool oneshot = false);
+QString cdbClearBreakpointCommand(const Breakpoint &bp);
// Parse extension command listing breakpoints.
// Note that not all fields are returned, since file, line, function are encoded
// in the expression (that is in addition deleted on resolving for a bp-type breakpoint).
-void parseBreakPoint(const GdbMi &gdbmi, BreakpointResponse *r, QString *expression = nullptr);
+void parseBreakPoint(const GdbMi &gdbmi, BreakpointParameters *r, QString *expression = nullptr);
// Write memory (f ...).
QString cdbWriteMemoryCommand(quint64 addr, const QByteArray &data);
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
index f5a34aa0d5..7b7b97b280 100644
--- a/src/plugins/debugger/debugger.pro
+++ b/src/plugins/debugger/debugger.pro
@@ -41,7 +41,6 @@ HEADERS += \
procinterrupt.h \
registerhandler.h \
snapshothandler.h \
- snapshotwindow.h \
sourceagent.h \
sourcefileshandler.h \
sourceutils.h \
@@ -89,7 +88,6 @@ SOURCES += \
procinterrupt.cpp \
registerhandler.cpp \
snapshothandler.cpp \
- snapshotwindow.cpp \
sourceagent.cpp \
sourcefileshandler.cpp \
sourceutils.cpp \
diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs
index 4f53499ee7..674e3c7ff9 100644
--- a/src/plugins/debugger/debugger.qbs
+++ b/src/plugins/debugger/debugger.qbs
@@ -72,7 +72,6 @@ Project {
"procinterrupt.cpp", "procinterrupt.h",
"registerhandler.cpp", "registerhandler.h",
"snapshothandler.cpp", "snapshothandler.h",
- "snapshotwindow.cpp", "snapshotwindow.h",
"sourceagent.cpp", "sourceagent.h",
"sourcefileshandler.cpp", "sourcefileshandler.h",
"sourceutils.cpp", "sourceutils.h",
@@ -143,7 +142,6 @@ Project {
prefix: "qml/"
files: [
"interactiveinterpreter.cpp", "interactiveinterpreter.h",
- "qmlcppengine.cpp", "qmlcppengine.h",
"qmlengine.cpp", "qmlengine.h",
"qmlengineutils.cpp", "qmlengineutils.h",
"qmlinspectoragent.cpp", "qmlinspectoragent.h",
diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
index d148fc9202..cfb3514683 100644
--- a/src/plugins/debugger/debuggeractions.cpp
+++ b/src/plugins/debugger/debuggeractions.cpp
@@ -101,8 +101,12 @@ void GlobalDebuggerOptions::fromSettings()
//
//////////////////////////////////////////////////////////////////////////
+static DebuggerSettings *theDebuggerSettings = nullptr;
+
DebuggerSettings::DebuggerSettings()
{
+ theDebuggerSettings = this;
+
const QString debugModeGroup = QLatin1String(debugModeSettingsGroupC);
const QString cdbSettingsGroup = QLatin1String(cdbSettingsGroupC);
@@ -580,6 +584,7 @@ DebuggerSettings::DebuggerSettings()
item->setText(tr("Enable Reverse Debugging"));
item->setCheckable(true);
item->setDefaultValue(false);
+ item->setIcon(Icons::REVERSE_MODE.icon());
insertItem(EnableReverseDebugging, item);
#ifdef Q_OS_WIN
@@ -693,10 +698,10 @@ SavedAction *DebuggerSettings::item(int code) const
return m_items.value(code, 0);
}
-QString DebuggerSettings::dump() const
+QString DebuggerSettings::dump()
{
QStringList settings;
- foreach (SavedAction *item, m_items) {
+ foreach (SavedAction *item, theDebuggerSettings->m_items) {
QString key = item->settingsKey();
if (!key.isEmpty()) {
const QString current = item->value().toString();
diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h
index 15f2e73d99..39d3571d45 100644
--- a/src/plugins/debugger/debuggeractions.h
+++ b/src/plugins/debugger/debuggeractions.h
@@ -61,7 +61,7 @@ public:
void insertItem(int code, Utils::SavedAction *item);
Utils::SavedAction *item(int code) const;
- QString dump() const;
+ static QString dump();
void readSettings();
void writeSettings() const;
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index f688662f65..f294555c7a 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -38,8 +38,8 @@ const char C_DEBUGMODE[] = "Debugger.DebugMode";
const char C_CPPDEBUGGER[] = "Gdb Debugger";
const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger";
-const char CppPerspectiveId[] = "Debugger.Perspective.Cpp";
-const char QmlPerspectiveId[] = "Debugger.Perspective.Qml";
+const char PRESET_PERSPRECTIVE_ID[] = "Debugger.Perspective.Preset";
+const char PERSPECTIVE_ID[] = "Debugger.Perspective";
// Menu Groups
const char G_GENERAL[] = "Debugger.Group.General";
diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h
index c9eb7c0f7e..3fd58068a1 100644
--- a/src/plugins/debugger/debuggercore.h
+++ b/src/plugins/debugger/debuggercore.h
@@ -27,6 +27,7 @@
#include "debuggerconstants.h"
+#include <coreplugin/id.h>
#include <projectexplorer/abi.h>
#include <QObject>
@@ -43,7 +44,10 @@ QT_END_NAMESPACE
namespace CPlusPlus { class Snapshot; }
-namespace Utils { class SavedAction; }
+namespace Utils {
+class BaseTreeView;
+class SavedAction;
+}
namespace Debugger {
@@ -51,12 +55,9 @@ class DebuggerRunTool;
namespace Internal {
-class BreakHandler;
-class DebuggerEngine;
class Symbol;
class Section;
class GlobalDebuggerOptions;
-class WatchTreeView;
enum TestCases
{
@@ -65,34 +66,14 @@ enum TestCases
};
// Some convenience.
-void updateState(DebuggerRunTool *runTool);
-void updateLocalsWindow(bool showReturn);
-bool hasSnapshots();
void openTextEditor(const QString &titlePattern, const QString &contents);
-// void runTest(const QString &fileName);
-void showMessage(const QString &msg, int channel, int timeout = -1);
-
-bool isReverseDebugging();
-void runControlStarted(DebuggerRunTool *runTool);
-void runControlFinished(DebuggerRunTool *runTool);
-void displayDebugger(DebuggerRunTool *runTool);
-void synchronizeBreakpoints();
-
-void saveModeToRestore();
QWidget *mainWindow();
-void raiseWatchersWindow();
-bool isRegistersWindowVisible();
-bool isModulesWindowVisible();
void showModuleSymbols(const QString &moduleName, const QVector<Internal::Symbol> &symbols);
void showModuleSections(const QString &moduleName, const QVector<Internal::Section> &sections);
-void openMemoryEditor();
-
-void setThreadBoxContents(const QStringList &list, int index);
QSharedPointer<Internal::GlobalDebuggerOptions> globalDebuggerOptions();
-WatchTreeView *inspectorView();
QVariant sessionValue(const QByteArray &name);
void setSessionValue(const QByteArray &name, const QVariant &value);
QVariant configValue(const QString &name);
@@ -105,9 +86,6 @@ bool boolSetting(int code);
QString stringSetting(int code);
QStringList stringListSetting(int code);
-BreakHandler *breakHandler();
-DebuggerEngine *currentEngine();
-
QMessageBox *showMessageBox(int icon, const QString &title,
const QString &text, int buttons = 0);
@@ -124,6 +102,7 @@ QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool c
QStringList qtBuildPaths();
void addDebugInfoTask(unsigned id, const QString &cmd);
+QWidget *addSearch(Utils::BaseTreeView *treeView);
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index c0618ee818..028fa92211 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -28,25 +28,34 @@
#include "debuggerinternalconstants.h"
#include "debuggeractions.h"
#include "debuggercore.h"
+#include "debuggerdialogs.h"
#include "debuggericons.h"
#include "debuggerruncontrol.h"
#include "debuggertooltipmanager.h"
+#include "analyzer/analyzermanager.h"
#include "breakhandler.h"
#include "disassembleragent.h"
+#include "localsandexpressionswindow.h"
#include "logwindow.h"
+#include "debuggermainwindow.h"
#include "memoryagent.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "sourcefileshandler.h"
#include "sourceutils.h"
#include "stackhandler.h"
+#include "stackwindow.h"
+#include "snapshothandler.h"
#include "terminal.h"
#include "threadshandler.h"
#include "watchhandler.h"
+#include "watchutils.h"
+#include "watchwindow.h"
#include "debugger/shared/peutils.h"
#include "console/console.h"
+#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>
@@ -59,18 +68,29 @@
#include <projectexplorer/taskhub.h>
#include <texteditor/texteditor.h>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/fontsettings.h>
+#include <utils/basetreeview.h>
#include <utils/fileinprojectfinder.h>
#include <utils/macroexpander.h>
#include <utils/processhandle.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/savedaction.h>
+#include <utils/styledbar.h>
+#include <utils/utilsicons.h>
+#include <QApplication>
+#include <QComboBox>
#include <QDebug>
-#include <QTimer>
-#include <QFileInfo>
#include <QDir>
+#include <QDockWidget>
+#include <QFileInfo>
+#include <QHeaderView>
+#include <QTextBlock>
+#include <QTimer>
+#include <QToolButton>
#include <QJsonArray>
#include <QJsonDocument>
@@ -113,6 +133,33 @@ QDebug operator<<(QDebug str, const DebuggerRunParameters &sp)
namespace Internal {
+static bool debuggerActionsEnabledHelper(DebuggerState state)
+{
+ switch (state) {
+ case InferiorRunOk:
+ case InferiorUnrunnable:
+ case InferiorStopOk:
+ return true;
+ case InferiorStopRequested:
+ case InferiorRunRequested:
+ case InferiorRunFailed:
+ case DebuggerNotReady:
+ case EngineSetupRequested:
+ case EngineSetupOk:
+ case EngineSetupFailed:
+ case EngineRunRequested:
+ case EngineRunFailed:
+ case InferiorStopFailed:
+ case InferiorShutdownRequested:
+ case InferiorShutdownFinished:
+ case EngineShutdownRequested:
+ case EngineShutdownFinished:
+ case DebuggerFinished:
+ return false;
+ }
+ return false;
+}
+
Location::Location(const StackFrame &frame, bool marker)
{
m_fileName = frame.file;
@@ -128,13 +175,22 @@ Location::Location(const StackFrame &frame, bool marker)
LocationMark::LocationMark(DebuggerEngine *engine, const FileName &file, int line)
: TextMark(file, line, Constants::TEXT_MARK_CATEGORY_LOCATION), m_engine(engine)
{
- setIcon(Icons::LOCATION.icon());
setPriority(TextMark::HighPriority);
+ updateIcon();
+}
+
+void LocationMark::updateIcon()
+{
+ const Icon *icon = &Icons::WATCHPOINT;
+ if (m_engine && EngineManager::currentEngine() == m_engine)
+ icon = m_engine->isReverseDebugging() ? &Icons::REVERSE_LOCATION : &Icons::LOCATION;
+ setIcon(icon->icon());
+ updateMarker();
}
bool LocationMark::isDraggable() const
{
- return m_engine->hasCapability(JumpToLineCapability);
+ return m_engine && m_engine->hasCapability(JumpToLineCapability);
}
void LocationMark::dragToLine(int line)
@@ -213,41 +269,108 @@ class DebuggerEnginePrivate : public QObject
public:
DebuggerEnginePrivate(DebuggerEngine *engine)
- : m_engine(engine),
- m_modulesHandler(engine),
- m_registerHandler(engine),
- m_sourceFilesHandler(engine),
- m_stackHandler(engine),
- m_threadsHandler(engine),
- m_watchHandler(engine),
- m_disassemblerAgent(engine)
+ : m_engine(engine),
+ m_breakHandler(engine),
+ m_modulesHandler(engine),
+ m_registerHandler(engine),
+ m_sourceFilesHandler(engine),
+ m_stackHandler(engine),
+ m_threadsHandler(engine),
+ m_watchHandler(engine),
+ m_disassemblerAgent(engine)
+ {
+ m_logWindow = new LogWindow(m_engine); // Needed before start()
+ m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT));
+ m_debuggerName = DebuggerEngine::tr("Debugger");
+
+ connect(action(EnableReverseDebugging), &SavedAction::valueChanged,
+ this, [this] { updateState(true); });
+ }
+
+
+ ~DebuggerEnginePrivate()
{
- connect(&m_locationTimer, &QTimer::timeout,
- this, &DebuggerEnginePrivate::resetLocation);
+ destroyPerspective();
+
+ delete m_logWindow;
+ delete m_breakWindow;
+ delete m_returnWindow;
+ delete m_localsWindow;
+ delete m_watchersWindow;
+ delete m_inspectorWindow;
+ delete m_registerWindow;
+ delete m_modulesWindow;
+ delete m_sourceFilesWindow;
+ delete m_stackWindow;
+ delete m_threadsWindow;
+
+ delete m_breakView;
+ delete m_returnView;
+ delete m_localsView;
+ delete m_watchersView;
+ delete m_inspectorView;
+ delete m_registerView;
+ delete m_modulesView;
+ delete m_sourceFilesView;
+ delete m_stackView;
+ delete m_threadsView;
}
- void doShutdownEngine();
- void doShutdownInferior();
+ void setupViews();
+
+ void destroyPerspective()
+ {
+ if (!m_perspective)
+ return;
+
+ EngineManager::unregisterEngine(m_engine);
+
+ // Give up ownership on claimed breakpoints.
+ m_breakHandler.releaseAllBreakpoints();
+ DebuggerToolTipManager::deregisterEngine(m_engine);
+ m_memoryAgents.handleDebuggerFinished();
+
+ m_perspective->destroy();
+ m_perspective = nullptr;
+
+ setBusyCursor(false);
+ }
+
+ void updateReturnViewHeader(int section, int, int newSize)
+ {
+ if (m_perspective && m_returnView && m_returnView->header())
+ m_returnView->header()->resizeSection(section, newSize);
+ }
+
+ void doShutdownEngine()
+ {
+ m_engine->setState(EngineShutdownRequested);
+ m_engine->startDying();
+ m_engine->showMessage("CALL: SHUTDOWN ENGINE");
+ m_engine->shutdownEngine();
+ }
+
+ void doShutdownInferior()
+ {
+ m_engine->setState(InferiorShutdownRequested);
+ //QTC_ASSERT(isMasterEngine(), return);
+ resetLocation();
+ m_engine->showMessage("CALL: SHUTDOWN INFERIOR");
+ m_engine->shutdownInferior();
+ }
void doFinishDebugger()
{
- QTC_ASSERT(state() == EngineShutdownFinished, qDebug() << state());
- m_engine->setState(DebuggerFinished);
+ QTC_ASSERT(m_state == EngineShutdownFinished, qDebug() << m_state);
resetLocation();
- if (isMasterEngine()) {
- if (m_runTool) {
- m_progress.setProgressValue(1000);
- m_progress.reportFinished();
- m_modulesHandler.removeAll();
- m_stackHandler.removeAll();
- m_threadsHandler.removeAll();
- m_watchHandler.cleanup();
- Internal::runControlFinished(m_runTool);
- m_runTool->reportStopped();
- m_runTool->appendMessage(tr("Debugging has finished"), NormalMessageFormat);
- m_runTool.clear();
- }
- }
+ m_progress.setProgressValue(1000);
+ m_progress.reportFinished();
+ m_modulesHandler.removeAll();
+ m_stackHandler.removeAll();
+ m_threadsHandler.removeAll();
+ m_watchHandler.cleanup();
+ m_engine->showMessage(tr("Debugger finished."), StatusBar);
+ m_engine->setState(DebuggerFinished); // Also destroys views.
}
void scheduleResetLocation()
@@ -272,13 +395,45 @@ public:
DebuggerToolTipManager::resetLocation();
}
+ void selectThread(int index)
+ {
+ ThreadId id = m_engine->threadsHandler()->threadAt(index);
+ m_engine->selectThread(id);
+ }
+
+ void handleOperateByInstructionTriggered(bool on)
+ {
+ // Go to source only if we have the file.
+ // if (DebuggerEngine *cppEngine = m_engine->cppEngine()) {
+ if (m_stackHandler.currentIndex() >= 0) {
+ const StackFrame frame = m_stackHandler.currentFrame();
+ if (on || frame.isUsable())
+ m_engine->gotoLocation(Location(frame, true));
+ }
+ // }
+ }
+
+ bool operatesByInstruction() const
+ {
+ return m_operateByInstructionAction.isChecked();
+ }
+
public:
- DebuggerState state() const { return m_state; }
- bool isMasterEngine() const { return m_engine->isMasterEngine(); }
+ void setInitialActionStates();
+ void setBusyCursor(bool on);
+ void cleanupViews();
+ void updateState(bool alsoUpdateCompanion);
+ void updateReverseActions();
DebuggerEngine *m_engine = nullptr; // Not owned.
- DebuggerEngine *m_masterEngine = nullptr; // Not owned
- QPointer<DebuggerRunTool> m_runTool; // Not owned.
+ QPointer<RunConfiguration> m_runConfiguration; // Not owned.
+ QString m_debuggerName;
+ Perspective *m_perspective = nullptr;
+ DebuggerRunParameters m_runParameters;
+ IDevice::ConstPtr m_device;
+
+ QPointer<DebuggerEngine> m_companionEngine;
+ bool m_isPrimaryEngine = true;
// The current state.
DebuggerState m_state = DebuggerNotReady;
@@ -286,6 +441,7 @@ public:
// Terminal m_terminal;
ProcessHandle m_inferiorPid;
+ BreakHandler m_breakHandler;
ModulesHandler m_modulesHandler;
RegisterHandler m_registerHandler;
SourceFilesHandler m_sourceFilesHandler;
@@ -305,8 +461,330 @@ public:
// Safety net to avoid infinite lookups.
QSet<QString> m_lookupRequests; // FIXME: Integrate properly.
QPointer<QWidget> m_alertBox;
+
+ QPointer<BaseTreeView> m_breakView;
+ QPointer<BaseTreeView> m_returnView;
+ QPointer<BaseTreeView> m_localsView;
+ QPointer<BaseTreeView> m_watchersView;
+ QPointer<WatchTreeView> m_inspectorView;
+ QPointer<BaseTreeView> m_registerView;
+ QPointer<BaseTreeView> m_modulesView;
+ QPointer<BaseTreeView> m_sourceFilesView;
+ QPointer<BaseTreeView> m_stackView;
+ QPointer<BaseTreeView> m_threadsView;
+ QPointer<QWidget> m_breakWindow;
+ QPointer<QWidget> m_returnWindow;
+ QPointer<QWidget> m_localsWindow;
+ QPointer<QWidget> m_watchersWindow;
+ QPointer<QWidget> m_inspectorWindow;
+ QPointer<QWidget> m_registerWindow;
+ QPointer<QWidget> m_modulesWindow;
+ QPointer<QWidget> m_sourceFilesWindow;
+ QPointer<QWidget> m_stackWindow;
+ QPointer<QWidget> m_threadsWindow;
+ QPointer<LogWindow> m_logWindow;
+ QPointer<LocalsAndInspectorWindow> m_localsAndInspectorWindow;
+
+ QPointer<QLabel> m_threadLabel;
+ QPointer<QComboBox> m_threadBox;
+
+ bool m_busy = false;
+ bool m_isDying = false;
+
+ QAction m_debugWithoutDeployAction;
+ QAction m_attachToQmlPortAction;
+ QAction m_attachToRemoteServerAction;
+ QAction m_startRemoteCdbAction;
+ QAction m_attachToCoreAction;
+ QAction m_detachAction;
+ OptionalAction m_continueAction{tr("Continue")};
+ QAction m_exitAction{tr("Stop Debugger")}; // On application output button if "Stop" is possible
+ OptionalAction m_interruptAction{tr("Interrupt")}; // On the fat debug button if "Pause" is possible
+ QAction m_abortAction{tr("Abort Debugging")};
+ QAction m_stepIntoAction{tr("Step Into")};
+ QAction m_stepOutAction{tr("Step Out")};
+ QAction m_runToLineAction{tr("Run to Line")}; // In the debug menu
+ QAction m_runToSelectedFunctionAction{tr("Run to Selected Function")};
+ QAction m_jumpToLineAction{tr("Jump to Line")};
+ // In the Debug menu.
+ QAction m_returnFromFunctionAction{tr("Immediately Return From Inner Function")};
+ QAction m_stepOverAction{tr("Step Over")};
+ QAction m_watchAction{tr("Add Expression Evaluator")};
+ QAction m_breakAction{tr("Toggle Breakpoint")};
+ QAction m_resetAction{tr("Restart Debugging")};
+ OptionalAction m_operateByInstructionAction{tr("Operate by Instruction")};
+ QAction m_recordForReverseOperationAction{tr("Record information to allpow reversal of Direction")};
+ OptionalAction m_operateInReverseDirectionAction{tr("Reverse Direction")};
+ OptionalAction m_snapshotAction{tr("Take Snapshot of Process State")};
+
+ QPointer<TerminalRunner> m_terminalRunner;
};
+void DebuggerEnginePrivate::setupViews()
+{
+ const DebuggerRunParameters &rp = m_engine->runParameters();
+
+ QTC_CHECK(!m_perspective);
+ const QString id = Constants::PERSPECTIVE_ID + m_debuggerName + rp.displayName;
+ m_perspective = new Perspective(id, m_engine->displayName());
+
+ m_progress.setProgressRange(0, 1000);
+ FutureProgress *fp = ProgressManager::addTask(m_progress.future(),
+ tr("Launching Debugger"), "Debugger.Launcher");
+ connect(fp, &FutureProgress::canceled, m_engine, &DebuggerEngine::quitDebugger);
+ fp->setKeepOnFinish(FutureProgress::HideOnFinish);
+ m_progress.reportStarted();
+
+ m_inferiorPid = rp.attachPID.isValid() ? rp.attachPID : ProcessHandle();
+// if (m_inferiorPid.isValid())
+// m_runControl->setApplicationProcessHandle(m_inferiorPid);
+
+ m_operateByInstructionAction.setEnabled(true);
+ m_operateByInstructionAction.setVisible(m_engine->hasCapability(DisassemblerCapability));
+ m_operateByInstructionAction.setIcon(Debugger::Icons::SINGLE_INSTRUCTION_MODE.icon());
+ m_operateByInstructionAction.setCheckable(true);
+ m_operateByInstructionAction.setChecked(boolSetting(OperateByInstruction));
+ connect(&m_operateByInstructionAction, &QAction::triggered,
+ this, &DebuggerEnginePrivate::handleOperateByInstructionTriggered);
+
+ QTC_ASSERT(m_state == DebuggerNotReady || m_state == DebuggerFinished, qDebug() << m_state);
+ m_progress.setProgressValue(200);
+
+// m_terminal.setup();
+// if (m_terminal.isUsable()) {
+// connect(&m_terminal, &Terminal::stdOutReady, [this](const QString &msg) {
+// m_engine->showMessage(msg, Utils::StdOutFormatSameLine);
+// });
+// connect(&m_terminal, &Terminal::stdErrReady, [this](const QString &msg) {
+// m_engine->showMessage(msg, Utils::StdErrFormatSameLine);
+// });
+// connect(&m_terminal, &Terminal::error, [this](const QString &msg) {
+// m_engine->showMessage(msg, Utils::ErrorMessageFormat);
+// });
+// }
+
+ connect(&m_locationTimer, &QTimer::timeout,
+ this, &DebuggerEnginePrivate::resetLocation);
+
+ QSettings *settings = ICore::settings();
+ const QString perspectiveId = m_perspective->id();
+
+ m_modulesView = new BaseTreeView;
+ m_modulesView->setModel(m_modulesHandler.model());
+ m_modulesView->setSortingEnabled(true);
+ m_modulesView->setSettings(settings, "Debugger.ModulesView");
+ connect(m_modulesView, &BaseTreeView::aboutToShow,
+ m_engine, &DebuggerEngine::reloadModules,
+ Qt::QueuedConnection);
+ m_modulesWindow = addSearch(m_modulesView);
+ m_modulesWindow->setObjectName(DOCKWIDGET_MODULES + perspectiveId);
+ m_modulesWindow->setWindowTitle(tr("&Modules"));
+
+ m_registerView = new BaseTreeView;
+ m_registerView->setModel(m_registerHandler.model());
+ m_registerView->setRootIsDecorated(true);
+ m_registerView->setSettings(settings, "Debugger.RegisterView");
+ connect(m_registerView, &BaseTreeView::aboutToShow,
+ m_engine, &DebuggerEngine::reloadRegisters,
+ Qt::QueuedConnection);
+ m_registerWindow = addSearch(m_registerView);
+ m_registerWindow->setObjectName(DOCKWIDGET_REGISTER + m_perspective->id());
+ m_registerWindow->setWindowTitle(tr("Reg&isters"));
+
+ m_stackView = new BaseTreeView;
+ m_stackView->setModel(m_stackHandler.model());
+ m_stackView->setSettings(settings, "Debugger.StackView");
+ m_stackView->setIconSize(QSize(10, 10));
+ m_stackWindow = addSearch(m_stackView);
+ m_stackWindow->setObjectName(DOCKWIDGET_STACK + m_perspective->id());
+ m_stackWindow->setWindowTitle(tr("&Stack"));
+
+ m_sourceFilesView = new BaseTreeView;
+ m_sourceFilesView->setModel(m_sourceFilesHandler.model());
+ m_sourceFilesView->setSortingEnabled(true);
+ m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView");
+ connect(m_sourceFilesView, &BaseTreeView::aboutToShow,
+ m_engine, &DebuggerEngine::reloadSourceFiles,
+ Qt::QueuedConnection);
+ m_sourceFilesWindow = addSearch(m_sourceFilesView);
+ m_sourceFilesWindow->setObjectName(DOCKWIDGET_SOURCE_FILES + m_perspective->id());
+ m_sourceFilesWindow->setWindowTitle(tr("Source Files"));
+
+ m_threadsView = new BaseTreeView;
+ m_threadsView->setModel(m_threadsHandler.model());
+ m_threadsView->setSortingEnabled(true);
+ m_threadsView->setSettings(settings, "Debugger.ThreadsView");
+ m_threadsView->setIconSize(QSize(10, 10));
+ m_threadsWindow = addSearch(m_threadsView);
+ m_threadsWindow->setObjectName(DOCKWIDGET_THREADS + m_perspective->id());
+ m_threadsWindow->setWindowTitle(tr("&Threads"));
+
+ m_returnView = new WatchTreeView{ReturnType};
+ m_returnView->setModel(m_watchHandler.model());
+ m_returnWindow = addSearch(m_returnView);
+ m_returnWindow->setObjectName("CppDebugReturn" + m_perspective->id());
+ m_returnWindow->setWindowTitle(tr("Locals"));
+ m_returnWindow->setVisible(false);
+
+ m_localsView = new WatchTreeView{LocalsType};
+ m_localsView->setModel(m_watchHandler.model());
+ m_localsView->setSettings(settings, "Debugger.LocalsView");
+ m_localsWindow = addSearch(m_localsView);
+ m_localsWindow->setObjectName("CppDebugLocals" + m_perspective->id());
+ m_localsWindow->setWindowTitle(tr("Locals"));
+
+ m_inspectorView = new WatchTreeView{InspectType};
+ m_inspectorView->setModel(m_watchHandler.model());
+ m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view.
+ m_inspectorWindow = addSearch(m_inspectorView);
+ m_inspectorWindow->setObjectName("Inspector" + m_perspective->id());
+ m_inspectorWindow->setWindowTitle(tr("Locals"));
+
+ m_watchersView = new WatchTreeView{WatchersType};
+ m_watchersView->setModel(m_watchHandler.model());
+ m_watchersView->setSettings(settings, "Debugger.WatchersView");
+ m_watchersWindow = addSearch(m_watchersView);
+ m_watchersWindow->setObjectName("CppDebugWatchers" + m_perspective->id());
+ m_watchersWindow->setWindowTitle(tr("&Expressions"));
+
+ m_localsAndInspectorWindow = new LocalsAndInspectorWindow(
+ m_localsWindow, m_inspectorWindow, m_returnWindow);
+ m_localsAndInspectorWindow->setObjectName(DOCKWIDGET_LOCALS_AND_INSPECTOR + m_perspective->id());
+ m_localsAndInspectorWindow->setWindowTitle(m_localsWindow->windowTitle());
+
+ // Locals
+ connect(m_localsView->header(), &QHeaderView::sectionResized,
+ this, &DebuggerEnginePrivate::updateReturnViewHeader, Qt::QueuedConnection);
+
+ m_breakView = new BaseTreeView;
+ m_breakView->setIconSize(QSize(10, 10));
+ m_breakView->setWindowIcon(Icons::BREAKPOINTS.icon());
+ m_breakView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ connect(action(UseAddressInBreakpointsView), &QAction::toggled,
+ this, [this](bool on) { m_breakView->setColumnHidden(BreakpointAddressColumn, !on); });
+ m_breakView->setSettings(settings, "Debugger.BreakWindow");
+ m_breakView->setModel(m_breakHandler.model());
+ m_breakView->setRootIsDecorated(true);
+ m_breakWindow = addSearch(m_breakView);
+ m_breakWindow->setObjectName(DOCKWIDGET_BREAK + m_perspective->id());
+ m_breakWindow->setWindowTitle(tr("&Breakpoints"));
+
+ m_perspective->addToolBarWidget(EngineManager::engineChooser());
+
+ m_perspective->addToolBarAction(&m_continueAction);
+ m_perspective->addToolBarAction(&m_interruptAction);
+
+ m_perspective->addToolBarAction(&m_exitAction);
+ m_perspective->addToolBarAction(&m_stepOverAction);
+ m_perspective->addToolBarAction(&m_stepIntoAction);
+ m_perspective->addToolBarAction(&m_stepOutAction);
+ m_perspective->addToolBarAction(&m_resetAction);
+ m_perspective->addToolBarAction(&m_operateByInstructionAction);
+
+ m_continueAction.setIcon(Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon());
+ connect(&m_continueAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecContinue);
+
+ m_exitAction.setIcon(Icons::DEBUG_EXIT_SMALL.icon());
+ connect(&m_exitAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::requestRunControlStop);
+
+ m_interruptAction.setIcon(Icons::DEBUG_INTERRUPT_SMALL_TOOLBAR.icon());
+ connect(&m_interruptAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecInterrupt);
+
+ m_abortAction.setToolTip(tr("Aborts debugging and resets the debugger to the initial state."));
+ connect(&m_abortAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::abortDebugger);
+
+ m_resetAction.setToolTip(tr("Restart the debugging session."));
+ m_resetAction.setIcon(Icons::RESTART_TOOLBAR.icon());
+ connect(&m_resetAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleReset);
+
+ m_stepOverAction.setIcon(Icons::STEP_OVER_TOOLBAR.icon());
+ connect(&m_stepOverAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecNext);
+
+ m_stepIntoAction.setIcon(Icons::STEP_INTO_TOOLBAR.icon());
+ connect(&m_stepIntoAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecStep);
+
+ m_stepOutAction.setIcon(Icons::STEP_OUT_TOOLBAR.icon());
+ connect(&m_stepOutAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecStepOut);
+
+ connect(&m_runToLineAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecRunToLine);
+
+ connect(&m_runToSelectedFunctionAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecRunToSelectedFunction);
+
+ connect(&m_returnFromFunctionAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecReturn);
+
+ connect(&m_jumpToLineAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleExecJumpToLine);
+
+ m_perspective->addToolBarAction(&m_recordForReverseOperationAction);
+ connect(&m_recordForReverseOperationAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleRecordReverse);
+
+ m_perspective->addToolBarAction(&m_operateInReverseDirectionAction);
+ connect(&m_operateInReverseDirectionAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::handleReverseDirection);
+
+ m_perspective->addToolBarAction(&m_snapshotAction);
+ connect(&m_snapshotAction, &QAction::triggered,
+ m_engine, &DebuggerEngine::createSnapshot);
+
+ m_perspective->addToolbarSeparator();
+
+ m_threadLabel = new QLabel(tr("Threads:"));
+ m_perspective->addToolBarWidget(m_threadLabel);
+
+ m_threadBox = new QComboBox;
+ m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ connect(m_threadBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
+ this, &DebuggerEnginePrivate::selectThread);
+
+ m_perspective->addToolBarWidget(m_threadBox);
+
+ connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
+ this, [this](const FontSettings &settings) {
+ if (!boolSetting(FontSizeFollowsEditor))
+ return;
+ const qreal size = settings.fontZoom() * settings.fontSize() / 100.;
+ QFont font = m_breakWindow->font();
+ font.setPointSizeF(size);
+ m_breakWindow->setFont(font);
+ m_logWindow->setFont(font);
+ m_localsWindow->setFont(font);
+ m_modulesWindow->setFont(font);
+ //m_consoleWindow->setFont(font);
+ m_registerWindow->setFont(font);
+ m_returnWindow->setFont(font);
+ m_sourceFilesWindow->setFont(font);
+ m_stackWindow->setFont(font);
+ m_threadsWindow->setFont(font);
+ m_watchersWindow->setFont(font);
+ m_inspectorWindow->setFont(font);
+ });
+
+ m_perspective->setParentPerspective(Debugger::Constants::PRESET_PERSPRECTIVE_ID);
+ m_perspective->addWindow(m_stackWindow, Perspective::SplitVertical, nullptr);
+ m_perspective->addWindow(m_breakWindow, Perspective::SplitHorizontal, m_stackWindow);
+ m_perspective->addWindow(m_threadsWindow, Perspective::AddToTab, m_breakWindow,false);
+ m_perspective->addWindow(m_modulesWindow, Perspective::AddToTab, m_threadsWindow, false);
+ m_perspective->addWindow(m_sourceFilesWindow, Perspective::AddToTab, m_modulesWindow, false);
+ m_perspective->addWindow(m_localsAndInspectorWindow, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea);
+ m_perspective->addWindow(m_watchersWindow, Perspective::AddToTab, m_localsAndInspectorWindow, true, Qt::RightDockWidgetArea);
+ m_perspective->addWindow(m_registerWindow, Perspective::AddToTab, m_watchersWindow, true, Qt::RightDockWidgetArea);
+ m_perspective->addWindow(m_logWindow, Perspective::AddToTab, nullptr, false, Qt::TopDockWidgetArea);
+
+ Debugger::registerPerspective(m_perspective);
+ m_perspective->select();
+}
//////////////////////////////////////////////////////////////////////
//
@@ -317,14 +795,20 @@ public:
DebuggerEngine::DebuggerEngine()
: d(new DebuggerEnginePrivate(this))
{
+ updateState(false);
}
DebuggerEngine::~DebuggerEngine()
{
- disconnect();
+// EngineManager::unregisterEngine(this);
delete d;
}
+void DebuggerEngine::setDebuggerName(const QString &name)
+{
+ d->m_debuggerName = name;
+}
+
QString DebuggerEngine::stateName(int s)
{
# define SN(x) case x: return QLatin1String(#x);
@@ -357,6 +841,31 @@ void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
showMessage(msg, StatusBar, timeout);
}
+void DebuggerEngine::updateLocalsWindow(bool showReturn)
+{
+ d->m_returnWindow->setVisible(showReturn);
+ d->m_localsView->resizeColumns();
+}
+
+bool DebuggerEngine::isRegistersWindowVisible() const
+{
+ return d->m_registerWindow->isVisible();
+}
+
+bool DebuggerEngine::isModulesWindowVisible() const
+{
+ return d->m_modulesWindow->isVisible();
+}
+
+void DebuggerEngine::setThreadBoxContents(const QStringList &list, int index)
+{
+ QSignalBlocker blocker(d->m_threadBox);
+ d->m_threadBox->clear();
+ for (const QString &item : list)
+ d->m_threadBox->addItem(item);
+ d->m_threadBox->setCurrentIndex(index);
+}
+
void DebuggerEngine::frameUp()
{
int currentIndex = stackHandler()->currentIndex();
@@ -375,74 +884,47 @@ void DebuggerEngine::doUpdateLocals(const UpdateParameters &)
ModulesHandler *DebuggerEngine::modulesHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->modulesHandler()
- : &d->m_modulesHandler;
+ return &d->m_modulesHandler;
}
RegisterHandler *DebuggerEngine::registerHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->registerHandler()
- : &d->m_registerHandler;
+ return &d->m_registerHandler;
}
StackHandler *DebuggerEngine::stackHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->stackHandler()
- : &d->m_stackHandler;
+ return &d->m_stackHandler;
}
ThreadsHandler *DebuggerEngine::threadsHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->threadsHandler()
- : &d->m_threadsHandler;
+ return &d->m_threadsHandler;
}
WatchHandler *DebuggerEngine::watchHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->watchHandler()
- : &d->m_watchHandler;
+ return &d->m_watchHandler;
}
SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
- return d->m_masterEngine
- ? d->m_masterEngine->sourceFilesHandler()
- : &d->m_sourceFilesHandler;
-}
-
-QAbstractItemModel *DebuggerEngine::modulesModel() const
-{
- return modulesHandler()->model();
-}
-
-QAbstractItemModel *DebuggerEngine::registerModel() const
-{
- return registerHandler()->model();
+ return &d->m_sourceFilesHandler;
}
-QAbstractItemModel *DebuggerEngine::stackModel() const
-{
- return stackHandler()->model();
-}
-
-QAbstractItemModel *DebuggerEngine::threadsModel() const
+BreakHandler *DebuggerEngine::breakHandler() const
{
- return threadsHandler()->model();
+ return &d->m_breakHandler;
}
-QAbstractItemModel *DebuggerEngine::watchModel() const
+LogWindow *DebuggerEngine::logWindow() const
{
- return watchHandler()->model();
+ return d->m_logWindow;
}
-QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
+DisassemblerAgent *DebuggerEngine::disassemblerAgent() const
{
- return sourceFilesHandler()->model();
+ return &d->m_disassemblerAgent;
}
void DebuggerEngine::fetchMemory(MemoryAgent *, quint64 addr, quint64 length)
@@ -463,48 +945,30 @@ void DebuggerEngine::setRegisterValue(const QString &name, const QString &value)
Q_UNUSED(value);
}
-void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
+void DebuggerEngine::setRunParameters(const DebuggerRunParameters &runParameters)
{
- QTC_ASSERT(!d->m_runTool, notifyEngineSetupFailed(); return);
- d->m_runTool = runTool;
+ d->m_runParameters = runParameters;
}
-void DebuggerEngine::start()
+void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
{
- QTC_ASSERT(d->m_runTool, notifyEngineSetupFailed(); return);
-
- d->m_progress.setProgressRange(0, 1000);
- FutureProgress *fp = ProgressManager::addTask(d->m_progress.future(),
- tr("Launching Debugger"), "Debugger.Launcher");
- connect(fp, &FutureProgress::canceled, this, &DebuggerEngine::quitDebugger);
- fp->setKeepOnFinish(FutureProgress::HideOnFinish);
- d->m_progress.reportStarted();
+ RunControl *runControl = runTool->runControl();
+ d->m_runConfiguration = runControl->runConfiguration();
+ d->m_device = runControl->device();
+ if (!d->m_device)
+ d->m_device = d->m_runParameters.inferior.device;
+ d->m_terminalRunner = runTool->terminalRunner();
- const DebuggerRunParameters &rp = runParameters();
- d->m_inferiorPid = rp.attachPID.isValid() ? rp.attachPID : ProcessHandle();
- if (d->m_inferiorPid.isValid())
- d->m_runTool->runControl()->setApplicationProcessHandle(d->m_inferiorPid);
-
- action(OperateByInstruction)->setEnabled(hasCapability(DisassemblerCapability));
- action(OperateByInstruction)->setChecked(boolSetting(OperateByInstruction));
-
- QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
- qDebug() << state());
- d->m_progress.setProgressValue(200);
+ validateExecutable();
-// d->m_terminal.setup();
-// if (d->m_terminal.isUsable()) {
-// connect(&d->m_terminal, &Terminal::stdOutReady, [this](const QString &msg) {
-// d->m_runTool->appendMessage(msg, Utils::StdOutFormatSameLine);
-// });
-// connect(&d->m_terminal, &Terminal::stdErrReady, [this](const QString &msg) {
-// d->m_runTool->appendMessage(msg, Utils::StdErrFormatSameLine);
-// });
-// connect(&d->m_terminal, &Terminal::error, [this](const QString &msg) {
-// d->m_runTool->appendMessage(msg, Utils::ErrorMessageFormat);
-// });
-// }
+ d->setupViews();
+}
+void DebuggerEngine::start()
+{
+ EngineManager::registerEngine(this);
+ d->m_watchHandler.resetWatchers();
+ d->setInitialActionStates();
setState(EngineSetupRequested);
showMessage("CALL: SETUP ENGINE");
setupEngine();
@@ -521,7 +985,7 @@ void DebuggerEngine::gotoLocation(const Location &loc)
d->resetLocation();
if (loc.canBeDisassembled()
- && ((hasCapability(OperateByInstructionCapability) && boolSetting(OperateByInstruction))
+ && ((hasCapability(OperateByInstructionCapability) && d->operatesByInstruction())
|| !loc.hasDebugInfo()) )
{
d->m_disassemblerAgent.setLocation(loc);
@@ -546,13 +1010,37 @@ void DebuggerEngine::gotoLocation(const Location &loc)
if (newEditor)
editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
- if (loc.needsMarker())
+ if (loc.needsMarker()) {
d->m_locationMark.reset(new LocationMark(this, FileName::fromString(file), line));
+ d->m_locationMark->setToolTip(tr("Current debugger location of %1").arg(displayName()));
+ }
+}
+
+void DebuggerEngine::gotoCurrentLocation()
+{
+ int top = stackHandler()->currentIndex();
+ if (top >= 0)
+ gotoLocation(stackHandler()->currentFrame());
}
const DebuggerRunParameters &DebuggerEngine::runParameters() const
{
- return runTool()->runParameters();
+ return d->m_runParameters;
+}
+
+DebuggerRunParameters &DebuggerEngine::mutableRunParameters() const
+{
+ return d->m_runParameters;
+}
+
+IDevice::ConstPtr DebuggerEngine::device() const
+{
+ return d->m_device;
+}
+
+DebuggerEngine *DebuggerEngine::companionEngine() const
+{
+ return d->m_companionEngine;
}
DebuggerState DebuggerEngine::state() const
@@ -560,6 +1048,21 @@ DebuggerState DebuggerEngine::state() const
return d->m_state;
}
+void DebuggerEngine::abortDebugger()
+{
+ resetLocation();
+ if (!d->m_isDying) {
+ // Be friendly the first time. This will change targetState().
+ showMessage("ABORTING DEBUGGER. FIRST TIME.");
+ quitDebugger();
+ } else {
+ // We already tried. Try harder.
+ showMessage("ABORTING DEBUGGER. SECOND TIME.");
+ abortDebuggerProcess();
+ emit requestRunControlFinish();
+ }
+}
+
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
switch (from) {
@@ -621,20 +1124,12 @@ static bool isAllowedTransition(DebuggerState from, DebuggerState to)
return false;
}
-void DebuggerEngine::setupSlaveEngine()
-{
- QTC_CHECK(state() == DebuggerNotReady);
- setState(EngineSetupRequested);
- showMessage("CALL: SETUP SLAVE ENGINE");
- setupEngine();
-}
-
void DebuggerEngine::notifyEngineSetupFailed()
{
showMessage("NOTE: ENGINE SETUP FAILED");
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupFailed);
- if (isMasterEngine() && runTool()) {
+ if (d->m_isPrimaryEngine) {
showMessage(tr("Debugging has failed"), NormalMessageFormat);
d->m_progress.setProgressValue(900);
d->m_progress.reportCanceled();
@@ -653,28 +1148,13 @@ void DebuggerEngine::notifyEngineSetupOk()
d->m_progress.setProgressValue(250);
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupOk);
- if (isMasterEngine()) {
- if (runTool())
- runTool()->reportStarted();
- // Slaves will get called setupSlaveInferior() below.
- setState(EngineRunRequested);
- showMessage("CALL: RUN ENGINE");
- d->m_progress.setProgressValue(300);
- runEngine();
- }
-}
-
-void DebuggerEngine::runSlaveEngine()
-{
- QTC_ASSERT(isSlaveEngine(), return);
- QTC_CHECK(state() == EngineSetupOk);
+ // Slaves will get called setupSlaveInferior() below.
setState(EngineRunRequested);
- showMessage("CALL: RUN SLAVE ENGINE");
+ showMessage("CALL: RUN ENGINE");
d->m_progress.setProgressValue(300);
runEngine();
}
-
void DebuggerEngine::notifyEngineRunOkAndInferiorUnrunnable()
{
showMessage("NOTE: INFERIOR UNRUNNABLE");
@@ -769,7 +1249,7 @@ void DebuggerEngine::notifyInferiorStopOk()
return;
}
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
- showStatusMessage(tr("Stopped."));
+ showMessage(tr("Stopped."), StatusBar);
setState(InferiorStopOk);
}
@@ -777,10 +1257,11 @@ void DebuggerEngine::notifyInferiorSpontaneousStop()
{
showMessage("NOTE: INFERIOR SPONTANEOUS STOP");
QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
- showStatusMessage(tr("Stopped."));
+ showMessage(tr("Stopped."), StatusBar);
setState(InferiorStopOk);
if (boolSetting(RaiseOnInterrupt))
ICore::raiseWindow(Internal::mainWindow());
+ EngineManager::activateEngine(this);
}
void DebuggerEngine::notifyInferiorStopFailed()
@@ -791,13 +1272,277 @@ void DebuggerEngine::notifyInferiorStopFailed()
d->doShutdownEngine();
}
-void DebuggerEnginePrivate::doShutdownInferior()
+void DebuggerEnginePrivate::setInitialActionStates()
{
- m_engine->setState(InferiorShutdownRequested);
- //QTC_ASSERT(isMasterEngine(), return);
- resetLocation();
- m_engine->showMessage("CALL: SHUTDOWN INFERIOR");
- m_engine->shutdownInferior();
+ m_returnWindow->setVisible(false);
+ setBusyCursor(false);
+
+ m_recordForReverseOperationAction.setCheckable(true);
+ m_recordForReverseOperationAction.setChecked(false);
+ m_recordForReverseOperationAction.setIcon(Icons::RECORD_OFF.icon());
+ m_recordForReverseOperationAction.setToolTip(tr(
+ "<html><head/><body><p>Record information to enable stepping backwards.</p><p>"
+ "<b>Note:</b> This feature is very slow and unstable on the GDB side. "
+ "It exhibits unpredictable behavior when going backwards over system "
+ "calls and is very likely to destroy your debugging session.</p></body></html>"));
+
+ m_operateInReverseDirectionAction.setCheckable(true);
+ m_operateInReverseDirectionAction.setChecked(false);
+ m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_FORWARD.icon());
+
+ m_snapshotAction.setIcon(Utils::Icons::SNAPSHOT_TOOLBAR.icon());
+
+ m_attachToQmlPortAction.setEnabled(true);
+ m_attachToCoreAction.setEnabled(true);
+ m_attachToRemoteServerAction.setEnabled(true);
+ m_detachAction.setEnabled(false);
+
+ m_watchAction.setEnabled(true);
+ m_breakAction.setEnabled(false);
+ m_snapshotAction.setEnabled(false);
+ m_operateByInstructionAction.setEnabled(false);
+
+ m_exitAction.setEnabled(false);
+ m_abortAction.setEnabled(false);
+ m_resetAction.setEnabled(false);
+
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+
+ m_stepIntoAction.setEnabled(true);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(true);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_stepOverAction.setEnabled(true);
+
+ action(AutoDerefPointers)->setEnabled(true);
+ action(ExpandStack)->setEnabled(false);
+
+ m_threadLabel->setEnabled(false);
+}
+
+void DebuggerEnginePrivate::updateState(bool alsoUpdateCompanion)
+{
+ if (!m_perspective)
+ return;
+ QTC_ASSERT(m_threadBox, return);
+ m_threadBox->setCurrentIndex(m_threadsHandler.currentThreadIndex());
+
+ const DebuggerState state = m_state;
+ const bool companionPreventsAction = m_engine->companionPreventsActions();
+
+ // Fixme: hint tr("Debugger is Busy");
+ // Exactly one of m_interuptAction and m_continueAction should be
+ // visible, possibly disabled.
+ if (state == DebuggerNotReady) {
+ // Happens when companion starts, otherwise this should not happen.
+ QTC_CHECK(m_companionEngine);
+ m_interruptAction.setVisible(true);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setVisible(false);
+ m_continueAction.setEnabled(false);
+ m_stepOverAction.setEnabled(true);
+ m_stepIntoAction.setEnabled(true);
+ m_stepOutAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(true);
+ } else if (state == InferiorStopOk) {
+ // F5 continues, Shift-F5 kills. It is "continuable".
+ m_interruptAction.setVisible(false);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setVisible(true);
+ m_continueAction.setEnabled(!companionPreventsAction);
+ m_stepOverAction.setEnabled(!companionPreventsAction);
+ m_stepIntoAction.setEnabled(!companionPreventsAction);
+ m_stepOutAction.setEnabled(!companionPreventsAction);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_localsAndInspectorWindow->setShowLocals(true);
+ } else if (state == InferiorRunOk) {
+ // Shift-F5 interrupts. It is also "interruptible".
+ m_interruptAction.setVisible(true);
+ m_interruptAction.setEnabled(!companionPreventsAction);
+ m_continueAction.setVisible(false);
+ m_continueAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
+ m_stepIntoAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_localsAndInspectorWindow->setShowLocals(false);
+ } else if (state == DebuggerFinished) {
+ const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ // We don't want to do anything anymore.
+ m_interruptAction.setVisible(true);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setVisible(false);
+ m_continueAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
+ m_stepIntoAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(canRun);
+ setBusyCursor(false);
+ cleanupViews();
+ } else if (state == InferiorUnrunnable) {
+ // We don't want to do anything anymore.
+ m_interruptAction.setVisible(true);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setVisible(false);
+ m_continueAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
+ m_stepIntoAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ // show locals in core dumps
+ m_localsAndInspectorWindow->setShowLocals(true);
+ } else {
+ // Everything else is "undisturbable".
+ m_interruptAction.setVisible(true);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setVisible(false);
+ m_continueAction.setEnabled(false);
+ m_stepOverAction.setEnabled(false);
+ m_stepIntoAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(false);
+ }
+
+ m_attachToQmlPortAction.setEnabled(true);
+ m_attachToCoreAction.setEnabled(true);
+ m_attachToRemoteServerAction.setEnabled(true);
+
+ m_threadBox->setEnabled(state == InferiorStopOk || state == InferiorUnrunnable);
+ m_threadLabel->setEnabled(m_threadBox->isEnabled());
+
+ const bool isCore = m_engine->runParameters().startMode == AttachCore;
+ const bool stopped = state == InferiorStopOk;
+ const bool detachable = stopped && !isCore;
+ m_detachAction.setEnabled(detachable);
+
+ if (stopped)
+ QApplication::alert(mainWindow(), 3000);
+
+ updateReverseActions();
+
+ const bool canSnapshot = m_engine->hasCapability(SnapshotCapability);
+ m_snapshotAction.setVisible(canSnapshot);
+ m_snapshotAction.setEnabled(stopped && !isCore);
+
+ m_watchAction.setEnabled(true);
+ m_breakAction.setEnabled(true);
+
+ const bool canOperateByInstruction = m_engine->hasCapability(OperateByInstructionCapability);
+ m_operateByInstructionAction.setVisible(canOperateByInstruction);
+ m_operateByInstructionAction.setEnabled(canOperateByInstruction && (stopped || isCore));
+
+ m_abortAction.setEnabled(state != DebuggerNotReady
+ && state != DebuggerFinished);
+ m_resetAction.setEnabled((stopped || state == DebuggerNotReady)
+ && m_engine->hasCapability(ResetInferiorCapability));
+
+ m_stepIntoAction.setEnabled(stopped || state == DebuggerNotReady);
+ m_stepIntoAction.setToolTip(QString());
+
+ m_stepOverAction.setEnabled(stopped || state == DebuggerNotReady);
+ m_stepOverAction.setToolTip(QString());
+
+ m_stepOutAction.setEnabled(stopped);
+ m_runToLineAction.setEnabled(stopped && m_engine->hasCapability(RunToLineCapability));
+ m_runToSelectedFunctionAction.setEnabled(stopped);
+ m_returnFromFunctionAction.
+ setEnabled(stopped && m_engine->hasCapability(ReturnFromFunctionCapability));
+
+ const bool canJump = stopped && m_engine->hasCapability(JumpToLineCapability);
+ m_jumpToLineAction.setEnabled(canJump);
+
+ const bool actionsEnabled = m_engine->debuggerActionsEnabled();
+ const bool canDeref = actionsEnabled && m_engine->hasCapability(AutoDerefPointersCapability);
+ action(AutoDerefPointers)->setEnabled(canDeref);
+ action(AutoDerefPointers)->setEnabled(true);
+ action(ExpandStack)->setEnabled(actionsEnabled);
+
+ const bool notbusy = state == InferiorStopOk
+ || state == DebuggerNotReady
+ || state == DebuggerFinished
+ || state == InferiorUnrunnable;
+ setBusyCursor(!notbusy);
+
+ if (alsoUpdateCompanion && m_companionEngine)
+ m_companionEngine->updateState(false);
+}
+
+void DebuggerEnginePrivate::updateReverseActions()
+{
+ const bool stopped = m_state == InferiorStopOk;
+ const bool reverseEnabled = boolSetting(EnableReverseDebugging);
+ const bool canReverse = reverseEnabled && m_engine->hasCapability(ReverseSteppingCapability);
+ const bool doesRecord = m_recordForReverseOperationAction.isChecked();
+
+ m_recordForReverseOperationAction.setVisible(canReverse);
+ m_recordForReverseOperationAction.setEnabled(canReverse && stopped);
+ m_recordForReverseOperationAction.setIcon(doesRecord
+ ? Icons::RECORD_ON.icon()
+ : Icons::RECORD_OFF.icon());
+
+ m_operateInReverseDirectionAction.setVisible(canReverse);
+ m_operateInReverseDirectionAction.setEnabled(canReverse && stopped && doesRecord);
+ m_operateInReverseDirectionAction.setIcon(Icons::DIRECTION_BACKWARD.icon());
+ m_operateInReverseDirectionAction.setText(DebuggerEngine::tr("Operate in reverse direction"));
+}
+
+void DebuggerEnginePrivate::cleanupViews()
+{
+ const bool closeSource = boolSetting(CloseSourceBuffersOnExit);
+ const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit);
+
+ QList<IDocument *> toClose;
+ foreach (IDocument *document, DocumentModel::openedDocuments()) {
+ const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool();
+ if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) {
+ bool keepIt = true;
+ if (document->isModified())
+ keepIt = true;
+ else if (document->filePath().toString().contains("qeventdispatcher"))
+ keepIt = false;
+ else if (isMemory)
+ keepIt = !closeMemory;
+ else
+ keepIt = !closeSource;
+
+ if (keepIt)
+ document->setProperty(Constants::OPENED_BY_DEBUGGER, false);
+ else
+ toClose.append(document);
+ }
+ }
+ EditorManager::closeDocuments(toClose);
+}
+
+void DebuggerEnginePrivate::setBusyCursor(bool busy)
+{
+ //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy);
+ if (m_isDying)
+ return;
+ if (busy == m_busy)
+ return;
+ m_busy = busy;
+ const QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
+ m_breakWindow->setCursor(cursor);
+ //m_consoleWindow->setCursor(cursor);
+ m_localsWindow->setCursor(cursor);
+ m_modulesWindow->setCursor(cursor);
+ m_logWindow->setCursor(cursor);
+ m_registerWindow->setCursor(cursor);
+ m_returnWindow->setCursor(cursor);
+ m_sourceFilesWindow->setCursor(cursor);
+ m_stackWindow->setCursor(cursor);
+ m_threadsWindow->setCursor(cursor);
+ m_watchersWindow->setCursor(cursor);
}
void DebuggerEngine::notifyInferiorShutdownFinished()
@@ -813,7 +1558,7 @@ void DebuggerEngine::notifyInferiorIll()
showMessage("NOTE: INFERIOR ILL");
// This can be issued in almost any state. The inferior could still be
// alive as some previous notifications might have been bogus.
- runTool()->startDying();
+ startDying();
if (state() == InferiorRunRequested) {
// We asked for running, but did not see a response.
// Assume the inferior is dead.
@@ -824,25 +1569,6 @@ void DebuggerEngine::notifyInferiorIll()
d->doShutdownInferior();
}
-void DebuggerEngine::shutdownSlaveEngine()
-{
- QTC_CHECK(isAllowedTransition(state(),EngineShutdownRequested));
- setState(EngineShutdownRequested);
- shutdownEngine();
-}
-
-void DebuggerEnginePrivate::doShutdownEngine()
-{
- // Slaves do not proceed by themselves.
- if (!isMasterEngine())
- return;
- m_engine->setState(EngineShutdownRequested);
- QTC_ASSERT(m_runTool, return);
- m_runTool->startDying();
- m_engine->showMessage("CALL: SHUTDOWN ENGINE");
- m_engine->shutdownEngine();
-}
-
void DebuggerEngine::notifyEngineShutdownFinished()
{
showMessage("NOTE: ENGINE SHUTDOWN FINISHED");
@@ -858,7 +1584,7 @@ void DebuggerEngine::notifyEngineIll()
// CALLGRIND_DUMP_STATS;
//#endif
showMessage("NOTE: ENGINE ILL ******");
- runTool()->startDying();
+ startDying();
switch (state()) {
case InferiorRunRequested:
case InferiorRunOk:
@@ -891,8 +1617,7 @@ void DebuggerEngine::notifyEngineSpontaneousShutdown()
#endif
showMessage("NOTE: ENGINE SPONTANEOUS SHUTDOWN");
setState(EngineShutdownFinished, true);
- if (isMasterEngine())
- d->doFinishDebugger();
+ d->doFinishDebugger();
}
void DebuggerEngine::notifyInferiorExited()
@@ -907,6 +1632,53 @@ void DebuggerEngine::notifyInferiorExited()
d->doShutdownEngine();
}
+void DebuggerEngine::updateState(bool alsoUpdateCompanion)
+{
+ d->updateState(alsoUpdateCompanion);
+}
+
+WatchTreeView *DebuggerEngine::inspectorView()
+{
+ return d->m_inspectorView;
+}
+
+void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
+{
+ //qDebug() << "PLUGIN OUTPUT: " << channel << msg;
+ QTC_ASSERT(d->m_logWindow, qDebug() << "MSG: " << msg; return);
+ switch (channel) {
+ case StatusBar:
+ d->m_logWindow->showInput(LogMisc, msg);
+ d->m_logWindow->showOutput(LogMisc, msg);
+ Debugger::showStatusMessage(msg, timeout);
+ break;
+ case LogMiscInput:
+ d->m_logWindow->showInput(LogMisc, msg);
+ d->m_logWindow->showOutput(LogMisc, msg);
+ break;
+ case LogInput:
+ d->m_logWindow->showInput(LogInput, msg);
+ d->m_logWindow->showOutput(LogInput, msg);
+ break;
+ case LogError:
+ d->m_logWindow->showInput(LogError, QLatin1String("ERROR: ") + msg);
+ d->m_logWindow->showOutput(LogError, QLatin1String("ERROR: ") + msg);
+ break;
+ case AppOutput:
+ case AppStuff:
+ d->m_logWindow->showOutput(channel, msg);
+ emit appendMessageRequested(msg, StdOutFormatSameLine, false);
+ break;
+ case AppError:
+ d->m_logWindow->showOutput(channel, msg);
+ emit appendMessageRequested(msg, StdErrFormatSameLine, false);
+ break;
+ default:
+ d->m_logWindow->showOutput(channel, msg);
+ break;
+ }
+}
+
void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode,
QProcess::ExitStatus exitStatus, const QString &backendName)
{
@@ -930,7 +1702,7 @@ void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode,
break;
default: {
// Initiate shutdown sequence
- masterEngine()->notifyInferiorIll();
+ notifyInferiorIll();
const QString msg = exitStatus == QProcess::CrashExit ?
tr("The %1 process terminated.") :
tr("The %2 process terminated unexpectedly (exit code %1).").arg(exitCode);
@@ -941,15 +1713,7 @@ void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode,
}
}
-void DebuggerEngine::slaveEngineStateChanged(DebuggerEngine *slaveEngine,
- DebuggerState state)
-{
- Q_UNUSED(slaveEngine);
- Q_UNUSED(state);
-}
-
-static inline QString msgStateChanged(DebuggerState oldState, DebuggerState newState,
- bool forced, bool master)
+static QString msgStateChanged(DebuggerState oldState, DebuggerState newState, bool forced)
{
QString result;
QTextStream str(&result);
@@ -958,14 +1722,12 @@ static inline QString msgStateChanged(DebuggerState oldState, DebuggerState newS
str << " BY FORCE";
str << " from " << DebuggerEngine::stateName(oldState) << '(' << oldState
<< ") to " << DebuggerEngine::stateName(newState) << '(' << newState << ')';
- if (master)
- str << " [master]";
return result;
}
void DebuggerEngine::setState(DebuggerState state, bool forced)
{
- const QString msg = msgStateChanged(d->m_state, state, forced, isMasterEngine());
+ const QString msg = msgStateChanged(d->m_state, state, forced);
DebuggerState oldState = d->m_state;
d->m_state = state;
@@ -975,49 +1737,25 @@ void DebuggerEngine::setState(DebuggerState state, bool forced)
if (state == EngineRunRequested) {
DebuggerToolTipManager::registerEngine(this);
- }
-
- if (state == DebuggerFinished) {
- // Give up ownership on claimed breakpoints.
- for (Breakpoint bp : breakHandler()->engineBreakpoints(this))
- bp.notifyBreakpointReleased();
- DebuggerToolTipManager::deregisterEngine(this);
- d->m_memoryAgents.handleDebuggerFinished();
- prepareForRestart();
+ emit engineStarted();
}
showMessage(msg, LogDebug);
- updateViews();
- if (isSlaveEngine())
- masterEngine()->slaveEngineStateChanged(this, state);
-}
-
-void DebuggerEngine::updateViews()
-{
- // The slave engines are not entitled to change the view. Their wishes
- // should be coordinated by their master engine.
- Internal::updateState(runTool());
-}
-
-bool DebuggerEngine::isSlaveEngine() const
-{
- return d->m_masterEngine != nullptr;
-}
+ d->updateState(true);
-bool DebuggerEngine::isMasterEngine() const
-{
- return d->m_masterEngine == nullptr;
-}
+ if (oldState != d->m_state)
+ emit EngineManager::instance()->engineStateChanged(this);
-void DebuggerEngine::setMasterEngine(DebuggerEngine *masterEngine)
-{
- d->m_masterEngine = masterEngine;
+ if (state == DebuggerFinished) {
+ d->destroyPerspective();
+ emit engineFinished();
+ }
}
-DebuggerEngine *DebuggerEngine::masterEngine()
+bool DebuggerEngine::isPrimaryEngine() const
{
- return d->m_masterEngine ? d->m_masterEngine : this;
+ return d->m_isPrimaryEngine;
}
bool DebuggerEngine::canDisplayTooltip() const
@@ -1037,11 +1775,6 @@ QString DebuggerEngine::toFileInProject(const QUrl &fileUrl)
return d->m_fileFinder.findFile(fileUrl);
}
-void DebuggerEngine::removeBreakpointMarker(const Breakpoint &bp)
-{
- d->m_disassemblerAgent.removeBreakpointMarker(bp);
-}
-
QString DebuggerEngine::expand(const QString &string) const
{
return runParameters().macroExpander->expand(string);
@@ -1053,40 +1786,26 @@ QString DebuggerEngine::nativeStartupCommands() const
runParameters().additionalStartupCommands}).join('\n'));
}
-void DebuggerEngine::updateBreakpointMarker(const Breakpoint &bp)
+Perspective *DebuggerEngine::perspective() const
{
- d->m_disassemblerAgent.updateBreakpointMarker(bp);
+ return d->m_perspective;
+}
+
+void DebuggerEngine::updateMarkers()
+{
+ if (d->m_locationMark)
+ d->m_locationMark->updateIcon();
+
+ d->m_disassemblerAgent.updateLocationMarker();
}
bool DebuggerEngine::debuggerActionsEnabled() const
{
- return debuggerActionsEnabled(d->m_state);
+ return debuggerActionsEnabledHelper(d->m_state);
}
-bool DebuggerEngine::debuggerActionsEnabled(DebuggerState state)
+bool DebuggerEngine::companionPreventsActions() const
{
- switch (state) {
- case InferiorRunOk:
- case InferiorUnrunnable:
- case InferiorStopOk:
- return true;
- case InferiorStopRequested:
- case InferiorRunRequested:
- case InferiorRunFailed:
- case DebuggerNotReady:
- case EngineSetupRequested:
- case EngineSetupOk:
- case EngineSetupFailed:
- case EngineRunRequested:
- case EngineRunFailed:
- case InferiorStopFailed:
- case InferiorShutdownRequested:
- case InferiorShutdownFinished:
- case EngineShutdownRequested:
- case EngineShutdownFinished:
- case DebuggerFinished:
- return false;
- }
return false;
}
@@ -1096,7 +1815,6 @@ void DebuggerEngine::notifyInferiorPid(const ProcessHandle &pid)
return;
d->m_inferiorPid = pid;
if (pid.isValid()) {
- d->m_runTool->runControl()->setApplicationProcessHandle(pid);
showMessage(tr("Taking notice of pid %1").arg(pid.pid()));
DebuggerStartMode sm = runParameters().startMode;
if (sm == StartInternal || sm == StartExternal || sm == AttachExternal)
@@ -1111,21 +1829,30 @@ qint64 DebuggerEngine::inferiorPid() const
bool DebuggerEngine::isReverseDebugging() const
{
- return Internal::isReverseDebugging();
+ return d->m_operateInReverseDirectionAction.isChecked();
}
-void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
+void DebuggerEngine::handleBeginOfRecordingReached()
{
- if (DebuggerRunTool *tool = runTool())
- tool->showMessage(msg, channel, timeout);
+ showStatusMessage(tr("Reverse-execution history exhausted. Going forward again."));
+ d->m_operateInReverseDirectionAction.setChecked(false);
+ d->updateReverseActions();
+}
+
+void DebuggerEngine::handleRecordingFailed()
+{
+ showStatusMessage(tr("Reverse-execution recording failed.."));
+ d->m_operateInReverseDirectionAction.setChecked(false);
+ d->m_recordForReverseOperationAction.setChecked(false);
+ d->updateReverseActions();
+ executeRecordReverse(false);
}
// Called by DebuggerRunControl.
void DebuggerEngine::quitDebugger()
{
showMessage(QString("QUIT DEBUGGER REQUESTED IN STATE %1").arg(state()));
- QTC_ASSERT(runTool(), return);
- runTool()->startDying();
+ startDying();
switch (state()) {
case InferiorStopOk:
case InferiorStopFailed:
@@ -1134,7 +1861,7 @@ void DebuggerEngine::quitDebugger()
break;
case InferiorRunOk:
setState(InferiorStopRequested);
- showStatusMessage(tr("Attempting to interrupt."));
+ showMessage(tr("Attempting to interrupt."), StatusBar);
interruptInferior();
break;
case EngineSetupRequested:
@@ -1162,11 +1889,10 @@ void DebuggerEngine::quitDebugger()
void DebuggerEngine::requestInterruptInferior()
{
- QTC_CHECK(isMasterEngine());
QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
setState(InferiorStopRequested);
showMessage("CALL: INTERRUPT INFERIOR");
- showStatusMessage(tr("Attempting to interrupt."));
+ showMessage(tr("Attempting to interrupt."), StatusBar);
interruptInferior();
}
@@ -1176,15 +1902,24 @@ void DebuggerEngine::progressPing()
d->m_progress.setProgressValue(progress);
}
-DebuggerRunTool *DebuggerEngine::runTool() const
+bool DebuggerEngine::isStartupRunConfiguration() const
+{
+ return d->m_runConfiguration == RunConfiguration::startupRunConfiguration();
+}
+
+void DebuggerEngine::setCompanionEngine(DebuggerEngine *engine)
+{
+ d->m_companionEngine = engine;
+}
+
+void DebuggerEngine::setSecondaryEngine()
{
- return d->m_runTool.data();
+ d->m_isPrimaryEngine = false;
}
TerminalRunner *DebuggerEngine::terminal() const
{
- QTC_ASSERT(d->m_runTool, return nullptr);
- return d->m_runTool->terminalRunner();
+ return d->m_terminalRunner;
}
void DebuggerEngine::selectWatchData(const QString &)
@@ -1199,7 +1934,7 @@ void DebuggerEngine::watchPoint(const QPoint &pnt)
cmd.callback = [this](const DebuggerResponse &response) {
qulonglong addr = response.data["selected"].toAddress();
if (addr == 0)
- showStatusMessage(tr("Could not find a widget."));
+ showMessage(tr("Could not find a widget."), StatusBar);
// Add the watcher entry nevertheless, as that's the place where
// the user expects visual feedback.
watchHandler()->watchExpression(response.data["expr"].data(), QString(), true);
@@ -1297,112 +2032,42 @@ void DebuggerEngine::updateAll()
{
}
-#if 0
- // FIXME: Remove explicit use of BreakpointData
- if (!bp->engine && acceptsBreakpoint(id)) {
- QTC_CHECK(state == BreakpointNew);
- // Take ownership of the breakpoint.
- bp->engine = this;
- }
-#endif
-
-void DebuggerEngine::attemptBreakpointSynchronization()
+QString DebuggerEngine::displayName() const
{
- showMessage("ATTEMPT BREAKPOINT SYNCHRONIZATION");
- if (!stateAcceptsBreakpointChanges()) {
- showMessage("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE");
- return;
- }
-
- BreakHandler *handler = breakHandler();
-
- for (Breakpoint bp : handler->unclaimedBreakpoints()) {
- // Take ownership of the breakpoint. Requests insertion.
- if (acceptsBreakpoint(bp)) {
- showMessage(QString("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
- .arg(bp.id().toString()).arg(bp.state()));
- bp.setEngine(this);
- } else {
- showMessage(QString("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
- .arg(bp.id().toString()).arg(bp.state()));
- }
- }
-
- bool done = true;
- for (Breakpoint bp : handler->engineBreakpoints(this)) {
- switch (bp.state()) {
- case BreakpointNew:
- // Should not happen once claimed.
- QTC_CHECK(false);
- continue;
- case BreakpointInsertRequested:
- done = false;
- insertBreakpoint(bp);
- continue;
- case BreakpointChangeRequested:
- done = false;
- changeBreakpoint(bp);
- continue;
- case BreakpointRemoveRequested:
- done = false;
- removeBreakpoint(bp);
- continue;
- case BreakpointChangeProceeding:
- case BreakpointInsertProceeding:
- case BreakpointRemoveProceeding:
- done = false;
- //qDebug() << "BREAKPOINT " << id << " STILL IN PROGRESS, STATE"
- // << handler->state(id);
- continue;
- case BreakpointInserted:
- //qDebug() << "BREAKPOINT " << id << " IS GOOD";
- continue;
- case BreakpointDead:
- // Can happen temporarily during Breakpoint destruction.
- // BreakpointItem::deleteThis() intentionally lets the event loop run,
- // during which an attemptBreakpointSynchronization() might kick in.
- continue;
- }
- }
-
- if (done)
- showMessage("BREAKPOINTS ARE SYNCHRONIZED");
- else
- showMessage("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED");
-}
-
-bool DebuggerEngine::acceptsBreakpoint(Breakpoint bp) const
-{
- Q_UNUSED(bp);
- return false;
+ //: e.g. LLDB for "myproject", shows up i
+ return tr("%1 for \"%2\"").arg(d->m_debuggerName, runParameters().displayName);
}
-void DebuggerEngine::insertBreakpoint(Breakpoint bp)
+void DebuggerEngine::insertBreakpoint(const Breakpoint &bp)
{
- BreakpointState state = bp.state();
- QTC_ASSERT(state == BreakpointInsertRequested,
- qDebug() << bp.id() << this << state);
+ QTC_ASSERT(bp, return);
+ BreakpointState state = bp->state();
+ QTC_ASSERT(state == BreakpointInsertionRequested,
+ qDebug() << bp->modelId() << this << state);
QTC_CHECK(false);
}
-void DebuggerEngine::removeBreakpoint(Breakpoint bp)
+void DebuggerEngine::removeBreakpoint(const Breakpoint &bp)
{
- BreakpointState state = bp.state();
+ QTC_ASSERT(bp, return);
+ BreakpointState state = bp->state();
QTC_ASSERT(state == BreakpointRemoveRequested,
- qDebug() << bp.id() << this << state);
+ qDebug() << bp->responseId() << this << state);
QTC_CHECK(false);
}
-void DebuggerEngine::changeBreakpoint(Breakpoint bp)
+void DebuggerEngine::updateBreakpoint(const Breakpoint &bp)
{
- BreakpointState state = bp.state();
- QTC_ASSERT(state == BreakpointChangeRequested,
- qDebug() << bp.id() << this << state);
+ QTC_ASSERT(bp, return);
+ BreakpointState state = bp->state();
+ QTC_ASSERT(state == BreakpointUpdateRequested,
+ qDebug() << bp->responseId() << this << state);
QTC_CHECK(false);
}
-void DebuggerEngine::enableSubBreakpoint(const QString &, bool)
+void DebuggerEngine::enableSubBreakpoint(const SubBreakpoint &sbp, bool)
{
+ QTC_ASSERT(sbp, return);
QTC_CHECK(false);
}
@@ -1411,67 +2076,27 @@ void DebuggerEngine::assignValueInDebugger(WatchItem *,
{
}
-void DebuggerEngine::detachDebugger()
-{
-}
-
-void DebuggerEngine::executeStep()
-{
-}
-
-void DebuggerEngine::executeStepOut()
-{
-}
-
-void DebuggerEngine::executeNext()
-{
-}
-
-void DebuggerEngine::executeStepI()
-{
-}
-
-void DebuggerEngine::executeNextI()
-{
-}
-
-void DebuggerEngine::executeReturn()
-{
-}
-
-void DebuggerEngine::continueInferior()
-{
-}
-
-void DebuggerEngine::interruptInferior()
-{
-}
-
-void DebuggerEngine::executeRunToLine(const ContextData &)
+void DebuggerEngine::handleRecordReverse(bool record)
{
+ executeRecordReverse(record);
+ d->updateReverseActions();
}
-void DebuggerEngine::executeRunToFunction(const QString &)
+void DebuggerEngine::handleReverseDirection(bool reverse)
{
+ executeReverse(reverse);
+ updateMarkers();
+ d->updateReverseActions();
}
-void DebuggerEngine::executeJumpToLine(const ContextData &)
+void DebuggerEngine::executeDebuggerCommand(const QString &)
{
-}
-
-void DebuggerEngine::executeDebuggerCommand(const QString &, DebuggerLanguages)
-{
- showStatusMessage(tr("This debugger cannot handle user input."));
-}
-
-BreakHandler *DebuggerEngine::breakHandler() const
-{
- return Internal::breakHandler();
+ showMessage(tr("This debugger cannot handle user input."), StatusBar);
}
bool DebuggerEngine::isDying() const
{
- return !runTool() || runTool()->isDying();
+ return d->m_isDying;
}
QString DebuggerEngine::msgStopped(const QString &reason)
@@ -1535,22 +2160,379 @@ void DebuggerEngine::updateMemoryViews()
void DebuggerEngine::openDisassemblerView(const Location &location)
{
- auto agent = new DisassemblerAgent(this);
+ DisassemblerAgent *agent = new DisassemblerAgent(this);
agent->setLocation(location);
}
-void DebuggerRunParameters::validateExecutable()
+void DebuggerEngine::raiseWatchersWindow()
+{
+ if (d->m_watchersView) {
+ if (auto dock = qobject_cast<QDockWidget *>(d->m_watchersView->parentWidget())) {
+ if (QAction *act = dock->toggleViewAction()) {
+ if (!act->isChecked())
+ QTimer::singleShot(1, act, [act] { act->trigger(); });
+ dock->raise();
+ }
+ }
+ }
+}
+
+void DebuggerEngine::openMemoryEditor()
+{
+ AddressDialog dialog;
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+ MemoryViewSetupData data;
+ data.startAddress = dialog.address();
+ openMemoryView(data);
+}
+
+void DebuggerEngine::updateLocalsView(const GdbMi &all)
{
+ WatchHandler *handler = watchHandler();
+
+ const GdbMi typeInfo = all["typeinfo"];
+ handler->recordTypeInfo(typeInfo);
+
+ const GdbMi data = all["data"];
+ handler->insertItems(data);
+
+ const GdbMi ns = all["qtnamespace"];
+ if (ns.isValid()) {
+ setQtNamespace(ns.data());
+ showMessage("FOUND NAMESPACED QT: " + ns.data());
+ }
+
+ static int count = 0;
+ showMessage(QString("<Rebuild Watchmodel %1 @ %2 >")
+ .arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
+ showMessage(tr("Finished retrieving data"), 400, StatusBar);
+
+ DebuggerToolTipManager::updateEngine(this);
+
+ const bool partial = all["partial"].toInt();
+ if (!partial)
+ updateMemoryViews();
+}
+
+bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
+{
+ return state() == InferiorStopOk && context.isCppEditor;
+}
+
+void DebuggerEngine::updateItem(const QString &iname)
+{
+ if (d->m_lookupRequests.contains(iname)) {
+ showMessage(QString("IGNORING REPEATED REQUEST TO EXPAND " + iname));
+ WatchHandler *handler = watchHandler();
+ WatchItem *item = handler->findItem(iname);
+ QTC_CHECK(item);
+ WatchModelBase *model = handler->model();
+ QTC_CHECK(model);
+ if (item && !model->hasChildren(model->indexForItem(item))) {
+ handler->notifyUpdateStarted(UpdateParameters(iname));
+ item->setValue(decodeData({}, "notaccessible"));
+ item->setHasChildren(false);
+ item->outdated = false;
+ item->update();
+ handler->notifyUpdateFinished();
+ return;
+ }
+ // We could legitimately end up here after expanding + closing + re-expaning an item.
+ }
+ d->m_lookupRequests.insert(iname);
+
+ UpdateParameters params;
+ params.partialVariable = iname;
+ doUpdateLocals(params);
+}
+
+void DebuggerEngine::updateWatchData(const QString &iname)
+{
+ // This is used in cases where re-evaluation is ok for the same iname
+ // e.g. when changing the expression in a watcher.
+ UpdateParameters params;
+ params.partialVariable = iname;
+ doUpdateLocals(params);
+}
+
+void DebuggerEngine::expandItem(const QString &iname)
+{
+ updateItem(iname);
+}
+
+void DebuggerEngine::handleExecDetach()
+{
+ resetLocation();
+ detachDebugger();
+}
+
+void DebuggerEngine::handleExecContinue()
+{
+ resetLocation();
+ continueInferior();
+}
+
+void DebuggerEngine::handleExecInterrupt()
+{
+ resetLocation();
+ requestInterruptInferior();
+}
+
+void DebuggerEngine::handleReset()
+{
+ resetLocation();
+ resetInferior();
+}
+
+void DebuggerEngine::handleExecStep()
+{
+ if (state() == DebuggerNotReady) {
+ DebuggerRunTool::setBreakOnMainNextTime();
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ } else {
+ resetLocation();
+ if (d->operatesByInstruction())
+ executeStepI();
+ else
+ executeStep();
+ }
+}
+
+void DebuggerEngine::handleExecNext()
+{
+ if (state() == DebuggerNotReady) {
+ DebuggerRunTool::setBreakOnMainNextTime();
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ } else {
+ resetLocation();
+ if (d->operatesByInstruction())
+ executeNextI();
+ else
+ executeNext();
+ }
+}
+
+void DebuggerEngine::handleExecStepOut()
+{
+ resetLocation();
+ executeStepOut();
+}
+
+void DebuggerEngine::handleExecReturn()
+{
+ resetLocation();
+ executeReturn();
+}
+
+void DebuggerEngine::handleExecJumpToLine()
+{
+ resetLocation();
+ if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
+ ContextData location = getLocationContext(textEditor->textDocument(),
+ textEditor->currentLine());
+ if (location.isValid())
+ executeJumpToLine(location);
+ }
+}
+
+void DebuggerEngine::handleExecRunToLine()
+{
+ resetLocation();
+ if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
+ ContextData location = getLocationContext(textEditor->textDocument(),
+ textEditor->currentLine());
+ if (location.isValid())
+ executeRunToLine(location);
+ }
+}
+
+void DebuggerEngine::handleExecRunToSelectedFunction()
+{
+ BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
+ QTC_ASSERT(textEditor, return);
+ QTextCursor cursor = textEditor->textCursor();
+ QString functionName = cursor.selectedText();
+ if (functionName.isEmpty()) {
+ const QTextBlock block = cursor.block();
+ const QString line = block.text();
+ foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
+ QString a;
+ for (int i = str.size(); --i >= 0; ) {
+ if (!str.at(i).isLetterOrNumber())
+ break;
+ a = str.at(i) + a;
+ }
+ if (!a.isEmpty()) {
+ functionName = a;
+ break;
+ }
+ }
+ }
+
+ if (functionName.isEmpty()) {
+ showMessage(tr("No function selected."), StatusBar);
+ } else {
+ showMessage(tr("Running to function \"%1\".").arg(functionName), StatusBar);
+ resetLocation();
+ executeRunToFunction(functionName);
+ }
+}
+
+void DebuggerEngine::handleAddToWatchWindow()
+{
+ // Requires a selection, but that's the only case we want anyway.
+ BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
+ if (!textEditor)
+ return;
+ QTextCursor tc = textEditor->textCursor();
+ QString exp;
+ if (tc.hasSelection()) {
+ exp = tc.selectedText();
+ } else {
+ int line, column;
+ exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
+ }
+ if (hasCapability(WatchComplexExpressionsCapability))
+ exp = removeObviousSideEffects(exp);
+ else
+ exp = fixCppExpression(exp);
+ exp = exp.trimmed();
+ if (exp.isEmpty()) {
+ // Happens e.g. when trying to evaluate 'char' or 'return'.
+ AsynchronousMessageBox::warning(tr("Warning"),
+ tr("Select a valid expression to evaluate."));
+ return;
+ }
+ watchHandler()->watchVariable(exp);
+}
+
+void DebuggerEngine::handleFrameDown()
+{
+ frameDown();
+}
+
+void DebuggerEngine::handleFrameUp()
+{
+ frameUp();
+}
+
+void DebuggerEngine::checkState(DebuggerState state, const char *file, int line)
+{
+ const DebuggerState current = d->m_state;
+ if (current == state)
+ return;
+
+ QString msg = QString("UNEXPECTED STATE: %1 WANTED: %2 IN %3:%4")
+ .arg(stateName(current)).arg(stateName(state)).arg(QLatin1String(file)).arg(line);
+
+ showMessage(msg, LogError);
+ qDebug("%s", qPrintable(msg));
+}
+
+bool DebuggerEngine::isNativeMixedEnabled() const
+{
+ return d->m_runParameters.isNativeMixedDebugging();
+}
+
+bool DebuggerEngine::isNativeMixedActive() const
+{
+ return isNativeMixedEnabled(); //&& boolSetting(OperateNativeMixed);
+}
+
+bool DebuggerEngine::isNativeMixedActiveFrame() const
+{
+ if (!isNativeMixedActive())
+ return false;
+ if (stackHandler()->frames().isEmpty())
+ return false;
+ StackFrame frame = stackHandler()->frameAt(0);
+ return frame.language == QmlLanguage;
+}
+
+void DebuggerEngine::startDying() const
+{
+ d->m_isDying = true;
+ if (DebuggerEngine *other = d->m_companionEngine)
+ other->d->m_isDying = true;
+}
+
+bool DebuggerRunParameters::isCppDebugging() const
+{
+ return cppEngineType == GdbEngineType
+ || cppEngineType == LldbEngineType
+ || cppEngineType == CdbEngineType;
+}
+
+bool DebuggerRunParameters::isNativeMixedDebugging() const
+{
+ return nativeMixedEnabled && isCppDebugging() && isQmlDebugging;
+}
+
+QString DebuggerEngine::formatStartParameters() const
+{
+ const DebuggerRunParameters &sp = d->m_runParameters;
+ QString rc;
+ QTextStream str(&rc);
+ str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode
+ << "\nABI: " << sp.toolChainAbi.toString() << '\n';
+ str << "Languages: ";
+ if (sp.isCppDebugging())
+ str << "c++ ";
+ if (sp.isQmlDebugging)
+ str << "qml";
+ str << '\n';
+ if (!sp.inferior.executable.isEmpty()) {
+ str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable)
+ << ' ' << sp.inferior.commandLineArguments;
+ if (d->m_terminalRunner)
+ str << " [terminal]";
+ str << '\n';
+ if (!sp.inferior.workingDirectory.isEmpty())
+ str << "Directory: " << QDir::toNativeSeparators(sp.inferior.workingDirectory)
+ << '\n';
+ }
+ QString cmd = sp.debugger.executable;
+ if (!cmd.isEmpty())
+ str << "Debugger: " << QDir::toNativeSeparators(cmd) << '\n';
+ if (!sp.coreFile.isEmpty())
+ str << "Core: " << QDir::toNativeSeparators(sp.coreFile) << '\n';
+ if (sp.attachPID.isValid())
+ str << "PID: " << sp.attachPID.pid() << ' ' << sp.crashParameter << '\n';
+ if (!sp.projectSourceDirectory.isEmpty()) {
+ str << "Project: " << QDir::toNativeSeparators(sp.projectSourceDirectory) << '\n';
+ str << "Additional Search Directories:"
+ << sp.additionalSearchDirectories.join(QLatin1Char(' ')) << '\n';
+ }
+ if (!sp.remoteChannel.isEmpty())
+ str << "Remote: " << sp.remoteChannel << '\n';
+ if (!sp.qmlServer.host().isEmpty())
+ str << "QML server: " << sp.qmlServer.host() << ':' << sp.qmlServer.port() << '\n';
+ str << "Sysroot: " << sp.sysRoot << '\n';
+ str << "Debug Source Location: " << sp.debugSourceLocation.join(QLatin1Char(':')) << '\n';
+ return rc;
+}
+
+// CppDebuggerEngine
+
+Context CppDebuggerEngine::languageContext() const
+{
+ return Context(Constants::C_CPPDEBUGGER);
+}
+
+void CppDebuggerEngine::validateExecutable()
+{
+ DebuggerRunParameters &rp = mutableRunParameters();
const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds);
bool warnOnInappropriateDebugger = false;
QString detailedWarning;
- switch (toolChainAbi.binaryFormat()) {
+ switch (rp.toolChainAbi.binaryFormat()) {
case Abi::PEFormat: {
QString preferredDebugger;
- if (toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
- if (cppEngineType == CdbEngineType)
+ if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
+ if (rp.cppEngineType == CdbEngineType)
preferredDebugger = "GDB";
- } else if (cppEngineType != CdbEngineType) {
+ } else if (rp.cppEngineType != CdbEngineType) {
// osFlavor() is MSVC, so the recommended debugger is CDB
preferredDebugger = "CDB";
}
@@ -1562,12 +2544,12 @@ void DebuggerRunParameters::validateExecutable()
"experience for this binary format.").arg(preferredDebugger);
break;
}
- if (warnOnRelease && cppEngineType == CdbEngineType) {
- if (!symbolFile.endsWith(".exe", Qt::CaseInsensitive))
- symbolFile.append(".exe");
+ if (warnOnRelease && rp.cppEngineType == CdbEngineType) {
+ if (!rp.symbolFile.endsWith(".exe", Qt::CaseInsensitive))
+ rp.symbolFile.append(".exe");
QString errorMessage;
QStringList rc;
- if (getPDBFiles(symbolFile, &rc, &errorMessage) && !rc.isEmpty())
+ if (getPDBFiles(rp.symbolFile, &rc, &errorMessage) && !rc.isEmpty())
return;
if (!errorMessage.isEmpty()) {
detailedWarning.append('\n');
@@ -1579,7 +2561,7 @@ void DebuggerRunParameters::validateExecutable()
break;
}
case Abi::ElfFormat: {
- if (cppEngineType == CdbEngineType) {
+ if (rp.cppEngineType == CdbEngineType) {
warnOnInappropriateDebugger = true;
detailedWarning = DebuggerEngine::tr(
"The inferior is in the ELF format.\n"
@@ -1588,11 +2570,11 @@ void DebuggerRunParameters::validateExecutable()
break;
}
- Utils::ElfReader reader(symbolFile);
+ Utils::ElfReader reader(rp.symbolFile);
const ElfData elfData = reader.readHeaders();
const QString error = reader.errorString();
- Internal::showMessage("EXAMINING " + symbolFile, LogDebug);
+ showMessage("EXAMINING " + rp.symbolFile, LogDebug);
QByteArray msg = "ELF SECTIONS: ";
static const QList<QByteArray> interesting = {
@@ -1615,15 +2597,15 @@ void DebuggerRunParameters::validateExecutable()
if (interesting.contains(header.name))
seen.insert(header.name);
}
- Internal::showMessage(QString::fromUtf8(msg), LogDebug);
+ showMessage(QString::fromUtf8(msg), LogDebug);
if (!error.isEmpty()) {
- Internal::showMessage("ERROR WHILE READING ELF SECTIONS: " + error, LogDebug);
+ showMessage("ERROR WHILE READING ELF SECTIONS: " + error, LogDebug);
return;
}
if (elfData.sectionHeaders.isEmpty()) {
- Internal::showMessage("NO SECTION HEADERS FOUND. IS THIS AN EXECUTABLE?", LogDebug);
+ showMessage("NO SECTION HEADERS FOUND. IS THIS AN EXECUTABLE?", LogDebug);
return;
}
@@ -1654,7 +2636,7 @@ void DebuggerRunParameters::validateExecutable()
QRegExp exp = itExp->first;
int index = exp.indexIn(string);
if (index != -1) {
- sourcePathMap.insert(string.left(index) + exp.cap(1), itExp->second);
+ rp.sourcePathMap.insert(string.left(index) + exp.cap(1), itExp->second);
found = true;
break;
}
@@ -1696,127 +2678,6 @@ void DebuggerRunParameters::validateExecutable()
}
}
-void DebuggerEngine::updateLocalsView(const GdbMi &all)
-{
- WatchHandler *handler = watchHandler();
-
- const GdbMi typeInfo = all["typeinfo"];
- handler->recordTypeInfo(typeInfo);
-
- const GdbMi data = all["data"];
- handler->insertItems(data);
-
- const GdbMi ns = all["qtnamespace"];
- if (ns.isValid()) {
- setQtNamespace(ns.data());
- showMessage("FOUND NAMESPACED QT: " + ns.data());
- }
-
- static int count = 0;
- showMessage(QString("<Rebuild Watchmodel %1 @ %2 >")
- .arg(++count).arg(LogWindow::logTimeStamp()), LogMiscInput);
- showStatusMessage(tr("Finished retrieving data"), 400);
-
- DebuggerToolTipManager::updateEngine(this);
-
- const bool partial = all["partial"].toInt();
- if (!partial)
- updateMemoryViews();
-}
-
-bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
-{
- return state() == InferiorStopOk && context.isCppEditor;
-}
-
-void DebuggerEngine::updateItem(const QString &iname)
-{
- if (d->m_lookupRequests.contains(iname)) {
- showMessage(QString("IGNORING REPEATED REQUEST TO EXPAND " + iname));
- WatchHandler *handler = watchHandler();
- WatchItem *item = handler->findItem(iname);
- QTC_CHECK(item);
- WatchModelBase *model = handler->model();
- QTC_CHECK(model);
- if (item && !model->hasChildren(model->indexForItem(item))) {
- handler->notifyUpdateStarted(UpdateParameters(iname));
- item->setValue(decodeData({}, "notaccessible"));
- item->setHasChildren(false);
- item->outdated = false;
- item->update();
- handler->notifyUpdateFinished();
- return;
- }
- // We could legitimately end up here after expanding + closing + re-expaning an item.
- }
- d->m_lookupRequests.insert(iname);
-
- UpdateParameters params;
- params.partialVariable = iname;
- doUpdateLocals(params);
-}
-
-void DebuggerEngine::updateWatchData(const QString &iname)
-{
- // This is used in cases where re-evaluation is ok for the same iname
- // e.g. when changing the expression in a watcher.
- UpdateParameters params;
- params.partialVariable = iname;
- doUpdateLocals(params);
-}
-
-void DebuggerEngine::expandItem(const QString &iname)
-{
- updateItem(iname);
-}
-
-void DebuggerEngine::checkState(DebuggerState state, const char *file, int line)
-{
- const DebuggerState current = d->m_state;
- if (current == state)
- return;
-
- QString msg = QString("UNEXPECTED STATE: %1 WANTED: %2 IN %3:%4")
- .arg(stateName(current)).arg(stateName(state)).arg(QLatin1String(file)).arg(line);
-
- showMessage(msg, LogError);
- qDebug("%s", qPrintable(msg));
-}
-
-bool DebuggerEngine::isNativeMixedEnabled() const
-{
- if (DebuggerRunTool *rt = runTool())
- return rt->runParameters().isNativeMixedDebugging();
- return false;
-}
-
-bool DebuggerEngine::isNativeMixedActive() const
-{
- return isNativeMixedEnabled(); //&& boolSetting(OperateNativeMixed);
-}
-
-bool DebuggerEngine::isNativeMixedActiveFrame() const
-{
- if (!isNativeMixedActive())
- return false;
- if (stackHandler()->frames().isEmpty())
- return false;
- StackFrame frame = stackHandler()->frameAt(0);
- return frame.language == QmlLanguage;
-}
-
-bool DebuggerRunParameters::isCppDebugging() const
-{
- return cppEngineType == CdbEngineType
- || cppEngineType == GdbEngineType
- || cppEngineType == LldbEngineType;
-}
-
-bool DebuggerRunParameters::isNativeMixedDebugging() const
-{
- return nativeMixedEnabled && isCppDebugging() && isQmlDebugging;
-}
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h
index 37d4f10a10..1463408583 100644
--- a/src/plugins/debugger/debuggerengine.h
+++ b/src/plugins/debugger/debuggerengine.h
@@ -29,7 +29,9 @@
#include "debuggerconstants.h"
#include "debuggeritem.h"
#include "debuggerprotocol.h"
+#include "breakhandler.h"
+#include <coreplugin/icontext.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/runconfiguration.h>
#include <texteditor/textmark.h>
@@ -41,12 +43,14 @@
QT_BEGIN_NAMESPACE
class QDebug;
class QPoint;
-class QAbstractItemModel;
QT_END_NAMESPACE
namespace Core { class IOptionsPage; }
-namespace Utils { class MacroExpander; }
+namespace Utils {
+class MacroExpander;
+class Perspective;
+} // Utils
namespace Debugger {
@@ -62,7 +66,9 @@ class DisassemblerAgent;
class MemoryAgent;
class WatchItem;
class BreakHandler;
+class BreakpointParameters;
class LocationMark;
+class LogWindow;
class ModulesHandler;
class RegisterHandler;
class StackHandler;
@@ -70,8 +76,7 @@ class StackFrame;
class SourceFilesHandler;
class ThreadsHandler;
class WatchHandler;
-class Breakpoint;
-class QmlCppEngine;
+class WatchTreeView;
class DebuggerToolTipContext;
class MemoryViewSetupData;
class TerminalRunner;
@@ -157,7 +162,6 @@ public:
bool isCppDebugging() const;
bool isNativeMixedDebugging() const;
- void validateExecutable();
Utils::MacroExpander *macroExpander = nullptr;
@@ -219,32 +223,21 @@ private:
quint64 m_address = 0;
};
-enum LocationType { UnknownLocation, LocationByFile, LocationByAddress };
-
-class ContextData
-{
-public:
- bool isValid() const { return type != UnknownLocation; }
-
-public:
- LocationType type = UnknownLocation;
- QString fileName;
- int lineNumber = 0;
- quint64 address = 0;
-};
-
class DebuggerEngine : public QObject
{
Q_OBJECT
public:
- explicit DebuggerEngine();
+ DebuggerEngine();
~DebuggerEngine() override;
- const DebuggerRunParameters &runParameters() const;
+ void setRunTool(DebuggerRunTool *runTool);
+ void setRunParameters(const DebuggerRunParameters &runParameters);
- virtual void setRunTool(DebuggerRunTool *runTool);
- DebuggerRunTool *runTool() const;
+ const DebuggerRunParameters &runParameters() const;
+ bool isStartupRunConfiguration() const;
+ void setCompanionEngine(DebuggerEngine *engine);
+ void setSecondaryEngine();
void start();
@@ -269,6 +262,7 @@ public:
void updateWatchData(const QString &iname); // FIXME: Merge with above.
virtual void selectWatchData(const QString &iname);
+ virtual void validateExecutable() {}
virtual void prepareForRestart() {}
virtual void abortDebuggerProcess() {} // second attempt
@@ -308,39 +302,39 @@ public:
virtual void updateAll();
virtual void updateLocals();
+ virtual Core::Context languageContext() const { return {}; }
+ virtual QString displayName() const;
+
virtual bool stateAcceptsBreakpointChanges() const { return true; }
- virtual void attemptBreakpointSynchronization();
- virtual bool acceptsBreakpoint(Breakpoint bp) const = 0;
- virtual void insertBreakpoint(Breakpoint bp); // FIXME: make pure
- virtual void removeBreakpoint(Breakpoint bp); // FIXME: make pure
- virtual void changeBreakpoint(Breakpoint bp); // FIXME: make pure
- virtual void enableSubBreakpoint(const QString &locid, bool on);
+ virtual bool acceptsBreakpoint(const BreakpointParameters &bp) const = 0;
+ virtual void insertBreakpoint(const Breakpoint &bp) = 0;
+ virtual void removeBreakpoint(const Breakpoint &bp) = 0;
+ virtual void updateBreakpoint(const Breakpoint &bp) = 0;
+ virtual void enableSubBreakpoint(const SubBreakpoint &sbp, bool enabled);
virtual bool acceptsDebuggerCommands() const { return true; }
- virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages);
+ virtual void executeDebuggerCommand(const QString &command);
virtual void assignValueInDebugger(WatchItem *item,
const QString &expr, const QVariant &value);
virtual void selectThread(Internal::ThreadId threadId) = 0;
- virtual Internal::ModulesHandler *modulesHandler() const;
- virtual Internal::RegisterHandler *registerHandler() const;
- virtual Internal::StackHandler *stackHandler() const;
- virtual Internal::ThreadsHandler *threadsHandler() const;
- virtual Internal::WatchHandler *watchHandler() const;
- virtual Internal::SourceFilesHandler *sourceFilesHandler() const;
- virtual Internal::BreakHandler *breakHandler() const;
-
- virtual QAbstractItemModel *modulesModel() const;
- virtual QAbstractItemModel *registerModel() const;
- virtual QAbstractItemModel *stackModel() const;
- virtual QAbstractItemModel *threadsModel() const;
- virtual QAbstractItemModel *watchModel() const;
- virtual QAbstractItemModel *sourceFilesModel() const;
+ virtual void executeRecordReverse(bool) {}
+ virtual void executeReverse(bool) {}
+
+ ModulesHandler *modulesHandler() const;
+ RegisterHandler *registerHandler() const;
+ StackHandler *stackHandler() const;
+ ThreadsHandler *threadsHandler() const;
+ WatchHandler *watchHandler() const;
+ SourceFilesHandler *sourceFilesHandler() const;
+ BreakHandler *breakHandler() const;
+ LogWindow *logWindow() const;
+ DisassemblerAgent *disassemblerAgent() const;
void progressPing();
bool debuggerActionsEnabled() const;
- static bool debuggerActionsEnabled(DebuggerState state);
+ virtual bool companionPreventsActions() const;
DebuggerState state() const;
bool isDying() const;
@@ -349,7 +343,13 @@ public:
void notifyInferiorPid(const Utils::ProcessHandle &pid);
qint64 inferiorPid() const;
+
bool isReverseDebugging() const;
+ void handleBeginOfRecordingReached();
+ void handleRecordingFailed();
+ void handleRecordReverse(bool);
+ void handleReverseDirection(bool);
+
void handleCommand(int role, const QVariant &value);
// Convenience
@@ -359,30 +359,32 @@ public:
virtual void resetLocation();
virtual void gotoLocation(const Internal::Location &location);
+ void gotoCurrentLocation();
virtual void quitDebugger(); // called when pressing the stop button
+ void abortDebugger();
- void updateViews();
- bool isSlaveEngine() const;
- bool isMasterEngine() const;
- DebuggerEngine *masterEngine();
- virtual DebuggerEngine *activeEngine() { return this; }
- virtual DebuggerEngine *cppEngine() { return nullptr; }
+ bool isPrimaryEngine() const;
virtual bool canDisplayTooltip() const;
- virtual void notifyInferiorIll();
-
QString toFileInProject(const QUrl &fileUrl);
- void updateBreakpointMarker(const Breakpoint &bp);
- void removeBreakpointMarker(const Breakpoint &bp);
QString expand(const QString &string) const;
QString nativeStartupCommands() const;
+ Utils::Perspective *perspective() const;
+ void updateMarkers();
+
+signals:
+ void engineStarted();
+ void engineFinished();
+ void requestRunControlFinish();
+ void requestRunControlStop();
+ void attachToCoreRequested(const QString &coreFile);
+ void appendMessageRequested(const QString &msg,
+ Utils::OutputFormat format,
+ bool appendNewLine) const;
protected:
- // The base notify*() function implementation should be sufficient
- // in most cases, but engines are free to override them to do some
- // engine specific cleanup like stopping timers etc.
void notifyEngineSetupOk();
void notifyEngineSetupFailed();
void notifyEngineRunFailed();
@@ -398,14 +400,60 @@ protected:
void notifyInferiorRunOk();
void notifyInferiorRunFailed();
+ void notifyInferiorIll();
+ void notifyInferiorExited();
+
void notifyInferiorStopOk();
void notifyInferiorSpontaneousStop();
void notifyInferiorStopFailed();
- public: // FIXME: Remove, currently needed for Android.
- void notifyInferiorExited();
+public:
+ void updateState(bool alsoUpdateCompanion);
+ QString formatStartParameters() const;
+ WatchTreeView *inspectorView();
+ void updateLocalsWindow(bool showReturn);
+ void raiseWatchersWindow();
+
+ bool isRegistersWindowVisible() const;
+ bool isModulesWindowVisible() const;
+
+ void setThreadBoxContents(const QStringList &list, int index);
+
+ void openMemoryEditor();
+
+ void handleExecDetach();
+ void handleExecContinue();
+ void handleExecInterrupt();
+ void handleUserStop();
+ void handleAbort();
+ void handleReset();
+ void handleExecStep();
+ void handleExecNext();
+ void handleExecStepOut();
+ void handleExecReturn();
+ void handleExecJumpToLine();
+ void handleExecRunToLine();
+ void handleExecRunToSelectedFunction();
+ void handleAddToWatchWindow();
+ void handleFrameDown();
+ void handleFrameUp();
+ void handleOperateByInstructionTriggered(bool operateByInstructionTriggered);
+
+ // Breakpoint state transitions
+ void notifyBreakpointInsertProceeding(const Breakpoint &bp);
+ void notifyBreakpointInsertOk(const Breakpoint &bp);
+ void notifyBreakpointInsertFailed(const Breakpoint &bp);
+ void notifyBreakpointChangeOk(const Breakpoint &bp);
+ void notifyBreakpointChangeProceeding(const Breakpoint &bp);
+ void notifyBreakpointChangeFailed(const Breakpoint &bp);
+ void notifyBreakpointPending(const Breakpoint &bp);
+ void notifyBreakpointRemoveProceeding(const Breakpoint &bp);
+ void notifyBreakpointRemoveOk(const Breakpoint &bp);
+ void notifyBreakpointRemoveFailed(const Breakpoint &bp);
+ void notifyBreakpointNeedsReinsertion(const Breakpoint &bp);
- protected:
+protected:
+ void setDebuggerName(const QString &name);
void notifyDebuggerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus,
const QString &backendName);
@@ -424,29 +472,27 @@ protected:
virtual void shutdownEngine() = 0;
virtual void resetInferior() {}
- virtual void detachDebugger();
- virtual void executeStep();
- virtual void executeStepOut();
- virtual void executeNext();
- virtual void executeStepI();
- virtual void executeNextI();
- virtual void executeReturn();
+ virtual void detachDebugger() {}
+ virtual void executeStep() {}
+ virtual void executeStepOut() {}
+ virtual void executeNext() {}
+ virtual void executeStepI() {}
+ virtual void executeNextI() {}
+ virtual void executeReturn() {}
- virtual void continueInferior();
- virtual void interruptInferior();
+ virtual void continueInferior() {}
+ virtual void interruptInferior() {}
void requestInterruptInferior();
- virtual void executeRunToLine(const Internal::ContextData &data);
- virtual void executeRunToFunction(const QString &functionName);
- virtual void executeJumpToLine(const Internal::ContextData &data);
+ virtual void executeRunToLine(const Internal::ContextData &) {}
+ virtual void executeRunToFunction(const QString &) {}
+ virtual void executeJumpToLine(const Internal::ContextData &) {}
virtual void frameUp();
virtual void frameDown();
virtual void doUpdateLocals(const UpdateParameters &params);
- void setMasterEngine(DebuggerEngine *masterEngine);
-
TerminalRunner *terminal() const;
static QString msgStopped(const QString &reason = QString());
@@ -457,35 +503,43 @@ protected:
bool showStoppedBySignalMessageBox(const QString meaning, QString name);
void showStoppedByExceptionMessageBox(const QString &description);
- virtual void setupSlaveEngine();
- virtual void runSlaveEngine();
- virtual void shutdownSlaveEngine();
-
- virtual void slaveEngineStateChanged(DebuggerEngine *engine,
- DebuggerState state);
-
void updateLocalsView(const GdbMi &all);
void checkState(DebuggerState state, const char *file, int line);
bool isNativeMixedEnabled() const;
bool isNativeMixedActive() const;
bool isNativeMixedActiveFrame() const;
+ void startDying() const;
+
+protected:
+ DebuggerRunParameters &mutableRunParameters() const;
+ ProjectExplorer::IDevice::ConstPtr device() const;
+ DebuggerEngine *companionEngine() const;
private:
- // Wrapper engine needs access to state of its subengines.
- friend class QmlCppEngine;
friend class DebuggerPluginPrivate;
-
friend class DebuggerEnginePrivate;
friend class LocationMark;
DebuggerEnginePrivate *d;
};
+class CppDebuggerEngine : public DebuggerEngine
+{
+public:
+ CppDebuggerEngine() {}
+ ~CppDebuggerEngine() override {}
+
+ void validateExecutable() override;
+ Core::Context languageContext() const override;
+};
+
class LocationMark : public TextEditor::TextMark
{
public:
LocationMark(DebuggerEngine *engine, const Utils::FileName &file, int line);
void removedFromEditor() override { updateLineNumber(0); }
+ void updateIcon();
+
private:
bool isDraggable() const override;
void dragToLine(int line) override;
diff --git a/src/plugins/debugger/debuggericons.cpp b/src/plugins/debugger/debuggericons.cpp
index 15d480e3f7..776e54afe1 100644
--- a/src/plugins/debugger/debuggericons.cpp
+++ b/src/plugins/debugger/debuggericons.cpp
@@ -81,9 +81,18 @@ const Icon DEBUG_EXIT_SMALL_TOOLBAR({
const Icon LOCATION({
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
+const Icon REVERSE_LOCATION({
+ {":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
+ {":/debugger/images/debugger_reversemode.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
const Icon REVERSE_MODE({
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
{":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint);
+const Icon DIRECTION_BACKWARD({
+ {":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
+ {":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint);
+const Icon DIRECTION_FORWARD({
+ {":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
+ {":/debugger/images/location.png", Theme::IconsInfoColor}}, Icon::Tint);
const Icon APP_ON_TOP({
{":/utils/images/app-on-top.png", Theme::PanelTextColorMid}}, Icon::MenuTintedStyle);
const Icon APP_ON_TOP_TOOLBAR({
diff --git a/src/plugins/debugger/debuggericons.h b/src/plugins/debugger/debuggericons.h
index 7d8bf804c1..0030597dbf 100644
--- a/src/plugins/debugger/debuggericons.h
+++ b/src/plugins/debugger/debuggericons.h
@@ -55,7 +55,10 @@ extern const Utils::Icon DEBUG_INTERRUPT_SMALL_TOOLBAR;
extern const Utils::Icon DEBUG_EXIT_SMALL;
extern const Utils::Icon DEBUG_EXIT_SMALL_TOOLBAR;
extern const Utils::Icon LOCATION;
+extern const Utils::Icon REVERSE_LOCATION;
extern const Utils::Icon REVERSE_MODE;
+extern const Utils::Icon DIRECTION_FORWARD;
+extern const Utils::Icon DIRECTION_BACKWARD;
extern const Utils::Icon APP_ON_TOP;
extern const Utils::Icon APP_ON_TOP_TOOLBAR;
extern const Utils::Icon SELECT;
diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h
index 0ec6df1111..cb9591e8ad 100644
--- a/src/plugins/debugger/debuggerinternalconstants.h
+++ b/src/plugins/debugger/debuggerinternalconstants.h
@@ -31,16 +31,18 @@ namespace Debugger {
namespace Internal {
// DebuggerMainWindow dock widget names
-const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";
-const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules";
-const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register";
-const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output";
-const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots";
-const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack";
-const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles";
-const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads";
+const char DOCKWIDGET_BREAKPOINTMANAGER[] = "Debugger.Docks.BreakpointManager";
+const char DOCKWIDGET_ENGINEMANAGER[] = "Debugger.Docks.Snapshots";
+const char DOCKWIDGET_GLOBALLOG[] = "Debugger.Docks.GlobalLog";
+
+const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";
+const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules";
+const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register";
+const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output";
+const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack";
+const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles";
+const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads";
const char DOCKWIDGET_LOCALS_AND_INSPECTOR[] = "Debugger.Docks.LocalsAndInspector";
-const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.Watchers";
} // namespace Internal
diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp
index c2ae3fa0dd..ed950d4ca2 100644
--- a/src/plugins/debugger/debuggermainwindow.cpp
+++ b/src/plugins/debugger/debuggermainwindow.cpp
@@ -49,6 +49,7 @@
#include <QAction>
#include <QComboBox>
+#include <QDebug>
#include <QDockWidget>
#include <QHBoxLayout>
#include <QMenu>
@@ -64,56 +65,212 @@ namespace Utils {
const char LAST_PERSPECTIVE_KEY[] = "LastPerspective";
-DebuggerMainWindow::DebuggerMainWindow()
+static DebuggerMainWindow *theMainWindow = nullptr;
+
+class ToolbarOperation
+{
+public:
+ void attachToToolbar(QWidget *parent)
+ {
+ QLayout *layout = parent->layout();
+ if (toolBarWidget) {
+ toolBarWidget->setParent(parent);
+ layout->addWidget(toolBarWidget);
+ }
+ if (toolBarAction) {
+ toolBarAction->m_toolButton = new QToolButton(parent);
+ toolBarAction->m_toolButton->setToolButtonStyle(toolBarAction->m_toolButtonStyle);
+ toolBarAction->m_toolButton->setProperty("panelwidget", true);
+ toolBarAction->m_toolButton->setDefaultAction(toolBarAction);
+ toolBarAction->m_toolButton->setVisible(toolBarAction->isVisible());
+ layout->addWidget(toolBarAction->m_toolButton);
+ }
+ if (toolBarPlainAction) {
+ toolBarPlainActionButton = new QToolButton(parent);
+ toolBarPlainActionButton->setProperty("panelwidget", true);
+ toolBarPlainActionButton->setDefaultAction(toolBarPlainAction);
+ layout->addWidget(toolBarPlainActionButton);
+ }
+ if (separator) {
+ separator->setParent(parent);
+ layout->addWidget(separator);
+ }
+ }
+
+ void detachFromToolbar()
+ {
+ if (toolBarWidget) {
+ toolBarWidget->setParent(nullptr);
+ }
+ if (toolBarAction) {
+ delete toolBarAction->m_toolButton;
+ toolBarAction->m_toolButton = nullptr;
+ }
+ if (toolBarPlainAction) {
+ delete toolBarPlainActionButton;
+ toolBarPlainActionButton = nullptr;
+ }
+ if (separator) {
+ separator->setParent(nullptr);
+ }
+ }
+
+ QPointer<QAction> toolBarPlainAction; // Owned by plugin if present.
+ QPointer<OptionalAction> toolBarAction; // Owned by plugin if present.
+ QPointer<QWidget> toolBarWidget; // Owned by plugin if present.
+
+ // Helper/wrapper widget owned by us if present.
+ QPointer<QToolButton> toolBarPlainActionButton;
+ QPointer<QWidget> toolBarWidgetParent;
+ QPointer<QWidget> separator;
+};
+
+class DockOperation
+{
+public:
+ QPointer<QWidget> widget;
+ QByteArray anchorDockId;
+ Perspective::OperationType operationType = Perspective::Raise;
+ bool visibleByDefault = true;
+ Qt::DockWidgetArea area = Qt::BottomDockWidgetArea;
+};
+
+class PerspectivePrivate
+{
+public:
+ ~PerspectivePrivate() { destroyToolBar(); }
+
+ void showToolBar();
+ void hideToolBar();
+ void destroyToolBar();
+
+ QString m_id;
+ QString m_name;
+ QByteArray m_parentPerspective;
+ QVector<DockOperation> m_dockOperations;
+ QVector<ToolbarOperation> m_toolBarOperations;
+ QPointer<QWidget> m_centralWidget;
+ Perspective::Callback m_aboutToActivateCallback;
+ QPointer<QWidget> m_toolButtonBox;
+};
+
+class DebuggerMainWindowPrivate : public QObject
+{
+public:
+ DebuggerMainWindowPrivate(DebuggerMainWindow *parent);
+ ~DebuggerMainWindowPrivate();
+
+ void ensureToolBarDockExists();
+
+ void restorePerspective(Perspective *perspective);
+ void loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings = true);
+ void savePerspectiveHelper(const Perspective *perspective);
+ void destroyPerspective(Perspective *perspective);
+ void registerPerspective(Perspective *perspective);
+ void increaseChooserWidthIfNecessary(const QString &visibleName);
+ void resetCurrentPerspective();
+ Perspective *findPerspective(const QByteArray &perspectiveId) const;
+ int indexInChooser(Perspective *perspective) const;
+
+ DebuggerMainWindow *q = nullptr;
+ Perspective *m_currentPerspective = nullptr;
+ QComboBox *m_perspectiveChooser = nullptr;
+ QStackedWidget *m_centralWidgetStack = nullptr;
+ QHBoxLayout *m_toolBarLayout = nullptr;
+ QWidget *m_editorPlaceHolder = nullptr;
+ Utils::StatusLabel *m_statusLabel = nullptr;
+ QDockWidget *m_toolBarDock = nullptr;
+
+ QHash<QByteArray, QDockWidget *> m_dockForDockId;
+ QList<Perspective *> m_perspectives;
+};
+
+DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent)
+ : q(parent)
{
m_centralWidgetStack = new QStackedWidget;
m_statusLabel = new Utils::StatusLabel;
+ m_statusLabel->setProperty("panelwidget", true);
m_editorPlaceHolder = new EditorManagerPlaceHolder;
m_perspectiveChooser = new QComboBox;
m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser"));
+ m_perspectiveChooser->setProperty("panelwidget", true);
connect(m_perspectiveChooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
this, [this](int item) {
- restorePerspective(findPerspective(m_perspectiveChooser->itemData(item).toByteArray()));
+ restorePerspective(q->findPerspective(m_perspectiveChooser->itemData(item).toByteArray()));
});
+}
+
+DebuggerMainWindow::DebuggerMainWindow()
+ : d(new DebuggerMainWindowPrivate(this))
+{
+ theMainWindow = this;
setDockNestingEnabled(true);
setDockActionsVisible(false);
setDocumentMode(true);
connect(this, &FancyMainWindow::resetLayout,
- this, &DebuggerMainWindow::resetCurrentPerspective);
+ d, &DebuggerMainWindowPrivate::resetCurrentPerspective);
+
+ Context debugcontext(Debugger::Constants::C_DEBUGMODE);
+
+ ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
+ Command *cmd = ActionManager::registerAction(showCentralWidgetAction(),
+ "Debugger.Views.ShowCentralWidget", debugcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ cmd->setAttribute(Command::CA_UpdateText);
+ viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+ cmd = ActionManager::registerAction(menuSeparator1(),
+ "Debugger.Views.Separator1", debugcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+ cmd = ActionManager::registerAction(autoHideTitleBarsAction(),
+ "Debugger.Views.AutoHideTitleBars", debugcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+ cmd = ActionManager::registerAction(menuSeparator2(),
+ "Debugger.Views.Separator2", debugcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+ cmd = ActionManager::registerAction(resetLayoutAction(),
+ "Debugger.Views.ResetSimple", debugcontext);
+ cmd->setAttribute(Command::CA_Hide);
+ viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
}
DebuggerMainWindow::~DebuggerMainWindow()
{
+ delete d;
+ theMainWindow = nullptr;
+}
+
+DebuggerMainWindowPrivate::~DebuggerMainWindowPrivate()
+{
savePerspectiveHelper(m_currentPerspective);
delete m_editorPlaceHolder;
m_editorPlaceHolder = nullptr;
- // As we have to setParent(0) on dock widget that are not selected,
- // we keep track of all and make sure we don't leak any
- foreach (QDockWidget *dock, m_dockForDockId) {
- if (dock && !dock->parentWidget())
- delete dock;
- }
-
- foreach (const Perspective *perspective, m_perspectives)
- delete perspective;
}
void DebuggerMainWindow::registerPerspective(Perspective *perspective)
{
+ d->registerPerspective(perspective);
+}
+
+void DebuggerMainWindowPrivate::registerPerspective(Perspective *perspective)
+{
m_perspectives.append(perspective);
- QByteArray parentPerspective = perspective->parentPerspective();
+ QByteArray parentPerspective = perspective->d->m_parentPerspective;
// Add "main" perspectives to the chooser.
if (parentPerspective.isEmpty()) {
- m_perspectiveChooser->addItem(perspective->name(), perspective->m_id);
+ m_perspectiveChooser->addItem(perspective->name(), perspective->id());
increaseChooserWidthIfNecessary(perspective->name());
}
}
-void DebuggerMainWindow::increaseChooserWidthIfNecessary(const QString &visibleName)
+void DebuggerMainWindowPrivate::increaseChooserWidthIfNecessary(const QString &visibleName)
{
const int oldWidth = m_perspectiveChooser->width();
const int contentWidth = m_perspectiveChooser->fontMetrics().width(visibleName);
@@ -126,49 +283,32 @@ void DebuggerMainWindow::increaseChooserWidthIfNecessary(const QString &visibleN
m_perspectiveChooser->setFixedWidth(width);
}
-void DebuggerMainWindow::destroyDynamicPerspective(Perspective *perspective)
+void DebuggerMainWindowPrivate::destroyPerspective(Perspective *perspective)
{
- QTC_ASSERT(perspective, return);
savePerspectiveHelper(perspective);
-
m_perspectives.removeAll(perspective);
+
// Dynamic perspectives are currently not visible in the chooser.
// This might change in the future, make sure we notice.
const int idx = indexInChooser(perspective);
QTC_ASSERT(idx == -1, m_perspectiveChooser->removeItem(idx));
- QByteArray parentPerspective = perspective->parentPerspective();
- delete perspective;
+
// All dynamic perspectives currently have a static parent perspective.
// This might change in the future, make sure we notice.
- QTC_CHECK(!parentPerspective.isEmpty());
- restorePerspective(findPerspective(parentPerspective));
+ QTC_CHECK(!perspective->d->m_parentPerspective.isEmpty());
+ restorePerspective(findPerspective(perspective->d->m_parentPerspective));
}
void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS)
{
- m_statusLabel->showStatusMessage(message, timeoutMS);
-}
-
-void DebuggerMainWindow::raiseDock(const QByteArray &dockId)
-{
- QDockWidget *dock = m_dockForDockId.value(dockId);
- QTC_ASSERT(dock, return);
- QAction *act = dock->toggleViewAction();
- if (!act->isChecked())
- QTimer::singleShot(1, act, [act] { act->trigger(); });
- dock->raise();
-}
-
-QByteArray DebuggerMainWindow::currentPerspective() const
-{
- return m_currentPerspective ? m_currentPerspective->m_id : QByteArray();
+ d->m_statusLabel->showStatusMessage(message, timeoutMS);
}
void DebuggerMainWindow::onModeChanged(Core::Id mode)
{
if (mode == Debugger::Constants::MODE_DEBUG) {
setDockActionsVisible(true);
- restorePerspective(nullptr);
+ d->restorePerspective(nullptr);
} else {
setDockActionsVisible(false);
@@ -180,35 +320,39 @@ void DebuggerMainWindow::onModeChanged(Core::Id mode)
}
}
-void DebuggerMainWindow::setPerspectiveEnabled(const QByteArray &perspectiveId, bool enabled)
+Perspective *DebuggerMainWindow::findPerspective(const QByteArray &perspectiveId) const
{
- Perspective *perspective = findPerspective(perspectiveId);
- const int index = indexInChooser(perspective);
- QTC_ASSERT(index != -1, return);
- auto model = qobject_cast<QStandardItemModel*>(m_perspectiveChooser->model());
- QTC_ASSERT(model, return);
- QStandardItem *item = model->item(index, 0);
- item->setFlags(enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
+ return d->findPerspective(perspectiveId);
}
-Perspective *DebuggerMainWindow::findPerspective(const QByteArray &perspectiveId) const
+QWidget *DebuggerMainWindow::centralWidgetStack()
+{
+ return d->m_centralWidgetStack;
+}
+
+Perspective *DebuggerMainWindowPrivate::findPerspective(const QByteArray &perspectiveId) const
{
return Utils::findOr(m_perspectives, nullptr, [&](Perspective *perspective) {
- return perspective->m_id == perspectiveId;
+ return perspective->d->m_id.toUtf8() == perspectiveId;
});
}
-void DebuggerMainWindow::resetCurrentPerspective()
+void DebuggerMainWindow::closeEvent(QCloseEvent *)
+{
+ d->savePerspectiveHelper(d->m_currentPerspective);
+}
+
+void DebuggerMainWindowPrivate::resetCurrentPerspective()
{
loadPerspectiveHelper(m_currentPerspective, false);
}
-int DebuggerMainWindow::indexInChooser(Perspective *perspective) const
+int DebuggerMainWindowPrivate::indexInChooser(Perspective *perspective) const
{
- return perspective ? m_perspectiveChooser->findData(perspective->m_id) : -1;
+ return perspective ? m_perspectiveChooser->findData(perspective->d->m_id) : -1;
}
-void DebuggerMainWindow::restorePerspective(Perspective *perspective)
+void DebuggerMainWindowPrivate::restorePerspective(Perspective *perspective)
{
loadPerspectiveHelper(perspective, true);
@@ -217,8 +361,11 @@ void DebuggerMainWindow::restorePerspective(Perspective *perspective)
m_perspectiveChooser->setCurrentIndex(index);
}
-void DebuggerMainWindow::finalizeSetup()
+void DebuggerMainWindowPrivate::ensureToolBarDockExists()
{
+ if (m_toolBarDock)
+ return;
+
auto viewButton = new QToolButton;
viewButton->setText(tr("&Views"));
@@ -226,18 +373,15 @@ void DebuggerMainWindow::finalizeSetup()
closeButton->setIcon(Utils::Icons::CLOSE_SPLIT_BOTTOM.icon());
closeButton->setToolTip(tr("Leave Debug Mode"));
- auto toolbuttonBox = new QWidget;
- m_toolbuttonBoxLayout = new QHBoxLayout(toolbuttonBox);
- m_toolbuttonBoxLayout->setMargin(0);
- m_toolbuttonBoxLayout->setSpacing(0);
-
auto toolbar = new Utils::StyledBar;
toolbar->setProperty("topBorder", true);
auto hbox = new QHBoxLayout(toolbar);
+ m_toolBarLayout = hbox;
hbox->setMargin(0);
hbox->setSpacing(0);
hbox->addWidget(m_perspectiveChooser);
- hbox->addWidget(toolbuttonBox);
+ // <- All perspective toolbars will get inserted here, but only
+ // the current perspective's toolbar is set visible.
hbox->addStretch(3);
hbox->addWidget(m_statusLabel);
hbox->addStretch(1);
@@ -245,41 +389,6 @@ void DebuggerMainWindow::finalizeSetup()
hbox->addWidget(viewButton);
hbox->addWidget(closeButton);
- connect(viewButton, &QAbstractButton::clicked, [this, viewButton] {
- QMenu menu;
- addDockActionsToMenu(&menu);
- menu.exec(viewButton->mapToGlobal(QPoint()));
- });
-
- connect(closeButton, &QAbstractButton::clicked, [] {
- ModeManager::activateMode(Core::Constants::MODE_EDIT);
- });
-
- Context debugcontext(Debugger::Constants::C_DEBUGMODE);
-
- ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS);
- Command *cmd = ActionManager::registerAction(showCentralWidgetAction(),
- "Debugger.Views.ShowCentralWidget", debugcontext);
- cmd->setAttribute(Command::CA_Hide);
- cmd->setAttribute(Command::CA_UpdateText);
- viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
- cmd = ActionManager::registerAction(menuSeparator1(),
- "Debugger.Views.Separator1", debugcontext);
- cmd->setAttribute(Command::CA_Hide);
- viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
- cmd = ActionManager::registerAction(autoHideTitleBarsAction(),
- "Debugger.Views.AutoHideTitleBars", debugcontext);
- cmd->setAttribute(Command::CA_Hide);
- viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
- cmd = ActionManager::registerAction(menuSeparator2(),
- "Debugger.Views.Separator2", debugcontext);
- cmd->setAttribute(Command::CA_Hide);
- viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
- cmd = ActionManager::registerAction(resetLayoutAction(),
- "Debugger.Views.ResetSimple", debugcontext);
- cmd->setAttribute(Command::CA_Hide);
- viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
-
auto dock = new QDockWidget(tr("Toolbar"));
dock->setObjectName(QLatin1String("Toolbar"));
dock->setFeatures(QDockWidget::NoDockWidgetFeatures);
@@ -287,9 +396,18 @@ void DebuggerMainWindow::finalizeSetup()
dock->setTitleBarWidget(new QWidget(dock)); // hide title bar
dock->setProperty("managed_dockwidget", QLatin1String("true"));
dock->setWidget(toolbar);
- m_toolbarDock = dock;
+ m_toolBarDock = dock;
+ q->addDockWidget(Qt::BottomDockWidgetArea, m_toolBarDock);
- addDockWidget(Qt::BottomDockWidgetArea, dock);
+ connect(viewButton, &QAbstractButton::clicked, [this, viewButton] {
+ QMenu menu;
+ q->addDockActionsToMenu(&menu);
+ menu.exec(viewButton->mapToGlobal(QPoint()));
+ });
+
+ connect(closeButton, &QAbstractButton::clicked, [] {
+ ModeManager::activateMode(Core::Constants::MODE_EDIT);
+ });
}
QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow)
@@ -342,13 +460,12 @@ QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow)
return splitter;
}
-void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings)
+void DebuggerMainWindowPrivate::loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings)
{
// Clean up old perspective.
if (m_currentPerspective) {
savePerspectiveHelper(m_currentPerspective);
for (QDockWidget *dock : m_dockForDockId) {
- QTC_ASSERT(dock, continue);
dock->setParent(nullptr);
dock->widget()->setParent(nullptr);
ActionManager::unregisterAction(dock->toggleViewAction(),
@@ -357,22 +474,11 @@ void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fr
}
m_dockForDockId.clear();
- ICore::removeAdditionalContext(Context(Id::fromName(m_currentPerspective->m_id)));
+ ICore::removeAdditionalContext(m_currentPerspective->context());
QWidget *central = m_currentPerspective->centralWidget();
m_centralWidgetStack->removeWidget(central ? central : m_editorPlaceHolder);
- // Detach potentially re-used widgets to prevent deletion.
- for (const Perspective::ToolbarOperation &op : m_currentPerspective->m_toolbarOperations) {
- if (op.widget)
- op.widget->setParent(nullptr);
- if (op.toolbutton)
- op.toolbutton->setParent(nullptr);
- if (op.separator)
- op.separator->setParent(nullptr);
- }
-
- while (QLayoutItem *item = m_toolbuttonBoxLayout->takeAt(0))
- delete item;
+ m_currentPerspective->d->destroyToolBar();
}
if (perspective) {
@@ -380,201 +486,294 @@ void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fr
} else {
const QSettings *settings = ICore::settings();
m_currentPerspective = findPerspective(settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray());
- if (!m_currentPerspective)
- m_currentPerspective = findPerspective(Debugger::Constants::CppPerspectiveId);
+ // If we don't find a perspective with the stored name, pick any.
+ // This can happen e.g. when a plugin was disabled that provided
+ // the stored perspective, or when the save file was modified externally.
if (!m_currentPerspective && !m_perspectives.isEmpty())
m_currentPerspective = m_perspectives.first();
}
QTC_ASSERT(m_currentPerspective, return);
- ICore::addAdditionalContext(Context(Id::fromName(m_currentPerspective->m_id)));
+ ICore::addAdditionalContext(m_currentPerspective->context());
m_currentPerspective->aboutToActivate();
- for (const Perspective::ToolbarOperation &op : m_currentPerspective->m_toolbarOperations) {
- if (op.widget)
- m_toolbuttonBoxLayout->addWidget(op.widget);
- if (op.toolbutton)
- m_toolbuttonBoxLayout->addWidget(op.toolbutton);
- if (op.separator)
- m_toolbuttonBoxLayout->addWidget(op.separator);
- }
-
- for (const Perspective::Operation &op : m_currentPerspective->m_operations) {
+ for (const DockOperation &op : m_currentPerspective->d->m_dockOperations) {
QTC_ASSERT(op.widget, continue);
const QByteArray dockId = op.widget->objectName().toUtf8();
QDockWidget *dock = m_dockForDockId.value(dockId);
if (!dock) {
QTC_CHECK(!dockId.isEmpty());
- dock = addDockForWidget(op.widget);
+ dock = q->addDockForWidget(op.widget);
m_dockForDockId[dockId] = dock;
QAction *toggleViewAction = dock->toggleViewAction();
toggleViewAction->setText(dock->windowTitle());
Command *cmd = ActionManager::registerAction(toggleViewAction,
- Id("Dock.").withSuffix(dock->objectName()),
- Context(Id::fromName(m_currentPerspective->m_id)));
+ Id("Dock.").withSuffix(dock->objectName()),
+ m_currentPerspective->context());
cmd->setAttribute(Command::CA_Hide);
ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd);
}
// Restore parent/child relation, so that the widget hierarchy is clear.
- dock->setParent(this);
+ dock->setParent(q);
if (op.operationType == Perspective::Raise) {
dock->raise();
continue;
}
- addDockWidget(op.area, dock);
+ q->addDockWidget(op.area, dock);
QDockWidget *anchor = m_dockForDockId.value(op.anchorDockId);
- if (!anchor && op.area == Qt::BottomDockWidgetArea)
- anchor = m_toolbarDock;
+ if (!anchor && op.area == Qt::BottomDockWidgetArea) {
+ ensureToolBarDockExists();
+ anchor = m_toolBarDock;
+ }
+
if (anchor) {
switch (op.operationType) {
case Perspective::AddToTab:
- tabifyDockWidget(anchor, dock);
+ q->tabifyDockWidget(anchor, dock);
break;
case Perspective::SplitHorizontal:
- splitDockWidget(anchor, dock, Qt::Horizontal);
+ q->splitDockWidget(anchor, dock, Qt::Horizontal);
break;
case Perspective::SplitVertical:
- splitDockWidget(anchor, dock, Qt::Vertical);
+ q->splitDockWidget(anchor, dock, Qt::Vertical);
break;
default:
break;
}
}
- if (!op.visibleByDefault)
- dock->hide();
- else
- dock->show();
+ dock->setVisible(op.visibleByDefault);
}
+ m_currentPerspective->d->showToolBar();
+
if (fromStoredSettings) {
QSettings *settings = ICore::settings();
- settings->beginGroup(QString::fromLatin1(m_currentPerspective->m_id));
+ settings->beginGroup(m_currentPerspective->d->m_id);
if (settings->value(QLatin1String("ToolSettingsSaved"), false).toBool())
- restoreSettings(settings);
+ q->restoreSettings(settings);
settings->endGroup();
} else {
// By default, show the central widget
- showCentralWidgetAction()->setChecked(true);
+ q->showCentralWidgetAction()->setChecked(true);
}
QWidget *central = m_currentPerspective->centralWidget();
m_centralWidgetStack->addWidget(central ? central : m_editorPlaceHolder);
- showCentralWidgetAction()->setText(central ? central->windowTitle() : tr("Editor"));
+ q->showCentralWidgetAction()->setText(central ? central->windowTitle() : tr("Editor"));
m_statusLabel->clear();
}
-void DebuggerMainWindow::savePerspectiveHelper(const Perspective *perspective)
+void DebuggerMainWindowPrivate::savePerspectiveHelper(const Perspective *perspective)
{
if (!perspective)
return;
QSettings *settings = ICore::settings();
- settings->beginGroup(QString::fromLatin1(perspective->m_id));
- saveSettings(settings);
+ settings->beginGroup(perspective->d->m_id);
+ q->saveSettings(settings);
settings->setValue(QLatin1String("ToolSettingsSaved"), true);
settings->endGroup();
- settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), perspective->m_id);
+ settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), perspective->d->m_id);
}
// Perspective
-Perspective::Perspective(const QByteArray &id, const QString &name)
- : m_id(id), m_name(name)
+Perspective::Perspective(const QString &id, const QString &name)
+ : d(new PerspectivePrivate)
{
+ d->m_id = id;
+ d->m_name = name;
}
Perspective::~Perspective()
{
- for (const ToolbarOperation &op : m_toolbarOperations) {
- // op.widget and op.actions are owned by the plugins
- delete op.toolbutton;
- delete op.separator;
- }
+ delete d;
}
void Perspective::setCentralWidget(QWidget *centralWidget)
{
- QTC_ASSERT(m_centralWidget == nullptr, return);
- m_centralWidget = centralWidget;
+ QTC_ASSERT(d->m_centralWidget == nullptr, return);
+ d->m_centralWidget = centralWidget;
}
QString Perspective::name() const
{
- return m_name;
+ return d->m_name;
+}
+
+QString Perspective::id() const
+{
+ return d->m_id;
}
void Perspective::setAboutToActivateCallback(const Perspective::Callback &cb)
{
- m_aboutToActivateCallback = cb;
+ d->m_aboutToActivateCallback = cb;
}
void Perspective::aboutToActivate() const
{
- if (m_aboutToActivateCallback)
- m_aboutToActivateCallback();
+ if (d->m_aboutToActivateCallback)
+ d->m_aboutToActivateCallback();
}
-QByteArray Perspective::parentPerspective() const
+void Perspective::setParentPerspective(const QByteArray &parentPerspective)
{
- return m_parentPerspective;
+ d->m_parentPerspective = parentPerspective;
}
-void Perspective::setParentPerspective(const QByteArray &parentPerspective)
+void Perspective::setEnabled(bool enabled)
{
- m_parentPerspective = parentPerspective;
+ const int index = theMainWindow->d->indexInChooser(this);
+ QTC_ASSERT(index != -1, return);
+ auto model = qobject_cast<QStandardItemModel*>(theMainWindow->d->m_perspectiveChooser->model());
+ QTC_ASSERT(model, return);
+ QStandardItem *item = model->item(index, 0);
+ item->setFlags(enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
}
-QToolButton *Perspective::addToolbarAction(QAction *action, const QIcon &toolbarIcon)
+void Perspective::addToolBarAction(QAction *action)
{
+ auto toolButton = new QToolButton;
ToolbarOperation op;
- op.action = action;
- op.icon = toolbarIcon;
- op.toolbutton = new QToolButton;
- // QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget
- op.toolbutton->setProperty("panelwidget", true);
- op.toolbutton->setDefaultAction(toolbarIcon.isNull()
- ? action : ProxyAction::proxyActionWithIcon(action, toolbarIcon));
- m_toolbarOperations.append(op);
+ op.toolBarPlainAction = action;
+ op.toolBarPlainActionButton = toolButton;
+ d->m_toolBarOperations.append(op);
+}
- return op.toolbutton;
+void Perspective::addToolBarAction(OptionalAction *action)
+{
+ ToolbarOperation op;
+ op.toolBarAction = action;
+ d->m_toolBarOperations.append(op);
}
-void Perspective::addToolbarWidget(QWidget *widget)
+void Perspective::addToolBarWidget(QWidget *widget)
{
ToolbarOperation op;
- op.widget = widget;
+ op.toolBarWidget = widget;
// QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget
- op.widget->setProperty("panelwidget", true);
- m_toolbarOperations.append(op);
+ op.toolBarWidget->setProperty("panelwidget", true);
+ d->m_toolBarOperations.append(op);
}
void Perspective::addToolbarSeparator()
{
ToolbarOperation op;
op.separator = new StyledSeparator;
- m_toolbarOperations.append(op);
+ d->m_toolBarOperations.append(op);
}
QWidget *Perspective::centralWidget() const
{
- return m_centralWidget;
+ return d->m_centralWidget;
+}
+
+void Perspective::destroy()
+{
+ theMainWindow->d->destroyPerspective(this);
+}
+
+Perspective *Perspective::currentPerspective()
+{
+ return theMainWindow ? theMainWindow->d->m_currentPerspective : nullptr;
+}
+
+Context Perspective::context() const
+{
+ return Context(Id::fromName(d->m_id.toUtf8()));
+}
+
+void PerspectivePrivate::showToolBar()
+{
+ if (!m_toolButtonBox) {
+ m_toolButtonBox = new QWidget;
+ theMainWindow->d->m_toolBarLayout->insertWidget(1, m_toolButtonBox);
+
+ auto hbox = new QHBoxLayout(m_toolButtonBox);
+ hbox->setMargin(0);
+ hbox->setSpacing(0);
+ for (ToolbarOperation &op : m_toolBarOperations)
+ op.attachToToolbar(m_toolButtonBox);
+ }
+
+ for (ToolbarOperation &op : m_toolBarOperations) {
+ if (op.toolBarAction)
+ op.toolBarAction->m_toolButton->setVisible(op.toolBarAction->isVisible());
+ }
+
+ m_toolButtonBox->setVisible(true);
}
-void Perspective::addWindow(QWidget *widget, OperationType type, QWidget *anchorWidget,
- bool visibleByDefault, Qt::DockWidgetArea area)
+void PerspectivePrivate::hideToolBar()
+{
+ if (m_toolButtonBox)
+ m_toolButtonBox->setVisible(false);
+
+}
+void PerspectivePrivate::destroyToolBar()
{
- Operation op;
+ // Detach potentially re-used widgets to prevent deletion.
+ for (ToolbarOperation &op : m_toolBarOperations)
+ op.detachFromToolbar();
+
+ delete m_toolButtonBox;
+ m_toolButtonBox = nullptr;
+}
+
+void Perspective::addWindow(QWidget *widget,
+ Perspective::OperationType type,
+ QWidget *anchorWidget,
+ bool visibleByDefault,
+ Qt::DockWidgetArea area)
+{
+ DockOperation op;
op.widget = widget;
if (anchorWidget)
op.anchorDockId = anchorWidget->objectName().toUtf8();
op.operationType = type;
op.visibleByDefault = visibleByDefault;
op.area = area;
- m_operations.append(op);
+ d->m_dockOperations.append(op);
+}
+
+void Perspective::select()
+{
+ if (ModeManager::currentModeId() == Debugger::Constants::MODE_DEBUG && currentPerspective() == this) {
+ // Prevents additional show events triggering modules and register updates.
+ return;
+ }
+
+ ModeManager::activateMode(Debugger::Constants::MODE_DEBUG);
+ theMainWindow->d->restorePerspective(this);
+}
+
+// ToolbarAction
+
+OptionalAction::OptionalAction(const QString &text)
+ : QAction(text)
+{
+}
+
+OptionalAction::~OptionalAction()
+{
+ delete m_toolButton;
+}
+
+void OptionalAction::setVisible(bool on)
+{
+ QAction::setVisible(on);
+ if (m_toolButton)
+ m_toolButton->setVisible(on);
+}
+
+void OptionalAction::setToolButtonStyle(Qt::ToolButtonStyle style)
+{
+ m_toolButtonStyle = style;
}
} // Utils
diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h
index 30e646ccea..0721d5b5c5 100644
--- a/src/plugins/debugger/debuggermainwindow.h
+++ b/src/plugins/debugger/debuggermainwindow.h
@@ -30,28 +30,44 @@
#include <utils/fancymainwindow.h>
#include <utils/statuslabel.h>
-#include <QHBoxLayout>
+#include <QAction>
#include <QPointer>
-#include <QSet>
+#include <QToolButton>
#include <functional>
-QT_BEGIN_NAMESPACE
-class QComboBox;
-class QToolButton;
-class QStackedWidget;
-QT_END_NAMESPACE
-
-namespace Core { class Id; }
+namespace Core {
+class Context;
+class Id;
+} // Core
namespace Utils {
-class DEBUGGER_EXPORT Perspective
+// To be used for actions that need hideable toolbuttons.
+class DEBUGGER_EXPORT OptionalAction : public QAction
{
+ Q_OBJECT
+
+public:
+ OptionalAction(const QString &text = QString());
+ ~OptionalAction() override;
+
+ void setVisible(bool on);
+ void setToolButtonStyle(Qt::ToolButtonStyle style);
+
+public:
+ QPointer<QToolButton> m_toolButton;
+ Qt::ToolButtonStyle m_toolButtonStyle = Qt::ToolButtonIconOnly;
+};
+
+class DEBUGGER_EXPORT Perspective : public QObject
+{
+ Q_OBJECT
+
public:
enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise };
- explicit Perspective(const QByteArray &id, const QString &name);
+ explicit Perspective(const QString &id, const QString &name);
~Perspective();
void setCentralWidget(QWidget *centralWidget);
@@ -61,54 +77,36 @@ public:
bool visibleByDefault = true,
Qt::DockWidgetArea area = Qt::BottomDockWidgetArea);
- QToolButton *addToolbarAction(QAction *action, const QIcon &toolbarIcon = QIcon());
- void addToolbarWidget(QWidget *widget);
+ void addToolBarAction(QAction *action);
+ void addToolBarAction(OptionalAction *action);
+ void addToolBarWidget(QWidget *widget);
void addToolbarSeparator();
QWidget *centralWidget() const;
QString name() const;
+ QString id() const;
using Callback = std::function<void()>;
void setAboutToActivateCallback(const Callback &cb);
void aboutToActivate() const;
- QByteArray parentPerspective() const;
void setParentPerspective(const QByteArray &parentPerspective);
+ void setEnabled(bool enabled);
-private:
- Perspective(const Perspective &) = delete;
- void operator=(const Perspective &) = delete;
+ void destroy();
+ void select();
+ static Perspective *currentPerspective();
+
+ Core::Context context() const;
+ void showToolBar();
+ void hideToolBar();
+
+private:
friend class DebuggerMainWindow;
+ friend class DebuggerMainWindowPrivate;
class PerspectivePrivate *d = nullptr;
- class Operation
- {
- public:
- QPointer<QWidget> widget;
- QByteArray anchorDockId;
- OperationType operationType = Raise;
- bool visibleByDefault = true;
- Qt::DockWidgetArea area = Qt::BottomDockWidgetArea;
- };
-
- class ToolbarOperation
- {
- public:
- QPointer<QWidget> widget; // Owned by plugin if present
- QPointer<QAction> action; // Owned by plugin if present
- QPointer<QToolButton> toolbutton; // Owned here in case action is used
- QPointer<QWidget> separator;
- QIcon icon;
- };
-
- const QByteArray m_id;
- QString m_name;
- QByteArray m_parentPerspective;
- QVector<Operation> m_operations;
- QPointer<QWidget> m_centralWidget;
- Callback m_aboutToActivateCallback;
- QVector<ToolbarOperation> m_toolbarOperations;
};
class DEBUGGER_EXPORT DebuggerMainWindow : public FancyMainWindow
@@ -120,42 +118,18 @@ public:
~DebuggerMainWindow() override;
void registerPerspective(Perspective *perspective);
- void destroyDynamicPerspective(Perspective *perspective);
-
- void resetCurrentPerspective();
- void restorePerspective(Perspective *perspective);
-
- void finalizeSetup();
-
void showStatusMessage(const QString &message, int timeoutMS);
- void raiseDock(const QByteArray &dockId);
- QByteArray currentPerspective() const;
- QStackedWidget *centralWidgetStack() const { return m_centralWidgetStack; }
-
void onModeChanged(Core::Id mode);
- void setPerspectiveEnabled(const QByteArray &perspectiveId, bool enabled);
-
Perspective *findPerspective(const QByteArray &perspectiveId) const;
+ QWidget *centralWidgetStack();
private:
- void closeEvent(QCloseEvent *) final { savePerspectiveHelper(m_currentPerspective); }
-
- void loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings = true);
- void savePerspectiveHelper(const Perspective *perspective);
- void increaseChooserWidthIfNecessary(const QString &visibleName);
- int indexInChooser(Perspective *perspective) const;
-
- Perspective *m_currentPerspective = nullptr;
- QComboBox *m_perspectiveChooser = nullptr;
- QHBoxLayout *m_toolbuttonBoxLayout = nullptr;
- QStackedWidget *m_centralWidgetStack = nullptr;
- QWidget *m_editorPlaceHolder = nullptr;
- Utils::StatusLabel *m_statusLabel = nullptr;
- QDockWidget *m_toolbarDock = nullptr;
-
- QHash<QByteArray, QDockWidget *> m_dockForDockId;
- QList<Perspective *> m_perspectives;
+ void closeEvent(QCloseEvent *) final;
+
+ friend class Perspective;
+ friend class PerspectivePrivate;
+ class DebuggerMainWindowPrivate *d = nullptr;
};
DEBUGGER_EXPORT QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow);
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index 3c94e2339b..2df8a75141 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -25,7 +25,6 @@
#include "debuggerplugin.h"
-#include "debuggermainwindow.h"
#include "debuggeractions.h"
#include "debuggerinternalconstants.h"
#include "debuggercore.h"
@@ -44,7 +43,6 @@
#include "disassemblerlines.h"
#include "logwindow.h"
#include "moduleshandler.h"
-#include "snapshotwindow.h"
#include "stackhandler.h"
#include "stackwindow.h"
#include "watchhandler.h"
@@ -55,6 +53,7 @@
#include "localsandexpressionswindow.h"
#include "loadcoredialog.h"
#include "sourceutils.h"
+#include "snapshothandler.h"
#include "shared/hostutils.h"
#include "console/console.h"
@@ -399,40 +398,37 @@ namespace Internal {
void addCdbOptionPages(QList<IOptionsPage*> *opts);
void addGdbOptionPages(QList<IOptionsPage*> *opts);
-static QIcon visibleStartIcon(Id id, bool toolBarStyle)
-{
- if (id == Id(Constants::DEBUG)) {
- const static QIcon sidebarIcon =
- Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT);
- const static QIcon icon =
- Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL.icon(), sidebarIcon});
- const static QIcon iconToolBar =
- Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR.icon(), sidebarIcon});
- return toolBarStyle ? iconToolBar : icon;
- } else if (id == Id(Constants::CONTINUE)) {
- const static QIcon sidebarIcon =
- Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT);
- const static QIcon icon =
- Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL.icon(), sidebarIcon});
- const static QIcon iconToolBar =
- Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon(), sidebarIcon});
- return toolBarStyle ? iconToolBar : icon;
- } else if (id == Id(Constants::INTERRUPT)) {
- const static QIcon sidebarIcon =
- Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT);
- const static QIcon icon =
- Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL.icon(), sidebarIcon});
- const static QIcon iconToolBar =
- Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL_TOOLBAR.icon(), sidebarIcon});
- return toolBarStyle ? iconToolBar : icon;
- }
- return QIcon();
+static QIcon startIcon(bool toolBarStyle)
+{
+ const static QIcon sidebarIcon =
+ Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT);
+ const static QIcon icon =
+ Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL.icon(), sidebarIcon});
+ const static QIcon iconToolBar =
+ Icon::combinedIcon({ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR.icon(), sidebarIcon});
+ return toolBarStyle ? iconToolBar : icon;
+}
+
+static QIcon continueIcon(bool toolBarStyle)
+{
+ const static QIcon sidebarIcon =
+ Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT);
+ const static QIcon icon =
+ Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL.icon(), sidebarIcon});
+ const static QIcon iconToolBar =
+ Icon::combinedIcon({Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon(), sidebarIcon});
+ return toolBarStyle ? iconToolBar : icon;
}
-static void setProxyAction(ProxyAction *proxy, Id id)
+static QIcon interruptIcon(bool toolBarStyle)
{
- proxy->setAction(ActionManager::command(id)->action());
- proxy->setIcon(visibleStartIcon(id, true));
+ const static QIcon sidebarIcon =
+ Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT);
+ const static QIcon icon =
+ Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL.icon(), sidebarIcon});
+ const static QIcon iconToolBar =
+ Icon::combinedIcon({Icons::DEBUG_INTERRUPT_SMALL_TOOLBAR.icon(), sidebarIcon});
+ return toolBarStyle ? iconToolBar : icon;
}
QAction *addAction(QMenu *menu, const QString &display, bool on,
@@ -461,50 +457,6 @@ QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool c
///////////////////////////////////////////////////////////////////////
//
-// DummyEngine
-//
-///////////////////////////////////////////////////////////////////////
-
-class DummyEngine : public DebuggerEngine
-{
-public:
- DummyEngine() = default;
- ~DummyEngine() override = default;
-
- void setupEngine() override {}
- void runEngine() override {}
- void shutdownEngine() override {}
- void shutdownInferior() override {}
- bool hasCapability(unsigned cap) const override;
- bool acceptsBreakpoint(Breakpoint) const override { return false; }
- bool acceptsDebuggerCommands() const override { return false; }
- void selectThread(ThreadId) override {}
-};
-
-bool DummyEngine::hasCapability(unsigned cap) const
-{
- // This can only be a first approximation of what to expect when running.
- Project *project = ProjectTree::currentProject();
- if (!project)
- return false;
- Target *target = project->activeTarget();
- QTC_ASSERT(target, return 0);
- RunConfiguration *activeRc = target->activeRunConfiguration();
- QTC_ASSERT(activeRc, return 0);
-
- // This is a non-started Cdb or Gdb engine:
- if (activeRc->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger())
- return cap & (WatchpointByAddressCapability
- | BreakConditionCapability
- | TracePointCapability
- | OperateByInstructionCapability);
-
- // This is a Qml or unknown engine.
- return cap & AddWatcherCapability;
-}
-
-///////////////////////////////////////////////////////////////////////
-//
// DebugMode
//
///////////////////////////////////////////////////////////////////////
@@ -530,18 +482,14 @@ public:
//
///////////////////////////////////////////////////////////////////////
-static QWidget *addSearch(BaseTreeView *treeView, const QString &title,
- const QString &objectName)
+QWidget *addSearch(BaseTreeView *treeView)
{
QAction *act = action(UseAlternatingRowColors);
treeView->setAlternatingRowColors(act->isChecked());
QObject::connect(act, &QAction::toggled,
treeView, &BaseTreeView::setAlternatingRowColors);
- QWidget *widget = ItemViewFind::createSearchableWrapper(treeView);
- widget->setObjectName(objectName);
- widget->setWindowTitle(title);
- return widget;
+ return ItemViewFind::createSearchableWrapper(treeView);
}
static Kit::Predicate cdbPredicate(char wordWidth = 0)
@@ -626,6 +574,35 @@ static DebuggerPluginPrivate *dd = nullptr;
Implementation of DebuggerCore.
*/
+struct Callback
+{
+ Callback()
+ : cb([]{})
+ {}
+ Callback(void (DebuggerEngine::*func)())
+ : cb([func] { if (DebuggerEngine *engine = EngineManager::currentEngine()) (engine->*func)(); })
+ {}
+
+ std::function<void()> cb;
+};
+
+struct Action : public QAction
+{
+ Action(const QString &name, const QIcon &icon = {}) : QAction(name) { setIcon(icon); }
+ Action(const QString &name, const QIcon &icon, Callback cb, const QString &toolTip = {})
+ : Action(name, icon)
+ {
+ m_cb = cb;
+ setToolTip(toolTip);
+ connect(this, &QAction::triggered, this, &Action::onTriggered);
+ }
+ void onTriggered()
+ {
+ m_cb.cb();
+ }
+ Callback m_cb;
+};
+
class DebuggerPluginPrivate : public QObject
{
Q_OBJECT
@@ -639,19 +616,6 @@ public:
void aboutToShutdown();
void doShutdown();
- void connectEngine(DebuggerRunTool *runTool);
- void disconnectEngine() { connectEngine(nullptr); }
- DebuggerEngine *dummyEngine();
-
- void setThreadBoxContents(const QStringList &list, int index)
- {
- QSignalBlocker blocker(m_threadBox);
- m_threadBox->clear();
- for (const QString &item : list)
- m_threadBox->addItem(item);
- m_threadBox->setCurrentIndex(index);
- }
-
RunControl *attachToRunningProcess(Kit *kit, DeviceProcessItem process, bool contAfterAttach);
void writeSettings()
@@ -660,15 +624,6 @@ public:
// writeWindowSettings();
}
- void selectThread(int index)
- {
- QTC_ASSERT(m_currentRunTool, return);
- DebuggerEngine *engine = m_currentRunTool->activeEngine();
- QTC_ASSERT(engine, return);
- ThreadId id = engine->threadsHandler()->threadAt(index);
- engine->selectThread(id);
- }
-
void breakpointSetMarginActionTriggered(bool isMessageOnly, const ContextData &data)
{
QString message;
@@ -693,41 +648,17 @@ public:
return;
message = dialog.textValue();
}
- toggleBreakpoint(data, message);
- }
-
- void updateReturnViewHeader(int section, int, int newSize)
- {
- if (m_shuttingDown)
- return;
- m_returnView->header()->resizeSection(section, newSize);
- }
-
- void synchronizeBreakpoints()
- {
- showMessage(QLatin1String("ATTEMPT SYNC"), LogDebug);
- for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
- if (DebuggerEngine *engine = m_snapshotHandler->at(i)->engine())
- engine->attemptBreakpointSynchronization();
- }
+ BreakpointManager::toggleBreakpoint(data, message);
}
- void reloadSourceFiles() { if (m_currentRunTool) m_currentRunTool->engine()->reloadSourceFiles(); }
- void reloadRegisters() { if (m_currentRunTool) m_currentRunTool->engine()->reloadRegisters(); }
- void reloadModules() { if (m_currentRunTool) m_currentRunTool->engine()->reloadModules(); }
-
void editorOpened(IEditor *editor);
void updateBreakMenuItem(IEditor *editor);
- void setBusyCursor(bool busy);
void requestMark(TextEditorWidget *widget, int lineNumber,
TextMarkRequestKind kind);
void requestContextMenu(TextEditorWidget *widget,
int lineNumber, QMenu *menu);
- void activatePreviousMode();
- void activateDebugMode();
void toggleBreakpointHelper();
- void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString());
void onModeChanged(Id mode);
void updateDebugWithoutDeployMenu();
@@ -738,225 +669,26 @@ public:
void runScheduled();
void attachCore();
- void enableReverseDebuggingTriggered(const QVariant &value);
- void showStatusMessage(const QString &msg, int timeout = -1);
-
- void runControlStarted(DebuggerRunTool *runTool);
void runControlFinished(DebuggerRunTool *runTool);
void remoteCommand(const QStringList &options);
- void displayDebugger(DebuggerRunTool *runTool);
-
void dumpLog();
- void cleanupViews();
void setInitialState();
- void fontSettingsChanged(const FontSettings &settings);
-
- void updateState(DebuggerRunTool *runTool);
- void onCurrentProjectChanged(Project *project);
+ void onStartupProjectChanged(Project *project);
void sessionLoaded();
void aboutToUnloadSession();
void aboutToSaveSession();
-public:
- void updateDebugActions();
-
- void handleExecDetach()
- {
- currentEngine()->resetLocation();
- currentEngine()->detachDebugger();
- }
-
- void handleExecContinue()
- {
- currentEngine()->resetLocation();
- currentEngine()->continueInferior();
- }
-
- void handleExecInterrupt()
- {
- currentEngine()->resetLocation();
- currentEngine()->requestInterruptInferior();
- }
-
- void handleAbort()
- {
- if (dd->m_currentRunTool)
- dd->m_currentRunTool->abortDebugger();
- }
-
- void handleReset()
- {
- currentEngine()->resetLocation();
- currentEngine()->resetInferior();
- }
-
- void handleExecStep()
- {
- if (currentEngine()->state() == DebuggerNotReady) {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
- } else {
- currentEngine()->resetLocation();
- if (boolSetting(OperateByInstruction))
- currentEngine()->executeStepI();
- else
- currentEngine()->executeStep();
- }
- }
-
- void handleExecNext()
- {
- if (currentEngine()->state() == DebuggerNotReady) {
- DebuggerRunTool::setBreakOnMainNextTime();
- ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
- } else {
- currentEngine()->resetLocation();
- if (boolSetting(OperateByInstruction))
- currentEngine()->executeNextI();
- else
- currentEngine()->executeNext();
- }
- }
-
- void handleExecStepOut()
- {
- currentEngine()->resetLocation();
- currentEngine()->executeStepOut();
- }
-
- void handleExecReturn()
- {
- currentEngine()->resetLocation();
- currentEngine()->executeReturn();
- }
-
- void handleExecJumpToLine()
- {
- currentEngine()->resetLocation();
- if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
- ContextData location = getLocationContext(textEditor->textDocument(),
- textEditor->currentLine());
- if (location.isValid())
- currentEngine()->executeJumpToLine(location);
- }
- }
-
- void handleExecRunToLine()
- {
- currentEngine()->resetLocation();
- if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
- ContextData location = getLocationContext(textEditor->textDocument(),
- textEditor->currentLine());
- if (location.isValid())
- currentEngine()->executeRunToLine(location);
- }
- }
-
- void handleExecRunToSelectedFunction()
- {
- BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
- QTC_ASSERT(textEditor, return);
- QTextCursor cursor = textEditor->textCursor();
- QString functionName = cursor.selectedText();
- if (functionName.isEmpty()) {
- const QTextBlock block = cursor.block();
- const QString line = block.text();
- foreach (const QString &str, line.trimmed().split(QLatin1Char('('))) {
- QString a;
- for (int i = str.size(); --i >= 0; ) {
- if (!str.at(i).isLetterOrNumber())
- break;
- a = str.at(i) + a;
- }
- if (!a.isEmpty()) {
- functionName = a;
- break;
- }
- }
- }
-
- if (functionName.isEmpty()) {
- showStatusMessage(tr("No function selected."));
- } else {
- showStatusMessage(tr("Running to function \"%1\".")
- .arg(functionName));
- currentEngine()->resetLocation();
- currentEngine()->executeRunToFunction(functionName);
- }
- }
-
- void handleAddToWatchWindow()
- {
- // Requires a selection, but that's the only case we want anyway.
- BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
- if (!textEditor)
- return;
- QTextCursor tc = textEditor->textCursor();
- QString exp;
- if (tc.hasSelection()) {
- exp = tc.selectedText();
- } else {
- int line, column;
- exp = cppExpressionAt(textEditor->editorWidget(), tc.position(), &line, &column);
- }
- if (currentEngine()->hasCapability(WatchComplexExpressionsCapability))
- exp = removeObviousSideEffects(exp);
- else
- exp = fixCppExpression(exp);
- exp = exp.trimmed();
- if (exp.isEmpty()) {
- // Happens e.g. when trying to evaluate 'char' or 'return'.
- AsynchronousMessageBox::warning(tr("Warning"),
- tr("Select a valid expression to evaluate."));
- return;
- }
- currentEngine()->watchHandler()->watchVariable(exp);
- }
-
- void stopDebugger()
- {
- QTC_ASSERT(dd->m_currentRunTool, return);
- dd->m_currentRunTool->runControl()->initiateStop();
- }
-
- void handleFrameDown()
- {
- currentEngine()->frameDown();
- }
-
- void handleFrameUp()
- {
- currentEngine()->frameUp();
- }
-
- void handleOperateByInstructionTriggered(bool operateByInstructionTriggered)
- {
- // Go to source only if we have the file.
- if (DebuggerEngine *cppEngine = currentEngine()->cppEngine()) {
- if (cppEngine->stackHandler()->currentIndex() >= 0) {
- const StackFrame frame = cppEngine->stackHandler()->currentFrame();
- if (operateByInstructionTriggered || frame.isUsable())
- cppEngine->gotoLocation(Location(frame, true));
- }
- }
- }
-
- void showMessage(const QString &msg, int channel, int timeout = -1);
+ void handleOperateByInstructionTriggered(bool operateByInstructionTriggered);
bool parseArgument(QStringList::const_iterator &it,
const QStringList::const_iterator &cend, QString *errorMessage);
bool parseArguments(const QStringList &args, QString *errorMessage);
void parseCommandLineArguments();
- // Called when all dependent plugins have loaded.
- void initialize();
-
- void updateUiForProject(ProjectExplorer::Project *project);
- void updateUiForTarget(ProjectExplorer::Target *target);
- void updateActiveLanguages();
+ void updatePresetState();
public:
QPointer<DebuggerMainWindow> m_mainWindow;
@@ -965,93 +697,67 @@ public:
ActionContainer *m_menu = nullptr;
- Project *m_previousProject = nullptr;
- QPointer<Target> m_previousTarget;
- QPointer<RunConfiguration> m_previousRunConfiguration;
-
- Id m_previousMode;
QVector<DebuggerRunTool *> m_scheduledStarts;
- ProxyAction *m_visibleStartAction = nullptr;
- ProxyAction *m_hiddenStopAction = nullptr;
- QAction *m_startAction = nullptr;
- QAction *m_debugWithoutDeployAction = nullptr;
- QAction *m_startAndDebugApplicationAction = nullptr;
- QAction *m_attachToRunningApplication = nullptr;
- QAction *m_attachToUnstartedApplication = nullptr;
- QAction *m_attachToQmlPortAction = nullptr;
- QAction *m_attachToRemoteServerAction = nullptr;
- QAction *m_startRemoteCdbAction = nullptr;
- QAction *m_attachToCoreAction = nullptr;
- QAction *m_detachAction = nullptr;
- QAction *m_continueAction = nullptr;
- QAction *m_exitAction = nullptr; // On application output button if "Stop" is possible
- QAction *m_interruptAction = nullptr; // On the fat debug button if "Pause" is possible
- QAction *m_undisturbableAction = nullptr; // On the fat debug button if nothing can be done
- QAction *m_abortAction = nullptr;
- QAction *m_stepAction = nullptr;
- QAction *m_stepOutAction = nullptr;
- QAction *m_runToLineAction = nullptr; // In the debug menu
- QAction *m_runToSelectedFunctionAction = nullptr;
- QAction *m_jumpToLineAction = nullptr; // In the Debug menu.
- QAction *m_returnFromFunctionAction = nullptr;
- QAction *m_nextAction = nullptr;
- QAction *m_watchAction = nullptr;
+ ProxyAction m_visibleStartAction; // The fat debug button
+ ProxyAction m_hiddenStopAction;
+ QAction m_undisturbableAction;
+ OptionalAction m_startAction;
+ QAction m_debugWithoutDeployAction{tr("Start Debugging Without Deployment")};
+ QAction m_startAndDebugApplicationAction{tr("Start and Debug External Application...")};
+ QAction m_attachToRunningApplication{tr("Attach to Running Application...")};
+ QAction m_attachToUnstartedApplication{tr("Attach to Unstarted Application...")};
+ QAction m_attachToQmlPortAction{tr("Attach to QML Port...")};
+ QAction m_attachToRemoteServerAction{tr("Attach to Running Debug Server...")};
+ QAction m_startRemoteCdbAction{tr("Attach to Remote CDB Session...")};
+ QAction m_attachToCoreAction{tr("Load Core File...")};
+
+ Action m_detachAction{tr("Detach Debugger"), {}, &DebuggerEngine::handleExecDetach};
+ Action m_continueAction{tr("Continue"), continueIcon(false), &DebuggerEngine::handleExecContinue};
+
+ // On application output button if "Stop" is possible
+ Action m_exitAction{tr("Stop Debugger"), Icons::DEBUG_EXIT_SMALL.icon(), &DebuggerEngine::quitDebugger};
+
+ // On the fat debug button if "Pause" is possible
+ Action m_interruptAction{tr("Interrupt"), interruptIcon(false), &DebuggerEngine::handleExecInterrupt};
+ Action m_abortAction{tr("Abort Debugging"), {}, &DebuggerEngine::abortDebugger,
+ tr("Aborts debugging and resets the debugger to the initial state.")};
+ QAction m_stepAction{tr("Step Into")};
+ Action m_stepOutAction{tr("Step Out"), Icons::STEP_OUT.icon(), &DebuggerEngine::handleExecStepOut};
+
+ Action m_runToLineAction{tr("Run to Line"), {}, &DebuggerEngine::handleExecRunToLine};
+ Action m_runToSelectedFunctionAction{tr("Run to Selected Function"), {}, &DebuggerEngine::handleExecRunToSelectedFunction};
+ Action m_jumpToLineAction{tr("Jump to Line"), {}, &DebuggerEngine::handleExecJumpToLine};
+ // In the Debug menu.
+ Action m_returnFromFunctionAction{tr("Immediately Return From Inner Function"), {}, &DebuggerEngine::executeReturn};
+ QAction m_nextAction{tr("Step Over")};
+ Action m_watchAction{tr("Add Expression Evaluator"), {}, &DebuggerEngine::handleAddToWatchWindow};
Command *m_watchCommand = nullptr;
- QAction *m_breakAction = nullptr;
- QAction *m_reverseDirectionAction = nullptr;
- QAction *m_frameUpAction = nullptr;
- QAction *m_frameDownAction = nullptr;
- QAction *m_resetAction = nullptr;
- QAction *m_operateByInstructionAction = nullptr;
-
- QToolButton *m_reverseToolButton = nullptr;
-
- QLabel *m_threadLabel = nullptr;
- QComboBox *m_threadBox = nullptr;
-
- BaseTreeView *m_breakView = nullptr;
- BaseTreeView *m_returnView = nullptr;
- BaseTreeView *m_localsView = nullptr;
- BaseTreeView *m_watchersView = nullptr;
- WatchTreeView *m_inspectorView = nullptr;
- BaseTreeView *m_registerView = nullptr;
- BaseTreeView *m_modulesView = nullptr;
- BaseTreeView *m_snapshotView = nullptr;
- BaseTreeView *m_sourceFilesView = nullptr;
- BaseTreeView *m_stackView = nullptr;
- BaseTreeView *m_threadsView = nullptr;
-
- BreakHandler *m_breakHandler = nullptr;
-
- QPointer<QWidget> m_returnWindow;
- QPointer<QWidget> m_localsWindow;
- QPointer<QWidget> m_watchersWindow;
- QPointer<QWidget> m_inspectorWindow;
- QPointer<LocalsAndInspectorWindow> m_localsAndInspectorWindow;
- QPointer<QWidget> m_breakWindow;
- QPointer<QWidget> m_registerWindow;
- QPointer<QWidget> m_modulesWindow;
- QPointer<QWidget> m_snapshotWindow;
- QPointer<QWidget> m_sourceFilesWindow;
- QPointer<QWidget> m_stackWindow;
- QPointer<QWidget> m_threadsWindow;
- QPointer<LogWindow> m_logWindow;
-
- bool m_busy = false;
+ QAction m_breakAction{tr("Toggle Breakpoint")};
+ Action m_frameUpAction{tr("Move to Calling Frame"), {}, &DebuggerEngine::handleFrameDown};
+ Action m_frameDownAction{tr("Move to Called Frame"), {}, &DebuggerEngine::handleFrameUp};
+ Action m_resetAction{tr("Restart Debugging"), Icons::RESTART_TOOLBAR.icon(), &DebuggerEngine::handleReset,
+ tr("Restart the debugging session.")};
+ Action m_openMemoryEditorAction{tr("Memory..."), {}, &DebuggerEngine::openMemoryEditor};
+
+ BreakpointManager m_breakpointManager;
+ QPointer<BaseTreeView> m_breakpointManagerView;
+ QPointer<QWidget> m_breakpointManagerWindow;
+
+ QPointer<BaseTreeView> m_engineManagerView;
+ QPointer<QWidget> m_engineManagerWindow;
+ QPointer<GlobalLogWindow> m_globalLogWindow;
+
QString m_lastPermanentStatusMessage;
DebuggerPlugin *m_plugin = nullptr;
- SnapshotHandler *m_snapshotHandler = nullptr;
+ EngineManager m_engineManager;
QTimer m_shutdownTimer;
bool m_shuttingDown = false;
- QPointer<DebuggerEngine> m_previouslyActiveEngine;
- QPointer<DebuggerRunTool> m_currentRunTool;
DebuggerSettings *m_debuggerSettings = nullptr;
QStringList m_arguments;
DebuggerToolTipManager m_toolTipManager;
- DummyEngine *m_dummyEngine = nullptr;
const QSharedPointer<GlobalDebuggerOptions> m_globalDebuggerOptions;
DebuggerItemManager m_debuggerItemManager;
@@ -1083,36 +789,6 @@ DebuggerPluginPrivate::~DebuggerPluginPrivate()
delete m_debuggerSettings;
m_debuggerSettings = nullptr;
-
- delete m_snapshotHandler;
- m_snapshotHandler = nullptr;
-
- delete m_breakHandler;
- m_breakHandler = nullptr;
-
- delete m_returnWindow;
- delete m_localsWindow;
- delete m_watchersWindow;
- delete m_inspectorWindow;
- delete m_localsAndInspectorWindow;
- delete m_breakWindow;
- delete m_registerWindow;
- delete m_modulesWindow;
- delete m_snapshotWindow;
- delete m_sourceFilesWindow;
- delete m_stackWindow;
- delete m_threadsWindow;
- delete m_logWindow;
-}
-
-DebuggerEngine *DebuggerPluginPrivate::dummyEngine()
-{
- if (!m_dummyEngine) {
- m_dummyEngine = new DummyEngine;
- m_dummyEngine->setParent(this);
- m_dummyEngine->setObjectName("DummyEngine");
- }
- return m_dummyEngine;
}
static QString msgParameterMissing(const QString &a)
@@ -1318,12 +994,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
// Populate Windows->Views menu with standard actions.
Context debugcontext(Constants::C_DEBUGMODE);
- auto openMemoryEditorAction = new QAction(this);
- openMemoryEditorAction->setText(DebuggerPluginPrivate::tr("Memory..."));
- connect(openMemoryEditorAction, &QAction::triggered,
- this, &Internal::openMemoryEditor);
-
- Command *cmd = ActionManager::registerAction(openMemoryEditorAction,
+ Command *cmd = ActionManager::registerAction(&m_openMemoryEditorAction,
"Debugger.Views.OpenMemoryEditor", debugcontext);
cmd->setAttribute(Command::CA_Hide);
@@ -1332,8 +1003,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
TaskHub::addCategory(TASK_CATEGORY_DEBUGGER_RUNTIME,
tr("Debugger Runtime"));
- const QKeySequence debugKey = QKeySequence(useMacShortcuts ? tr("Ctrl+Y") : tr("F5"));
-
QSettings *settings = ICore::settings();
m_debuggerSettings = new DebuggerSettings;
@@ -1342,215 +1011,70 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
const Context cppDebuggercontext(C_CPPDEBUGGER);
const Context qmljsDebuggercontext(C_QMLDEBUGGER);
- m_busy = false;
-
- m_logWindow = new LogWindow;
- m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT));
-
- m_breakHandler = new BreakHandler;
- m_breakView = new BaseTreeView;
- m_breakView->setIconSize(QSize(10, 10));
- m_breakView->setWindowIcon(Icons::BREAKPOINTS.icon());
- m_breakView->setSelectionMode(QAbstractItemView::ExtendedSelection);
- connect(action(UseAddressInBreakpointsView), &QAction::toggled,
- this, [this](bool on) { m_breakView->setColumnHidden(BreakpointAddressColumn, !on); });
- m_breakView->setSettings(settings, "Debugger.BreakWindow");
- m_breakView->setModel(m_breakHandler->model());
- m_breakView->setRootIsDecorated(true);
- m_breakWindow = addSearch(m_breakView, tr("&Breakpoints"), DOCKWIDGET_BREAK);
-
- m_modulesView = new BaseTreeView;
- m_modulesView->setSortingEnabled(true);
- m_modulesView->setSettings(settings, "Debugger.ModulesView");
- connect(m_modulesView, &BaseTreeView::aboutToShow,
- this, &DebuggerPluginPrivate::reloadModules,
- Qt::QueuedConnection);
- m_modulesWindow = addSearch(m_modulesView, tr("&Modules"), DOCKWIDGET_MODULES);
-
- m_registerView = new BaseTreeView;
- m_registerView->setRootIsDecorated(true);
- m_registerView->setSettings(settings, "Debugger.RegisterView");
- connect(m_registerView, &BaseTreeView::aboutToShow,
- this, &DebuggerPluginPrivate::reloadRegisters,
- Qt::QueuedConnection);
- m_registerWindow = addSearch(m_registerView, tr("Reg&isters"), DOCKWIDGET_REGISTER);
-
- m_stackView = new StackTreeView;
- m_stackView->setSettings(settings, "Debugger.StackView");
- m_stackView->setIconSize(QSize(10, 10));
- m_stackWindow = addSearch(m_stackView, tr("&Stack"), DOCKWIDGET_STACK);
-
- m_sourceFilesView = new BaseTreeView;
- m_sourceFilesView->setSortingEnabled(true);
- m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView");
- connect(m_sourceFilesView, &BaseTreeView::aboutToShow,
- this, &DebuggerPluginPrivate::reloadSourceFiles,
- Qt::QueuedConnection);
- m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES);
-
- m_threadsView = new BaseTreeView;
- m_threadsView->setSortingEnabled(true);
- m_threadsView->setSettings(settings, "Debugger.ThreadsView");
- m_threadsView->setIconSize(QSize(10, 10));
- m_threadsWindow = addSearch(m_threadsView, tr("&Threads"), DOCKWIDGET_THREADS);
-
- m_returnView = new WatchTreeView(ReturnType); // No settings.
- m_returnWindow = addSearch(m_returnView, tr("Locals"), "CppDebugReturn");
-
- m_localsView = new WatchTreeView(LocalsType);
- m_localsView->setSettings(settings, "Debugger.LocalsView");
- m_localsWindow = addSearch(m_localsView, tr("Locals"), "CppDebugLocals");
-
- m_inspectorView = new WatchTreeView(InspectType); // No settings.
- m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view.
- m_inspectorWindow = addSearch(m_inspectorView, tr("Locals"), "Inspector");
-
- m_watchersView = new WatchTreeView(WatchersType);
- m_watchersView->setSettings(settings, "Debugger.WatchersView");
- m_watchersWindow = addSearch(m_watchersView, tr("&Expressions"), "CppDebugWatchers");
+ m_breakpointManagerView = new BaseTreeView;
+ m_breakpointManagerView->setIconSize(QSize(10, 10));
+ m_breakpointManagerView->setWindowIcon(Icons::BREAKPOINTS.icon());
+ m_breakpointManagerView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_breakpointManagerView->setSettings(settings, "Debugger.BreakWindow");
+ m_breakpointManagerView->setRootIsDecorated(true);
+ m_breakpointManagerView->setModel(BreakpointManager::model());
+ m_breakpointManagerWindow = addSearch(m_breakpointManagerView);
+ m_breakpointManagerWindow->setWindowTitle(tr("Breakpoint Preset"));
+ m_breakpointManagerWindow->setObjectName(DOCKWIDGET_BREAKPOINTMANAGER);
// Snapshot
- m_snapshotHandler = new SnapshotHandler;
- m_snapshotView = new SnapshotTreeView(m_snapshotHandler);
- m_snapshotView->setSettings(settings, "Debugger.SnapshotView");
- m_snapshotView->setIconSize(QSize(10, 10));
- m_snapshotView->setModel(m_snapshotHandler->model());
- m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS);
-
- // Locals
- connect(m_localsView->header(), &QHeaderView::sectionResized,
- this, &DebuggerPluginPrivate::updateReturnViewHeader, Qt::QueuedConnection);
-
- auto act = m_continueAction = new QAction(tr("Continue"), this);
- act->setIcon(visibleStartIcon(Id(Constants::CONTINUE), false));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue);
-
- act = m_exitAction = new QAction(tr("Stop Debugger"), this);
- act->setIcon(Icons::DEBUG_EXIT_SMALL.icon());
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::stopDebugger);
-
- act = m_interruptAction = new QAction(tr("Interrupt"), this);
- act->setIcon(visibleStartIcon(Id(Constants::INTERRUPT), false));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt);
-
- // A "disabled pause" seems to be a good choice.
- act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this);
- act->setIcon(visibleStartIcon(Id(Constants::INTERRUPT), false));
- act->setEnabled(false);
-
- act = m_abortAction = new QAction(tr("Abort Debugging"), this);
- act->setToolTip(tr("Aborts debugging and "
- "resets the debugger to the initial state."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort);
-
- act = m_resetAction = new QAction(tr("Restart Debugging"),this);
- act->setToolTip(tr("Restart the debugging session."));
- act->setIcon(Icons::RESTART_TOOLBAR.icon());
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset);
-
- act = m_nextAction = new QAction(tr("Step Over"), this);
- act->setIcon(Icons::STEP_OVER.icon());
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext);
-
- act = m_stepAction = new QAction(tr("Step Into"), this);
- act->setIcon(Icons::STEP_INTO.icon());
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep);
-
- act = m_stepOutAction = new QAction(tr("Step Out"), this);
- act->setIcon(Icons::STEP_OUT.icon());
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut);
-
- act = m_runToLineAction = new QAction(tr("Run to Line"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine);
-
- act = m_runToSelectedFunctionAction = new QAction(tr("Run to Selected Function"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction);
-
- act = m_returnFromFunctionAction =
- new QAction(tr("Immediately Return From Inner Function"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn);
-
- act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine);
-
- m_breakAction = new QAction(tr("Toggle Breakpoint"), this);
-
- act = m_watchAction = new QAction(tr("Add Expression Evaluator"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow);
+ m_engineManagerView = new BaseTreeView;
+ m_engineManagerView->setWindowTitle(tr("Running Debuggers"));
+ m_engineManagerView->setSettings(settings, "Debugger.SnapshotView");
+ m_engineManagerView->setIconSize(QSize(10, 10));
+ m_engineManagerView->setModel(m_engineManager.model());
+ m_engineManagerWindow = addSearch(m_engineManagerView);
+ m_engineManagerWindow->setWindowTitle(tr("Snapshots"));
+ m_engineManagerWindow->setObjectName(DOCKWIDGET_ENGINEMANAGER);
//act = m_snapshotAction = new QAction(tr("Create Snapshot"), this);
//act->setProperty(Role, RequestCreateSnapshotRole);
//act->setIcon(Icons::SNAPSHOT.icon());
- act = m_reverseDirectionAction = new QAction(tr("Reverse Direction"), this);
- act->setCheckable(true);
- act->setChecked(false);
- act->setCheckable(false);
- act->setIcon(Icons::REVERSE_MODE.icon());
- act->setIconVisibleInMenu(false);
-
- act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown);
+// connect(act, &QAction::triggered,
+// this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered);
- act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this);
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp);
-
- act = m_operateByInstructionAction = action(OperateByInstruction);
- connect(act, &QAction::triggered,
- this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered);
+ // Logging
+ m_globalLogWindow = new GlobalLogWindow;
ActionContainer *debugMenu = ActionManager::actionContainer(PE::M_DEBUG);
- m_localsAndInspectorWindow = new LocalsAndInspectorWindow
- (m_localsWindow, m_inspectorWindow, m_returnWindow);
- m_localsAndInspectorWindow->setObjectName(DOCKWIDGET_LOCALS_AND_INSPECTOR);
- m_localsAndInspectorWindow->setWindowTitle(m_localsWindow->windowTitle());
-
RunConfiguration::registerAspect<DebuggerRunConfigurationAspect>();
- // The main "Start Debugging" action.
- act = m_startAction = new QAction(this);
- act->setIcon(visibleStartIcon(Id(Constants::DEBUG), false));
- act->setText(tr("Start Debugging"));
- connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); });
-
- act = m_debugWithoutDeployAction = new QAction(this);
- act->setText(tr("Start Debugging Without Deployment"));
- connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); });
+ // The main "Start Debugging" action. Acts as "Continue" at times.
+ connect(&m_startAction, &QAction::triggered, this, [] {
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
+ });
- act = m_startAndDebugApplicationAction = new QAction(this);
- act->setText(tr("Start and Debug External Application..."));
- connect(act, &QAction::triggered, this, &StartApplicationDialog::startAndDebugApplication);
+ connect(&m_debugWithoutDeployAction, &QAction::triggered, this, [] {
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true);
+ });
- act = m_attachToCoreAction = new QAction(this);
- act->setText(tr("Load Core File..."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore);
+ connect(&m_startAndDebugApplicationAction, &QAction::triggered,
+ this, &StartApplicationDialog::startAndDebugApplication);
- act = m_attachToRemoteServerAction = new QAction(this);
- act->setText(tr("Attach to Running Debug Server..."));
- connect(act, &QAction::triggered, this, &StartApplicationDialog::attachToRemoteServer);
+ connect(&m_attachToCoreAction, &QAction::triggered,
+ this, &DebuggerPluginPrivate::attachCore);
- act = m_attachToRunningApplication = new QAction(this);
- act->setText(tr("Attach to Running Application..."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication);
+ connect(&m_attachToRemoteServerAction, &QAction::triggered,
+ this, &StartApplicationDialog::attachToRemoteServer);
- act = m_attachToUnstartedApplication = new QAction(this);
- act->setText(tr("Attach to Unstarted Application..."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog);
+ connect(&m_attachToRunningApplication, &QAction::triggered,
+ this, &DebuggerPluginPrivate::attachToRunningApplication);
- act = m_attachToQmlPortAction = new QAction(this);
- act->setText(tr("Attach to QML Port..."));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort);
+ connect(&m_attachToUnstartedApplication, &QAction::triggered,
+ this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog);
- if (HostOsInfo::isWindowsHost()) {
- m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this);
- connect(m_startRemoteCdbAction, &QAction::triggered,
- this, &DebuggerPluginPrivate::startRemoteCdbSession);
- }
+ connect(&m_attachToQmlPortAction, &QAction::triggered,
+ this, &DebuggerPluginPrivate::attachToQmlPort);
- act = m_detachAction = new QAction(this);
- act->setText(tr("Detach Debugger"));
- connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach);
+ connect(&m_startRemoteCdbAction, &QAction::triggered,
+ this, &DebuggerPluginPrivate::startRemoteCdbSession);
// "Start Debugging" sub-menu
// groups:
@@ -1561,50 +1085,57 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
ActionContainer *mstart = ActionManager::actionContainer(PE::M_DEBUG_STARTDEBUGGING);
- cmd = ActionManager::registerAction(m_startAction, Constants::DEBUG);
+ cmd = ActionManager::registerAction(&m_visibleStartAction, Constants::DEBUG);
+ cmd->setDescription(tr("Start Debugging or Continue"));
+ cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Y") : tr("F5")));
+ cmd->setAttribute(Command::CA_UpdateText);
+ cmd->setAttribute(Command::CA_UpdateIcon);
+ //mstart->addAction(cmd, CC::G_DEFAULT_ONE);
+
+ cmd = ActionManager::registerAction(&m_startAction, "Debugger.Start");
cmd->setDescription(tr("Start Debugging"));
- cmd->setDefaultKeySequence(debugKey);
cmd->setAttribute(Command::CA_UpdateText);
mstart->addAction(cmd, CC::G_DEFAULT_ONE);
- m_visibleStartAction = new ProxyAction(this);
- m_visibleStartAction->initialize(m_startAction);
- m_visibleStartAction->setAttribute(ProxyAction::UpdateText);
- m_visibleStartAction->setAction(m_startAction);
- ModeManager::addAction(m_visibleStartAction, Constants::P_ACTION_DEBUG);
+ m_visibleStartAction.initialize(&m_startAction);
+ m_visibleStartAction.setAttribute(ProxyAction::UpdateText);
+ m_visibleStartAction.setAction(&m_startAction);
+ m_visibleStartAction.setIcon(startIcon(true));
- cmd = ActionManager::registerAction(m_debugWithoutDeployAction,
+ ModeManager::addAction(&m_visibleStartAction, Constants::P_ACTION_DEBUG);
+
+ cmd = ActionManager::registerAction(&m_debugWithoutDeployAction,
"Debugger.DebugWithoutDeploy");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, CC::G_DEFAULT_ONE);
- cmd = ActionManager::registerAction(m_attachToRunningApplication,
+ cmd = ActionManager::registerAction(&m_attachToRunningApplication,
"Debugger.AttachToRemoteProcess");
cmd->setDescription(tr("Attach to Running Application"));
mstart->addAction(cmd, G_GENERAL);
- cmd = ActionManager::registerAction(m_attachToUnstartedApplication,
+ cmd = ActionManager::registerAction(&m_attachToUnstartedApplication,
"Debugger.AttachToUnstartedProcess");
cmd->setDescription(tr("Attach to Unstarted Application"));
mstart->addAction(cmd, G_GENERAL);
- cmd = ActionManager::registerAction(m_startAndDebugApplicationAction,
+ cmd = ActionManager::registerAction(&m_startAndDebugApplicationAction,
"Debugger.StartAndDebugApplication");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, G_GENERAL);
- cmd = ActionManager::registerAction(m_attachToCoreAction,
- "Debugger.AttachCore");
+ cmd = ActionManager::registerAction(&m_attachToCoreAction,
+ "Debugger.AttachCore");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_GENERAL);
- cmd = ActionManager::registerAction(m_attachToRemoteServerAction,
- "Debugger.AttachToRemoteServer");
+ cmd = ActionManager::registerAction(&m_attachToRemoteServerAction,
+ "Debugger.AttachToRemoteServer");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_SPECIAL);
- if (m_startRemoteCdbAction) {
- cmd = ActionManager::registerAction(m_startRemoteCdbAction,
+ if (HostOsInfo::isWindowsHost()) {
+ cmd = ActionManager::registerAction(&m_startRemoteCdbAction,
"Debugger.AttachRemoteCdb");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_SPECIAL);
@@ -1612,66 +1143,84 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
mstart->addSeparator(Context(CC::C_GLOBAL), Constants::G_START_QML);
- cmd = ActionManager::registerAction(m_attachToQmlPortAction, "Debugger.AttachToQmlPort");
+ cmd = ActionManager::registerAction(&m_attachToQmlPortAction, "Debugger.AttachToQmlPort");
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_START_QML);
- cmd = ActionManager::registerAction(m_detachAction, "Debugger.Detach");
+ cmd = ActionManager::registerAction(&m_detachAction, "Debugger.Detach");
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
- cmd = ActionManager::registerAction(m_interruptAction, Constants::INTERRUPT);
+ cmd = ActionManager::registerAction(&m_interruptAction, Constants::INTERRUPT);
cmd->setDescription(tr("Interrupt Debugger"));
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
- cmd = ActionManager::registerAction(m_continueAction, Constants::CONTINUE);
- cmd->setDefaultKeySequence(debugKey);
+ cmd = ActionManager::registerAction(&m_continueAction, Constants::CONTINUE);
+// cmd->setDefaultKeySequence(debugKey);
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
- cmd = ActionManager::registerAction(m_exitAction, Constants::STOP);
+ cmd = ActionManager::registerAction(&m_exitAction, Constants::STOP);
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
- m_hiddenStopAction = new ProxyAction(this);
- m_hiddenStopAction->initialize(cmd->action());
- m_hiddenStopAction->setAttribute(ProxyAction::UpdateText);
- m_hiddenStopAction->setAttribute(ProxyAction::UpdateIcon);
+ m_hiddenStopAction.initialize(cmd->action());
+ m_hiddenStopAction.setAttribute(ProxyAction::UpdateText);
+ m_hiddenStopAction.setAttribute(ProxyAction::UpdateIcon);
- cmd = ActionManager::registerAction(m_hiddenStopAction, Constants::HIDDEN_STOP);
+ cmd = ActionManager::registerAction(&m_hiddenStopAction, Constants::HIDDEN_STOP);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Shift+Ctrl+Y") : tr("Shift+F5")));
- cmd = ActionManager::registerAction(m_abortAction, Constants::ABORT);
+ cmd = ActionManager::registerAction(&m_abortAction, Constants::ABORT);
cmd->setDescription(tr("Reset Debugger"));
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
- cmd = ActionManager::registerAction(m_resetAction, Constants::RESET);
+ cmd = ActionManager::registerAction(&m_resetAction, Constants::RESET);
cmd->setDescription(tr("Restart Debugging"));
debugMenu->addAction(cmd, CC::G_DEFAULT_ONE);
debugMenu->addSeparator();
- cmd = ActionManager::registerAction(m_nextAction, Constants::NEXT);
+ cmd = ActionManager::registerAction(&m_nextAction, Constants::NEXT);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10")));
cmd->setAttribute(Command::CA_Hide);
cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
+ m_nextAction.setIcon(Icons::STEP_OVER.icon());
+ connect(&m_nextAction, &QAction::triggered, this, [this] {
+ if (DebuggerEngine *engine = EngineManager::currentEngine()) {
+ engine->executeNext();
+ } else {
+ DebuggerRunTool::setBreakOnMainNextTime();
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
+ }
+ });
- cmd = ActionManager::registerAction(m_stepAction, Constants::STEP);
+ cmd = ActionManager::registerAction(&m_stepAction, Constants::STEP);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11")));
cmd->setAttribute(Command::CA_Hide);
cmd->setAttribute(Command::CA_UpdateText);
debugMenu->addAction(cmd);
+ m_stepAction.setIcon(Icons::STEP_OVER.icon());
+ connect(&m_stepAction, &QAction::triggered, this, [this] {
+ if (DebuggerEngine *engine = EngineManager::currentEngine()) {
+ engine->executeStep();
+ } else {
+ DebuggerRunTool::setBreakOnMainNextTime();
+ ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, false);
+ }
+ });
+
- cmd = ActionManager::registerAction(m_stepOutAction, Constants::STEPOUT);
+ cmd = ActionManager::registerAction(&m_stepOutAction, Constants::STEPOUT);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11")));
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
- cmd = ActionManager::registerAction(m_runToLineAction,
+ cmd = ActionManager::registerAction(&m_runToLineAction,
"Debugger.RunToLine", cppDebuggercontext);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Shift+F8") : tr("Ctrl+F10")));
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
- cmd = ActionManager::registerAction(m_runToSelectedFunctionAction,
+ cmd = ActionManager::registerAction(&m_runToSelectedFunctionAction,
"Debugger.RunToSelectedFunction", cppDebuggercontext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F6")));
cmd->setAttribute(Command::CA_Hide);
@@ -1679,24 +1228,16 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
// and text up-to-date is a lot of hassle.
// debugMenu->addAction(cmd);
- cmd = ActionManager::registerAction(m_jumpToLineAction,
+ cmd = ActionManager::registerAction(&m_jumpToLineAction,
"Debugger.JumpToLine", cppDebuggercontext);
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
- cmd = ActionManager::registerAction(m_returnFromFunctionAction,
+ cmd = ActionManager::registerAction(&m_returnFromFunctionAction,
"Debugger.ReturnFromFunction", cppDebuggercontext);
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
- if (isReverseDebuggingEnabled()) {
- cmd = ActionManager::registerAction(m_reverseDirectionAction,
- Constants::REVERSE, cppDebuggercontext);
- cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? QString() : tr("F12")));
- cmd->setAttribute(Command::CA_Hide);
- debugMenu->addAction(cmd);
- }
-
debugMenu->addSeparator();
//cmd = ActionManager::registerAction(m_snapshotAction,
@@ -1705,20 +1246,20 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
//cmd->setAttribute(Command::CA_Hide);
//debugMenu->addAction(cmd);
- ActionManager::registerAction(m_frameDownAction,
+ ActionManager::registerAction(&m_frameDownAction,
"Debugger.FrameDown", cppDebuggercontext);
- ActionManager::registerAction(m_frameUpAction,
+ ActionManager::registerAction(&m_frameUpAction,
"Debugger.FrameUp", cppDebuggercontext);
- cmd = ActionManager::registerAction(m_operateByInstructionAction,
+ cmd = ActionManager::registerAction(action(OperateByInstruction),
Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext);
cmd->setAttribute(Command::CA_Hide);
debugMenu->addAction(cmd);
- cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak");
+ cmd = ActionManager::registerAction(&m_breakAction, "Debugger.ToggleBreak");
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("F8") : tr("F9")));
debugMenu->addAction(cmd);
- connect(m_breakAction, &QAction::triggered,
+ connect(&m_breakAction, &QAction::triggered,
this, &DebuggerPluginPrivate::toggleBreakpointHelper);
debugMenu->addSeparator();
@@ -1747,7 +1288,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
debugMenu->addSeparator();
- cmd = m_watchCommand = ActionManager::registerAction(m_watchAction, "Debugger.AddToWatch",
+ cmd = m_watchCommand = ActionManager::registerAction(&m_watchAction, "Debugger.AddToWatch",
Context(CppEditor::Constants::CPPEDITOR_ID, QmlJSEditor::Constants::C_QMLJSEDITOR_ID));
//cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W")));
debugMenu->addAction(cmd);
@@ -1758,13 +1299,9 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
connect(ModeManager::instance(), &ModeManager::currentModeChanged,
this, &DebuggerPluginPrivate::onModeChanged);
- connect(ModeManager::instance(), &ModeManager::currentModeChanged,
- m_mainWindow.data(), &DebuggerMainWindow::onModeChanged);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu);
- m_mainWindow->finalizeSetup();
-
// Debug mode setup
m_mode = new DebugMode;
m_modeWindow = createModeWindow(Constants::MODE_DEBUG, m_mainWindow);
@@ -1774,9 +1311,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
m_debugModeContext.setWidget(m_modeWindow);
ICore::addContextObject(&m_debugModeContext);
- connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
- this, &DebuggerPluginPrivate::updateUiForProject);
-
//
// Connections
//
@@ -1787,7 +1321,17 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
// TextEditor
connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged,
- this, &DebuggerPluginPrivate::fontSettingsChanged);
+ [this](const FontSettings &settings) {
+ if (!boolSetting(FontSizeFollowsEditor))
+ return;
+ qreal size = settings.fontZoom() * settings.fontSize() / 100.;
+ QFont font = m_breakpointManagerWindow->font();
+ font.setPointSizeF(size);
+ m_breakpointManagerWindow->setFont(font);
+ m_globalLogWindow->setFont(font);
+// m_snapshotWindow->setFont(font);
+ });
+
// ProjectExplorer
connect(SessionManager::instance(), &SessionManager::sessionLoaded,
@@ -1797,7 +1341,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession,
this, &DebuggerPluginPrivate::aboutToUnloadSession);
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
- this, &DebuggerPluginPrivate::updateDebugActions);
+ this, &DebuggerPluginPrivate::updatePresetState);
// EditorManager
connect(EditorManager::instance(), &EditorManager::editorOpened,
@@ -1809,78 +1353,42 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
connect(action(SettingsDialog), &QAction::triggered,
[] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); });
- if (isReverseDebuggingEnabled()) {
- m_reverseToolButton = new QToolButton;
- m_reverseToolButton->setDefaultAction(m_reverseDirectionAction);
- }
+ auto perspective = new Perspective(Constants::PRESET_PERSPRECTIVE_ID, tr("Debugger"));
+ Debugger::registerPerspective(perspective);
- m_threadLabel = new QLabel(tr("Threads:"));
-
- m_threadBox = new QComboBox;
- m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
- connect(m_threadBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
- this, &DebuggerPluginPrivate::selectThread);
-
-// ToolbarDescription qmlToolbar
-// qmlToolbar.addAction(qmlUpdateOnSaveDummyAction);
-// qmlToolbar.addAction(qmlShowAppOnTopDummyAction, Icons::APP_ON_TOP_TOOLBAR.icon());
-// qmlToolbar.addWidget(new StyledSeparator);
-// qmlToolbar.addAction(qmlSelectDummyAction, Icons::SELECT_TOOLBAR.icon());
-// qmlToolbar.addWidget(new StyledSeparator);
-
- auto perspective = new Perspective("Debugger", tr("Debugger"));
- perspective->addWindow(m_stackWindow, Perspective::SplitVertical, nullptr);
- perspective->addWindow(m_breakWindow, Perspective::SplitHorizontal, m_stackWindow);
- perspective->addWindow(m_threadsWindow, Perspective::AddToTab, m_breakWindow, false);
- perspective->addWindow(m_modulesWindow, Perspective::AddToTab, m_threadsWindow, false);
- perspective->addWindow(m_sourceFilesWindow, Perspective::AddToTab, m_modulesWindow, false);
- perspective->addWindow(m_snapshotWindow, Perspective::AddToTab, m_sourceFilesWindow, false);
- perspective->addWindow(m_localsAndInspectorWindow, Perspective::AddToTab, nullptr, true,
- Qt::RightDockWidgetArea);
- perspective->addWindow(m_watchersWindow, Perspective::AddToTab, m_localsAndInspectorWindow, true,
- Qt::RightDockWidgetArea);
- perspective->addWindow(m_logWindow, Perspective::AddToTab, nullptr, false, Qt::TopDockWidgetArea);
- perspective->addWindow(m_breakWindow, Perspective::Raise, nullptr);
- perspective->addWindow(m_registerWindow, Perspective::AddToTab, m_snapshotWindow, false);
-
- perspective->addToolbarAction(m_visibleStartAction);
- perspective->addToolbarAction(ActionManager::command(Constants::STOP)->action(), Icons::DEBUG_EXIT_SMALL_TOOLBAR.icon());
- perspective->addToolbarAction(ActionManager::command(Constants::NEXT)->action(), Icons::STEP_OVER_TOOLBAR.icon());
- perspective->addToolbarAction(ActionManager::command(Constants::STEP)->action(), Icons::STEP_INTO_TOOLBAR.icon());
- perspective->addToolbarAction(ActionManager::command(Constants::STEPOUT)->action(), Icons::STEP_OUT_TOOLBAR.icon());
- perspective->addToolbarAction(ActionManager::command(Constants::RESET)->action(), Icons::RESTART_TOOLBAR.icon());
- perspective->addToolbarAction(ActionManager::command(Constants::OPERATE_BY_INSTRUCTION)->action());
-
- if (isReverseDebuggingEnabled())
- perspective->addToolbarWidget(m_reverseToolButton);
-
- perspective->addToolbarSeparator();
- perspective->addToolbarWidget(m_threadLabel);
- perspective->addToolbarWidget(m_threadBox);
+ perspective->addToolBarWidget(EngineManager::engineChooser());
+ perspective->addToolBarAction(&m_startAction);
- Debugger::registerPerspective(perspective);
+// QAction *operateByInstructionAction = action(OperateByInstruction);
+// operateByInstructionAction->setText(tr("Start in Operate by Instruction mode"));
-// Perspective *qmlPerspective = createBasePerspective();
-// qmlPerspective->setName(tr("QML Debugger"));
-// qmlPerspective->addOperation({ DOCKWIDGET_REGISTER, DOCKWIDGET_SNAPSHOTS,
-// Perspective::AddToTab, false });
-//
-// Debugger::registerToolbar(QmlPerspectiveId, toolbarContainer);
-// Debugger::registerPerspective(QmlPerspectiveId, qmlPerspective);
- connect(action(EnableReverseDebugging), &SavedAction::valueChanged,
- this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered);
+// QAction *enableReverseDebuggingAction = action(EnableReverseDebugging);
+// enableReverseDebuggingAction->setText(tr("Start with recording information to reverse step if possible"));
+//// Icons::SINGLE_INSTRUCTION_MODE.icon()};
+// Action m_enableReverseDebuggingAction{tr("Start with recording information to reverse step if possible"),
+// Icons::REVERSE_MODE.icon()}
+// perspective->addToolbarAction(operateByInstructionAction);
+
+ perspective->addWindow(m_breakpointManagerWindow, Perspective::SplitVertical, nullptr);
+ perspective->addWindow(m_globalLogWindow, Perspective::SplitHorizontal, m_breakpointManagerWindow);
+ perspective->addWindow(m_engineManagerWindow, Perspective::AddToTab, m_globalLogWindow);
+
+// connect(action(EnableReverseDebugging), &SavedAction::valueChanged,
+// this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered);
setInitialState();
- connectEngine(nullptr);
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
- this, &DebuggerPluginPrivate::onCurrentProjectChanged);
+ this, &DebuggerPluginPrivate::onStartupProjectChanged);
+ connect(EngineManager::instance(), &EngineManager::engineStateChanged,
+ this, &DebuggerPluginPrivate::updatePresetState);
+ connect(EngineManager::instance(), &EngineManager::currentEngineChanged,
+ this, &DebuggerPluginPrivate::updatePresetState);
m_optionPages.append(new CommonOptionsPage(m_globalDebuggerOptions));
m_globalDebuggerOptions->fromSettings();
- m_returnWindow->setVisible(false);
return true;
}
@@ -1895,7 +1403,203 @@ QVariant configValue(const QString &name)
return ICore::settings()->value("DebugMode/" + name);
}
-void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project)
+void DebuggerPluginPrivate::updatePresetState()
+{
+ if (m_shuttingDown)
+ return;
+
+ Project *startupProject = SessionManager::startupProject();
+ RunConfiguration *startupRunConfig = RunConfiguration::startupRunConfiguration();
+ DebuggerEngine *currentEngine = EngineManager::currentEngine();
+
+ QString whyNot;
+ const bool canRun = startupProject
+ && ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot);
+
+ if (!currentEngine || !currentEngine->isStartupRunConfiguration()) {
+ // No engine running -- or -- we have a running engine but it does not
+ // correspond to the current start up project.
+ QString startupRunConfigName;
+ if (startupRunConfig)
+ startupRunConfigName = startupRunConfig->displayName();
+ if (startupRunConfigName.isEmpty() && startupProject)
+ startupRunConfigName = startupProject->displayName();
+
+ QString startToolTip = canRun ? tr("Start debugging of \"%1\"").arg(startupRunConfigName) : whyNot;
+ QString stepToolTip = canRun ? tr("Start \"%1\" and break at function \"main\"").arg(startupRunConfigName) : whyNot;
+ // Step into/next: Start and break at 'main' unless a debugger is running.
+ m_stepAction.setEnabled(canRun);
+ m_stepAction.setToolTip(stepToolTip);
+ m_nextAction.setEnabled(canRun);
+ m_nextAction.setToolTip(stepToolTip);
+ m_startAction.setEnabled(canRun);
+ m_startAction.setToolTip(startToolTip);
+ m_startAction.setText(startToolTip);
+ m_startAction.setIcon(startIcon(false));
+ m_startAction.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ m_startAction.setVisible(true);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(canRun);
+ m_visibleStartAction.setIcon(startIcon(true));
+ m_hiddenStopAction.setAction(&m_undisturbableAction);
+ m_detachAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_returnFromFunctionAction.setEnabled(false);
+ return;
+ }
+
+ QTC_ASSERT(currentEngine, return);
+
+ // We have a current engine, and it belongs to the startup runconfig.
+ m_stepAction.setToolTip(QString());
+ m_nextAction.setToolTip(QString());
+
+ // The 'state' bits only affect the fat debug button, not the preset start button.
+ m_startAction.setText(QString());
+ m_startAction.setToolTip(whyNot);
+ m_startAction.setIcon(startIcon(false));
+ m_startAction.setEnabled(false);
+ m_startAction.setVisible(false);
+
+ QString currentDisplayName = currentEngine->displayName();
+ m_interruptAction.setToolTip(tr("Interrupt \"%1\"").arg(currentDisplayName));
+ m_continueAction.setToolTip(tr("Continue \"%1\"").arg(currentDisplayName));
+
+ m_debugWithoutDeployAction.setEnabled(canRun);
+
+ // Global actions are redirected to running, active engine if possible.
+
+ const bool isCore = currentEngine->runParameters().startMode == AttachCore;
+
+ const DebuggerState state = currentEngine->state();
+ const bool companionPreventsAction = currentEngine->companionPreventsActions();
+
+ if (state == InferiorStopOk) {
+ // F5 continues, Shift-F5 kills. It is "continuable".
+ m_startAction.setEnabled(false);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(!companionPreventsAction);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_visibleStartAction.setAction(&m_continueAction);
+ m_visibleStartAction.setIcon(continueIcon(true));
+ m_hiddenStopAction.setAction(&m_exitAction);
+ m_stepAction.setEnabled(!companionPreventsAction);
+ m_nextAction.setEnabled(!companionPreventsAction);
+ m_jumpToLineAction.setEnabled(currentEngine->hasCapability(JumpToLineCapability));
+ m_returnFromFunctionAction.setEnabled(currentEngine->hasCapability(ReturnFromFunctionCapability));
+ m_detachAction.setEnabled(!isCore);
+ m_abortAction.setEnabled(true);
+ m_resetAction.setEnabled(currentEngine->hasCapability(ResetInferiorCapability));
+ m_stepOutAction.setEnabled(!companionPreventsAction);
+ m_runToLineAction.setEnabled(currentEngine->hasCapability(RunToLineCapability));
+ m_runToSelectedFunctionAction.setEnabled(true);
+ } else if (state == InferiorRunOk) {
+ // Shift-F5 interrupts. It is also "interruptible".
+ m_startAction.setEnabled(false);
+ m_interruptAction.setEnabled(!companionPreventsAction);
+ m_continueAction.setEnabled(false);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_visibleStartAction.setAction(&m_interruptAction);
+ m_visibleStartAction.setIcon(interruptIcon(true));
+ m_hiddenStopAction.setAction(&m_interruptAction);
+ m_stepAction.setEnabled(false);
+ m_nextAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_detachAction.setEnabled(false);
+ m_abortAction.setEnabled(true);
+ m_resetAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(false);
+ } else if (state == DebuggerFinished) {
+ // We don't want to do anything anymore.
+ m_startAction.setEnabled(canRun);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(canRun);
+ m_visibleStartAction.setAction(&m_startAction);
+ m_visibleStartAction.setIcon(startIcon(true));
+ m_hiddenStopAction.setAction(&m_undisturbableAction);
+ m_stepAction.setEnabled(false);
+ m_nextAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_detachAction.setEnabled(false);
+ m_abortAction.setEnabled(false);
+ m_resetAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(false);
+ } else if (state == InferiorUnrunnable) {
+ // We don't want to do anything anymore.
+ m_startAction.setEnabled(false);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+ m_exitAction.setEnabled(true);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_visibleStartAction.setAction(&m_undisturbableAction);
+ m_visibleStartAction.setIcon(startIcon(true));
+ m_hiddenStopAction.setAction(&m_exitAction);
+ m_stepAction.setEnabled(false);
+ m_nextAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_detachAction.setEnabled(false);
+ m_abortAction.setEnabled(true);
+ m_resetAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(false);
+ } else if (state == DebuggerNotReady) {
+ // The startup phase should be over once we are here
+ QTC_CHECK(false);
+ } else {
+ // Everything else is "undisturbable".
+ m_startAction.setEnabled(false);
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+ m_exitAction.setEnabled(false);
+ m_debugWithoutDeployAction.setEnabled(false);
+ m_visibleStartAction.setAction(&m_undisturbableAction);
+ m_visibleStartAction.setIcon(startIcon(true));
+ m_hiddenStopAction.setAction(&m_undisturbableAction);
+ m_stepAction.setEnabled(false);
+ m_nextAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_detachAction.setEnabled(false);
+ m_abortAction.setEnabled(true);
+ m_resetAction.setEnabled(false);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(false);
+ }
+
+// FIXME: Decentralize the actions below
+ const bool actionsEnabled = currentEngine->debuggerActionsEnabled();
+ const bool canDeref = actionsEnabled && currentEngine->hasCapability(AutoDerefPointersCapability);
+ action(AutoDerefPointers)->setEnabled(canDeref);
+ action(AutoDerefPointers)->setEnabled(true);
+ action(ExpandStack)->setEnabled(actionsEnabled);
+
+ m_startAndDebugApplicationAction.setEnabled(true);
+ m_attachToQmlPortAction.setEnabled(true);
+ m_attachToCoreAction.setEnabled(true);
+ m_attachToRemoteServerAction.setEnabled(true);
+ m_attachToRunningApplication.setEnabled(true);
+ m_attachToUnstartedApplication.setEnabled(true);
+
+ m_watchAction.setEnabled(true);
+ m_breakAction.setEnabled(true);
+}
+
+void DebuggerPluginPrivate::onStartupProjectChanged(Project *project)
{
RunConfiguration *activeRc = nullptr;
if (project) {
@@ -1905,34 +1609,12 @@ void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project)
if (!activeRc)
return;
}
- for (int i = 0, n = m_snapshotHandler->size(); i != n; ++i) {
+ for (DebuggerEngine *engine : EngineManager::engines()) {
// Run controls might be deleted during exit.
- if (DebuggerRunTool *runTool = m_snapshotHandler->at(i)) {
- if (RunControl *runControl = runTool->runControl()) {
- RunConfiguration *rc = runControl->runConfiguration();
- if (rc == activeRc) {
- m_snapshotHandler->setCurrentIndex(i);
- updateState(runTool);
- return;
- }
- }
- }
+ engine->updateState(false);
}
- // If we have a running debugger, don't touch it.
- if (m_snapshotHandler->size())
- return;
-
- // No corresponding debugger found. So we are ready to start one.
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(false);
- QString whyNot;
- const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot);
- m_startAction->setEnabled(canRun);
- m_startAction->setToolTip(whyNot);
- m_debugWithoutDeployAction->setEnabled(canRun);
- setProxyAction(m_visibleStartAction, Id(Constants::DEBUG));
+ updatePresetState();
}
void DebuggerPluginPrivate::attachCore()
@@ -2134,13 +1816,15 @@ void DebuggerPlugin::getEnginesState(QByteArray *json) const
};
QVariantMap states;
- for (int i = 0; i < dd->m_snapshotHandler->size(); ++i) {
- const DebuggerEngine *engine = dd->m_snapshotHandler->at(i)->engine();
+ int i = 0;
+ DebuggerEngine *currentEngine = EngineManager::currentEngine();
+ for (DebuggerEngine *engine : EngineManager::engines()) {
states[QString::number(i)] = QVariantMap({
- {"current", dd->m_snapshotHandler->currentIndex() == i},
+ {"current", engine == currentEngine},
{"pid", engine->inferiorPid()},
{"state", engine->state()}
});
+ ++i;
}
if (!states.isEmpty())
@@ -2188,14 +1872,6 @@ void DebuggerPluginPrivate::attachToQmlPort()
debugger->startRunControl();
}
-void DebuggerPluginPrivate::enableReverseDebuggingTriggered(const QVariant &value)
-{
- QTC_ASSERT(m_reverseToolButton, return);
- m_reverseToolButton->setVisible(value.toBool());
- m_reverseDirectionAction->setChecked(false);
- m_reverseDirectionAction->setEnabled(value.toBool());
-}
-
void DebuggerPluginPrivate::runScheduled()
{
for (DebuggerRunTool *debugger : m_scheduledStarts)
@@ -2215,50 +1891,47 @@ void DebuggerPluginPrivate::editorOpened(IEditor *editor)
void DebuggerPluginPrivate::updateBreakMenuItem(IEditor *editor)
{
- auto textEditor = qobject_cast<BaseTextEditor *>(editor);
- m_breakAction->setEnabled(textEditor != nullptr);
+ BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(editor);
+ m_breakAction.setEnabled(textEditor != nullptr);
}
void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget,
int lineNumber, QMenu *menu)
{
- Breakpoint bp;
+ GlobalBreakpoint gbp;
TextDocument *document = widget->textDocument();
ContextData args = getLocationContext(document, lineNumber);
if (args.type == LocationByAddress) {
- BreakpointResponse needle;
+ BreakpointParameters needle;
needle.type = BreakpointByAddress;
needle.address = args.address;
needle.lineNumber = -1;
- bp = breakHandler()->findSimilarBreakpoint(needle);
+ gbp = BreakpointManager::findSimilarBreakpoint(needle);
} else if (args.type == LocationByFile) {
- bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber);
- if (!bp)
- bp = breakHandler()->findBreakpointByFileAndLine(args.fileName, lineNumber, false);
+ gbp = BreakpointManager::findBreakpointByLocation(args);
}
- if (bp) {
- QString id = bp.id().toString();
+ if (gbp) {
// Remove existing breakpoint.
- auto act = menu->addAction(tr("Remove Breakpoint %1").arg(id));
- connect(act, &QAction::triggered, [bp] { bp.removeBreakpoint(); });
-
- // Enable/disable existing breakpoint.
- if (bp.isEnabled()) {
- act = menu->addAction(tr("Disable Breakpoint %1").arg(id));
- connect(act, &QAction::triggered, [bp] { bp.setEnabled(false); });
- } else {
- act = menu->addAction(tr("Enable Breakpoint %1").arg(id));
- connect(act, &QAction::triggered, [bp] { bp.setEnabled(true); });
- }
-
- // Edit existing breakpoint.
- act = menu->addAction(tr("Edit Breakpoint %1...").arg(id));
- connect(act, &QAction::triggered, [bp] {
- breakHandler()->editBreakpoint(bp, ICore::dialogParent());
- });
+ auto act = menu->addAction(tr("Remove Breakpoint"));
+ connect(act, &QAction::triggered, [gbp] { gbp->deleteBreakpoint(); });
+
+// // Enable/disable existing breakpoint.
+// if (gbp->isEnabled()) {
+// act = menu->addAction(tr("Disable Breakpoint %1").arg(id));
+// connect(act, &QAction::triggered, [gbp] { gbp.setEnabled(false); });
+// } else {
+// act = menu->addAction(tr("Enable Breakpoint %1").arg(id));
+// connect(act, &QAction::triggered, [gbp] { gbp.setEnabled(true); });
+// }
+
+// // Edit existing breakpoint.
+// act = menu->addAction(tr("Edit Breakpoint %1...").arg(id));
+// connect(act, &QAction::triggered, [gbp] {
+// globalBreakHandler()->editBreakpoint(gbp, ICore::dialogParent());
+// });
} else {
// Handle non-existing breakpoint.
@@ -2283,85 +1956,47 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget,
}
// Run to, jump to line below in stopped state.
- DebuggerEngine *engine = currentEngine();
- QTC_ASSERT(engine, return);
- if (engine->state() == InferiorStopOk && args.isValid()) {
- menu->addSeparator();
- if (engine->hasCapability(RunToLineCapability)) {
- auto act = menu->addAction(args.address
- ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16)
- : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber));
- connect(act, &QAction::triggered, this, [args] {
- DebuggerEngine *engine = currentEngine();
- QTC_ASSERT(engine, return);
- engine->executeRunToLine(args);
- });
- }
- if (engine->hasCapability(JumpToLineCapability)) {
- auto act = menu->addAction(args.address
- ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16)
- : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber));
- connect(act, &QAction::triggered, this, [args] {
- DebuggerEngine *engine = currentEngine();
- QTC_ASSERT(engine, return);
- engine->executeJumpToLine(args);
- });
- }
- // Disassemble current function in stopped state.
- if (engine->hasCapability(DisassemblerCapability)) {
- StackFrame frame;
- frame.function = cppFunctionAt(args.fileName, lineNumber, 1);
- frame.line = 42; // trick gdb into mixed mode.
- if (!frame.function.isEmpty()) {
- const QString text = tr("Disassemble Function \"%1\"")
- .arg(frame.function);
- auto act = new QAction(text, menu);
- connect(act, &QAction::triggered, this, [frame] {
- DebuggerEngine *engine = currentEngine();
+ for (const QPointer<DebuggerEngine> engine : EngineManager::engines()) {
+ if (engine->state() == InferiorStopOk && args.isValid()) {
+ menu->addSeparator();
+ if (engine->hasCapability(RunToLineCapability)) {
+ auto act = menu->addAction(args.address
+ ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16)
+ : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber));
+ connect(act, &QAction::triggered, this, [args, engine] {
QTC_ASSERT(engine, return);
- engine->openDisassemblerView(Location(frame));
+ engine->executeRunToLine(args);
});
- menu->addAction(act);
+ }
+ if (engine->hasCapability(JumpToLineCapability)) {
+ auto act = menu->addAction(args.address
+ ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16)
+ : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber));
+ connect(act, &QAction::triggered, this, [args, engine] {
+ QTC_ASSERT(engine, return);
+ engine->executeJumpToLine(args);
+ });
+ }
+ // Disassemble current function in stopped state.
+ if (engine->hasCapability(DisassemblerCapability)) {
+ StackFrame frame;
+ frame.function = cppFunctionAt(args.fileName, lineNumber, 1);
+ frame.line = 42; // trick gdb into mixed mode.
+ if (!frame.function.isEmpty()) {
+ const QString text = tr("Disassemble Function \"%1\"")
+ .arg(frame.function);
+ auto act = new QAction(text, menu);
+ connect(act, &QAction::triggered, this, [frame, engine] {
+ QTC_ASSERT(engine, return);
+ engine->openDisassemblerView(Location(frame));
+ });
+ menu->addAction(act);
+ }
}
}
}
}
-void DebuggerPluginPrivate::toggleBreakpoint(const ContextData &location, const QString &tracePointMessage)
-{
- QTC_ASSERT(location.isValid(), return);
- BreakHandler *handler = m_breakHandler;
- Breakpoint bp;
- if (location.type == LocationByFile) {
- bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, true);
- if (!bp)
- bp = handler->findBreakpointByFileAndLine(location.fileName, location.lineNumber, false);
- } else if (location.type == LocationByAddress) {
- bp = handler->findBreakpointByAddress(location.address);
- }
-
- if (bp) {
- bp.removeBreakpoint();
- } else {
- BreakpointParameters data;
- if (location.type == LocationByFile) {
- data.type = BreakpointByFileAndLine;
- if (boolSetting(BreakpointsFullPathByDefault))
- data.pathUsage = BreakpointUseFullPath;
- data.tracepoint = !tracePointMessage.isEmpty();
- data.message = tracePointMessage;
- data.fileName = location.fileName;
- data.lineNumber = location.lineNumber;
- } else if (location.type == LocationByAddress) {
- data.type = BreakpointByAddress;
- data.tracepoint = !tracePointMessage.isEmpty();
- data.message = tracePointMessage;
- data.address = location.address;
- }
- handler->appendBreakpoint(data);
- }
-}
-
void DebuggerPluginPrivate::toggleBreakpointHelper()
{
BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor();
@@ -2369,7 +2004,7 @@ void DebuggerPluginPrivate::toggleBreakpointHelper()
const int lineNumber = textEditor->currentLine();
ContextData location = getLocationContext(textEditor->textDocument(), lineNumber);
if (location.isValid())
- toggleBreakpoint(location);
+ BreakpointManager::toggleBreakpoint(location);
}
void DebuggerPluginPrivate::requestMark(TextEditorWidget *widget, int lineNumber,
@@ -2378,360 +2013,60 @@ void DebuggerPluginPrivate::requestMark(TextEditorWidget *widget, int lineNumber
if (kind == BreakpointRequest) {
ContextData location = getLocationContext(widget->textDocument(), lineNumber);
if (location.isValid())
- toggleBreakpoint(location);
+ BreakpointManager::toggleBreakpoint(location);
}
}
-// If updateEngine is set, the engine will update its threads/modules and so forth.
-void DebuggerPluginPrivate::displayDebugger(DebuggerRunTool *runTool)
-{
- QTC_ASSERT(runTool, return);
- DebuggerEngine *engine = runTool ? runTool->engine() : dummyEngine();
- QTC_ASSERT(engine, return);
-
- disconnectEngine();
- connectEngine(runTool);
- engine->updateAll();
- engine->updateViews();
-}
-
-void DebuggerPluginPrivate::connectEngine(DebuggerRunTool *runTool)
-{
- if (m_shuttingDown)
- return;
-
- m_currentRunTool = runTool;
- DebuggerEngine *engine = currentEngine();
- QTC_ASSERT(engine, return);
-
- if (m_previouslyActiveEngine == engine)
- return;
-
- if (m_previouslyActiveEngine)
- m_previouslyActiveEngine->resetLocation();
-
- m_previouslyActiveEngine = engine;
-
- m_localsView->setModel(engine->watchModel());
- m_modulesView->setModel(engine->modulesModel());
- m_registerView->setModel(engine->registerModel());
- m_returnView->setModel(engine->watchModel());
- m_sourceFilesView->setModel(engine->sourceFilesModel());
- m_stackView->setModel(engine->stackModel());
- m_threadsView->setModel(engine->threadsModel());
- m_watchersView->setModel(engine->watchModel());
- m_inspectorView->setModel(engine->watchModel());
-
- engine->watchHandler()->resetWatchers();
- m_localsView->hideProgressIndicator();
- updateActiveLanguages();
-}
-
-static void changeFontSize(QWidget *widget, qreal size)
-{
- QFont font = widget->font();
- font.setPointSizeF(size);
- widget->setFont(font);
-}
-
-void DebuggerPluginPrivate::fontSettingsChanged(const FontSettings &settings)
-{
- if (!boolSetting(FontSizeFollowsEditor))
- return;
- qreal size = settings.fontZoom() * settings.fontSize() / 100.;
- changeFontSize(m_breakWindow, size);
- changeFontSize(m_logWindow, size);
- changeFontSize(m_localsWindow, size);
- changeFontSize(m_modulesWindow, size);
- //changeFontSize(m_consoleWindow, size);
- changeFontSize(m_registerWindow, size);
- changeFontSize(m_returnWindow, size);
- changeFontSize(m_sourceFilesWindow, size);
- changeFontSize(m_stackWindow, size);
- changeFontSize(m_threadsWindow, size);
- changeFontSize(m_watchersWindow, size);
- changeFontSize(m_inspectorWindow, size);
-}
-
-void DebuggerPluginPrivate::cleanupViews()
-{
- m_reverseDirectionAction->setChecked(false);
- m_reverseDirectionAction->setEnabled(false);
-
- const bool closeSource = boolSetting(CloseSourceBuffersOnExit);
- const bool closeMemory = boolSetting(CloseMemoryBuffersOnExit);
-
- QList<IDocument *> toClose;
- foreach (IDocument *document, DocumentModel::openedDocuments()) {
- const bool isMemory = document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool();
- if (document->property(Constants::OPENED_BY_DEBUGGER).toBool()) {
- bool keepIt = true;
- if (document->isModified())
- keepIt = true;
- else if (document->filePath().toString().contains("qeventdispatcher"))
- keepIt = false;
- else if (isMemory)
- keepIt = !closeMemory;
- else
- keepIt = !closeSource;
-
- if (keepIt)
- document->setProperty(Constants::OPENED_BY_DEBUGGER, false);
- else
- toClose.append(document);
- }
- }
- EditorManager::closeDocuments(toClose);
-}
-
-void DebuggerPluginPrivate::setBusyCursor(bool busy)
-{
- //STATE_DEBUG("BUSY FROM: " << m_busy << " TO: " << busy);
- if (busy == m_busy)
- return;
- m_busy = busy;
- QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
- m_breakWindow->setCursor(cursor);
- //m_consoleWindow->setCursor(cursor);
- m_localsWindow->setCursor(cursor);
- m_modulesWindow->setCursor(cursor);
- m_logWindow->setCursor(cursor);
- m_registerWindow->setCursor(cursor);
- m_returnWindow->setCursor(cursor);
- m_sourceFilesWindow->setCursor(cursor);
- m_stackWindow->setCursor(cursor);
- m_threadsWindow->setCursor(cursor);
- m_watchersWindow->setCursor(cursor);
- m_snapshotWindow->setCursor(cursor);
-}
-
void DebuggerPluginPrivate::setInitialState()
{
- m_returnWindow->setVisible(false);
- setBusyCursor(false);
- m_reverseDirectionAction->setChecked(false);
- m_reverseDirectionAction->setEnabled(false);
m_toolTipManager.closeAllToolTips();
- m_startAndDebugApplicationAction->setEnabled(true);
- m_attachToQmlPortAction->setEnabled(true);
- m_attachToCoreAction->setEnabled(true);
- m_attachToRemoteServerAction->setEnabled(true);
- m_attachToRunningApplication->setEnabled(true);
- m_attachToUnstartedApplication->setEnabled(true);
- m_detachAction->setEnabled(false);
-
- m_watchAction->setEnabled(true);
- m_breakAction->setEnabled(false);
- //m_snapshotAction->setEnabled(false);
- m_operateByInstructionAction->setEnabled(false);
-
- m_exitAction->setEnabled(false);
- m_abortAction->setEnabled(false);
- m_resetAction->setEnabled(false);
-
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
-
- m_stepAction->setEnabled(true);
- m_stepOutAction->setEnabled(false);
- m_runToLineAction->setEnabled(false);
- m_runToSelectedFunctionAction->setEnabled(true);
- m_returnFromFunctionAction->setEnabled(false);
- m_jumpToLineAction->setEnabled(false);
- m_nextAction->setEnabled(true);
+ m_startAndDebugApplicationAction.setEnabled(true);
+ m_attachToQmlPortAction.setEnabled(true);
+ m_attachToCoreAction.setEnabled(true);
+ m_attachToRemoteServerAction.setEnabled(true);
+ m_attachToRunningApplication.setEnabled(true);
+ m_attachToUnstartedApplication.setEnabled(true);
+ m_detachAction.setEnabled(false);
+
+ m_watchAction.setEnabled(true);
+ m_breakAction.setEnabled(false);
+ //m_snapshotAction.setEnabled(false);
+ action(OperateByInstruction)->setChecked(false);
+
+ m_exitAction.setEnabled(false);
+ m_abortAction.setEnabled(false);
+ m_resetAction.setEnabled(false);
+
+ m_interruptAction.setEnabled(false);
+ m_continueAction.setEnabled(false);
+
+ m_stepAction.setEnabled(true);
+ m_stepOutAction.setEnabled(false);
+ m_runToLineAction.setEnabled(false);
+ m_runToSelectedFunctionAction.setEnabled(true);
+ m_returnFromFunctionAction.setEnabled(false);
+ m_jumpToLineAction.setEnabled(false);
+ m_nextAction.setEnabled(true);
action(AutoDerefPointers)->setEnabled(true);
action(ExpandStack)->setEnabled(false);
-
- m_threadLabel->setEnabled(false);
-}
-
-void DebuggerPluginPrivate::updateState(DebuggerRunTool *runTool)
-{
- if (m_shuttingDown)
- return;
- QTC_ASSERT(runTool, return);
- DebuggerEngine *engine = runTool->engine();
- QTC_ASSERT(engine, return);
- QTC_ASSERT(m_watchersView->model(), return);
- QTC_ASSERT(m_returnView->model(), return);
- QTC_ASSERT(!engine->isSlaveEngine(), return);
-
- m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThreadIndex());
-
- const DebuggerState state = engine->state();
- //showMessage(QString::fromLatin1("PLUGIN SET STATE: ")
- // + DebuggerEngine::stateName(state), LogStatus);
- //qDebug() << "PLUGIN SET STATE: " << state;
-
- static DebuggerState previousState = DebuggerNotReady;
- if (state == previousState)
- return;
-
- bool actionsEnabled = DebuggerEngine::debuggerActionsEnabled(state);
-
- if (state == DebuggerNotReady) {
- QTC_ASSERT(false, /* We use the Core's m_debugAction here */);
- // F5 starts debugging. It is "startable".
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(false);
- m_startAction->setEnabled(true);
- m_debugWithoutDeployAction->setEnabled(true);
- setProxyAction(m_visibleStartAction, Id(Constants::DEBUG));
- m_hiddenStopAction->setAction(m_undisturbableAction);
- } else if (state == InferiorStopOk) {
- // F5 continues, Shift-F5 kills. It is "continuable".
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(true);
- m_exitAction->setEnabled(true);
- m_startAction->setEnabled(false);
- m_debugWithoutDeployAction->setEnabled(false);
- setProxyAction(m_visibleStartAction, Id(Constants::CONTINUE));
- m_hiddenStopAction->setAction(m_exitAction);
- m_localsAndInspectorWindow->setShowLocals(true);
- } else if (state == InferiorRunOk) {
- // Shift-F5 interrupts. It is also "interruptible".
- m_interruptAction->setEnabled(true);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(true);
- m_startAction->setEnabled(false);
- m_debugWithoutDeployAction->setEnabled(false);
- setProxyAction(m_visibleStartAction, Id(Constants::INTERRUPT));
- m_hiddenStopAction->setAction(m_interruptAction);
- m_localsAndInspectorWindow->setShowLocals(false);
- } else if (state == DebuggerFinished) {
- const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE);
- // We don't want to do anything anymore.
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(false);
- m_startAction->setEnabled(canRun);
- m_debugWithoutDeployAction->setEnabled(canRun);
- setProxyAction(m_visibleStartAction, Id(Constants::DEBUG));
- m_hiddenStopAction->setAction(m_undisturbableAction);
- setBusyCursor(false);
- cleanupViews();
- } else if (state == InferiorUnrunnable) {
- // We don't want to do anything anymore.
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(true);
- m_startAction->setEnabled(false);
- m_debugWithoutDeployAction->setEnabled(false);
- m_visibleStartAction->setAction(m_undisturbableAction);
- m_hiddenStopAction->setAction(m_exitAction);
- // show locals in core dumps
- m_localsAndInspectorWindow->setShowLocals(true);
- } else {
- // Everything else is "undisturbable".
- m_interruptAction->setEnabled(false);
- m_continueAction->setEnabled(false);
- m_exitAction->setEnabled(false);
- m_startAction->setEnabled(false);
- m_debugWithoutDeployAction->setEnabled(false);
- m_visibleStartAction->setAction(m_undisturbableAction);
- m_hiddenStopAction->setAction(m_undisturbableAction);
- }
-
- m_startAndDebugApplicationAction->setEnabled(true);
- m_attachToQmlPortAction->setEnabled(true);
- m_attachToCoreAction->setEnabled(true);
- m_attachToRemoteServerAction->setEnabled(true);
- m_attachToRunningApplication->setEnabled(true);
- m_attachToUnstartedApplication->setEnabled(true);
-
- m_threadBox->setEnabled(state == InferiorStopOk || state == InferiorUnrunnable);
- m_threadLabel->setEnabled(m_threadBox->isEnabled());
-
- const bool isCore = runTool->runParameters().startMode == AttachCore;
- const bool stopped = state == InferiorStopOk;
- const bool detachable = stopped && !isCore;
- m_detachAction->setEnabled(detachable);
-
- if (stopped)
- QApplication::alert(mainWindow(), 3000);
-
- const bool canReverse = engine->hasCapability(ReverseSteppingCapability)
- && boolSetting(EnableReverseDebugging);
- m_reverseDirectionAction->setEnabled(canReverse);
-
- m_watchAction->setEnabled(true);
- m_breakAction->setEnabled(true);
-
- const bool canOperateByInstruction = engine->hasCapability(OperateByInstructionCapability)
- && (stopped || isCore);
- m_operateByInstructionAction->setEnabled(canOperateByInstruction);
-
- m_abortAction->setEnabled(state != DebuggerNotReady
- && state != DebuggerFinished);
- m_resetAction->setEnabled((stopped || state == DebuggerNotReady)
- && engine->hasCapability(ResetInferiorCapability));
-
- m_stepAction->setEnabled(stopped || state == DebuggerNotReady);
- m_nextAction->setEnabled(stopped || state == DebuggerNotReady);
- m_stepAction->setToolTip(QString());
- m_nextAction->setToolTip(QString());
-
- m_stepOutAction->setEnabled(stopped);
- m_runToLineAction->setEnabled(stopped && engine->hasCapability(RunToLineCapability));
- m_runToSelectedFunctionAction->setEnabled(stopped);
- m_returnFromFunctionAction->
- setEnabled(stopped && engine->hasCapability(ReturnFromFunctionCapability));
-
- const bool canJump = stopped && engine->hasCapability(JumpToLineCapability);
- m_jumpToLineAction->setEnabled(canJump);
-
- const bool canDeref = actionsEnabled && engine->hasCapability(AutoDerefPointersCapability);
- action(AutoDerefPointers)->setEnabled(canDeref);
- action(AutoDerefPointers)->setEnabled(true);
- action(ExpandStack)->setEnabled(actionsEnabled);
-
- const bool notbusy = state == InferiorStopOk
- || state == DebuggerNotReady
- || state == DebuggerFinished
- || state == InferiorUnrunnable;
- setBusyCursor(!notbusy);
-}
-
-void DebuggerPluginPrivate::updateDebugActions()
-{
- if (m_shuttingDown)
- return;
- //if we're currently debugging the actions are controlled by engine
- if (m_currentRunTool && m_currentRunTool->engine()->state() != DebuggerNotReady)
- return;
-
- QString whyNot;
- const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot);
- m_startAction->setEnabled(canRun);
- m_startAction->setToolTip(whyNot);
- m_debugWithoutDeployAction->setEnabled(canRun);
-
- // Step into/next: Start and break at 'main' unless a debugger is running.
- if (m_snapshotHandler->currentIndex() < 0) {
- m_stepAction->setEnabled(canRun);
- m_nextAction->setEnabled(canRun);
- if (canRun) {
- Project *project = SessionManager::startupProject();
- QTC_ASSERT(project, return);
- whyNot = tr("Start \"%1\" and break at function \"main()\"")
- .arg(project->displayName());
- }
- m_stepAction->setToolTip(whyNot);
- m_nextAction->setToolTip(whyNot);
- }
}
void DebuggerPluginPrivate::updateDebugWithoutDeployMenu()
{
const bool state = ProjectExplorerPlugin::projectExplorerSettings().deployBeforeRun;
- m_debugWithoutDeployAction->setVisible(state);
+ m_debugWithoutDeployAction.setVisible(state);
}
void DebuggerPluginPrivate::dumpLog()
{
+ DebuggerEngine *engine = EngineManager::currentEngine();
+ if (!engine)
+ return;
+ LogWindow *logWindow = engine->logWindow();
+ QTC_ASSERT(logWindow, return);
+
QString fileName = QFileDialog::getSaveFileName(ICore::mainWindow(),
tr("Save Debugger Log"), Utils::TemporaryDirectory::masterDirectoryPath());
if (fileName.isEmpty())
@@ -2739,63 +2074,34 @@ void DebuggerPluginPrivate::dumpLog()
FileSaver saver(fileName);
if (!saver.hasError()) {
QTextStream ts(saver.file());
- ts << m_logWindow->inputContents();
+ ts << logWindow->inputContents();
ts << "\n\n=======================================\n\n";
- ts << m_logWindow->combinedContents();
+ ts << logWindow->combinedContents();
saver.setResult(&ts);
}
saver.finalize(ICore::mainWindow());
}
-/*! Activates the previous mode when the current mode is the debug mode. */
-void DebuggerPluginPrivate::activatePreviousMode()
-{
- if (ModeManager::currentModeId() == MODE_DEBUG && m_previousMode.isValid()) {
- // If stopping the application also makes Qt Creator active (as the
- // "previously active application"), doing the switch synchronously
- // leads to funny effects with floating dock widgets
- const Core::Id mode = m_previousMode;
- QTimer::singleShot(0, this, [mode]() { ModeManager::activateMode(mode); });
- m_previousMode = Id();
- }
-}
-
-void DebuggerPluginPrivate::activateDebugMode()
-{
- m_reverseDirectionAction->setChecked(false);
- m_reverseDirectionAction->setEnabled(false);
- ModeManager::activateMode(MODE_DEBUG);
-}
-
void DebuggerPluginPrivate::sessionLoaded()
{
- m_breakHandler->loadSessionData();
- dummyEngine()->watchHandler()->loadSessionData();
+ BreakpointManager::loadSessionData();
+ WatchHandler::loadSessionData();
DebuggerToolTipManager::loadSessionData();
}
void DebuggerPluginPrivate::aboutToUnloadSession()
{
+ BreakpointManager::aboutToUnloadSession();
m_toolTipManager.sessionAboutToChange();
}
void DebuggerPluginPrivate::aboutToSaveSession()
{
- dummyEngine()->watchHandler()->saveSessionData();
- m_breakHandler->saveSessionData();
+ WatchHandler::saveSessionData();
+ BreakpointManager::saveSessionData();
DebuggerToolTipManager::saveSessionData();
}
-void DebuggerPluginPrivate::showStatusMessage(const QString &msg0, int timeout)
-{
- if (m_shuttingDown)
- return;
- showMessage(msg0, LogStatus);
- QString msg = msg0;
- msg.replace(QChar::LineFeed, QLatin1String("; "));
- m_mainWindow->showStatusMessage(msg, timeout);
-}
-
void DebuggerPluginPrivate::aboutToShutdown()
{
m_shuttingDown = true;
@@ -2805,9 +2111,9 @@ void DebuggerPluginPrivate::aboutToShutdown()
m_shutdownTimer.setInterval(0);
m_shutdownTimer.setSingleShot(true);
connect(&m_shutdownTimer, &QTimer::timeout, this, &DebuggerPluginPrivate::doShutdown);
- if (dd->m_currentRunTool) {
- if (dd->m_currentRunTool->engine()->state() != Debugger::DebuggerNotReady) {
- dd->m_currentRunTool->abortDebugger();
+ for (DebuggerEngine *engine : m_engineManager.engines()) {
+ if (engine && engine->state() != Debugger::DebuggerNotReady) {
+ engine->abortDebugger();
m_shutdownTimer.setInterval(3000);
}
}
@@ -2824,40 +2130,6 @@ QVariant sessionValue(const QByteArray &key)
return SessionManager::value(QString::fromUtf8(key));
}
-WatchTreeView *inspectorView()
-{
- return dd->m_inspectorView;
-}
-
-void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int timeout)
-{
- if (m_shuttingDown)
- return;
- //qDebug() << "PLUGIN OUTPUT: " << channel << msg;
- QTC_ASSERT(m_logWindow, return);
- switch (channel) {
- case StatusBar:
- // This will append to m_logWindow's output pane, too.
- showStatusMessage(msg, timeout);
- break;
- case LogMiscInput:
- m_logWindow->showInput(LogMisc, msg);
- m_logWindow->showOutput(LogMisc, msg);
- break;
- case LogInput:
- m_logWindow->showInput(LogInput, msg);
- m_logWindow->showOutput(LogInput, msg);
- break;
- case LogError:
- m_logWindow->showInput(LogError, QLatin1String("ERROR: ") + msg);
- m_logWindow->showOutput(LogError, QLatin1String("ERROR: ") + msg);
- break;
- default:
- m_logWindow->showOutput(channel, msg);
- break;
- }
-}
-
static void createNewDock(QWidget *widget)
{
auto dockWidget = new QDockWidget;
@@ -2867,84 +2139,6 @@ static void createNewDock(QWidget *widget)
dockWidget->show();
}
-static QString formatStartParameters(const DebuggerRunTool *debugger)
-{
- const DebuggerRunParameters &sp = debugger->runParameters();
- QString rc;
- QTextStream str(&rc);
- str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode
- << "\nABI: " << sp.toolChainAbi.toString() << '\n';
- str << "Languages: ";
- if (sp.isCppDebugging())
- str << "c++ ";
- if (sp.isQmlDebugging)
- str << "qml";
- str << '\n';
- if (!sp.inferior.executable.isEmpty()) {
- str << "Executable: " << QDir::toNativeSeparators(sp.inferior.executable)
- << ' ' << sp.inferior.commandLineArguments;
- if (debugger->terminalRunner())
- str << " [terminal]";
- str << '\n';
- if (!sp.inferior.workingDirectory.isEmpty())
- str << "Directory: " << QDir::toNativeSeparators(sp.inferior.workingDirectory)
- << '\n';
- }
- QString cmd = sp.debugger.executable;
- if (!cmd.isEmpty())
- str << "Debugger: " << QDir::toNativeSeparators(cmd) << '\n';
- if (!sp.coreFile.isEmpty())
- str << "Core: " << QDir::toNativeSeparators(sp.coreFile) << '\n';
- if (sp.attachPID.isValid())
- str << "PID: " << sp.attachPID.pid() << ' ' << sp.crashParameter << '\n';
- if (!sp.projectSourceDirectory.isEmpty()) {
- str << "Project: " << QDir::toNativeSeparators(sp.projectSourceDirectory) << '\n';
- str << "Additional Search Directories:"
- << sp.additionalSearchDirectories.join(QLatin1Char(' ')) << '\n';
- }
- if (!sp.remoteChannel.isEmpty())
- str << "Remote: " << sp.remoteChannel << '\n';
- if (!sp.qmlServer.host().isEmpty())
- str << "QML server: " << sp.qmlServer.host() << ':' << sp.qmlServer.port() << '\n';
- str << "Sysroot: " << sp.sysRoot << '\n';
- str << "Debug Source Location: " << sp.debugSourceLocation.join(QLatin1Char(':')) << '\n';
- return rc;
-}
-
-void DebuggerPluginPrivate::runControlStarted(DebuggerRunTool *runTool)
-{
- activateDebugMode();
- const QString message = tr("Starting debugger \"%1\" for ABI \"%2\"...")
- .arg(runTool->engine()->objectName())
- .arg(runTool->runParameters().toolChainAbi.toString());
- showStatusMessage(message);
- showMessage(formatStartParameters(runTool), LogDebug);
- showMessage(m_debuggerSettings->dump(), LogDebug);
- m_snapshotHandler->appendSnapshot(runTool);
- connectEngine(runTool);
-}
-
-void DebuggerPluginPrivate::runControlFinished(DebuggerRunTool *runTool)
-{
- showStatusMessage(tr("Debugger finished."));
- m_snapshotHandler->removeSnapshot(runTool);
- if (m_snapshotHandler->size() == 0) {
- if (m_shuttingDown) {
- doShutdown();
- return;
- }
- // Last engine quits.
- disconnectEngine();
- if (boolSetting(SwitchModeOnExit))
- activatePreviousMode();
- } else {
- // Connect to some existing engine.
- m_snapshotHandler->activateSnapshot(0);
- }
- m_operateByInstructionAction->setChecked(false);
- m_logWindow->clearUndoRedoStacks();
-}
-
void DebuggerPluginPrivate::remoteCommand(const QStringList &options)
{
if (options.isEmpty())
@@ -2978,15 +2172,12 @@ void addDebugInfoTask(unsigned id, const QString &cmd)
bool isReverseDebuggingEnabled()
{
+ return true;
+
static bool enabled = qEnvironmentVariableIsSet("QTC_DEBUGGER_ENABLE_REVERSE");
return enabled;
}
-bool isReverseDebugging()
-{
- return isReverseDebuggingEnabled() && dd->m_reverseDirectionAction->isChecked();
-}
-
void DebuggerPluginPrivate::extensionsInitialized()
{
// If the CppEditor or QmlJS editor plugin is there, we want to add something to
@@ -3021,14 +2212,6 @@ void DebuggerPluginPrivate::extensionsInitialized()
(ProjectExplorer::Constants::DEBUG_RUN_MODE, constraint);
}
-DebuggerEngine *currentEngine()
-{
- DebuggerEngine *engine = nullptr;
- if (dd->m_currentRunTool)
- engine = dd->m_currentRunTool->engine();
- return engine ? engine : dd->dummyEngine();
-}
-
SavedAction *action(int code)
{
return dd->m_debuggerSettings->item(code);
@@ -3049,11 +2232,6 @@ QStringList stringListSetting(int code)
return dd->m_debuggerSettings->item(code)->value().toStringList();
}
-BreakHandler *breakHandler()
-{
- return dd->m_breakHandler;
-}
-
void showModuleSymbols(const QString &moduleName, const Symbols &symbols)
{
auto w = new QTreeWidget;
@@ -3126,22 +2304,6 @@ void DebuggerPluginPrivate::doShutdown()
emit m_plugin->asynchronousShutdownFinished();
}
-void updateState(DebuggerRunTool *runTool)
-{
- dd->updateState(runTool);
-}
-
-void updateLocalsWindow(bool showReturn)
-{
- dd->m_returnWindow->setVisible(showReturn);
- dd->m_localsView->resizeColumns();
-}
-
-bool hasSnapshots()
-{
- return dd->m_snapshotHandler->size();
-}
-
void openTextEditor(const QString &titlePattern0, const QString &contents)
{
if (dd->m_shuttingDown)
@@ -3159,68 +2321,11 @@ void openTextEditor(const QString &titlePattern0, const QString &contents)
QTC_ASSERT(editor, return);
}
-// void runTest(const QString &fileName);
-void showMessage(const QString &msg, int channel, int timeout)
-{
- dd->showMessage(msg, channel, timeout);
-}
-
-void runControlStarted(DebuggerRunTool *runTool)
-{
- dd->runControlStarted(runTool);
-}
-
-void runControlFinished(DebuggerRunTool *runTool)
-{
- dd->runControlFinished(runTool);
-}
-
-void displayDebugger(DebuggerRunTool *runTool)
-{
- dd->displayDebugger(runTool);
-}
-
-void synchronizeBreakpoints()
-{
- dd->synchronizeBreakpoints();
-}
-
QWidget *mainWindow()
{
return dd->m_mainWindow;
}
-void raiseWatchersWindow()
-{
- if (currentEngine()->state() != DebuggerNotReady)
- dd->m_mainWindow->raiseDock(DOCKWIDGET_WATCHERS);
-}
-
-bool isRegistersWindowVisible()
-{
- return dd->m_registerWindow->isVisible();
-}
-
-bool isModulesWindowVisible()
-{
- return dd->m_modulesWindow->isVisible();
-}
-
-void openMemoryEditor()
-{
- AddressDialog dialog;
- if (dialog.exec() == QDialog::Accepted) {
- MemoryViewSetupData data;
- data.startAddress = dialog.address();
- currentEngine()->openMemoryView(data);
- }
-}
-
-void setThreadBoxContents(const QStringList &list, int index)
-{
- dd->setThreadBoxContents(list, index);
-}
-
QSharedPointer<Internal::GlobalDebuggerOptions> globalDebuggerOptions()
{
return dd->m_globalDebuggerOptions;
@@ -3309,82 +2414,26 @@ void DebuggerPlugin::extensionsInitialized()
dd->extensionsInitialized();
}
-void DebuggerPluginPrivate::updateUiForProject(Project *project)
-{
- if (m_previousProject) {
- disconnect(m_previousProject, &Project::activeTargetChanged,
- this, &DebuggerPluginPrivate::updateUiForTarget);
- }
- m_previousProject = project;
- if (!project) {
- updateUiForTarget(nullptr);
- return;
- }
- connect(project, &Project::activeTargetChanged,
- this, &DebuggerPluginPrivate::updateUiForTarget);
- updateUiForTarget(project->activeTarget());
-}
-
-void DebuggerPluginPrivate::updateUiForTarget(Target *target)
-{
- if (m_previousTarget) {
- disconnect(m_previousTarget.data(), &Target::activeRunConfigurationChanged,
- this, &DebuggerPluginPrivate::updateActiveLanguages);
- }
-
- m_previousTarget = target;
-
- if (!target) {
- updateActiveLanguages();
- return;
- }
-
- connect(target, &Target::activeRunConfigurationChanged,
- this, &DebuggerPluginPrivate::updateActiveLanguages);
- updateActiveLanguages();
-}
-
-void DebuggerPluginPrivate::updateActiveLanguages()
-{
- if (!dd->m_currentRunTool)
- return;
- const DebuggerRunParameters &rp = dd->m_currentRunTool->runParameters();
-// Id perspective = (languages & QmlLanguage) && !(languages & CppLanguage)
-// ? QmlPerspectiveId : CppPerspectiveId;
-// m_mainWindow->restorePerspective(perspective);
- if (rp.isCppDebugging())
- ICore::addAdditionalContext(Context(C_CPPDEBUGGER));
- else
- ICore::removeAdditionalContext(Context(C_CPPDEBUGGER));
-
- if (rp.isQmlDebugging)
- ICore::addAdditionalContext(Context(C_QMLDEBUGGER));
- else
- ICore::removeAdditionalContext(Context(C_QMLDEBUGGER));
-}
-
void DebuggerPluginPrivate::onModeChanged(Id mode)
{
+ m_mainWindow->onModeChanged(mode);
// FIXME: This one gets always called, even if switching between modes
// different then the debugger mode. E.g. Welcome and Help mode and
// also on shutdown.
if (mode == MODE_DEBUG) {
+// if (EngineManager::engines().isEmpty())
+// m_mainWindow->restorePerspective(Constants::PRESET_PERSPRECTIVE_ID);
+ EngineManager::selectUiForCurrentEngine();
if (IEditor *editor = EditorManager::currentEditor())
editor->widget()->setFocus();
m_toolTipManager.debugModeEntered();
- updateActiveLanguages();
} else {
m_toolTipManager.leavingDebugMode();
}
}
-void saveModeToRestore()
-{
- dd->m_previousMode = ModeManager::currentModeId();
-}
-
} // namespace Internal
static bool buildTypeAccepted(QFlags<ToolMode> toolMode, BuildConfiguration::BuildType buildType)
@@ -3507,28 +2556,10 @@ void registerPerspective(Perspective *perspective)
dd->m_mainWindow->registerPerspective(perspective);
}
-void setPerspectiveEnabled(const QByteArray &perspectiveId, bool enabled)
-{
- dd->m_mainWindow->setPerspectiveEnabled(perspectiveId, enabled);
-}
-
void selectPerspective(const QByteArray &perspectiveId)
{
- if (ModeManager::currentModeId() == MODE_DEBUG
- && dd->m_mainWindow->currentPerspective() == perspectiveId) {
- return;
- }
-
- // FIXME: Work-around aslong as the GammaRay integration does not use the same setup,
- if (perspectiveId.isEmpty())
- return;
- ModeManager::activateMode(MODE_DEBUG);
- dd->m_mainWindow->restorePerspective(dd->m_mainWindow->findPerspective(perspectiveId));
-}
-
-QByteArray currentPerspective()
-{
- return dd->m_mainWindow->currentPerspective();
+ if (auto perspective = dd->m_mainWindow->findPerspective(perspectiveId))
+ perspective->select();
}
QWidget *mainWindow()
diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h
index 68fefbacea..481cdaff59 100644
--- a/src/plugins/debugger/debuggerprotocol.h
+++ b/src/plugins/debugger/debuggerprotocol.h
@@ -301,6 +301,20 @@ const char DisplayImageFile[] = "imagefile:separate";
const char DisplayPlotData[] = "plotdata:separate";
const char DisplayArrayData[] = "arraydata:separate";
+enum LocationType { UnknownLocation, LocationByFile, LocationByAddress };
+
+class ContextData
+{
+public:
+ bool isValid() const { return type != UnknownLocation; }
+
+public:
+ LocationType type = UnknownLocation;
+ QString fileName;
+ int lineNumber = 0;
+ quint64 address = 0;
+};
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index 6c66f7eead..0f4908b4d0 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -36,6 +36,7 @@
#include "debuggerrunconfigurationaspect.h"
#include "breakhandler.h"
#include "shared/peutils.h"
+#include "snapshothandler.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
@@ -60,9 +61,11 @@
#include <utils/temporaryfile.h>
#include <utils/url.h>
+#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/messagebox.h>
+
#include <qmldebug/qmldebugcommandlinearguments.h>
#include <qtsupport/qtkitinformation.h>
@@ -70,7 +73,9 @@
#include <ssh/sshconnection.h>
#include <QTcpServer>
+#include <QTimer>
+using namespace Core;
using namespace Debugger::Internal;
using namespace ProjectExplorer;
using namespace Utils;
@@ -84,7 +89,6 @@ DebuggerEngine *createCdbEngine();
DebuggerEngine *createGdbEngine();
DebuggerEngine *createPdbEngine();
DebuggerEngine *createQmlEngine();
-DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine);
DebuggerEngine *createLldbEngine();
class LocalProcessRunner : public RunWorker
@@ -92,8 +96,8 @@ class LocalProcessRunner : public RunWorker
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::LocalProcessRunner)
public:
- LocalProcessRunner(RunControl *runControl, const Runnable &runnable)
- : RunWorker(runControl), m_runnable(runnable)
+ LocalProcessRunner(DebuggerRunTool *runTool, const Runnable &runnable)
+ : RunWorker(runTool->runControl()), m_runTool(runTool), m_runnable(runnable)
{
connect(&m_proc, &QProcess::errorOccurred,
this, &LocalProcessRunner::handleError);
@@ -120,16 +124,14 @@ public:
{
const QByteArray ba = m_proc.readAllStandardOutput();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
- showMessage(msg, LogOutput);
- showMessage(msg, AppOutput);
+ m_runTool->appendMessage(msg, StdOutFormatSameLine);
}
void handleStandardError()
{
const QByteArray ba = m_proc.readAllStandardError();
const QString msg = QString::fromLocal8Bit(ba, ba.length());
- showMessage(msg, LogOutput);
- showMessage(msg, AppError);
+ m_runTool->appendMessage(msg, StdErrFormatSameLine);
}
void handleFinished()
@@ -172,10 +174,11 @@ public:
"This is the default return value of error().");
}
- showMessage(msg, StatusBar);
+ m_runTool->showMessage(msg, StatusBar);
Core::AsynchronousMessageBox::critical(tr("Error"), msg);
}
+ QPointer<DebuggerRunTool> m_runTool;
Runnable m_runnable;
Utils::QtcProcess m_proc;
};
@@ -245,10 +248,14 @@ private:
class DebuggerRunToolPrivate
{
public:
- QPointer<TerminalRunner> terminalRunner;
+ bool useTerminal = false;
QPointer<CoreUnpacker> coreUnpacker;
QPointer<GdbServerPortsGatherer> portsGatherer;
bool addQmlServerInferiorCommandLineArgumentIfNeeded = false;
+ TerminalRunner *terminalRunner = nullptr;
+ int snapshotCounter = 0;
+ int engineStartsNeeded = 0;
+ int engineStopsNeeded = 0;
};
} // namespace Internal
@@ -372,7 +379,7 @@ void DebuggerRunTool::setUseTerminal(bool on)
&& boolSetting(UseCdbConsole);
if (on && !d->terminalRunner && !useCdbConsole) {
- d->terminalRunner = new TerminalRunner(this);
+ d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
addStartDependency(d->terminalRunner);
}
if (!on && d->terminalRunner) {
@@ -398,7 +405,7 @@ void DebuggerRunTool::setServerStartScript(const QString &serverStartScript)
serverStarter.executable = serverStartScript;
QtcProcess::addArg(&serverStarter.commandLineArguments, m_runParameters.inferior.executable);
QtcProcess::addArg(&serverStarter.commandLineArguments, m_runParameters.remoteChannel);
- addStartDependency(new LocalProcessRunner(runControl(), serverStarter));
+ addStartDependency(new LocalProcessRunner(this, serverStarter));
}
}
@@ -509,8 +516,6 @@ void DebuggerRunTool::addSearchDirectory(const QString &dir)
void DebuggerRunTool::start()
{
- Debugger::Internal::saveModeToRestore();
- Debugger::selectPerspective(Debugger::Constants::CppPerspectiveId);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
@@ -560,25 +565,25 @@ void DebuggerRunTool::start()
runControl()->setDisplayName(m_runParameters.displayName);
- DebuggerEngine *cppEngine = nullptr;
if (!m_engine) {
if (m_runParameters.isCppDebugging()) {
switch (m_runParameters.cppEngineType) {
case GdbEngineType:
- cppEngine = createGdbEngine();
+ m_engine = createGdbEngine();
break;
case CdbEngineType:
if (!HostOsInfo::isWindowsHost()) {
reportFailure(tr("Unsupported CDB host system."));
return;
}
- cppEngine = createCdbEngine();
+ m_engine = createCdbEngine();
break;
case LldbEngineType:
- cppEngine = createLldbEngine();
+ m_engine = createLldbEngine();
break;
case PdbEngineType: // FIXME: Yes, Python counts as C++...
- cppEngine = createPdbEngine();
+ QTC_CHECK(false); // Called from DebuggerRunTool constructor already.
+// m_engine = createPdbEngine();
break;
default:
if (!m_runParameters.isQmlDebugging) {
@@ -592,12 +597,11 @@ void DebuggerRunTool::start()
}
if (m_runParameters.isQmlDebugging) {
- if (cppEngine)
- m_engine = createQmlCppEngine(cppEngine);
- else
+ if (m_engine) {
+ m_engine2 = createQmlEngine();
+ } else {
m_engine = createQmlEngine();
- } else {
- m_engine = cppEngine;
+ }
}
}
@@ -607,12 +611,57 @@ void DebuggerRunTool::start()
}
m_engine->setRunTool(this);
+ m_engine->setRunParameters(m_runParameters);
+ m_engine->setCompanionEngine(m_engine2);
+ connect(m_engine, &DebuggerEngine::requestRunControlFinish,
+ runControl(), &RunControl::initiateFinish);
+ connect(m_engine, &DebuggerEngine::requestRunControlStop,
+ runControl(), &RunControl::initiateStop);
+ connect(m_engine, &DebuggerEngine::engineStarted,
+ this, [this] { handleEngineStarted(m_engine); });
+ connect(m_engine, &DebuggerEngine::engineFinished,
+ this, [this] { handleEngineFinished(m_engine); });
+ connect(m_engine, &DebuggerEngine::appendMessageRequested,
+ this, &DebuggerRunTool::appendMessage);
+ ++d->engineStartsNeeded;
+ ++d->engineStopsNeeded;
+
+ connect(m_engine, &DebuggerEngine::attachToCoreRequested, this, [this](const QString &coreFile) {
+ auto runConfig = runControl()->runConfiguration();
+ QTC_ASSERT(runConfig, return);
+ auto rc = new RunControl(runConfig, ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ auto name = QString(tr("%1 - Snapshot %2").arg(runControl()->displayName()).arg(++d->snapshotCounter));
+ auto debugger = new DebuggerRunTool(rc);
+ debugger->setStartMode(AttachCore);
+ debugger->setRunControlName(name);
+ debugger->setCoreFileName(coreFile, true);
+ debugger->startRunControl();
+ });
+
+ if (m_engine2) {
+ m_engine2->setRunTool(this);
+ m_engine2->setRunParameters(m_runParameters);
+ m_engine2->setCompanionEngine(m_engine);
+ m_engine2->setSecondaryEngine();
+ connect(m_engine2, &DebuggerEngine::requestRunControlFinish,
+ runControl(), &RunControl::initiateFinish);
+ connect(m_engine2, &DebuggerEngine::requestRunControlStop,
+ runControl(), &RunControl::initiateStop);
+ connect(m_engine2, &DebuggerEngine::engineStarted,
+ this, [this] { handleEngineStarted(m_engine2); });
+ connect(m_engine2, &DebuggerEngine::engineFinished,
+ this, [this] { handleEngineFinished(m_engine2); });
+ connect(m_engine2, &DebuggerEngine::appendMessageRequested,
+ this, &DebuggerRunTool::appendMessage);
+ ++d->engineStartsNeeded;
+ ++d->engineStopsNeeded;
+ }
if (m_runParameters.startMode == StartInternal) {
QStringList unhandledIds;
- for (const Breakpoint &bp : breakHandler()->allBreakpoints()) {
- if (bp.isEnabled() && !m_engine->acceptsBreakpoint(bp))
- unhandledIds.append(bp.id().toString());
+ for (const GlobalBreakpoint bp : BreakpointManager::globalBreakpoints()) {
+// if (bp->isEnabled() && !m_engine->acceptsBreakpoint(bp))
+// unhandledIds.append(bp.id().toString());
}
if (!unhandledIds.isEmpty()) {
QString warningMessage =
@@ -621,7 +670,7 @@ void DebuggerRunTool::start()
"Affected are breakpoints %1")
.arg(unhandledIds.join(QLatin1String(", ")));
- Internal::showMessage(warningMessage, LogWarning);
+ showMessage(warningMessage, LogWarning);
static bool checked = true;
if (checked)
@@ -634,20 +683,53 @@ void DebuggerRunTool::start()
}
appendMessage(tr("Debugging starts"), NormalMessageFormat);
- Internal::runControlStarted(this);
+ QString debuggerName = m_engine->objectName();
+ if (m_engine2)
+ debuggerName += ' ' + m_engine2->objectName();
+ const QString message = tr("Starting debugger \"%1\" for ABI \"%2\"...")
+ .arg(debuggerName).arg(m_runParameters.toolChainAbi.toString());
+ showStatusMessage(message);
+
+ showMessage(m_engine->formatStartParameters(), LogDebug);
+ showMessage(DebuggerSettings::dump(), LogDebug);
+
+ if (m_engine2)
+ m_engine2->start();
m_engine->start();
}
void DebuggerRunTool::stop()
{
- m_isDying = true;
QTC_ASSERT(m_engine, reportStopped(); return);
+ if (m_engine2)
+ m_engine2->quitDebugger();
m_engine->quitDebugger();
}
-const DebuggerRunParameters &DebuggerRunTool::runParameters() const
+void DebuggerRunTool::handleEngineStarted(DebuggerEngine *engine)
{
- return m_runParameters;
+ EngineManager::activateEngine(engine);
+
+ // Correct:
+// if (--d->engineStartsNeeded == 0) {
+// EngineManager::activateDebugMode();
+// reportStarted();
+// }
+
+ // Feels better, as the QML Engine might attach late or not at all.
+ if (engine == m_engine) {
+ EngineManager::activateDebugMode();
+ reportStarted();
+ }
+}
+
+void DebuggerRunTool::handleEngineFinished(DebuggerEngine *engine)
+{
+ engine->prepareForRestart();
+ if (--d->engineStopsNeeded == 0) {
+ appendMessage(tr("Debugging has finished"), NormalMessageFormat);
+ reportStopped();
+ }
}
bool DebuggerRunTool::isCppDebugging() const
@@ -684,36 +766,9 @@ void DebuggerRunTool::setSolibSearchPath(const QStringList &list)
m_runParameters.solibSearchPath = list;
}
-void DebuggerRunTool::notifyInferiorIll()
-{
- m_engine->notifyInferiorIll();
-}
-
-void DebuggerRunTool::notifyInferiorExited()
-{
- m_engine->notifyInferiorExited();
-}
-
void DebuggerRunTool::quitDebugger()
{
- m_isDying = true;
- m_engine->quitDebugger();
-}
-
-void DebuggerRunTool::abortDebugger()
-{
- m_engine->resetLocation();
- if (!m_isDying) {
- // Be friendly the first time. This will change targetState().
- showMessage("ABORTING DEBUGGER. FIRST TIME.");
- quitDebugger();
- } else {
- // We already tried. Try harder.
- showMessage("ABORTING DEBUGGER. SECOND TIME.");
- m_engine->abortDebuggerProcess();
- if (runControl())
- runControl()->initiateFinish();
- }
+ initiateStop();
}
bool DebuggerRunTool::fixupParameters()
@@ -807,9 +862,6 @@ bool DebuggerRunTool::fixupParameters()
if (rp.isNativeMixedDebugging())
rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
- if (rp.isCppDebugging() && !rp.skipExecutableValidation)
- rp.validateExecutable();
-
return true;
}
@@ -912,11 +964,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit, bool allowTer
}
}
-DebuggerEngine *DebuggerRunTool::activeEngine() const
-{
- return m_engine ? m_engine->activeEngine() : nullptr;
-}
-
void DebuggerRunTool::startRunControl()
{
ProjectExplorerPlugin::startRunControl(runControl());
@@ -931,13 +978,14 @@ void DebuggerRunTool::addSolibSearchDir(const QString &str)
DebuggerRunTool::~DebuggerRunTool()
{
- disconnect();
- if (m_engine) {
- DebuggerEngine *engine = m_engine;
- m_engine = nullptr;
- engine->disconnect();
- delete engine;
- }
+ if (m_runParameters.isSnapshot && !m_runParameters.coreFile.isEmpty())
+ QFile::remove(m_runParameters.coreFile);
+
+ delete m_engine2;
+ m_engine2 = nullptr;
+ delete m_engine;
+ m_engine = nullptr;
+
delete d;
}
@@ -946,7 +994,9 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
if (channel == ConsoleOutput)
debuggerConsole()->printItem(ConsoleItem::DefaultType, msg);
- Internal::showMessage(msg, channel, timeout);
+ m_engine->showMessage(msg, channel, timeout);
+ if (m_engine2)
+ m_engine->showMessage(msg, channel, timeout);
switch (channel) {
case AppOutput:
appendMessage(msg, StdOutFormatSameLine);
diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h
index dd42db024a..0692df7da7 100644
--- a/src/plugins/debugger/debuggerruncontrol.h
+++ b/src/plugins/debugger/debuggerruncontrol.h
@@ -28,6 +28,7 @@
#include "debugger_global.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"
+#include "terminal.h"
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
@@ -51,9 +52,6 @@ public:
bool allowTerminal = true);
~DebuggerRunTool() override;
- Internal::DebuggerEngine *engine() const { return m_engine; }
- Internal::DebuggerEngine *activeEngine() const;
-
void startRunControl();
void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1);
@@ -61,15 +59,8 @@ public:
void start() override;
void stop() override;
- void notifyInferiorIll();
- Q_SLOT void notifyInferiorExited(); // Called from Android.
void quitDebugger();
- void abortDebugger();
-
- const Internal::DebuggerRunParameters &runParameters() const;
- void startDying() { m_isDying = true; }
- bool isDying() const { return m_isDying; }
bool isCppDebugging() const;
bool isQmlDebugging() const;
int portsUsedByDebugger() const;
@@ -138,11 +129,13 @@ public:
private:
bool fixupParameters();
+ void handleEngineStarted(Internal::DebuggerEngine *engine);
+ void handleEngineFinished(Internal::DebuggerEngine *engine);
Internal::DebuggerRunToolPrivate *d;
- QPointer<Internal::DebuggerEngine> m_engine; // Master engine
+ QPointer<Internal::DebuggerEngine> m_engine;
+ QPointer<Internal::DebuggerEngine> m_engine2;
Internal::DebuggerRunParameters m_runParameters;
- bool m_isDying = false;
};
class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::ChannelProvider
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index 7ef8d4b8c9..d89e1ef1de 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -28,6 +28,7 @@
#include "debuggerengine.h"
#include "debuggerprotocol.h"
#include "debuggeractions.h"
+#include "snapshothandler.h"
#include "stackhandler.h"
#include "debuggercore.h"
#include "watchhandler.h"
@@ -1138,7 +1139,7 @@ static void slotTooltipOverrideRequested
return;
const TextDocument *document = editorWidget->textDocument();
- DebuggerEngine *engine = currentEngine();
+ DebuggerEngine *engine = EngineManager::currentEngine();
if (!engine || !engine->canDisplayTooltip())
return;
diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp
index d79be06f57..7dc4f65d63 100644
--- a/src/plugins/debugger/disassembleragent.cpp
+++ b/src/plugins/debugger/disassembleragent.cpp
@@ -68,12 +68,17 @@ public:
DisassemblerBreakpointMarker(const Breakpoint &bp, int lineNumber)
: TextMark(Utils::FileName(), lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_bp(bp)
{
- setIcon(bp.icon());
+ setIcon(bp->icon());
setPriority(TextMark::NormalPriority);
}
- bool isClickable() const override { return true; }
- void clicked() override { m_bp.removeBreakpoint(); }
+ bool isClickable() const final { return true; }
+
+ void clicked() final
+ {
+ QTC_ASSERT(m_bp, return);
+ m_bp->deleteGlobalOrThisBreakpoint();
+ }
public:
Breakpoint m_bp;
@@ -331,8 +336,8 @@ void DisassemblerAgent::setContentsToDocument(const DisassemblerLines &contents)
d->document->setPreferredDisplayName(QString("Disassembler (%1)")
.arg(d->location.functionName()));
- const Breakpoints bps = breakHandler()->engineBreakpoints(d->engine);
- for (Breakpoint bp : bps)
+ const Breakpoints bps = d->engine->breakHandler()->breakpoints();
+ for (const Breakpoint bp : bps)
updateBreakpointMarker(bp);
updateLocationMarker();
@@ -340,7 +345,9 @@ void DisassemblerAgent::setContentsToDocument(const DisassemblerLines &contents)
void DisassemblerAgent::updateLocationMarker()
{
- QTC_ASSERT(d->document, return);
+ if (!d->document)
+ return;
+
int lineNumber = d->lineForAddress(d->location.address());
if (d->location.needsMarker()) {
d->document->removeMark(&d->locationMark);
@@ -348,6 +355,8 @@ void DisassemblerAgent::updateLocationMarker()
d->document->addMark(&d->locationMark);
}
+ d->locationMark.updateIcon();
+
// Center cursor.
if (EditorManager::currentDocument() == d->document)
if (auto textEditor = qobject_cast<BaseTextEditor *>(EditorManager::currentEditor()))
@@ -359,9 +368,8 @@ void DisassemblerAgent::removeBreakpointMarker(const Breakpoint &bp)
if (!d->document)
return;
- BreakpointModelId id = bp.id();
- foreach (DisassemblerBreakpointMarker *marker, d->breakpointMarks) {
- if (marker->m_bp.id() == id) {
+ for (DisassemblerBreakpointMarker *marker : d->breakpointMarks) {
+ if (marker->m_bp == bp) {
d->breakpointMarks.removeOne(marker);
d->document->removeMark(marker);
delete marker;
@@ -373,7 +381,7 @@ void DisassemblerAgent::removeBreakpointMarker(const Breakpoint &bp)
void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
{
removeBreakpointMarker(bp);
- const quint64 address = bp.response().address;
+ const quint64 address = bp->address();
if (!address)
return;
@@ -384,7 +392,7 @@ void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
// HACK: If it's a FileAndLine breakpoint, and there's a source line
// above, move the marker up there. That allows setting and removing
// normal breakpoints from within the disassembler view.
- if (bp.type() == BreakpointByFileAndLine) {
+ if (bp->type() == BreakpointByFileAndLine) {
ContextData context = getLocationContext(d->document, lineNumber - 1);
if (context.type == LocationByFile)
--lineNumber;
diff --git a/src/plugins/debugger/disassembleragent.h b/src/plugins/debugger/disassembleragent.h
index ff6c80c7e2..aef71ebeaf 100644
--- a/src/plugins/debugger/disassembleragent.h
+++ b/src/plugins/debugger/disassembleragent.h
@@ -25,12 +25,13 @@
#pragma once
+#include "breakhandler.h"
+
#include <QObject>
namespace Debugger {
namespace Internal {
-class Breakpoint;
class DebuggerEngine;
class DisassemblerAgentPrivate;
class DisassemblerLines;
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index d16121f22c..be3fa49049 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -139,6 +139,7 @@ static bool isMostlyHarmlessMessage(const QStringRef &msg)
GdbEngine::GdbEngine()
{
setObjectName("GdbEngine");
+ setDebuggerName("GDB");
m_gdbOutputCodec = QTextCodec::codecForLocale();
m_inferiorOutputCodec = QTextCodec::codecForLocale();
@@ -323,6 +324,10 @@ void GdbEngine::handleResponse(const QString &buff)
}
m_pendingConsoleStreamOutput += data;
+ // Fragile, but it's all we have.
+ if (data.contains("\nNo more reverse-execution history.\n"))
+ handleBeginOfRecordingReached();
+
// Show some messages to give the impression something happens.
if (data.startsWith("Reading symbols from ")) {
showStatusMessage(tr("Reading %1...").arg(data.mid(21)), 1000);
@@ -559,25 +564,23 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
res.fromString(ba);
BreakHandler *handler = breakHandler();
Breakpoint bp;
- BreakpointResponse br;
for (const GdbMi &bkpt : res.children()) {
const QString nr = bkpt["number"].data();
- BreakpointResponseId rid(nr);
if (nr.contains('.')) {
// A sub-breakpoint.
- BreakpointResponse sub;
- updateResponse(sub, bkpt);
- sub.id = rid;
- sub.type = br.type;
- bp.insertSubBreakpoint(sub);
+ QTC_ASSERT(bp, continue);
+ SubBreakpoint loc = bp->findOrCreateSubBreakpoint(nr);
+ loc->params.updateFromGdbOutput(bkpt);
+ loc->params.type = bp->type();
} else {
// A primary breakpoint.
- bp = handler->findBreakpointByResponseId(rid);
- br = bp.response();
- updateResponse(br, bkpt);
- bp.setResponse(br);
+ bp = handler->findBreakpointByResponseId(nr);
+ if (bp)
+ bp->updateFromGdbOutput(bkpt);
}
}
+ if (bp)
+ bp->adjustMarker();
} else if (asyncClass == "breakpoint-created") {
// "{bkpt={number="1",type="breakpoint",disp="del",enabled="y",
// addr="<PENDING>",pending="main",times="0",
@@ -586,24 +589,22 @@ void GdbEngine::handleAsyncOutput(const QString &asyncClass, const GdbMi &result
// what="*0xbfffed48",times="0",original-location="*0xbfffed48"}}
BreakHandler *handler = breakHandler();
for (const GdbMi &bkpt : result.children()) {
- BreakpointResponse br;
+ const QString nr = bkpt["number"].data();
+ BreakpointParameters br;
br.type = BreakpointByFileAndLine;
- updateResponse(br, bkpt);
- handler->handleAlienBreakpoint(br, this);
+ br.updateFromGdbOutput(bkpt);
+ handler->handleAlienBreakpoint(nr, br);
}
} else if (asyncClass == "breakpoint-deleted") {
// "breakpoint-deleted" "{id="1"}"
// New in FSF gdb since 2011-04-27.
- QString nr = result["id"].data();
- BreakpointResponseId rid(nr);
- if (Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid)) {
- // This also triggers when a temporary breakpoint is hit.
- // We do not really want that, as this loses all information.
- // FIXME: Use a special marker for this case?
- // if (!bp.isOneShot()) ... is not sufficient.
- // It keeps temporary "Jump" breakpoints alive.
- bp.removeAlienBreakpoint();
- }
+ const QString nr = result["id"].data();
+ // This also triggers when a temporary breakpoint is hit.
+ // We do not really want that, as this loses all information.
+ // FIXME: Use a special marker for this case?
+ // if (!bp.isOneShot()) ... is not sufficient.
+ // It keeps temporary "Jump" breakpoints alive.
+ breakHandler()->removeAlienBreakpoint(nr);
} else if (asyncClass == "cmd-param-changed") {
// New since 2012-08-09
// "{param="debug remote",value="1"}"
@@ -696,11 +697,9 @@ void GdbEngine::interruptInferior()
showStatusMessage(tr("Stop requested..."), 5000);
showMessage("TRYING TO INTERRUPT INFERIOR");
if (HostOsInfo::isWindowsHost() && !m_isQnxGdb) {
- IDevice::ConstPtr device = runTool()->device();
- if (!device)
- device = runParameters().inferior.device;
- QTC_ASSERT(device, notifyInferiorStopFailed(); return);
- DeviceProcessSignalOperation::Ptr signalOperation = device->signalOperation();
+ IDevice::ConstPtr dev = device();
+ QTC_ASSERT(dev, notifyInferiorStopFailed(); return);
+ DeviceProcessSignalOperation::Ptr signalOperation = dev->signalOperation();
QTC_ASSERT(signalOperation, notifyInferiorStopFailed(); return);
connect(signalOperation.data(), &DeviceProcessSignalOperation::finished,
this, [this, signalOperation](const QString &error) {
@@ -927,6 +926,14 @@ void GdbEngine::handleResultRecord(DebuggerResponse *response)
QTC_CHECK(state() == InferiorRunOk);
notifyInferiorSpontaneousStop();
notifyEngineIll();
+ } else if (msg.startsWith("Process record: failed to record execution log.")) {
+ // Reverse execution recording failed. Full message is something like
+ // ~"Process record does not support instruction 0xfae64 at address 0x7ffff7dec6f8.\n"
+ notifyInferiorSpontaneousStop();
+ handleRecordingFailed();
+ } else if (msg.startsWith("Target multi-thread does not support this command.")) {
+ notifyInferiorSpontaneousStop();
+ handleRecordingFailed();
} else if (isGdbConnectionError(msg)) {
notifyInferiorExited();
} else {
@@ -1026,10 +1033,8 @@ bool GdbEngine::acceptsDebuggerCommands() const
// || state() == InferiorUnrunnable;
}
-void GdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
+void GdbEngine::executeDebuggerCommand(const QString &command)
{
- if (!(languages & CppLanguage))
- return;
QTC_CHECK(acceptsDebuggerCommands());
runCommand({command, NativeCommand});
}
@@ -1194,7 +1199,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
return;
}
- BreakpointResponseId rid(data["bkptno"].data());
+ const QString nr = data["bkptno"].data();
int lineNumber = 0;
QString fullName;
QString function;
@@ -1215,17 +1220,15 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
showMessage("INVALID STOPPED REASON", LogWarning);
}
- if (rid.isValid() && frame.isValid()) {
+ if (!nr.isEmpty() && frame.isValid()) {
// Use opportunity to update the breakpoint marker position.
- Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
- const BreakpointResponse &response = bp.response();
- QString fileName = response.fileName;
- if (fileName.isEmpty())
- fileName = bp.fileName();
- if (fileName.isEmpty())
- fileName = fullName;
- if (!fileName.isEmpty())
- bp.setMarkerFileAndLine(fileName, lineNumber);
+ if (Breakpoint bp = breakHandler()->findBreakpointByResponseId(nr)) {
+ QString fileName = bp->fileName();
+ if (fileName.isEmpty())
+ fileName = fullName;
+ if (!fileName.isEmpty())
+ bp->setMarkerFileAndLine(fileName, lineNumber);
+ }
}
//qDebug() << "BP " << rid << data.toString();
@@ -1406,14 +1409,16 @@ void GdbEngine::handleStop2(const GdbMi &data)
// {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
// thread-id="1",stopped-threads="all",core="2"
const GdbMi wpt = data["wpt"];
- const BreakpointResponseId rid(wpt["number"].data());
+ const QString rid = wpt["number"].data();
const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
const quint64 bpAddress = wpt["exp"].data().mid(1).toULongLong(nullptr, 0);
QString msg;
- if (bp.type() == WatchpointAtExpression)
- msg = bp.msgWatchpointByExpressionTriggered(rid.majorPart(), bp.expression());
- if (bp.type() == WatchpointAtAddress)
- msg = bp.msgWatchpointByAddressTriggered(rid.majorPart(), bpAddress);
+ if (bp) {
+ if (bp->type() == WatchpointAtExpression)
+ msg = bp->msgWatchpointByExpressionTriggered(bp->expression());
+ if (bp->type() == WatchpointAtAddress)
+ msg = bp->msgWatchpointByAddressTriggered(bpAddress);
+ }
GdbMi value = data["value"];
GdbMi oldValue = value["old"];
GdbMi newValue = value["new"];
@@ -1427,10 +1432,10 @@ void GdbEngine::handleStop2(const GdbMi &data)
GdbMi gNumber = data["bkptno"]; // 'number' or 'bkptno'?
if (!gNumber.isValid())
gNumber = data["number"];
- const BreakpointResponseId rid(gNumber.data());
+ const QString rid = gNumber.data();
const QString threadId = data["thread-id"].data();
- const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
- showStatusMessage(bp.msgBreakpointTriggered(rid.majorPart(), threadId));
+ if (const Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid))
+ showStatusMessage(bp->msgBreakpointTriggered(threadId));
m_currentThread = threadId;
} else {
QString reasontr = msgStopped(reason);
@@ -1575,7 +1580,7 @@ void GdbEngine::handleExecuteContinue(const DebuggerResponse &response)
CHECK_STATE(InferiorStopOk);
// FIXME: Fix translation in master.
showStatusMessage(msg, 5000);
- gotoLocation(stackHandler()->currentFrame());
+ gotoCurrentLocation();
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed() ;
@@ -1649,6 +1654,10 @@ QString GdbEngine::cleanupFullName(const QString &fileName)
void GdbEngine::shutdownInferior()
{
CHECK_STATE(InferiorShutdownRequested);
+ if (runParameters().startMode == AttachCore) {
+ notifyInferiorShutdownFinished();
+ return;
+ }
DebuggerCommand cmd;
cmd.function = QLatin1String(runParameters().closeMode == DetachAtClose ? "detach " : "kill ");
cmd.callback = CB(handleInferiorShutdown);
@@ -1748,45 +1757,49 @@ static QString msgNoGdbBinaryForToolChain(const Abi &tc)
bool GdbEngine::hasCapability(unsigned cap) const
{
- if (cap & (ReverseSteppingCapability
- | AutoDerefPointersCapability
- | DisassemblerCapability
- | RegisterCapability
- | ShowMemoryCapability
- | JumpToLineCapability
- | ReloadModuleCapability
- | ReloadModuleSymbolsCapability
- | BreakOnThrowAndCatchCapability
- | BreakConditionCapability
- | BreakIndividualLocationsCapability
- | TracePointCapability
- | ReturnFromFunctionCapability
- | CreateFullBacktraceCapability
- | WatchpointByAddressCapability
- | WatchpointByExpressionCapability
- | AddWatcherCapability
- | AddWatcherWhileRunningCapability
- | WatchWidgetsCapability
- | ShowModuleSymbolsCapability
- | ShowModuleSectionsCapability
- | CatchCapability
- | OperateByInstructionCapability
- | RunToLineCapability
- | WatchComplexExpressionsCapability
- | MemoryAddressCapability
- | AdditionalQmlStackCapability
- | NativeMixedCapability
- | ResetInferiorCapability))
- return true;
-
- if (runParameters().startMode == AttachCore)
- return false;
-
- // FIXME: Remove in case we have gdb 7.x on macOS.
- if (runParameters().toolChainAbi.os() == Abi::DarwinOS)
- return false;
-
- return cap == SnapshotCapability;
+ if (runParameters().startMode == AttachCore) {
+ return cap & (AutoDerefPointersCapability
+ | DisassemblerCapability
+ | RegisterCapability
+ | ShowMemoryCapability
+ | CreateFullBacktraceCapability
+ | ShowModuleSymbolsCapability
+ | ShowModuleSectionsCapability
+ | WatchComplexExpressionsCapability
+ | MemoryAddressCapability
+ | AdditionalQmlStackCapability);
+ }
+
+ return cap & (AutoDerefPointersCapability
+ | DisassemblerCapability
+ | RegisterCapability
+ | ShowMemoryCapability
+ | JumpToLineCapability
+ | ReloadModuleCapability
+ | ReloadModuleSymbolsCapability
+ | BreakOnThrowAndCatchCapability
+ | BreakConditionCapability
+ | BreakIndividualLocationsCapability
+ | TracePointCapability
+ | ReturnFromFunctionCapability
+ | CreateFullBacktraceCapability
+ | WatchpointByAddressCapability
+ | WatchpointByExpressionCapability
+ | AddWatcherCapability
+ | AddWatcherWhileRunningCapability
+ | WatchWidgetsCapability
+ | ShowModuleSymbolsCapability
+ | ShowModuleSectionsCapability
+ | CatchCapability
+ | OperateByInstructionCapability
+ | RunToLineCapability
+ | WatchComplexExpressionsCapability
+ | MemoryAddressCapability
+ | AdditionalQmlStackCapability
+ | NativeMixedCapability
+ | ResetInferiorCapability
+ | SnapshotCapability
+ | ReverseSteppingCapability);
}
@@ -1828,7 +1841,9 @@ void GdbEngine::executeStep()
} else {
DebuggerCommand cmd;
cmd.flags = RunRequest|NeedsFlush;
- cmd.function = QLatin1String(isReverseDebugging() ? "reverse-step" : "-exec-step");
+ cmd.function = "-exec-step";
+ if (isReverseDebugging())
+ cmd.function += " --reverse";
cmd.callback = CB(handleExecuteStep);
runCommand(cmd);
}
@@ -1878,7 +1893,9 @@ void GdbEngine::executeStepI()
showStatusMessage(tr("Step by instruction requested..."), 5000);
DebuggerCommand cmd;
cmd.flags = RunRequest|NeedsFlush;
- cmd.function = QLatin1String(isReverseDebugging() ? "reverse-stepi" : "-exec-step-instruction");
+ cmd.function = "-exec-step-instruction";
+ if (isReverseDebugging())
+ cmd.function += "--reverse";
cmd.callback = CB(handleExecuteContinue);
runCommand(cmd);
}
@@ -1912,7 +1929,9 @@ void GdbEngine::executeNext()
} else {
DebuggerCommand cmd;
cmd.flags = RunRequest;
- cmd.function = QLatin1String(isReverseDebugging() ? "reverse-next" : "-exec-next");
+ cmd.function = "-exec-next";
+ if (isReverseDebugging())
+ cmd.function += " --reverse";
cmd.callback = CB(handleExecuteNext);
runCommand(cmd);
}
@@ -1942,10 +1961,13 @@ void GdbEngine::handleExecuteNext(const DebuggerResponse &response)
} else if (msg.startsWith("Cannot execute this command while the selected thread is running.")) {
showExecutionError(msg);
notifyInferiorRunFailed();
+ } else if (msg.startsWith("Target multi-thread does not support this command.")) {
+ notifyInferiorRunFailed();
+ handleRecordingFailed();
} else {
- AsynchronousMessageBox::critical(tr("Execution Error"),
+ AsynchronousMessageBox::warning(tr("Execution Error"),
tr("Cannot continue debugged process:") + '\n' + msg);
- notifyInferiorIll();
+ //notifyInferiorIll();
}
}
@@ -1957,7 +1979,9 @@ void GdbEngine::executeNextI()
showStatusMessage(tr("Step next instruction requested..."), 5000);
DebuggerCommand cmd;
cmd.flags = RunRequest;
- cmd.function = QLatin1String(isReverseDebugging() ? "reverse-nexti" : "-exec-next-instruction");
+ cmd.function = "-exec-next-instruction";
+ if (isReverseDebugging())
+ cmd.function += " --reverse";
cmd.callback = CB(handleExecuteContinue);
runCommand(cmd);
}
@@ -2028,6 +2052,14 @@ void GdbEngine::executeReturn()
runCommand({"-exec-return", RunRequest, CB(handleExecuteReturn)});
}
+void GdbEngine::executeRecordReverse(bool record)
+{
+ if (record)
+ runCommand({"record full"});
+ else
+ runCommand({"record stop"});
+}
+
void GdbEngine::handleExecuteReturn(const DebuggerResponse &response)
{
if (response.resultClass == ResultDone) {
@@ -2074,120 +2106,6 @@ void GdbEngine::setTokenBarrier()
//
//////////////////////////////////////////////////////////////////////
-void GdbEngine::updateResponse(BreakpointResponse &response, const GdbMi &bkpt)
-{
- QTC_ASSERT(bkpt.isValid(), return);
-
- QString originalLocation;
- QString file;
- QString fullName;
-
- response.multiple = false;
- response.enabled = true;
- response.pending = false;
- response.condition.clear();
- for (const GdbMi &child : bkpt.children()) {
- if (child.hasName("number")) {
- response.id = BreakpointResponseId(child.data());
- } else if (child.hasName("func")) {
- response.functionName = child.data();
- } else if (child.hasName("addr")) {
- // <MULTIPLE> happens in constructors, inline functions, and
- // at other places like 'foreach' lines. In this case there are
- // fields named "addr" in the response and/or the address
- // is called <MULTIPLE>.
- //qDebug() << "ADDR: " << child.data() << (child.data() == "<MULTIPLE>");
- if (child.data() == "<MULTIPLE>")
- response.multiple = true;
- if (child.data().startsWith("0x"))
- response.address = child.toAddress();
- } else if (child.hasName("file")) {
- file = child.data();
- } else if (child.hasName("fullname")) {
- fullName = child.data();
- } else if (child.hasName("line")) {
- // The line numbers here are the uncorrected ones. So don't
- // change it if we know better already.
- if (response.correctedLineNumber == 0)
- response.lineNumber = child.toInt();
- } else if (child.hasName("cond")) {
- // gdb 6.3 likes to "rewrite" conditions. Just accept that fact.
- response.condition = child.data();
- } else if (child.hasName("enabled")) {
- response.enabled = (child.data() == "y");
- } else if (child.hasName("disp")) {
- response.oneShot = child.data() == "del";
- } else if (child.hasName("pending")) {
- // Any content here would be interesting only if we did accept
- // spontaneously appearing breakpoints (user using gdb commands).
- if (file.isEmpty())
- file = child.data();
- response.pending = true;
- } else if (child.hasName("at")) {
- // Happens with gdb 6.4 symbianelf.
- QString ba = child.data();
- if (ba.startsWith('<') && ba.endsWith('>'))
- ba = ba.mid(1, ba.size() - 2);
- response.functionName = ba;
- } else if (child.hasName("thread")) {
- response.threadSpec = child.toInt();
- } else if (child.hasName("type")) {
- // "breakpoint", "hw breakpoint", "tracepoint", "hw watchpoint"
- // {bkpt={number="2",type="hw watchpoint",disp="keep",enabled="y",
- // what="*0xbfffed48",times="0",original-location="*0xbfffed48"}}
- if (child.data().contains("tracepoint")) {
- response.tracepoint = true;
- } else if (child.data() == "hw watchpoint" || child.data() == "watchpoint") {
- QString what = bkpt["what"].data();
- if (what.startsWith("*0x")) {
- response.type = WatchpointAtAddress;
- response.address = what.mid(1).toULongLong(nullptr, 0);
- } else {
- response.type = WatchpointAtExpression;
- response.expression = what;
- }
- } else if (child.data() == "breakpoint") {
- QString catchType = bkpt["catch-type"].data();
- if (catchType == "throw")
- response.type = BreakpointAtThrow;
- else if (catchType == "catch")
- response.type = BreakpointAtCatch;
- else if (catchType == "fork")
- response.type = BreakpointAtFork;
- else if (catchType == "exec")
- response.type = BreakpointAtExec;
- else if (catchType == "syscall")
- response.type = BreakpointAtSysCall;
- }
- } else if (child.hasName("times")) {
- response.hitCount = child.toInt();
- } else if (child.hasName("original-location")) {
- originalLocation = child.data();
- }
- // This field is not present. Contents needs to be parsed from
- // the plain "ignore" response.
- //else if (child.hasName("ignore"))
- // response.ignoreCount = child.data();
- }
-
- QString name;
- if (!fullName.isEmpty()) {
- name = cleanupFullName(fullName);
- response.fileName = name;
- //if (data->markerFileName().isEmpty())
- // data->setMarkerFileName(name);
- } else {
- name = file;
- // Use fullName() once we have a mapping which is more complete than
- // gdb's own. No point in assigning markerFileName for now.
- }
- if (!name.isEmpty())
- response.fileName = name;
-
- if (response.fileName.isEmpty())
- response.updateLocation(originalLocation);
-}
-
QString GdbEngine::breakLocation(const QString &file) const
{
QString where = m_fullToShortName.value(file);
@@ -2234,84 +2152,76 @@ QString GdbEngine::breakpointLocation2(const BreakpointParameters &data)
return GdbMi::escapeCString(fileName) + ':' + QString::number(data.lineNumber);
}
-void GdbEngine::handleInsertInterpreterBreakpoint(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleInsertInterpreterBreakpoint(const DebuggerResponse &response,
+ const Breakpoint &bp)
{
- BreakpointResponse br = bp.response();
- bool pending = response.data["pending"].toInt();
+ QTC_ASSERT(bp, return);
+ const bool pending = response.data["pending"].toInt();
if (pending) {
- bp.notifyBreakpointInsertOk();
+ notifyBreakpointInsertOk(bp);
} else {
- br.id = BreakpointResponseId(response.data["number"].data());
- updateResponse(br, response.data);
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
+ bp->setResponseId(response.data["number"].data());
+ bp->updateFromGdbOutput(response.data);
+ notifyBreakpointInsertOk(bp);
}
}
void GdbEngine::handleInterpreterBreakpointModified(const GdbMi &data)
{
- BreakpointModelId id(data["modelid"].data());
- Breakpoint bp = breakHandler()->breakpointById(id);
- BreakpointResponse br = bp.response();
- updateResponse(br, data);
- bp.setResponse(br);
+ int modelId = data["modelid"].toInt();
+ Breakpoint bp = breakHandler()->findBreakpointByModelId(modelId);
+ QTC_ASSERT(bp, return);
+ bp->updateFromGdbOutput(data);
}
-void GdbEngine::handleWatchInsert(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp)
{
if (bp && response.resultClass == ResultDone) {
- BreakpointResponse br = bp.response();
// "Hardware watchpoint 2: *0xbfffed40\n"
QString ba = response.consoleStreamOutput;
GdbMi wpt = response.data["wpt"];
if (wpt.isValid()) {
// Mac yields:
//>32^done,wpt={number="4",exp="*4355182176"}
- br.id = BreakpointResponseId(wpt["number"].data());
+ bp->setResponseId(wpt["number"].data());
QString exp = wpt["exp"].data();
if (exp.startsWith('*'))
- br.address = exp.mid(1).toULongLong(nullptr, 0);
- bp.setResponse(br);
- QTC_CHECK(!bp.needsChange());
- bp.notifyBreakpointInsertOk();
+ bp->setAddress(exp.mid(1).toULongLong(nullptr, 0));
+ QTC_CHECK(!bp->needsChange());
+ notifyBreakpointInsertOk(bp);
} else if (ba.startsWith("Hardware watchpoint ")
|| ba.startsWith("Watchpoint ")) {
// Non-Mac: "Hardware watchpoint 2: *0xbfffed40\n"
const int end = ba.indexOf(':');
const int begin = ba.lastIndexOf(' ', end) + 1;
const QString address = ba.mid(end + 2).trimmed();
- br.id = BreakpointResponseId(ba.mid(begin, end - begin));
+ bp->setResponseId(ba.mid(begin, end - begin));
if (address.startsWith('*'))
- br.address = address.mid(1).toULongLong(nullptr, 0);
- bp.setResponse(br);
- QTC_CHECK(!bp.needsChange());
- bp.notifyBreakpointInsertOk();
+ bp->setAddress(address.mid(1).toULongLong(nullptr, 0));
+ QTC_CHECK(!bp->needsChange());
+ notifyBreakpointInsertOk(bp);
} else {
showMessage("CANNOT PARSE WATCHPOINT FROM " + ba);
}
}
}
-void GdbEngine::handleCatchInsert(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleCatchInsert(const DebuggerResponse &response, const Breakpoint &bp)
{
- if (bp && response.resultClass == ResultDone)
- bp.notifyBreakpointInsertOk();
+ if (response.resultClass == ResultDone)
+ notifyBreakpointInsertOk(bp);
}
-void GdbEngine::handleBkpt(const GdbMi &bkpt, Breakpoint bp)
+void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
{
- BreakpointResponse br = bp.response();
QTC_ASSERT(bp, return);
const QString nr = bkpt["number"].data();
- const BreakpointResponseId rid(nr);
- QTC_ASSERT(rid.isValid(), return);
if (nr.contains('.')) {
// A sub-breakpoint.
- BreakpointResponse sub;
- updateResponse(sub, bkpt);
- sub.id = rid;
- sub.type = bp.type();
- bp.insertSubBreakpoint(sub);
+ SubBreakpoint sub = bp->findOrCreateSubBreakpoint(nr);
+ QTC_ASSERT(sub, return);
+ sub->params.updateFromGdbOutput(bkpt);
+ sub->params.type = bp->type();
return;
}
@@ -2319,35 +2229,33 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, Breakpoint bp)
// http://permalink.gmane.org/gmane.comp.gdb.patches/83936
const GdbMi locations = bkpt["locations"];
if (locations.isValid()) {
- for (const GdbMi &loc : locations.children()) {
+ for (const GdbMi &location : locations.children()) {
// A sub-breakpoint.
- const QString subnr = loc["number"].data();
- const BreakpointResponseId subrid(subnr);
- BreakpointResponse sub;
- updateResponse(sub, loc);
- sub.id = subrid;
- sub.type = br.type;
- bp.insertSubBreakpoint(sub);
+ const QString subnr = location["number"].data();
+ SubBreakpoint sub = bp->findOrCreateSubBreakpoint(subnr);
+ QTC_ASSERT(sub, return);
+ sub->params.updateFromGdbOutput(location);
+ sub->params.type = bp->type();
}
}
// A (the?) primary breakpoint.
- updateResponse(br, bkpt);
- br.id = rid;
- bp.setResponse(br);
+ bp->setResponseId(nr);
+ bp->updateFromGdbOutput(bkpt);
}
-void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp)
{
- if (bp.state() == BreakpointRemoveRequested) {
+ QTC_ASSERT(bp, return);
+ if (bp->state() == BreakpointRemoveRequested) {
if (response.resultClass == ResultDone) {
// This delete was deferred. Act now.
const GdbMi mainbkpt = response.data["bkpt"];
- bp.notifyBreakpointRemoveProceeding();
+ notifyBreakpointRemoveProceeding(bp);
DebuggerCommand cmd("-break-delete " + mainbkpt["number"].data());
cmd.flags = NeedsTemporaryStop;
runCommand(cmd);
- bp.notifyBreakpointRemoveOk();
+ notifyBreakpointRemoveOk(bp);
return;
}
}
@@ -2359,17 +2267,17 @@ void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint
// iterate over all items to update main- and sub-data.
for (const GdbMi &bkpt : response.data.children())
handleBkpt(bkpt, bp);
- if (bp.needsChange()) {
- bp.notifyBreakpointChangeAfterInsertNeeded();
- changeBreakpoint(bp);
+ if (bp->needsChange()) {
+ bp->gotoState(BreakpointUpdateRequested, BreakpointInsertionProceeding);
+ updateBreakpoint(bp);
} else {
- bp.notifyBreakpointInsertOk();
+ notifyBreakpointInsertOk(bp);
}
} else if (response.data["msg"].data().contains("Unknown option")) {
// Older version of gdb don't know the -a option to set tracepoints
// ^error,msg="mi_cmd_break_insert: Unknown option ``a''"
- const QString fileName = bp.fileName();
- const int lineNumber = bp.lineNumber();
+ const QString fileName = bp->fileName();
+ const int lineNumber = bp->lineNumber();
DebuggerCommand cmd("trace \"" + GdbMi::escapeCString(fileName) + "\":"
+ QString::number(lineNumber),
NeedsTemporaryStop);
@@ -2378,18 +2286,17 @@ void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
// know how to do pending breakpoints using CLI but not MI. So try
// again with MI.
- DebuggerCommand cmd("break " + breakpointLocation2(bp.parameters()),
+ DebuggerCommand cmd("break " + breakpointLocation2(bp->requestedParameters()),
NeedsTemporaryStop);
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert2(r, bp); };
runCommand(cmd);
}
}
-void GdbEngine::handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakInsert2(const DebuggerResponse &response, const Breakpoint &bp)
{
if (response.resultClass == ResultDone) {
- QTC_ASSERT(bp, return);
- bp.notifyBreakpointInsertOk();
+ notifyBreakpointInsertOk(bp);
} else {
// Note: gdb < 60800 doesn't "do" pending breakpoints.
// Not much we can do about it except implementing the
@@ -2398,49 +2305,49 @@ void GdbEngine::handleBreakInsert2(const DebuggerResponse &response, Breakpoint
}
}
-void GdbEngine::handleBreakDisable(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakDisable(const DebuggerResponse &response, const Breakpoint &bp)
{
- QTC_CHECK(response.resultClass == ResultDone);
- // This should only be the requested state.
- QTC_ASSERT(!bp.isEnabled(), /* Prevent later recursion */);
- BreakpointResponse br = bp.response();
- br.enabled = false;
- bp.setResponse(br);
- changeBreakpoint(bp); // Maybe there's more to do.
+ if (response.resultClass == ResultDone) {
+ // This should only be the requested state.
+ QTC_ASSERT(bp, return);
+ bp->setEnabled(false);
+ // GDB does *not* touch the subbreakpoints in that case
+ // bp->forFirstLevelChildren([&](const SubBreakpoint &l) { l->params.enabled = false; });
+ updateBreakpoint(bp); // Maybe there's more to do.
+ }
}
-void GdbEngine::handleBreakEnable(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakEnable(const DebuggerResponse &response, const Breakpoint &bp)
{
- QTC_CHECK(response.resultClass == ResultDone);
- // This should only be the requested state.
- QTC_ASSERT(bp.isEnabled(), /* Prevent later recursion */);
- BreakpointResponse br = bp.response();
- br.enabled = true;
- bp.setResponse(br);
- changeBreakpoint(bp); // Maybe there's more to do.
+ if (response.resultClass == ResultDone) {
+ QTC_ASSERT(bp, return);
+ // This should only be the requested state.
+ bp->setEnabled(true);
+ // GDB does *not* touch the subbreakpoints in that case
+ //bp->forFirstLevelChildren([&](const SubBreakpoint &l) { l->params.enabled = true; });
+ updateBreakpoint(bp); // Maybe there's more to do.
+ }
}
-void GdbEngine::handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp)
{
QTC_CHECK(response.resultClass == ResultDone);
- BreakpointResponse br = bp.response();
- br.threadSpec = bp.threadSpec();
- bp.setResponse(br);
- bp.notifyBreakpointNeedsReinsertion();
+ QTC_ASSERT(bp, return);
+ // Parsing is fragile. Assume we got what we asked for instead.
+ bp->setThreadSpec(bp->requestedParameters().threadSpec);
+ notifyBreakpointNeedsReinsertion(bp);
insertBreakpoint(bp);
}
-void GdbEngine::handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp)
{
QTC_CHECK(response.resultClass == ResultDone);
- BreakpointResponse br = bp.response();
- br.lineNumber = bp.lineNumber();
- bp.setResponse(br);
- bp.notifyBreakpointNeedsReinsertion();
+ QTC_ASSERT(bp, return);
+ notifyBreakpointNeedsReinsertion(bp);
insertBreakpoint(bp);
}
-void GdbEngine::handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp)
+void GdbEngine::handleBreakIgnore(const DebuggerResponse &response, const Breakpoint &bp)
{
// gdb 6.8:
// ignore 2 0:
@@ -2453,22 +2360,21 @@ void GdbEngine::handleBreakIgnore(const DebuggerResponse &response, Breakpoint b
//
// gdb 6.3 does not produce any console output
QTC_CHECK(response.resultClass == ResultDone);
+ QTC_ASSERT(bp, return);
//QString msg = _(response.consoleStreamOutput);
- BreakpointResponse br = bp.response();
//if (msg.contains(__("Will stop next time breakpoint")))
// response.ignoreCount = _("0");
//else if (msg.contains(__("Will ignore next")))
// response.ignoreCount = data->ignoreCount;
// FIXME: this assumes it is doing the right thing...
- const BreakpointParameters &parameters = bp.parameters();
- br.ignoreCount = parameters.ignoreCount;
- br.command = parameters.command;
- bp.setResponse(br);
- changeBreakpoint(bp); // Maybe there's more to do.
+ bp->setIgnoreCount(bp->requestedParameters().ignoreCount);
+ bp->setCommand(bp->requestedParameters().command);
+ updateBreakpoint(bp); // Maybe there's more to do.
}
-void GdbEngine::handleBreakCondition(const DebuggerResponse &, Breakpoint bp)
+void GdbEngine::handleBreakCondition(const DebuggerResponse &, const Breakpoint &bp)
{
+ QTC_ASSERT(bp, return);
// Can happen at invalid condition strings.
//QTC_CHECK(response.resultClass == ResultDone)
// We just assume it was successful. Otherwise we had to parse
@@ -2477,10 +2383,8 @@ void GdbEngine::handleBreakCondition(const DebuggerResponse &, Breakpoint bp)
// QByteArray msg = response.data.findChild("msg").data();
// if (msg.startsWith("Error parsing breakpoint condition. "
// " Will try again when we hit the breakpoint."))
- BreakpointResponse br = bp.response();
- br.condition = bp.condition();
- bp.setResponse(br);
- changeBreakpoint(bp); // Maybe there's more to do.
+ bp->setCondition(bp->requestedParameters().condition);
+ updateBreakpoint(bp); // Maybe there's more to do.
}
bool GdbEngine::stateAcceptsBreakpointChanges() const
@@ -2497,27 +2401,28 @@ bool GdbEngine::stateAcceptsBreakpointChanges() const
}
}
-bool GdbEngine::acceptsBreakpoint(Breakpoint bp) const
+bool GdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
if (runParameters().startMode == AttachCore)
return false;
- if (bp.parameters().isCppBreakpoint())
+ if (bp.isCppBreakpoint())
return true;
return isNativeMixedEnabled();
}
-void GdbEngine::insertBreakpoint(Breakpoint bp)
+void GdbEngine::insertBreakpoint(const Breakpoint &bp)
{
// Set up fallback in case of pending breakpoints which aren't handled
- // by the MI interface.
- QTC_CHECK(bp.state() == BreakpointInsertRequested);
- bp.notifyBreakpointInsertProceeding();
+ // by the MI interface.A
+ QTC_ASSERT(bp, return);
+ QTC_CHECK(bp->state() == BreakpointInsertionRequested);
+ notifyBreakpointInsertProceeding(bp);
- const BreakpointParameters &data = bp.parameters();
+ const BreakpointParameters &requested = bp->requestedParameters();
- if (!data.isCppBreakpoint()) {
+ if (!requested.isCppBreakpoint()) {
DebuggerCommand cmd("insertInterpreterBreakpoint", NeedsTemporaryStop);
- bp.addToCommand(&cmd);
+ bp->addToCommand(&cmd);
cmd.callback = [this, bp](const DebuggerResponse &r) { handleInsertInterpreterBreakpoint(r, bp); };
runCommand(cmd);
return;
@@ -2526,14 +2431,14 @@ void GdbEngine::insertBreakpoint(Breakpoint bp)
const auto handleWatch = [this, bp](const DebuggerResponse &r) { handleWatchInsert(r, bp); };
const auto handleCatch = [this, bp](const DebuggerResponse &r) { handleCatchInsert(r, bp); };
- BreakpointType type = bp.type();
+ BreakpointType type = requested.type;
DebuggerCommand cmd;
if (type == WatchpointAtAddress) {
- cmd.function = "watch " + addressSpec(bp.address());
+ cmd.function = "watch " + addressSpec(requested.address);
cmd.callback = handleWatch;
} else if (type == WatchpointAtExpression) {
- cmd.function = "watch " + bp.expression();
+ cmd.function = "watch " + requested.expression;
cmd.callback = handleWatch;
} else if (type == BreakpointAtFork) {
cmd.function = "catch fork";
@@ -2549,61 +2454,61 @@ void GdbEngine::insertBreakpoint(Breakpoint bp)
cmd.function = "catch syscall";
cmd.callback = handleCatch;
} else {
- if (bp.isTracepoint()) {
+ if (requested.isTracepoint()) {
cmd.function = "-break-insert -a -f ";
} else {
- int spec = bp.threadSpec();
+ int spec = requested.threadSpec;
cmd.function = "-break-insert ";
if (spec >= 0)
cmd.function += "-p " + QString::number(spec);
cmd.function += " -f ";
}
- if (bp.isOneShot())
+ if (requested.oneShot)
cmd.function += "-t ";
- if (!bp.isEnabled())
+ if (!requested.enabled)
cmd.function += "-d ";
- if (int ignoreCount = bp.ignoreCount())
+ if (int ignoreCount = requested.ignoreCount)
cmd.function += "-i " + QString::number(ignoreCount) + ' ';
- QString condition = bp.condition();
+ QString condition = requested.condition;
if (!condition.isEmpty())
cmd.function += " -c \"" + condition.replace('"', "\\\"") + "\" ";
- cmd.function += breakpointLocation(bp.parameters());
+ cmd.function += breakpointLocation(requested);
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); };
}
cmd.flags = NeedsTemporaryStop;
runCommand(cmd);
}
-void GdbEngine::changeBreakpoint(Breakpoint bp)
+void GdbEngine::updateBreakpoint(const Breakpoint &bp)
{
- const BreakpointParameters &data = bp.parameters();
- QTC_ASSERT(data.type != UnknownBreakpointType, return);
- const BreakpointResponse &response = bp.response();
- QTC_ASSERT(response.id.isValid(), return);
- const QString bpnr = response.id.toString();
- const BreakpointState state = bp.state();
- if (state == BreakpointChangeRequested)
- bp.notifyBreakpointChangeProceeding();
- const BreakpointState state2 = bp.state();
- QTC_ASSERT(state2 == BreakpointChangeProceeding, qDebug() << state2);
+ QTC_ASSERT(bp, return);
+ const BreakpointParameters &requested = bp->requestedParameters();
+ QTC_ASSERT(requested.type != UnknownBreakpointType, return);
+ QTC_ASSERT(!bp->responseId().isEmpty(), return);
+ const QString bpnr = bp->responseId();
+ const BreakpointState state = bp->state();
+ if (state == BreakpointUpdateRequested)
+ notifyBreakpointChangeProceeding(bp);
+ const BreakpointState state2 = bp->state();
+ QTC_ASSERT(state2 == BreakpointUpdateProceeding, qDebug() << state2);
DebuggerCommand cmd;
- if (!response.pending && data.threadSpec != response.threadSpec) {
+ if (!bp->isPending() && requested.threadSpec != bp->threadSpec()) {
// The only way to change this seems to be to re-set the bp completely.
cmd.function = "-break-delete " + bpnr;
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakThreadSpec(r, bp); };
- } else if (!response.pending && data.lineNumber != response.lineNumber) {
+ } else if (!bp->isPending() && requested.lineNumber != bp->lineNumber()) {
// The only way to change this seems to be to re-set the bp completely.
cmd.function = "-break-delete " + bpnr;
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakLineNumber(r, bp); };
- } else if (data.command != response.command) {
+ } else if (requested.command != bp->command()) {
cmd.function = "-break-commands " + bpnr;
- for (QString command : data.command.split('\n')) {
+ for (QString command : requested.command.split('\n')) {
if (!command.isEmpty()) {
// escape backslashes and quotes
command.replace('\\', "\\\\");
@@ -2612,58 +2517,59 @@ void GdbEngine::changeBreakpoint(Breakpoint bp)
}
}
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); };
- } else if (!data.conditionsMatch(response.condition)) {
- cmd.function = "condition " + bpnr + ' ' + data.condition;
+ } else if (!requested.conditionsMatch(bp->condition())) {
+ cmd.function = "condition " + bpnr + ' ' + requested.condition;
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakCondition(r, bp); };
- } else if (data.ignoreCount != response.ignoreCount) {
- cmd.function = "ignore " + bpnr + ' ' + QString::number(data.ignoreCount);
+ } else if (requested.ignoreCount != bp->ignoreCount()) {
+ cmd.function = "ignore " + bpnr + ' ' + QString::number(requested.ignoreCount);
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakIgnore(r, bp); };
- } else if (!data.enabled && response.enabled) {
+ } else if (!requested.enabled && bp->isEnabled()) {
cmd.function = "-break-disable " + bpnr;
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakDisable(r, bp); };
- } else if (data.enabled && !response.enabled) {
+ } else if (requested.enabled && !bp->isEnabled()) {
cmd.function = "-break-enable " + bpnr;
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakEnable(r, bp); };
} else {
- bp.notifyBreakpointChangeOk();
+ notifyBreakpointChangeOk(bp);
return;
}
cmd.flags = NeedsTemporaryStop;
runCommand(cmd);
}
-void GdbEngine::enableSubBreakpoint(const QString &locId, bool on)
+void GdbEngine::enableSubBreakpoint(const SubBreakpoint &sbp, bool on)
{
- DebuggerCommand cmd((on ? "-break-enable " : "-break-disable ") + locId);
+ QTC_ASSERT(sbp, return);
+ DebuggerCommand cmd((on ? "-break-enable " : "-break-disable ") + sbp->responseId);
runCommand(cmd);
}
-void GdbEngine::removeBreakpoint(Breakpoint bp)
+void GdbEngine::removeBreakpoint(const Breakpoint &bp)
{
- QTC_CHECK(bp.state() == BreakpointRemoveRequested);
- BreakpointResponse br = bp.response();
+ QTC_ASSERT(bp, return);
+ QTC_CHECK(bp->state() == BreakpointRemoveRequested);
- const BreakpointParameters &data = bp.parameters();
- if (!data.isCppBreakpoint()) {
+ const BreakpointParameters &requested = bp->requestedParameters();
+ if (!requested.isCppBreakpoint()) {
DebuggerCommand cmd("removeInterpreterBreakpoint");
- bp.addToCommand(&cmd);
+ bp->addToCommand(&cmd);
runCommand(cmd);
- bp.notifyBreakpointRemoveOk();
+ notifyBreakpointRemoveOk(bp);
return;
}
- if (br.id.isValid()) {
+ if (!bp->responseId().isEmpty()) {
// We already have a fully inserted breakpoint.
- bp.notifyBreakpointRemoveProceeding();
- showMessage(QString("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
- DebuggerCommand cmd("-break-delete " + br.id.toString(), NeedsTemporaryStop);
+ notifyBreakpointRemoveProceeding(bp);
+ showMessage(QString("DELETING BP %1 IN %2").arg(bp->responseId()).arg(bp->fileName()));
+ DebuggerCommand cmd("-break-delete " + bp->responseId(), NeedsTemporaryStop);
runCommand(cmd);
// Pretend it succeeds without waiting for response. Feels better.
// Otherwise, clicking in the gutter leaves the breakpoint visible
// for quite some time, so the user assumes a mis-click and clicks
// again, effectivly re-introducing the breakpoint.
- bp.notifyBreakpointRemoveOk();
+ notifyBreakpointRemoveOk(bp);
} else {
// Breakpoint was scheduled to be inserted, but we haven't had
@@ -3060,7 +2966,7 @@ void GdbEngine::activateFrame(int frameIndex)
QTC_ASSERT(frameIndex < handler->stackSize(), return);
handler->setCurrentIndex(frameIndex);
- gotoLocation(stackHandler()->currentFrame());
+ gotoCurrentLocation();
if (handler->frameAt(frameIndex).language != QmlLanguage) {
// Assuming the command always succeeds this saves a roundtrip.
@@ -3086,7 +2992,7 @@ void GdbEngine::handleThreadInfo(const DebuggerResponse &response)
if (other.isValid())
selectThread(other);
}
- updateViews(); // Adjust Threads combobox.
+ updateState(false); // Adjust Threads combobox.
if (boolSetting(ShowThreadNames)) {
runCommand({"threadnames " + action(MaximalStackDepth)->value().toString(),
Discardable, CB(handleThreadNames)});
@@ -3125,7 +3031,7 @@ void GdbEngine::handleThreadNames(const DebuggerResponse &response)
thread.name = decodeData(name["value"].data(), name["valueencoded"].data());
handler->updateThread(thread);
}
- updateViews();
+ updateState(false);
}
}
@@ -3156,21 +3062,7 @@ void GdbEngine::createSnapshot()
void GdbEngine::handleMakeSnapshot(const DebuggerResponse &response, const QString &coreFile)
{
if (response.resultClass == ResultDone) {
- //snapshot.setDate(QDateTime::currentDateTime());
- StackFrames frames = stackHandler()->frames();
- QString function = "<unknown>";
- if (!frames.isEmpty()) {
- const StackFrame &frame = frames.at(0);
- function = frame.function + ":" + QString::number(frame.line);
- }
- auto runConfig = runTool()->runControl()->runConfiguration();
- QTC_ASSERT(runConfig, return);
- auto rc = new RunControl(runConfig, ProjectExplorer::Constants::DEBUG_RUN_MODE);
- auto debugger = new DebuggerRunTool(rc);
- debugger->setStartMode(AttachCore);
- debugger->setRunControlName(function + ": " + QDateTime::currentDateTime().toString());
- debugger->setCoreFileName(coreFile, true);
- debugger->startRunControl();
+ emit attachToCoreRequested(coreFile);
} else {
QString msg = response.data["msg"].data();
AsynchronousMessageBox::critical(tr("Snapshot Creation Error"),
@@ -3187,7 +3079,7 @@ void GdbEngine::handleMakeSnapshot(const DebuggerResponse &response, const QStri
void GdbEngine::reloadRegisters()
{
- if (!Internal::isRegistersWindowVisible())
+ if (!isRegistersWindowVisible())
return;
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
@@ -3912,10 +3804,7 @@ void GdbEngine::reloadDebuggingHelpers()
void GdbEngine::handleGdbError(QProcess::ProcessError error)
{
- QString program;
- // avoid accessing invalid memory if the process crashed
- if (runTool())
- program = runParameters().debugger.executable;
+ const QString program = runParameters().debugger.executable;
QString msg = RunWorker::userMessageForProcessError(error, program);
QString errorString = m_gdbProc.errorString();
if (!errorString.isEmpty())
@@ -4203,7 +4092,7 @@ void GdbEngine::setupInferior()
if (rp.startMode != AttachCore) {
showStatusMessage(tr("Setting breakpoints..."));
showMessage(tr("Setting breakpoints..."));
- attemptBreakpointSynchronization();
+ BreakpointManager::claimBreakpointsForEngine(this);
}
if (rp.startMode == AttachToRemoteProcess) {
@@ -4593,9 +4482,6 @@ void GdbEngine::handleExecRun(const DebuggerResponse &response)
//showStatusMessage(tr("Running..."));
showMessage("INFERIOR STARTED");
showMessage(msgInferiorSetupOk(), StatusBar);
- // FIXME: That's the wrong place for it.
- if (boolSetting(EnableReverseDebugging))
- runCommand({"target record"});
} else {
QString msg = response.data["msg"].data();
//QTC_CHECK(status() == InferiorRunOk);
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index aa16c0c401..dbd437ffd8 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -47,7 +47,6 @@ namespace Debugger {
namespace Internal {
class BreakpointParameters;
-class BreakpointResponse;
class DebugInfoTask;
class DebugInfoTaskHandler;
class DebuggerResponse;
@@ -65,7 +64,7 @@ struct CoreInfo
const QString &coreFile);
};
-class GdbEngine : public DebuggerEngine
+class GdbEngine : public CppDebuggerEngine
{
Q_OBJECT
@@ -74,8 +73,6 @@ public:
~GdbEngine() final;
private: ////////// General Interface //////////
- DebuggerEngine *cppEngine() final { return this; }
-
void handleGdbStartFailed();
void prepareForRestart() final;
@@ -86,7 +83,7 @@ private: ////////// General Interface //////////
void resetInferior() final;
bool acceptsDebuggerCommands() const final;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) final;
+ void executeDebuggerCommand(const QString &command) final;
////////// General State //////////
@@ -189,11 +186,11 @@ private: ////////// General Interface //////////
// This should be always the last call in a function.
bool stateAcceptsBreakpointChanges() const final;
- bool acceptsBreakpoint(Breakpoint bp) const final;
- void insertBreakpoint(Breakpoint bp) final;
- void removeBreakpoint(Breakpoint bp) final;
- void changeBreakpoint(Breakpoint bp) final;
- void enableSubBreakpoint(const QString &locId, bool on) final;
+ bool acceptsBreakpoint(const BreakpointParameters &bp) const final;
+ void insertBreakpoint(const Breakpoint &bp) final;
+ void removeBreakpoint(const Breakpoint &bp) final;
+ void updateBreakpoint(const Breakpoint &bp) final;
+ void enableSubBreakpoint(const SubBreakpoint &sbp, bool on) final;
void executeStep() final;
void executeStepOut() final;
@@ -209,6 +206,7 @@ private: ////////// General Interface //////////
void executeRunToFunction(const QString &functionName) final;
void executeJumpToLine(const ContextData &data) final;
void executeReturn() final;
+ void executeRecordReverse(bool reverse);
void handleExecuteContinue(const DebuggerResponse &response);
void handleExecuteStep(const DebuggerResponse &response);
@@ -223,26 +221,24 @@ private: ////////// General Interface //////////
void selectThread(ThreadId threadId) final;
void activateFrame(int index) final;
- void handleAutoContinueInferior();
//
// Breakpoint specific stuff
//
void handleBreakModifications(const GdbMi &bkpts);
- void handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakDisable(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakEnable(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakCondition(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp);
- void handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp);
- void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, Breakpoint bp);
+ void handleBreakIgnore(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakDisable(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakEnable(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakInsert2(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakCondition(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, const Breakpoint &bp);
void handleInterpreterBreakpointModified(const GdbMi &data);
- void handleWatchInsert(const DebuggerResponse &response, Breakpoint bp);
- void handleCatchInsert(const DebuggerResponse &response, Breakpoint bp);
- void handleBkpt(const GdbMi &bkpt, Breakpoint bp);
- void updateResponse(BreakpointResponse &response, const GdbMi &bkpt);
+ void handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleCatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
+ void handleBkpt(const GdbMi &bkpt, const Breakpoint &bp);
QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
QString breakLocation(const QString &file) const;
diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp
index 32f0a2cbf7..952505e51f 100644
--- a/src/plugins/debugger/lldb/lldbengine.cpp
+++ b/src/plugins/debugger/lldb/lldbengine.cpp
@@ -84,6 +84,7 @@ static int &currentToken()
LldbEngine::LldbEngine()
{
setObjectName("LldbEngine");
+ setDebuggerName("LLDB");
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
this, &LldbEngine::updateLocals);
@@ -114,7 +115,7 @@ LldbEngine::~LldbEngine()
m_lldbProc.disconnect();
}
-void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
+void LldbEngine::executeDebuggerCommand(const QString &command)
{
DebuggerCommand cmd("executeDebuggerCommand");
cmd.arg("command", command);
@@ -175,13 +176,18 @@ void LldbEngine::shutdownInferior()
void LldbEngine::shutdownEngine()
{
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
- m_lldbProc.kill();
- notifyEngineShutdownFinished();
+ if (m_lldbProc.state() == QProcess::Running)
+ m_lldbProc.terminate();
+ else
+ notifyEngineShutdownFinished();
}
void LldbEngine::abortDebuggerProcess()
{
- m_lldbProc.kill();
+ if (m_lldbProc.state() == QProcess::Running)
+ m_lldbProc.kill();
+ else
+ notifyEngineShutdownFinished();
}
void LldbEngine::setupEngine()
@@ -290,17 +296,9 @@ void LldbEngine::setupEngine()
}
cmd2.callback = [this](const DebuggerResponse &response) {
- bool success = response.data["success"].toInt();
+ const bool success = response.data["success"].toInt();
if (success) {
- for (Breakpoint bp : breakHandler()->unclaimedBreakpoints()) {
- if (acceptsBreakpoint(bp)) {
- bp.setEngine(this);
- insertBreakpoint(bp);
- } else {
- showMessage(QString("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
- .arg(bp.id().toString()).arg(bp.state()));
- }
- }
+ BreakpointManager::claimBreakpointsForEngine(this);
} else {
notifyEngineSetupFailed();
}
@@ -442,7 +440,7 @@ void LldbEngine::activateFrame(int frameIndex)
QTC_ASSERT(frameIndex < handler->stackSize(), return);
handler->setCurrentIndex(frameIndex);
- gotoLocation(handler->currentFrame());
+ gotoCurrentLocation();
DebuggerCommand cmd("activateFrame");
cmd.arg("index", frameIndex);
@@ -477,104 +475,103 @@ bool LldbEngine::stateAcceptsBreakpointChanges() const
}
}
-bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
+bool LldbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
if (runParameters().startMode == AttachCore)
return false;
- if (bp.parameters().isCppBreakpoint())
+ if (bp.isCppBreakpoint())
return true;
return isNativeMixedEnabled();
}
-void LldbEngine::insertBreakpoint(Breakpoint bp)
+void LldbEngine::insertBreakpoint(const Breakpoint &bp)
{
+ QTC_ASSERT(bp, return);
DebuggerCommand cmd("insertBreakpoint");
cmd.callback = [this, bp](const DebuggerResponse &response) {
- QTC_CHECK(bp.state() == BreakpointInsertProceeding);
+ QTC_CHECK(bp && bp->state() == BreakpointInsertionProceeding);
updateBreakpointData(bp, response.data, true);
};
- bp.addToCommand(&cmd);
- bp.notifyBreakpointInsertProceeding();
+ bp->addToCommand(&cmd);
+ notifyBreakpointInsertProceeding(bp);
runCommand(cmd);
}
-void LldbEngine::changeBreakpoint(Breakpoint bp)
+void LldbEngine::updateBreakpoint(const Breakpoint &bp)
{
- const BreakpointResponse &response = bp.response();
+ QTC_ASSERT(bp, return);
DebuggerCommand cmd("changeBreakpoint");
- cmd.arg("lldbid", response.id.toString());
+ cmd.arg("lldbid", bp->responseId());
cmd.callback = [this, bp](const DebuggerResponse &response) {
- QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
+ QTC_CHECK(bp && bp->state() == BreakpointUpdateProceeding);
updateBreakpointData(bp, response.data, false);
};
- bp.addToCommand(&cmd);
- bp.notifyBreakpointChangeProceeding();
+ bp->addToCommand(&cmd);
+ notifyBreakpointChangeProceeding(bp);
runCommand(cmd);
}
-void LldbEngine::removeBreakpoint(Breakpoint bp)
+void LldbEngine::removeBreakpoint(const Breakpoint &bp)
{
- const BreakpointResponse &response = bp.response();
- if (response.id.isValid()) {
+ QTC_ASSERT(bp, return);
+ if (!bp->responseId().isEmpty()) {
DebuggerCommand cmd("removeBreakpoint");
- cmd.arg("lldbid", response.id.toString());
- cmd.callback = [bp](const DebuggerResponse &) {
- QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
- Breakpoint bp0 = bp;
- bp0.notifyBreakpointRemoveOk();
- };
- bp.notifyBreakpointRemoveProceeding();
+ cmd.arg("lldbid", bp->responseId());
+ notifyBreakpointRemoveProceeding(bp);
runCommand(cmd);
+
+ // Pretend it succeeds without waiting for response. Feels better.
+ // Otherwise, clicking in the gutter leaves the breakpoint visible
+ // for quite some time, so the user assumes a mis-click and clicks
+ // again, effectivly re-introducing the breakpoint.
+ notifyBreakpointRemoveOk(bp);
}
}
-void LldbEngine::updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added)
+void LldbEngine::updateBreakpointData(const Breakpoint &bp, const GdbMi &bkpt, bool added)
{
- BreakHandler *handler = breakHandler();
- BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
- if (!bp.isValid())
- bp = handler->findBreakpointByResponseId(rid);
- BreakpointResponse response = bp.response();
+ QTC_ASSERT(bp, return);
+ QString rid = bkpt["lldbid"].data();
+ QTC_ASSERT(bp, return);
if (added)
- response.id = rid;
- QTC_CHECK(response.id == rid);
- response.address = 0;
- response.enabled = bkpt["enabled"].toInt();
- response.ignoreCount = bkpt["ignorecount"].toInt();
- response.condition = fromHex(bkpt["condition"].data());
- response.hitCount = bkpt["hitcount"].toInt();
- response.fileName = bkpt["file"].data();
- response.lineNumber = bkpt["line"].toInt();
+ bp->setResponseId(rid);
+ QTC_CHECK(bp->responseId() == rid);
+ bp->setAddress(0);
+ bp->setEnabled(bkpt["enabled"].toInt());
+ bp->setIgnoreCount(bkpt["ignorecount"].toInt());
+ bp->setCondition(fromHex(bkpt["condition"].data()));
+ bp->setHitCount(bkpt["hitcount"].toInt());
+ bp->setFileName(bkpt["file"].data());
+ bp->setLineNumber(bkpt["line"].toInt());
GdbMi locations = bkpt["locations"];
const int numChild = int(locations.children().size());
if (numChild > 1) {
for (const GdbMi &location : locations.children()) {
- const int locid = location["locid"].toInt();
- BreakpointResponse sub;
- sub.id = BreakpointResponseId(rid.majorPart(), locid);
- sub.type = response.type;
- sub.address = location["addr"].toAddress();
- sub.functionName = location["func"].data();
- sub.fileName = location["file"].data();
- sub.lineNumber = location["line"].toInt();
- bp.insertSubBreakpoint(sub);
+ const QString locid = QString("%1.%2").arg(rid).arg(location["locid"].data());
+ SubBreakpoint loc = bp->findOrCreateSubBreakpoint(locid);
+ QTC_ASSERT(loc, continue);
+ loc->params.type = bp->type();
+ loc->params.address = location["addr"].toAddress();
+ loc->params.functionName = location["function"].data();
+ loc->params.fileName = location["file"].data();
+ loc->params.lineNumber = location["line"].toInt();
}
- response.pending = false;
+ bp->setPending(false);
} else if (numChild == 1) {
const GdbMi location = locations.childAt(0);
- response.address = location["addr"].toAddress();
- response.functionName = location["func"].data();
- response.pending = false;
+ bp->setAddress(location["addr"].toAddress());
+ bp->setFunctionName(location["function"].data());
+ bp->setPending(false);
} else {
// This can happen for pending breakpoints.
- showMessage(QString("NO LOCATIONS (YET) FOR BP %1").arg(response.toString()));
+ showMessage(QString("NO LOCATIONS (YET) FOR BP %1").arg(bp->parameters().toString()));
}
- bp.setResponse(response);
+ bp->adjustMarker();
if (added)
- bp.notifyBreakpointInsertOk();
+ notifyBreakpointInsertOk(bp);
else
- bp.notifyBreakpointChangeOk();
+ notifyBreakpointChangeOk(bp);
}
void LldbEngine::handleOutputNotification(const GdbMi &output)
@@ -896,7 +893,7 @@ void LldbEngine::handleLocationNotification(const GdbMi &reportedLocation)
void LldbEngine::reloadRegisters()
{
- if (!Internal::isRegistersWindowVisible())
+ if (!isRegistersWindowVisible())
return;
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
@@ -1012,7 +1009,8 @@ void LldbEngine::setRegisterValue(const QString &name, const QString &value)
bool LldbEngine::hasCapability(unsigned cap) const
{
- if (cap & (ReverseSteppingCapability
+ if (cap & (0
+ //| ReverseSteppingCapability
| AutoDerefPointersCapability
| DisassemblerCapability
| RegisterCapability
diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h
index 55bd6b603f..a6487de3bc 100644
--- a/src/plugins/debugger/lldb/lldbengine.h
+++ b/src/plugins/debugger/lldb/lldbengine.h
@@ -41,17 +41,14 @@
#include <QMap>
#include <QVariant>
-
namespace Debugger {
namespace Internal {
-class GdbMi;
-
/* A debugger engine interfacing the LLDB debugger
* using its Python interface.
*/
-class LldbEngine : public DebuggerEngine
+class LldbEngine : public CppDebuggerEngine
{
Q_OBJECT
@@ -63,8 +60,6 @@ signals:
void outputReady(const QString &data);
private:
- DebuggerEngine *cppEngine() override { return this; }
-
void executeStep() override;
void executeStepOut() override;
void executeNext() override;
@@ -92,13 +87,13 @@ private:
// This should be always the last call in a function.
bool stateAcceptsBreakpointChanges() const override;
- bool acceptsBreakpoint(Breakpoint bp) const override;
- void insertBreakpoint(Breakpoint bp) override;
- void removeBreakpoint(Breakpoint bp) override;
- void changeBreakpoint(Breakpoint bp) override;
+ bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
+ void insertBreakpoint(const Breakpoint &bp) override;
+ void removeBreakpoint(const Breakpoint &bp) override;
+ void updateBreakpoint(const Breakpoint &bp) override;
void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value) override;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override;
+ void executeDebuggerCommand(const QString &command) override;
void loadSymbols(const QString &moduleName) override;
void loadAllSymbols() override;
@@ -130,7 +125,7 @@ private:
void handleResponse(const QString &data);
void updateAll() override;
void doUpdateLocals(const UpdateParameters &params) override;
- void updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added);
+ void updateBreakpointData(const Breakpoint &bp, const GdbMi &bkpt, bool added);
void fetchStack(int limit);
void runCommand(const DebuggerCommand &cmd) override;
diff --git a/src/plugins/debugger/logwindow.cpp b/src/plugins/debugger/logwindow.cpp
index 9b309bade8..dca4aae538 100644
--- a/src/plugins/debugger/logwindow.cpp
+++ b/src/plugins/debugger/logwindow.cpp
@@ -58,6 +58,52 @@
namespace Debugger {
namespace Internal {
+GlobalLogWindow *theGlobalLog = nullptr;
+
+static LogChannel channelForChar(QChar c)
+{
+ switch (c.unicode()) {
+ case 'd': return LogDebug;
+ case 'w': return LogWarning;
+ case 'e': return LogError;
+ case '<': return LogInput;
+ case '>': return LogOutput;
+ case 's': return LogStatus;
+ case 't': return LogTime;
+ default: return LogMisc;
+ }
+}
+
+QChar static charForChannel(int channel)
+{
+ switch (channel) {
+ case LogDebug: return QLatin1Char('d');
+ case LogWarning: return QLatin1Char('w');
+ case LogError: return QLatin1Char('e');
+ case LogInput: return QLatin1Char('<');
+ case LogOutput: return QLatin1Char('>');
+ case LogStatus: return QLatin1Char('s');
+ case LogTime: return QLatin1Char('t');
+ case LogMisc:
+ default: return QLatin1Char(' ');
+ }
+}
+
+static bool writeLogContents(const QPlainTextEdit *editor, QWidget *parent)
+{
+ bool success = false;
+ while (!success) {
+ const QString fileName = QFileDialog::getSaveFileName(parent, LogWindow::tr("Log File"));
+ if (fileName.isEmpty())
+ break;
+ Utils::FileSaver saver(fileName, QIODevice::Text);
+ saver.write(editor->toPlainText().toUtf8());
+ if (saver.finalize(parent))
+ success = true;
+ }
+ return success;
+}
+
/////////////////////////////////////////////////////////////////////
//
// OutputHighlighter
@@ -77,7 +123,7 @@ private:
using Utils::Theme;
QTextCharFormat format;
Theme *theme = Utils::creatorTheme();
- switch (LogWindow::channelForChar(text.isEmpty() ? QChar() : text.at(0))) {
+ switch (channelForChar(text.isEmpty() ? QChar() : text.at(0))) {
case LogInput:
format.setForeground(theme->color(Theme::Debugger_LogWindow_LogInput));
setFormat(1, text.size(), format);
@@ -149,15 +195,14 @@ class DebuggerPane : public QPlainTextEdit
Q_OBJECT
public:
- DebuggerPane(LogWindow *parent)
- : QPlainTextEdit(parent)
+ explicit DebuggerPane()
{
setFrameStyle(QFrame::NoFrame);
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
m_clearContentsAction = new QAction(this);
m_clearContentsAction->setText(tr("Clear Contents"));
m_clearContentsAction->setEnabled(true);
- connect(m_clearContentsAction, &QAction::triggered,
- parent, &LogWindow::clearContents);
m_saveContentsAction = new QAction(this);
m_saveContentsAction->setText(tr("Save Contents"));
@@ -168,8 +213,6 @@ public:
m_reloadDebuggingHelpersAction = new QAction(this);
m_reloadDebuggingHelpersAction->setText(tr("Reload Debugging Helpers"));
m_reloadDebuggingHelpersAction->setEnabled(true);
- connect(m_reloadDebuggingHelpersAction, &QAction::triggered,
- this, &DebuggerPane::reloadDebuggingHelpers);
}
void contextMenuEvent(QContextMenuEvent *ev) override
@@ -212,24 +255,18 @@ public:
setUndoRedoEnabled(true);
}
+ QAction *clearContentsAction() const { return m_clearContentsAction; }
+ QAction *reloadDebuggingHelpersAction() const { return m_reloadDebuggingHelpersAction; }
+
private:
- void saveContents();
- void reloadDebuggingHelpers();
+ void saveContents() { writeLogContents(this, this); }
QAction *m_clearContentsAction;
QAction *m_saveContentsAction;
QAction *m_reloadDebuggingHelpersAction;
};
-void DebuggerPane::saveContents()
-{
- LogWindow::writeLogContents(this, this);
-}
-void DebuggerPane::reloadDebuggingHelpers()
-{
- currentEngine()->reloadDebuggingHelpers();
-}
/////////////////////////////////////////////////////////////////////
//
@@ -241,9 +278,12 @@ class InputPane : public DebuggerPane
{
Q_OBJECT
public:
- InputPane(LogWindow *parent)
- : DebuggerPane(parent)
+ InputPane(LogWindow *logWindow)
{
+ connect(clearContentsAction(), &QAction::triggered,
+ logWindow, &LogWindow::clearContents);
+ connect(reloadDebuggingHelpersAction(), &QAction::triggered,
+ logWindow->engine(), &DebuggerEngine::reloadDebuggingHelpers);
(void) new InputHighlighter(this);
}
@@ -307,10 +347,13 @@ class CombinedPane : public DebuggerPane
{
Q_OBJECT
public:
- CombinedPane(LogWindow *parent)
- : DebuggerPane(parent)
+ CombinedPane(LogWindow *logWindow)
{
(void) new OutputHighlighter(this);
+ connect(clearContentsAction(), &QAction::triggered,
+ logWindow, &LogWindow::clearContents);
+ connect(reloadDebuggingHelpersAction(), &QAction::triggered,
+ logWindow->engine(), &DebuggerEngine::reloadDebuggingHelpers);
}
void gotoResult(int i)
@@ -347,8 +390,8 @@ public:
//
/////////////////////////////////////////////////////////////////////
-LogWindow::LogWindow(QWidget *parent)
- : QWidget(parent)
+LogWindow::LogWindow(DebuggerEngine *engine)
+ : m_engine(engine)
{
setWindowTitle(tr("Debugger &Log"));
setObjectName(QLatin1String("Log"));
@@ -362,14 +405,10 @@ LogWindow::LogWindow(QWidget *parent)
m_combinedText = new CombinedPane(this);
m_combinedText->setReadOnly(true);
m_combinedText->setReadOnly(false);
- m_combinedText->setSizePolicy(QSizePolicy::MinimumExpanding,
- QSizePolicy::MinimumExpanding);
// Input only.
m_inputText = new InputPane(this);
m_inputText->setReadOnly(false);
- m_inputText->setSizePolicy(QSizePolicy::MinimumExpanding,
- QSizePolicy::MinimumExpanding);
m_commandEdit = new Utils::FancyLineEdit(this);
m_commandEdit->setFrame(false);
@@ -445,23 +484,33 @@ LogWindow::LogWindow(QWidget *parent)
.arg(Core::Constants::IDE_DISPLAY_NAME));
}
+LogWindow::~LogWindow()
+{
+ disconnect(&m_outputTimer, &QTimer::timeout, this, &LogWindow::doOutput);
+ m_outputTimer.stop();
+ doOutput();
+}
+
void LogWindow::executeLine()
{
m_ignoreNextInputEcho = true;
- currentEngine()->
- executeDebuggerCommand(m_inputText->textCursor().block().text(), CppLanguage);
+ m_engine->executeDebuggerCommand(m_inputText->textCursor().block().text());
}
void LogWindow::repeatLastCommand()
{
- currentEngine()->debugLastCommand();
+ m_engine->debugLastCommand();
+}
+
+DebuggerEngine *LogWindow::engine() const
+{
+ return m_engine;
}
void LogWindow::sendCommand()
{
- DebuggerEngine *engine = currentEngine();
- if (engine->acceptsDebuggerCommands())
- engine->executeDebuggerCommand(m_commandEdit->text(), CppLanguage);
+ if (m_engine->acceptsDebuggerCommands())
+ m_engine->executeDebuggerCommand(m_commandEdit->text());
else
showOutput(LogError, tr("User commands are not accepted in the current state."));
}
@@ -512,6 +561,8 @@ void LogWindow::doOutput()
if (m_queuedOutput.isEmpty())
return;
+ theGlobalLog->doOutput(m_queuedOutput);
+
QTextCursor cursor = m_combinedText->textCursor();
const bool atEnd = cursor.atEnd();
@@ -543,6 +594,8 @@ void LogWindow::showInput(int channel, const QString &input)
cursor.movePosition(QTextCursor::End);
m_inputText->setTextCursor(cursor);
m_inputText->ensureCursorVisible();
+
+ theGlobalLog->doInput(input);
}
void LogWindow::clearContents()
@@ -597,50 +650,102 @@ QString LogWindow::logTimeStamp()
return lastTimeStamp;
}
-bool LogWindow::writeLogContents(const QPlainTextEdit *editor, QWidget *parent)
+/////////////////////////////////////////////////////////////////////
+//
+// GlobalLogWindow
+//
+/////////////////////////////////////////////////////////////////////
+
+GlobalLogWindow::GlobalLogWindow()
{
- bool success = false;
- while (!success) {
- const QString fileName = QFileDialog::getSaveFileName(parent, tr("Log File"));
- if (fileName.isEmpty())
- break;
- Utils::FileSaver saver(fileName, QIODevice::Text);
- saver.write(editor->toPlainText().toUtf8());
- if (saver.finalize(parent))
- success = true;
- }
- return success;
+ theGlobalLog = this;
+
+ setWindowTitle(tr("Global Debugger &Log"));
+ setObjectName("GlobalLog");
+
+ auto m_splitter = new Core::MiniSplitter(Qt::Horizontal);
+ m_splitter->setParent(this);
+
+ m_rightPane = new DebuggerPane;
+ m_rightPane->setReadOnly(true);
+
+ m_leftPane = new DebuggerPane;
+ m_leftPane->setReadOnly(true);
+
+ m_splitter->addWidget(m_leftPane);
+ m_splitter->addWidget(m_rightPane);
+ m_splitter->setStretchFactor(0, 1);
+ m_splitter->setStretchFactor(1, 3);
+
+ auto layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget(m_splitter);
+ layout->addWidget(new Core::FindToolBarPlaceHolder(this));
+ setLayout(layout);
+
+ auto aggregate = new Aggregation::Aggregate;
+ aggregate->add(m_rightPane);
+ aggregate->add(new Core::BaseTextFind(m_rightPane));
+
+ aggregate = new Aggregation::Aggregate;
+ aggregate->add(m_leftPane);
+ aggregate->add(new Core::BaseTextFind(m_leftPane));
+
+ connect(m_leftPane->clearContentsAction(), &QAction::triggered,
+ this, &GlobalLogWindow::clearContents);
+ connect(m_rightPane->clearContentsAction(), &QAction::triggered,
+ this, &GlobalLogWindow::clearContents);
}
-QChar LogWindow::charForChannel(int channel)
+GlobalLogWindow::~GlobalLogWindow()
{
- switch (channel) {
- case LogDebug: return QLatin1Char('d');
- case LogWarning: return QLatin1Char('w');
- case LogError: return QLatin1Char('e');
- case LogInput: return QLatin1Char('<');
- case LogOutput: return QLatin1Char('>');
- case LogStatus: return QLatin1Char('s');
- case LogTime: return QLatin1Char('t');
- case LogMisc:
- default: return QLatin1Char(' ');
- }
}
-LogChannel LogWindow::channelForChar(QChar c)
+void GlobalLogWindow::doOutput(const QString &output)
{
- switch (c.unicode()) {
- case 'd': return LogDebug;
- case 'w': return LogWarning;
- case 'e': return LogError;
- case '<': return LogInput;
- case '>': return LogOutput;
- case 's': return LogStatus;
- case 't': return LogTime;
- default: return LogMisc;
+ QTextCursor cursor = m_rightPane->textCursor();
+ const bool atEnd = cursor.atEnd();
+
+ m_rightPane->append(output);
+
+ if (atEnd) {
+ cursor.movePosition(QTextCursor::End);
+ m_rightPane->setTextCursor(cursor);
+ m_rightPane->ensureCursorVisible();
}
}
+void GlobalLogWindow::doInput(const QString &input)
+{
+ if (boolSetting(LogTimeStamps))
+ m_leftPane->append(LogWindow::logTimeStamp());
+ m_leftPane->append(input);
+ QTextCursor cursor = m_leftPane->textCursor();
+ cursor.movePosition(QTextCursor::End);
+ m_leftPane->setTextCursor(cursor);
+ m_leftPane->ensureCursorVisible();
+}
+
+void GlobalLogWindow::clearContents()
+{
+ m_rightPane->clear();
+ m_leftPane->clear();
+}
+
+void GlobalLogWindow::setCursor(const QCursor &cursor)
+{
+ m_rightPane->viewport()->setCursor(cursor);
+ m_leftPane->viewport()->setCursor(cursor);
+ QWidget::setCursor(cursor);
+}
+
+void GlobalLogWindow::clearUndoRedoStacks()
+{
+ m_leftPane->clearUndoRedoStacks();
+ m_rightPane->clearUndoRedoStacks();
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/logwindow.h b/src/plugins/debugger/logwindow.h
index f5024d2014..b800837d09 100644
--- a/src/plugins/debugger/logwindow.h
+++ b/src/plugins/debugger/logwindow.h
@@ -40,6 +40,8 @@ namespace Utils { class FancyLineEdit; }
namespace Debugger {
namespace Internal {
+class DebuggerEngine;
+class DebuggerPane;
class CombinedPane;
class InputPane;
@@ -48,7 +50,10 @@ class LogWindow : public QWidget
Q_OBJECT
public:
- explicit LogWindow(QWidget *parent = nullptr);
+ explicit LogWindow(DebuggerEngine *engine);
+ ~LogWindow() final;
+
+ DebuggerEngine *engine() const;
void setCursor(const QCursor &cursor);
@@ -59,11 +64,6 @@ public:
static QString logTimeStamp();
- static bool writeLogContents(const QPlainTextEdit *editor, QWidget *parent = nullptr);
-
- static QChar charForChannel(int channel);
- static LogChannel channelForChar(QChar c);
-
void clearContents();
void sendCommand();
void executeLine();
@@ -73,7 +73,6 @@ public:
void repeatLastCommand();
signals:
- void showPage();
void statusMessageRequested(const QString &msg, int);
private:
@@ -83,6 +82,27 @@ private:
QString m_queuedOutput;
Utils::FancyLineEdit *m_commandEdit;
bool m_ignoreNextInputEcho;
+ DebuggerEngine *m_engine;
+};
+
+class GlobalLogWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit GlobalLogWindow();
+ ~GlobalLogWindow() final;
+
+ void setCursor(const QCursor &cursor);
+
+ void clearUndoRedoStacks();
+ void clearContents();
+ void doInput(const QString &input);
+ void doOutput(const QString &output);
+
+private:
+ DebuggerPane *m_rightPane; // everything
+ DebuggerPane *m_leftPane; // combined input
};
} // namespace Internal
diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp
index 1ff061bf48..981951894d 100644
--- a/src/plugins/debugger/pdb/pdbengine.cpp
+++ b/src/plugins/debugger/pdb/pdbengine.cpp
@@ -65,12 +65,11 @@ namespace Internal {
PdbEngine::PdbEngine()
{
setObjectName("PdbEngine");
+ setDebuggerName("PDB");
}
-void PdbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
+void PdbEngine::executeDebuggerCommand(const QString &command)
{
- if (!(languages & CppLanguage))
- return;
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
if (state() == DebuggerNotReady) {
showMessage("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + command);
@@ -157,7 +156,7 @@ void PdbEngine::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
showStatusMessage(tr("Running requested..."), 5000);
- attemptBreakpointSynchronization();
+ BreakpointManager::claimBreakpointsForEngine(this);
notifyEngineRunAndInferiorStopOk();
updateAll();
}
@@ -246,35 +245,44 @@ void PdbEngine::selectThread(ThreadId threadId)
Q_UNUSED(threadId)
}
-bool PdbEngine::acceptsBreakpoint(Breakpoint bp) const
+bool PdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
- const QString fileName = bp.fileName();
+ const QString fileName = bp.fileName;
return fileName.endsWith(".py");
}
-void PdbEngine::insertBreakpoint(Breakpoint bp)
+void PdbEngine::insertBreakpoint(const Breakpoint &bp)
{
- QTC_CHECK(bp.state() == BreakpointInsertRequested);
- bp.notifyBreakpointInsertProceeding();
+ QTC_ASSERT(bp, return);
+ QTC_CHECK(bp->state() == BreakpointInsertionRequested);
+ notifyBreakpointInsertProceeding(bp);
QString loc;
- if (bp.type() == BreakpointByFunction)
- loc = bp.functionName();
+ const BreakpointParameters &params = bp->requestedParameters();
+ if (params.type == BreakpointByFunction)
+ loc = params.functionName;
else
- loc = bp.fileName() + ':' + QString::number(bp.lineNumber());
+ loc = params.fileName + ':' + QString::number(params.lineNumber);
postDirectCommand("break " + loc);
}
-void PdbEngine::removeBreakpoint(Breakpoint bp)
+void PdbEngine::updateBreakpoint(const Breakpoint &bp)
{
- QTC_CHECK(bp.state() == BreakpointRemoveRequested);
- bp.notifyBreakpointRemoveProceeding();
- BreakpointResponse br = bp.response();
- showMessage(QString("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
- postDirectCommand("clear " + br.id.toString());
+ Q_UNUSED(bp);
+ QTC_CHECK(false);
+}
+
+void PdbEngine::removeBreakpoint(const Breakpoint &bp)
+{
+ QTC_ASSERT(bp, return);
+ QTC_CHECK(bp->state() == BreakpointRemoveRequested);
+ notifyBreakpointRemoveProceeding(bp);
+ showMessage(QString("DELETING BP %1 IN %2")
+ .arg(bp->responseId()).arg(bp->fileName()));
+ postDirectCommand("clear " + bp->responseId());
// Pretend it succeeds without waiting for response.
- bp.notifyBreakpointRemoveOk();
+ notifyBreakpointRemoveOk(bp);
}
void PdbEngine::loadSymbols(const QString &moduleName)
@@ -459,8 +467,8 @@ void PdbEngine::handleOutput(const QString &data)
void PdbEngine::handleOutput2(const QString &data)
{
- foreach (QString line, data.split('\n')) {
-
+ const QStringList lines = data.split('\n');
+ for (const QString &line : lines) {
GdbMi item;
item.fromString(line);
@@ -479,21 +487,25 @@ void PdbEngine::handleOutput2(const QString &data)
} else if (line.startsWith("state=")) {
refreshState(item);
} else if (line.startsWith("Breakpoint")) {
- int pos1 = line.indexOf(" at ");
+ const int pos1 = line.indexOf(" at ");
QTC_ASSERT(pos1 != -1, continue);
- QString bpnr = line.mid(11, pos1 - 11);
- int pos2 = line.lastIndexOf(':');
+ const QString bpnr = line.mid(11, pos1 - 11);
+ const int pos2 = line.lastIndexOf(':');
QTC_ASSERT(pos2 != -1, continue);
- BreakpointResponse br;
- br.id = BreakpointResponseId(bpnr);
- br.fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
- br.lineNumber = line.mid(pos2 + 1).toInt();
- Breakpoint bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
- if (bp.isValid()) {
- bp.setResponse(br);
- QTC_CHECK(!bp.needsChange());
- bp.notifyBreakpointInsertOk();
- }
+ const QString fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
+ const int lineNumber = line.mid(pos2 + 1).toInt();
+ const Breakpoint bp = Utils::findOrDefault(breakHandler()->breakpoints(), [&](const Breakpoint &bp) {
+ return bp->parameters().isLocatedAt(fileName, lineNumber, bp->markerFileName())
+ || bp->requestedParameters().isLocatedAt(fileName, lineNumber, bp->markerFileName());
+ });
+ QTC_ASSERT(bp, continue);
+ bp->setResponseId(bpnr);
+ bp->setFileName(fileName);
+ bp->setLineNumber(lineNumber);
+ bp->adjustMarker();
+ bp->setPending(false);
+ QTC_CHECK(!bp->needsChange());
+ notifyBreakpointInsertOk(bp);
}
}
}
diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h
index ccef9d1e47..09966f229e 100644
--- a/src/plugins/debugger/pdb/pdbengine.h
+++ b/src/plugins/debugger/pdb/pdbengine.h
@@ -71,13 +71,14 @@ private:
void activateFrame(int index) override;
void selectThread(ThreadId threadId) override;
- bool acceptsBreakpoint(Breakpoint bp) const override;
- void insertBreakpoint(Breakpoint bp) override;
- void removeBreakpoint(Breakpoint bp) override;
+ bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
+ void insertBreakpoint(const Breakpoint &bp) override;
+ void updateBreakpoint(const Breakpoint &bp) override;
+ void removeBreakpoint(const Breakpoint &bp) override;
void assignValueInDebugger(WatchItem *item,
const QString &expr, const QVariant &value) override;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override;
+ void executeDebuggerCommand(const QString &command) override;
void loadSymbols(const QString &moduleName) override;
void loadAllSymbols() override;
diff --git a/src/plugins/debugger/qml/qml.pri b/src/plugins/debugger/qml/qml.pri
index 7a76d64e6c..d8d2edf36f 100644
--- a/src/plugins/debugger/qml/qml.pri
+++ b/src/plugins/debugger/qml/qml.pri
@@ -1,7 +1,6 @@
HEADERS += \
$$PWD/qmlengine.h \
$$PWD/qmlengineutils.h \
- $$PWD/qmlcppengine.h \
$$PWD/interactiveinterpreter.h \
$$PWD/qmlv8debuggerclientconstants.h \
$$PWD/qmlinspectoragent.h
@@ -9,6 +8,5 @@ HEADERS += \
SOURCES += \
$$PWD/qmlengine.cpp \
$$PWD/qmlengineutils.cpp \
- $$PWD/qmlcppengine.cpp \
$$PWD/interactiveinterpreter.cpp \
$$PWD/qmlinspectoragent.cpp
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 62034f245f..8f8816ff44 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -169,10 +169,10 @@ public:
void setBreakpoint(const QString type, const QString target,
bool enabled = true,int line = 0, int column = 0,
const QString condition = QString(), int ignoreCount = -1);
- void clearBreakpoint(int breakpoint);
+ void clearBreakpoint(const Breakpoint &bp);
bool canChangeBreakpoint() const;
- void changeBreakpoint(int breakpoint, bool enabled);
+ void changeBreakpoint(const Breakpoint &bp, bool enabled);
void setExceptionBreak(Exceptions type, bool enabled = false);
@@ -204,9 +204,8 @@ public:
QHash<int, QmlV8ObjectData> refVals; // The mapping of target object handles to retrieved values.
int sequence = -1;
QmlEngine *engine;
- QHash<BreakpointModelId, int> breakpoints;
- QHash<int, BreakpointModelId> breakpointsSync;
- QList<int> breakpointsTemp;
+ QHash<int, Breakpoint> breakpointsSync;
+ QList<QString> breakpointsTemp;
LookupItems currentlyLookingUp; // Id -> inames
@@ -260,14 +259,14 @@ QmlEngine::QmlEngine()
: d(new QmlEnginePrivate(this, new QmlDebugConnection(this)))
{
setObjectName("QmlEngine");
+ setDebuggerName(tr("QML Debugger"));
+
QmlDebugConnection *connection = d->connection();
connect(stackHandler(), &StackHandler::stackChanged,
this, &QmlEngine::updateCurrentContext);
connect(stackHandler(), &StackHandler::currentIndexChanged,
this, &QmlEngine::updateCurrentContext);
- connect(inspectorView(), &WatchTreeView::currentIndexChanged,
- this, &QmlEngine::updateCurrentContext);
connect(&d->applicationLauncher, &ApplicationLauncher::processExited,
this, &QmlEngine::disconnected);
@@ -278,7 +277,7 @@ QmlEngine::QmlEngine()
debuggerConsole()->populateFileFinder();
debuggerConsole()->setScriptEvaluator([this](const QString &expr) {
- executeDebuggerCommand(expr, QmlLanguage);
+ executeDebuggerCommand(expr);
});
d->connectionTimer.setInterval(4000);
@@ -336,7 +335,7 @@ void QmlEngine::handleLauncherStarted()
{
// FIXME: The QmlEngine never calls notifyInferiorPid() triggering the
// raising, so do it here manually for now.
- runTool()->runControl()->applicationProcessHandle().activate();
+ ProcessHandle(inferiorPid()).activate();
tryToConnect();
}
@@ -347,7 +346,10 @@ void QmlEngine::appMessage(const QString &msg, Utils::OutputFormat /* format */)
void QmlEngine::connectionEstablished()
{
- attemptBreakpointSynchronization();
+ connect(inspectorView(), &WatchTreeView::currentIndexChanged,
+ this, &QmlEngine::updateCurrentContext);
+
+ BreakpointManager::claimBreakpointsForEngine(this);
if (state() == EngineRunRequested)
notifyEngineRunAndInferiorRunOk();
@@ -435,7 +437,7 @@ void QmlEngine::appStartupFailed(const QString &errorMessage)
{
QString error = tr("Could not connect to the in-process QML debugger. %1").arg(errorMessage);
- if (isMasterEngine()) {
+ if (companionEngine()) {
auto infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(Core::Constants::IDE_DISPLAY_NAME);
@@ -522,7 +524,8 @@ void QmlEngine::runEngine()
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
- if (!isSlaveEngine()) {
+ if (isPrimaryEngine()) {
+ // QML only.
if (runParameters().startMode == AttachToRemoteServer)
tryToConnect();
else if (runParameters().startMode == AttachToRemoteProcess)
@@ -538,10 +541,9 @@ void QmlEngine::startApplicationLauncher()
{
if (!d->applicationLauncher.isRunning()) {
const Runnable runnable = runParameters().inferior;
- runTool()->appendMessage(tr("Starting %1 %2").arg(
- QDir::toNativeSeparators(runnable.executable),
- runnable.commandLineArguments),
- Utils::NormalMessageFormat);
+ showMessage(tr("Starting %1 %2").arg(QDir::toNativeSeparators(runnable.executable),
+ runnable.commandLineArguments),
+ Utils::NormalMessageFormat);
d->applicationLauncher.start(runnable);
}
}
@@ -565,8 +567,7 @@ void QmlEngine::shutdownInferior()
// }
d->runCommand({DISCONNECT});
- if (isSlaveEngine())
- resetLocation();
+ resetLocation();
stopApplicationLauncher();
closeConnection();
@@ -583,8 +584,7 @@ void QmlEngine::shutdownEngine()
stopApplicationLauncher();
notifyEngineShutdownFinished();
- if (!isSlaveEngine())
- showMessage(QString(), StatusBar);
+ showMessage(QString(), StatusBar);
}
void QmlEngine::setupEngine()
@@ -689,34 +689,31 @@ void QmlEngine::selectThread(ThreadId threadId)
Q_UNUSED(threadId)
}
-void QmlEngine::insertBreakpoint(Breakpoint bp)
+void QmlEngine::insertBreakpoint(const Breakpoint &bp)
{
- BreakpointState state = bp.state();
- QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << bp << this << state);
- bp.notifyBreakpointInsertProceeding();
+ QTC_ASSERT(bp, return);
+ const BreakpointState state = bp->state();
+ QTC_ASSERT(state == BreakpointInsertionRequested, qDebug() << bp << this << state);
+ notifyBreakpointInsertProceeding(bp);
- const BreakpointParameters &params = bp.parameters();
- if (params.type == BreakpointAtJavaScriptThrow) {
- BreakpointResponse br = bp.response();
- br.pending = false;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
- d->setExceptionBreak(AllExceptions, params.enabled);
+ const BreakpointParameters &requested = bp->requestedParameters();
+ if (requested.type == BreakpointAtJavaScriptThrow) {
+ bp->setPending(false);
+ notifyBreakpointInsertOk(bp);
+ d->setExceptionBreak(AllExceptions, requested.enabled);
- } else if (params.type == BreakpointByFileAndLine) {
- d->setBreakpoint(SCRIPTREGEXP, params.fileName,
- params.enabled, params.lineNumber, 0,
- params.condition, params.ignoreCount);
+ } else if (requested.type == BreakpointByFileAndLine) {
+ d->setBreakpoint(SCRIPTREGEXP, requested.fileName,
+ requested.enabled, requested.lineNumber, 0,
+ requested.condition, requested.ignoreCount);
- } else if (params.type == BreakpointOnQmlSignalEmit) {
- d->setBreakpoint(EVENT, params.functionName, params.enabled);
- BreakpointResponse br = bp.response();
- br.pending = false;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
+ } else if (requested.type == BreakpointOnQmlSignalEmit) {
+ d->setBreakpoint(EVENT, requested.functionName, requested.enabled);
+ bp->setPending(false);
+ notifyBreakpointInsertOk(bp);
}
- d->breakpointsSync.insert(d->sequence, bp.id());
+ d->breakpointsSync.insert(d->sequence, bp);
}
void QmlEngine::resetLocation()
@@ -725,114 +722,64 @@ void QmlEngine::resetLocation()
d->currentlyLookingUp.clear();
}
-void QmlEngine::removeBreakpoint(Breakpoint bp)
+void QmlEngine::removeBreakpoint(const Breakpoint &bp)
{
- const BreakpointParameters &params = bp.parameters();
+ QTC_ASSERT(bp, return);
+ const BreakpointParameters &params = bp->requestedParameters();
- BreakpointState state = bp.state();
+ const BreakpointState state = bp->state();
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << bp << this << state);
- bp.notifyBreakpointRemoveProceeding();
-
- int breakpoint = d->breakpoints.value(bp.id());
- d->breakpoints.remove(bp.id());
+ notifyBreakpointRemoveProceeding(bp);
if (params.type == BreakpointAtJavaScriptThrow)
d->setExceptionBreak(AllExceptions);
else if (params.type == BreakpointOnQmlSignalEmit)
d->setBreakpoint(EVENT, params.functionName, false);
else
- d->clearBreakpoint(breakpoint);
+ d->clearBreakpoint(bp);
- if (bp.state() == BreakpointRemoveProceeding)
- bp.notifyBreakpointRemoveOk();
+ if (bp->state() == BreakpointRemoveProceeding)
+ notifyBreakpointRemoveOk(bp);
}
-void QmlEngine::changeBreakpoint(Breakpoint bp)
+void QmlEngine::updateBreakpoint(const Breakpoint &bp)
{
- BreakpointState state = bp.state();
- QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << bp << this << state);
- bp.notifyBreakpointChangeProceeding();
+ QTC_ASSERT(bp, return);
+ const BreakpointState state = bp->state();
+ QTC_ASSERT(state == BreakpointUpdateRequested, qDebug() << bp << this << state);
+ notifyBreakpointChangeProceeding(bp);
- const BreakpointParameters &params = bp.parameters();
+ const BreakpointParameters &requested = bp->requestedParameters();
- BreakpointResponse br = bp.response();
- if (params.type == BreakpointAtJavaScriptThrow) {
- d->setExceptionBreak(AllExceptions, params.enabled);
- } else if (params.type == BreakpointOnQmlSignalEmit) {
- d->setBreakpoint(EVENT, params.functionName, params.enabled);
+ if (requested.type == BreakpointAtJavaScriptThrow) {
+ d->setExceptionBreak(AllExceptions, requested.enabled);
+ bp->setEnabled(requested.enabled);
+ } else if (requested.type == BreakpointOnQmlSignalEmit) {
+ d->setBreakpoint(EVENT, requested.functionName, requested.enabled);
+ bp->setEnabled(requested.enabled);
} else if (d->canChangeBreakpoint()) {
- d->changeBreakpoint(d->breakpoints.value(bp.id()), params.enabled);
+ d->changeBreakpoint(bp, requested.enabled);
} else {
- d->clearBreakpoint(d->breakpoints.take(bp.id()));
- d->setBreakpoint(SCRIPTREGEXP, params.fileName,
- params.enabled, params.lineNumber, 0,
- params.condition, params.ignoreCount);
- d->breakpointsSync.insert(d->sequence, bp.id());
+ d->clearBreakpoint(bp);
+ d->setBreakpoint(SCRIPTREGEXP, requested.fileName,
+ requested.enabled, requested.lineNumber, 0,
+ requested.condition, requested.ignoreCount);
+ d->breakpointsSync.insert(d->sequence, bp);
}
- br.enabled = params.enabled;
- bp.setResponse(br);
- if (bp.state() == BreakpointChangeProceeding)
- bp.notifyBreakpointChangeOk();
+ if (bp->state() == BreakpointUpdateProceeding)
+ notifyBreakpointChangeOk(bp);
}
-void QmlEngine::attemptBreakpointSynchronization()
+bool QmlEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
- if (!stateAcceptsBreakpointChanges()) {
- showMessage("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE");
- return;
- }
-
- BreakHandler *handler = breakHandler();
-
- DebuggerEngine *bpOwner = masterEngine();
- for (Breakpoint bp : handler->unclaimedBreakpoints()) {
- // Take ownership of the breakpoint. Requests insertion.
- if (acceptsBreakpoint(bp))
- bp.setEngine(bpOwner);
- }
-
- for (Breakpoint bp : handler->engineBreakpoints(bpOwner)) {
- switch (bp.state()) {
- case BreakpointNew:
- // Should not happen once claimed.
- QTC_CHECK(false);
- continue;
- case BreakpointInsertRequested:
- insertBreakpoint(bp);
- continue;
- case BreakpointChangeRequested:
- changeBreakpoint(bp);
- continue;
- case BreakpointRemoveRequested:
- removeBreakpoint(bp);
- continue;
- case BreakpointChangeProceeding:
- case BreakpointInsertProceeding:
- case BreakpointRemoveProceeding:
- case BreakpointInserted:
- case BreakpointDead:
- continue;
- }
- QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bp << state());
- }
-
- DebuggerEngine::attemptBreakpointSynchronization();
-}
-
-bool QmlEngine::acceptsBreakpoint(Breakpoint bp) const
-{
- if (!bp.parameters().isCppBreakpoint())
- return true;
-
- //If it is a Cpp Breakpoint query if the type can be also handled by the debugger client
//TODO: enable setting of breakpoints before start of debug session
//For now, the event breakpoint can be set after the activeDebuggerClient is known
//This is because the older client does not support BreakpointOnQmlSignalHandler
- BreakpointType type = bp.type();
- return type == BreakpointOnQmlSignalEmit
- || type == BreakpointByFileAndLine
- || type == BreakpointAtJavaScriptThrow;
+ if (bp.type == BreakpointOnQmlSignalEmit || bp.type == BreakpointAtJavaScriptThrow)
+ return true;
+
+ return bp.isQmlFileAndLineBreakpoint();
}
void QmlEngine::loadSymbols(const QString &moduleName)
@@ -1041,6 +988,11 @@ void QmlEngine::doUpdateLocals(const UpdateParameters &params)
d->updateLocals();
}
+Context QmlEngine::languageContext() const
+{
+ return Context(Constants::C_QMLDEBUGGER);
+}
+
void QmlEngine::disconnected()
{
showMessage(tr("QML Debugger disconnected."), StatusBar);
@@ -1084,11 +1036,8 @@ void QmlEngine::updateCurrentContext()
+ (context.isEmpty() ? tr("Global QML Context") : context));
}
-void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages languages)
+void QmlEngine::executeDebuggerCommand(const QString &command)
{
- if (!(languages & QmlLanguage))
- return;
-
if (state() == InferiorStopOk) {
StackHandler *handler = stackHandler();
if (handler->isContentsValid() && handler->currentFrame().isUsable()) {
@@ -1116,6 +1065,16 @@ void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages
}
}
+bool QmlEngine::companionPreventsActions() const
+{
+ // We need a C++ Engine in a Running state to do anything sensible
+ // as otherwise the debugger services in the debuggee are unresponsive.
+ if (DebuggerEngine *companion = companionEngine())
+ return companion->state() != InferiorRunOk;
+
+ return false;
+}
+
void QmlEnginePrivate::updateScriptSource(const QString &fileName, int lineOffset, int columnOffset,
const QString &source)
{
@@ -1181,11 +1140,8 @@ void QmlEngine::connectionFailed()
// this is only an error if we are already connected and something goes wrong.
if (isConnected()) {
showMessage(tr("QML Debugger: Connection failed."), StatusBar);
-
- if (!isSlaveEngine()) { // normal flow for slave engine when gdb exits
- notifyInferiorSpontaneousStop();
- notifyInferiorIll();
- }
+ notifyInferiorSpontaneousStop();
+ notifyInferiorIll();
} else {
d->connectionTimer.stop();
connectionStartupFailed();
@@ -1492,7 +1448,7 @@ void QmlEnginePrivate::setBreakpoint(const QString type, const QString target,
}
}
-void QmlEnginePrivate::clearBreakpoint(int breakpoint)
+void QmlEnginePrivate::clearBreakpoint(const Breakpoint &bp)
{
// { "seq" : <number>,
// "type" : "request",
@@ -1502,7 +1458,7 @@ void QmlEnginePrivate::clearBreakpoint(int breakpoint)
// }
DebuggerCommand cmd(CLEARBREAKPOINT);
- cmd.arg(BREAKPOINT, breakpoint);
+ cmd.arg(BREAKPOINT, bp->responseId().toInt());
runCommand(cmd);
}
@@ -1511,10 +1467,10 @@ bool QmlEnginePrivate::canChangeBreakpoint() const
return supportChangeBreakpoint;
}
-void QmlEnginePrivate::changeBreakpoint(int breakpoint, bool enabled)
+void QmlEnginePrivate::changeBreakpoint(const Breakpoint &bp, bool enabled)
{
DebuggerCommand cmd(CHANGEBREAKPOINT);
- cmd.arg(BREAKPOINT, breakpoint);
+ cmd.arg(BREAKPOINT, bp->responseId().toInt());
cmd.arg(ENABLED, enabled);
runCommand(cmd);
}
@@ -1780,27 +1736,26 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
int seq = resp.value("request_seq").toInt();
const QVariantMap breakpointData = resp.value(BODY).toMap();
- int index = breakpointData.value("breakpoint").toInt();
+ const QString index = QString::number(breakpointData.value("breakpoint").toInt());
if (breakpointsSync.contains(seq)) {
- BreakpointModelId id = breakpointsSync.take(seq);
- breakpoints.insert(id, index);
+ Breakpoint bp = breakpointsSync.take(seq);
+ QTC_ASSERT(bp, return);
+ bp->setParameters(bp->requestedParameters()); // Assume it worked.
+ bp->setResponseId(index);
//Is actual position info present? Then breakpoint was
//accepted
const QVariantList actualLocations =
breakpointData.value("actual_locations").toList();
+ const int line = breakpointData.value("line").toInt() + 1;
if (actualLocations.count()) {
//The breakpoint requested line should be same as
//actual line
- BreakHandler *handler = engine->breakHandler();
- Breakpoint bp = handler->breakpointById(id);
- if (bp.state() != BreakpointInserted) {
- BreakpointResponse br = bp.response();
- br.lineNumber = breakpointData.value("line").toInt() + 1;
- br.pending = false;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
+ if (bp && bp->state() != BreakpointInserted) {
+ bp->setLineNumber(line);
+ bp->setPending(false);
+ engine->notifyBreakpointInsertOk(bp);
}
}
@@ -1900,14 +1855,18 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
bool inferiorStop = true;
- QList<int> v8BreakpointIds;
- {
- const QVariantList v8BreakpointIdList = breakData.value("breakpoints").toList();
- for (const QVariant &breakpointId : v8BreakpointIdList)
- v8BreakpointIds << breakpointId.toInt();
+ QList<Breakpoint> v8Breakpoints;
+
+ const QVariantList v8BreakpointIdList = breakData.value("breakpoints").toList();
+ for (const QVariant &breakpointId : v8BreakpointIdList) {
+ const QString x = breakpointId.toString();
+ const QString responseId = QString::number(breakpointId.toInt());
+ Breakpoint bp = engine->breakHandler()->findBreakpointByResponseId(responseId);
+ QTC_ASSERT(bp, continue);
+ v8Breakpoints << bp;
}
- if (!v8BreakpointIds.isEmpty() && invocationText.startsWith("[anonymous]()")
+ if (!v8Breakpoints.isEmpty() && invocationText.startsWith("[anonymous]()")
&& scriptUrl.endsWith(".qml")
&& sourceLineText.trimmed().startsWith('(')) {
@@ -1915,24 +1874,20 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
// -> relocate the breakpoint to column: 1 and continue
int newColumn = sourceLineText.indexOf('(') + 1;
- BreakHandler *handler = engine->breakHandler();
-
- for (int v8Id : v8BreakpointIds) {
- const BreakpointModelId id = breakpoints.key(v8Id);
- Breakpoint bp = handler->breakpointById(id);
- if (bp.isValid()) {
- const BreakpointParameters &params = bp.parameters();
-
- clearBreakpoint(v8Id);
- setBreakpoint(SCRIPTREGEXP,
- params.fileName,
- params.enabled,
- params.lineNumber,
- newColumn,
- params.condition,
- params.ignoreCount);
- breakpointsSync.insert(sequence, id);
- }
+
+ for (const Breakpoint &bp : v8Breakpoints) {
+ QTC_ASSERT(bp, continue);
+ const BreakpointParameters &params = bp->requestedParameters();
+
+ clearBreakpoint(bp);
+ setBreakpoint(SCRIPTREGEXP,
+ params.fileName,
+ params.enabled,
+ params.lineNumber,
+ newColumn,
+ params.condition,
+ params.ignoreCount);
+ breakpointsSync.insert(sequence, bp);
}
continueDebugging(Continue);
inferiorStop = false;
@@ -1946,29 +1901,23 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
if (inferiorStop) {
//Update breakpoint data
- BreakHandler *handler = engine->breakHandler();
- for (int v8Id : v8BreakpointIds) {
- const BreakpointModelId id = breakpoints.key(v8Id);
- Breakpoint bp = handler->breakpointById(id);
- if (bp) {
- BreakpointResponse br = bp.response();
- if (br.functionName.isEmpty()) {
- br.functionName = invocationText;
- bp.setResponse(br);
- }
- if (bp.state() != BreakpointInserted) {
- br.lineNumber = breakData.value("sourceLine").toInt() + 1;
- br.pending = false;
- bp.setResponse(br);
- bp.notifyBreakpointInsertOk();
- }
+ for (const Breakpoint &bp : v8Breakpoints) {
+ QTC_ASSERT(bp, continue);
+ if (bp->functionName().isEmpty()) {
+ bp->setFunctionName(invocationText);
+ }
+ if (bp->state() != BreakpointInserted) {
+ bp->setLineNumber(breakData.value("sourceLine").toInt() + 1);
+ bp->setPending(false);
+ engine->notifyBreakpointInsertOk(bp);
}
}
if (engine->state() == InferiorRunOk) {
- for (const QVariant &breakpointId : v8BreakpointIds) {
- if (breakpointsTemp.contains(breakpointId.toInt()))
- clearBreakpoint(breakpointId.toInt());
+ for (const Breakpoint &bp : v8Breakpoints) {
+ QTC_ASSERT(bp, continue);
+ if (breakpointsTemp.contains(bp->responseId()))
+ clearBreakpoint(bp);
}
engine->notifyInferiorSpontaneousStop();
backtrace();
diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h
index bdd6b2d64c..76b0452c16 100644
--- a/src/plugins/debugger/qml/qmlengine.h
+++ b/src/plugins/debugger/qml/qmlengine.h
@@ -34,7 +34,6 @@
namespace Debugger {
namespace Internal {
-class WatchItem;
class QmlEnginePrivate;
class QmlInspectorAgent;
@@ -68,7 +67,6 @@ private:
void setState(DebuggerState state, bool forced) override;
void gotoLocation(const Internal::Location &location) override;
- void insertBreakpoint(Breakpoint bp) override;
bool canDisplayTooltip() const override { return false; }
@@ -97,10 +95,10 @@ private:
void activateFrame(int index) override;
void selectThread(ThreadId threadId) override;
- void attemptBreakpointSynchronization() override;
- void removeBreakpoint(Breakpoint bp) override;
- void changeBreakpoint(Breakpoint bp) override;
- bool acceptsBreakpoint(Breakpoint bp) const override;
+ bool acceptsBreakpoint(const BreakpointParameters &bp) const final;
+ void insertBreakpoint(const Breakpoint &bp) final;
+ void removeBreakpoint(const Breakpoint &bp) final;
+ void updateBreakpoint(const Breakpoint &bp) final;
void assignValueInDebugger(WatchItem *item,
const QString &expr, const QVariant &value) override;
@@ -117,12 +115,14 @@ private:
void updateItem(const QString &iname) override;
void expandItem(const QString &iname) override;
void selectWatchData(const QString &iname) override;
- void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override;
+ void executeDebuggerCommand(const QString &command) override;
+ bool companionPreventsActions() const override;
bool hasCapability(unsigned) const override;
void quitDebugger() override;
void doUpdateLocals(const UpdateParameters &params) override;
+ Core::Context languageContext() const override;
void closeConnection();
void startApplicationLauncher();
@@ -135,7 +135,6 @@ private:
bool isConnected() const;
private:
- friend class QmlCppEngine;
friend class QmlEnginePrivate;
friend class QmlInspectorAgent;
QmlEnginePrivate *d;
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp
index 3057a753e0..de47d33eff 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp
@@ -67,7 +67,8 @@ Q_LOGGING_CATEGORY(qmlInspectorLog, "qtc.dbg.qmlinspector")
QmlInspectorAgent::QmlInspectorAgent(QmlEngine *engine, QmlDebugConnection *connection)
: m_qmlEngine(engine)
, m_objectToSelect(WatchItem::InvalidId)
- , m_masterEngine(engine->masterEngine())
+ , m_toolsClient(nullptr)
+ , m_targetToSync(NoTarget)
, m_debugIdToSelect(WatchItem::InvalidId)
, m_currentSelectedDebugId(WatchItem::InvalidId)
, m_inspectorToolsContext("Debugger.QmlInspector")
@@ -786,7 +787,7 @@ void QmlInspectorAgent::toolsClientStateChanged(QmlDebugClient::State state)
Core::ICore::addAdditionalContext(m_inspectorToolsContext);
m_toolsClientConnected = true;
- enableTools(m_masterEngine->state() == InferiorRunOk);
+ enableTools(m_qmlEngine->state() == InferiorRunOk);
if (m_showAppOnTopAction->isChecked())
m_toolsClient->showAppOnTop(true);
@@ -901,7 +902,7 @@ void QmlInspectorAgent::setActiveEngineClient(BaseEngineDebugClient *client)
void QmlInspectorAgent::jumpToObjectDefinitionInEditor(
const FileReference &objSource, int debugId)
{
- const QString fileName = m_masterEngine->toFileInProject(objSource.url());
+ const QString fileName = m_qmlEngine->toFileInProject(objSource.url());
Core::EditorManager::openEditorAt(fileName, objSource.lineNumber());
if (debugId != WatchItem::InvalidId && debugId != m_currentSelectedDebugId) {
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.h b/src/plugins/debugger/qml/qmlinspectoragent.h
index 4d76c5f2a8..516bcf6c62 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.h
+++ b/src/plugins/debugger/qml/qmlinspectoragent.h
@@ -134,7 +134,6 @@ private:
QList<int> m_fetchDataIds;
QTimer m_delayQueryTimer;
- DebuggerEngine *m_masterEngine;
QHash<QString, QmlDebug::BaseEngineDebugClient*> m_engineClients;
QmlDebug::BaseToolsClient *m_toolsClient = nullptr;
diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp
index 1ee023aa31..c3be1132d8 100644
--- a/src/plugins/debugger/registerhandler.cpp
+++ b/src/plugins/debugger/registerhandler.cpp
@@ -676,8 +676,8 @@ bool RegisterHandler::setData(const QModelIndex &idx, const QVariant &data, int
bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
{
- const bool actionsEnabled = m_engine->debuggerActionsEnabled();
const DebuggerState state = m_engine->state();
+ const bool actionsEnabled = m_engine->debuggerActionsEnabled();
RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.index());
RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.index());
diff --git a/src/plugins/debugger/snapshothandler.cpp b/src/plugins/debugger/snapshothandler.cpp
index 21dcaf9d1e..619a3f5fdd 100644
--- a/src/plugins/debugger/snapshothandler.cpp
+++ b/src/plugins/debugger/snapshothandler.cpp
@@ -25,15 +25,28 @@
#include "snapshothandler.h"
+#include "analyzer/analyzermanager.h"
+#include "debuggeractions.h"
#include "debuggerinternalconstants.h"
#include "debuggericons.h"
#include "debuggercore.h"
#include "debuggerruncontrol.h"
+#include "stackhandler.h"
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+
+#include <utils/basetreeview.h>
+#include <utils/treemodel.h>
#include <utils/qtcassert.h>
#include <QDebug>
-#include <QFile>
+#include <QMenu>
+#include <QTimer>
+
+using namespace Core;
+using namespace Utils;
namespace Debugger {
namespace Internal {
@@ -102,177 +115,300 @@ QDebug operator<<(QDebug d, const SnapshotData &f)
}
#endif
+class EngineItem : public QObject, public TreeItem
+{
+public:
+ QVariant data(int column, int role) const final;
+ bool setData(int row, const QVariant &data, int role) final;
+
+ const bool m_isPreset = false;
+ QPointer<DebuggerEngine> m_engine;
+};
+
+class EngineManagerPrivate : public QObject
+{
+public:
+ EngineManagerPrivate()
+ {
+ m_engineModel.setHeader({EngineManager::tr("Name"), EngineManager::tr("File")});
+ m_engineModel.rootItem()->appendChild(new EngineItem); // The preset case.
+
+ m_engineChooser = new QComboBox;
+ m_engineChooser->setVisible(false);
+ m_engineChooser->setModel(&m_engineModel);
+ connect(m_engineChooser, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
+ this, &EngineManagerPrivate::activateEngineByIndex);
+ }
+
+ ~EngineManagerPrivate()
+ {
+ delete m_engineChooser;
+ }
+
+ EngineItem *findEngineItem(DebuggerEngine *engine);
+ void activateEngine(DebuggerEngine *engine);
+ void activateEngineItem(EngineItem *engineItem);
+ void activateEngineByIndex(int index);
+ void selectUiForCurrentEngine();
+ void updateEngineChooserVisibility();
+
+ TreeModel<TypedTreeItem<EngineItem>, EngineItem> m_engineModel;
+ QPointer<EngineItem> m_currentItem;
+ Core::Id m_previousMode;
+ QPointer<QComboBox> m_engineChooser;
+};
+
////////////////////////////////////////////////////////////////////////
//
-// SnapshotHandler
+// EngineManager
//
////////////////////////////////////////////////////////////////////////
/*!
- \class Debugger::Internal::SnapshotHandler
- \brief The SnapshotHandler class provides a model to represent the
- snapshots in a QTreeView.
-
- A snapshot represents a debugging session.
+ \class Debugger::Internal::EngineManager
+ \brief The EngineManager manages running debugger engines.
*/
-SnapshotHandler::SnapshotHandler() = default;
+static EngineManager *theEngineManager = nullptr;
+static EngineManagerPrivate *d = nullptr;
-SnapshotHandler::~SnapshotHandler()
+EngineManager::EngineManager()
{
- for (int i = m_snapshots.size(); --i >= 0; ) {
- if (DebuggerRunTool *runTool = at(i)) {
- const DebuggerRunParameters &rp = runTool->runParameters();
- if (rp.isSnapshot && !rp.coreFile.isEmpty())
- QFile::remove(rp.coreFile);
- }
- }
+ theEngineManager = this;
+ d = new EngineManagerPrivate;
}
-int SnapshotHandler::rowCount(const QModelIndex &parent) const
+QWidget *EngineManager::engineChooser()
{
- // Since the stack is not a tree, row count is 0 for any valid parent
- return parent.isValid() ? 0 : m_snapshots.size();
+ return d->m_engineChooser;
}
-int SnapshotHandler::columnCount(const QModelIndex &parent) const
+EngineManager::~EngineManager()
{
- return parent.isValid() ? 0 : 2;
+ theEngineManager = nullptr;
+ delete d;
}
-QVariant SnapshotHandler::data(const QModelIndex &index, int role) const
+EngineManager *EngineManager::instance()
{
- if (!index.isValid() || index.row() >= m_snapshots.size())
- return QVariant();
+ return theEngineManager;
+}
- const DebuggerRunTool *runTool = at(index.row());
+QAbstractItemModel *EngineManager::model()
+{
+ return &d->m_engineModel;
+}
- if (role == SnapshotCapabilityRole)
- return runTool && runTool->activeEngine()->hasCapability(SnapshotCapability);
+void EngineManager::activateEngine(DebuggerEngine *engine)
+{
+ d->activateEngine(engine);
+}
- if (!runTool)
- return QLatin1String("<finished>");
+QVariant EngineItem::data(int column, int role) const
+{
+ if (m_engine) {
+ if (role == SnapshotCapabilityRole)
+ return m_engine->hasCapability(SnapshotCapability);
+
+ const DebuggerRunParameters &rp = m_engine->runParameters();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (column) {
+ case 0:
+ return m_engine->displayName();
+ case 1:
+ return rp.coreFile.isEmpty() ? rp.inferior.executable : rp.coreFile;
+ }
+ return QVariant();
+
+ case Qt::ToolTipRole:
+ return QVariant();
+
+ case Qt::DecorationRole:
+ // Return icon that indicates whether this is the active engine
+ if (column == 0)
+ return d->m_currentItem == this ? Icons::LOCATION.icon() : Icons::EMPTY.icon();
+
+ default:
+ break;
+ }
+ } else {
+ switch (role) {
+ case Qt::DisplayRole:
+ return EngineManager::tr("Debugger Preset");
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
- const DebuggerRunParameters &rp = runTool->runParameters();
+bool EngineItem::setData(int row, const QVariant &value, int role)
+{
+ Q_UNUSED(row);
+ if (!m_engine)
+ return false;
+
+ if (role == BaseTreeView::ItemActivatedRole) {
+ EngineItem *engineItem = d->findEngineItem(m_engine);
+ d->activateEngineItem(engineItem);
+ return true;
+ }
- switch (role) {
- case Qt::DisplayRole:
- switch (index.column()) {
- case 0:
- return rp.displayName;
- case 1:
- return rp.coreFile.isEmpty() ? rp.inferior.executable : rp.coreFile;
- }
- return QVariant();
+ if (role == BaseTreeView::ItemViewEventRole) {
+ ItemViewEvent ev = value.value<ItemViewEvent>();
+
+ if (auto cmev = ev.as<QContextMenuEvent>()) {
- case Qt::ToolTipRole:
- return QVariant();
+ auto menu = new QMenu(ev.view());
- case Qt::DecorationRole:
- // Return icon that indicates whether this is the active stack frame.
- if (index.column() == 0)
- return (index.row() == m_currentIndex) ? Icons::LOCATION.icon() : Icons::EMPTY.icon();
+ QAction *actCreate = menu->addAction(tr("Create Snapshot"));
+ actCreate->setEnabled(m_engine->hasCapability(SnapshotCapabilityRole));
+ menu->addSeparator();
- default:
- break;
+ QAction *actRemove = menu->addAction(tr("Abort Debugger"));
+ actRemove->setEnabled(true);
+
+ QAction *act = menu->exec(cmev->globalPos());
+
+ if (act == actCreate && m_engine)
+ m_engine->createSnapshot();
+ else if (act == actRemove && m_engine)
+ m_engine->quitDebugger();
+
+ return true;
+ }
+
+ if (auto kev = ev.as<QKeyEvent>(QEvent::KeyPress)) {
+ if (kev->key() == Qt::Key_Delete && m_engine) {
+ m_engine->quitDebugger();
+ } else if (kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Enter) {
+ d->activateEngineByIndex(row);
+ }
+ return true;
+ }
}
- return QVariant();
+
+ return false;
}
-QVariant SnapshotHandler::headerData(int section, Qt::Orientation orientation, int role) const
+void EngineManagerPrivate::activateEngineByIndex(int index)
{
- if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
- switch (section) {
- case 0: return tr("Name");
- case 1: return tr("File");
- };
+ activateEngineItem(m_engineModel.rootItem()->childAt(index));
+}
+
+void EngineManagerPrivate::activateEngineItem(EngineItem *engineItem)
+{
+ if (m_currentItem) {
+ if (DebuggerEngine *engine = m_currentItem->m_engine) {
+ const Context context = engine->languageContext();
+ ICore::removeAdditionalContext(context);
+ }
}
- return QVariant();
+
+ m_currentItem = engineItem;
+
+ if (m_currentItem) {
+ if (DebuggerEngine *engine = m_currentItem->m_engine) {
+ const Context context = engine->languageContext();
+ ICore::addAdditionalContext(context);
+ engine->gotoCurrentLocation();
+ }
+ }
+
+ selectUiForCurrentEngine();
}
-Qt::ItemFlags SnapshotHandler::flags(const QModelIndex &index) const
+void EngineManagerPrivate::selectUiForCurrentEngine()
{
- if (index.row() >= m_snapshots.size())
- return nullptr;
- if (index.row() == m_snapshots.size())
- return QAbstractTableModel::flags(index);
- return true ? QAbstractTableModel::flags(index) : Qt::ItemFlags({});
+ Perspective *perspective = nullptr;
+ int row = 0;
+
+ if (m_currentItem && m_currentItem->m_engine) {
+ perspective = m_currentItem->m_engine->perspective();
+ row = m_engineModel.rootItem()->indexOf(m_currentItem);
+ }
+
+ m_engineChooser->setCurrentIndex(row);
+
+ if (perspective)
+ perspective->select();
+ else
+ selectPerspective(Debugger::Constants::PRESET_PERSPRECTIVE_ID);
+
+ m_engineModel.rootItem()->forFirstLevelChildren([this](EngineItem *engineItem) {
+ if (engineItem && engineItem->m_engine)
+ engineItem->m_engine->updateMarkers();
+ });
+
+ emit theEngineManager->currentEngineChanged();
}
-void SnapshotHandler::activateSnapshot(int index)
+void EngineManager::selectUiForCurrentEngine()
{
- beginResetModel();
- m_currentIndex = index;
- //qDebug() << "ACTIVATING INDEX: " << m_currentIndex << " OF " << size();
- Internal::displayDebugger(at(index));
- endResetModel();
+ d->selectUiForCurrentEngine();
}
-void SnapshotHandler::createSnapshot(int index)
+EngineItem *EngineManagerPrivate::findEngineItem(DebuggerEngine *engine)
{
- DebuggerRunTool *runTool = at(index);
- QTC_ASSERT(runTool, return);
- runTool->engine()->createSnapshot();
+ return m_engineModel.rootItem()->findFirstLevelChild([engine](EngineItem *engineItem) {
+ return engineItem->m_engine == engine;
+ });
}
-void SnapshotHandler::removeSnapshot(int index)
+void EngineManagerPrivate::activateEngine(DebuggerEngine *engine)
{
- DebuggerRunTool *runTool = at(index);
- //qDebug() << "REMOVING " << runTool;
- QTC_ASSERT(runTool, return);
-#if 0
- // See http://sourceware.org/bugzilla/show_bug.cgi?id=11241.
- setState(EngineSetupRequested);
- postCommand("set stack-cache off");
-#endif
- //QString fileName = runTool->startParameters().coreFile;
- //if (!fileName.isEmpty())
- // QFile::remove(fileName);
- beginResetModel();
- m_snapshots.removeAt(index);
- if (index == m_currentIndex)
- m_currentIndex = -1;
- else if (index < m_currentIndex)
- --m_currentIndex;
- //runTool->quitDebugger();
- endResetModel();
+ EngineItem *engineItem = findEngineItem(engine);
+ activateEngineItem(engineItem);
}
+void EngineManagerPrivate::updateEngineChooserVisibility()
+{
+ // Show it if there's more than one option (i.e. not the the preset engine only)
+ const int count = m_engineModel.rootItem()->childCount();
+ m_engineChooser->setVisible(count >= 2);
+}
-void SnapshotHandler::removeAll()
+void EngineManager::registerEngine(DebuggerEngine *engine)
{
- beginResetModel();
- m_snapshots.clear();
- m_currentIndex = -1;
- endResetModel();
+ auto engineItem = new EngineItem;
+ engineItem->m_engine = engine;
+ d->m_engineModel.rootItem()->appendChild(engineItem);
+ d->updateEngineChooserVisibility();
}
-void SnapshotHandler::appendSnapshot(DebuggerRunTool *runTool)
+void EngineManager::activateDebugMode()
{
- beginResetModel();
- m_snapshots.append(runTool);
- m_currentIndex = size() - 1;
- endResetModel();
+ if (ModeManager::currentModeId() != Constants::MODE_DEBUG) {
+ d->m_previousMode = ModeManager::currentModeId();
+ ModeManager::activateMode(Constants::MODE_DEBUG);
+ }
}
-void SnapshotHandler::removeSnapshot(DebuggerRunTool *runTool)
+void EngineManager::unregisterEngine(DebuggerEngine *engine)
{
// Could be that the run controls died before it was appended.
- int index = m_snapshots.indexOf(runTool);
- if (index != -1)
- removeSnapshot(index);
+ if (auto engineItem = d->findEngineItem(engine))
+ d->m_engineModel.destroyItem(engineItem);
+
+ d->updateEngineChooserVisibility();
+ emit theEngineManager->currentEngineChanged();
}
-void SnapshotHandler::setCurrentIndex(int index)
+QList<QPointer<DebuggerEngine>> EngineManager::engines()
{
- beginResetModel();
- m_currentIndex = index;
- endResetModel();
+ QList<QPointer<DebuggerEngine>> result;
+ d->m_engineModel.forItemsAtLevel<1>([&result](EngineItem *engineItem) {
+ if (DebuggerEngine *engine = engineItem->m_engine)
+ result.append(engine);
+ });
+ return result;
}
-DebuggerRunTool *SnapshotHandler::at(int i) const
+QPointer<DebuggerEngine> EngineManager::currentEngine()
{
- return m_snapshots.at(i).data();
+ return d->m_currentItem ? d->m_currentItem->m_engine : nullptr;
}
} // namespace Internal
diff --git a/src/plugins/debugger/snapshothandler.h b/src/plugins/debugger/snapshothandler.h
index 6b93b20e32..080d4dfbe1 100644
--- a/src/plugins/debugger/snapshothandler.h
+++ b/src/plugins/debugger/snapshothandler.h
@@ -25,47 +25,43 @@
#pragma once
+#include <utils/treemodel.h>
+
#include <QAbstractTableModel>
+#include <QComboBox>
#include <QPointer>
namespace Debugger {
-
-class DebuggerRunTool;
-
namespace Internal {
-class SnapshotHandler : public QAbstractTableModel
+class DebuggerEngine;
+
+class EngineManager : public QObject
{
Q_OBJECT
public:
- explicit SnapshotHandler();
- ~SnapshotHandler() override;
+ explicit EngineManager();
+ ~EngineManager() final;
+
+ static EngineManager *instance();
+ static QAbstractItemModel *model();
+
+ static void registerEngine(DebuggerEngine *engine);
+ static void unregisterEngine(DebuggerEngine *engine);
+ static void activateEngine(DebuggerEngine *engine);
+ static void activateDebugMode();
- // Called from SnapshotHandler after a new snapshot has been added
- void removeAll();
- QAbstractItemModel *model() { return this; }
- int currentIndex() const { return m_currentIndex; }
- void appendSnapshot(DebuggerRunTool *runTool);
- void removeSnapshot(DebuggerRunTool *runTool);
- void setCurrentIndex(int index);
- int size() const { return m_snapshots.size(); }
- DebuggerRunTool *at(int index) const;
+ static QList<QPointer<DebuggerEngine> > engines();
+ static QPointer<DebuggerEngine> currentEngine();
- void createSnapshot(int index);
- void activateSnapshot(int index);
- void removeSnapshot(int index);
+ static void selectUiForCurrentEngine();
-private:
- // QAbstractTableModel
- int rowCount(const QModelIndex &parent) const override;
- int columnCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
+ static QWidget *engineChooser();
- int m_currentIndex = -1;
- QList< QPointer<DebuggerRunTool> > m_snapshots;
+signals:
+ void engineStateChanged(DebuggerEngine *engine);
+ void currentEngineChanged();
};
} // namespace Internal
diff --git a/src/plugins/debugger/snapshotwindow.cpp b/src/plugins/debugger/snapshotwindow.cpp
deleted file mode 100644
index 777d152e47..0000000000
--- a/src/plugins/debugger/snapshotwindow.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "snapshotwindow.h"
-#include "snapshothandler.h"
-
-#include "debuggeractions.h"
-#include "debuggerinternalconstants.h"
-#include "debuggercore.h"
-#include "debuggerruncontrol.h"
-
-#include <utils/qtcassert.h>
-#include <utils/savedaction.h>
-
-#include <QDebug>
-
-#include <QMenu>
-#include <QKeyEvent>
-
-namespace Debugger {
-namespace Internal {
-
-///////////////////////////////////////////////////////////////////////
-//
-// SnapshotWindow
-//
-///////////////////////////////////////////////////////////////////////
-
-SnapshotTreeView::SnapshotTreeView(SnapshotHandler *handler)
-{
- m_snapshotHandler = handler;
- setWindowTitle(tr("Snapshots"));
-}
-
-void SnapshotTreeView::rowActivated(const QModelIndex &index)
-{
- m_snapshotHandler->activateSnapshot(index.row());
-}
-
-void SnapshotTreeView::keyPressEvent(QKeyEvent *ev)
-{
- if (ev->key() == Qt::Key_Delete) {
- QItemSelectionModel *sm = selectionModel();
- QTC_ASSERT(sm, return);
- QModelIndexList si = sm->selectedIndexes();
- if (si.isEmpty())
- si.append(currentIndex().sibling(currentIndex().row(), 0));
-
- foreach (const QModelIndex &idx, si)
- if (idx.column() == 0)
- removeSnapshot(idx.row());
- }
- BaseTreeView::keyPressEvent(ev);
-}
-
-void SnapshotTreeView::contextMenuEvent(QContextMenuEvent *ev)
-{
- QModelIndex idx = indexAt(ev->pos());
-
- QMenu menu;
-
- QAction *actCreate = menu.addAction(tr("Create Snapshot"));
- actCreate->setEnabled(idx.data(SnapshotCapabilityRole).toBool());
- menu.addSeparator();
-
- QAction *actRemove = menu.addAction(tr("Remove Snapshot"));
- actRemove->setEnabled(idx.isValid());
-
- menu.addSeparator();
- menu.addAction(action(SettingsDialog));
-
- QAction *act = menu.exec(ev->globalPos());
-
- if (act == actCreate)
- m_snapshotHandler->createSnapshot(idx.row());
- else if (act == actRemove)
- removeSnapshot(idx.row());
-}
-
-void SnapshotTreeView::removeSnapshot(int i)
-{
- m_snapshotHandler->at(i)->quitDebugger();
-}
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/snapshotwindow.h b/src/plugins/debugger/snapshotwindow.h
deleted file mode 100644
index a80284bacd..0000000000
--- a/src/plugins/debugger/snapshotwindow.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#pragma once
-
-#include <utils/basetreeview.h>
-
-namespace Debugger {
-namespace Internal {
-
-class SnapshotHandler;
-
-class SnapshotTreeView : public Utils::BaseTreeView
-{
- Q_OBJECT
-
-public:
- explicit SnapshotTreeView(SnapshotHandler *handler);
-
-private:
- void rowActivated(const QModelIndex &index);
- void removeSnapshot(int i);
- void keyPressEvent(QKeyEvent *ev) override;
- void contextMenuEvent(QContextMenuEvent *ev) override;
-
- SnapshotHandler *m_snapshotHandler;
-};
-
-} // namespace Internal
-} // namespace Debugger
diff --git a/src/plugins/debugger/sourcefileshandler.cpp b/src/plugins/debugger/sourcefileshandler.cpp
index c7761c7b29..3de9b48360 100644
--- a/src/plugins/debugger/sourcefileshandler.cpp
+++ b/src/plugins/debugger/sourcefileshandler.cpp
@@ -121,7 +121,7 @@ bool SourceFilesHandler::setData(const QModelIndex &idx, const QVariant &data, i
QModelIndex index = idx.sibling(idx.row(), 0);
QString name = index.data().toString();
- auto addAction = [this, menu](const QString &display, bool on, const std::function<void()> &onTriggered) {
+ auto addAction = [menu](const QString &display, bool on, const std::function<void()> &onTriggered) {
QAction *act = menu->addAction(display);
act->setEnabled(on);
QObject::connect(act, &QAction::triggered, onTriggered);
diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp
index a1acd42769..12dd466422 100644
--- a/src/plugins/debugger/terminal.cpp
+++ b/src/plugins/debugger/terminal.cpp
@@ -25,17 +25,17 @@
#include "terminal.h"
-#include "debuggerruncontrol.h"
-
-#include <QDebug>
-#include <QIODevice>
-#include <QSocketNotifier>
+#include <projectexplorer/runconfiguration.h>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <utils/hostosinfo.h>
+#include <QDebug>
+#include <QIODevice>
+#include <QSocketNotifier>
+
#ifdef Q_OS_UNIX
# define DEBUGGER_USE_TERMINAL
#endif
@@ -168,13 +168,12 @@ void Terminal::onSlaveReaderActivated(int fd)
#endif
}
-TerminalRunner::TerminalRunner(DebuggerRunTool *debugger)
- : RunWorker(debugger->runControl())
+TerminalRunner::TerminalRunner(RunControl *runControl, const Runnable &stubRunnable)
+ : RunWorker(runControl)
{
setDisplayName("TerminalRunner");
- const DebuggerRunParameters &rp = debugger->runParameters();
- m_stubRunnable = rp.inferior;
+ m_stubRunnable = stubRunnable;
connect(&m_stubProc, &ConsoleProcess::processError,
this, &TerminalRunner::stubError);
diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h
index 509c8350e3..d6caa55f98 100644
--- a/src/plugins/debugger/terminal.h
+++ b/src/plugins/debugger/terminal.h
@@ -71,7 +71,8 @@ private:
class TerminalRunner : public ProjectExplorer::RunWorker
{
public:
- explicit TerminalRunner(DebuggerRunTool *runControl);
+ TerminalRunner(ProjectExplorer::RunControl *runControl,
+ const ProjectExplorer::Runnable &stubRunnable);
qint64 applicationPid() const { return m_applicationPid; }
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp
index 4ba1284fdb..a4fd57dad6 100644
--- a/src/plugins/debugger/threadshandler.cpp
+++ b/src/plugins/debugger/threadshandler.cpp
@@ -367,7 +367,7 @@ void ThreadsHandler::updateThreadBox()
forItemsAtLevel<1>([&list](ThreadItem *item) {
list.append(QString::fromLatin1("#%1 %2").arg(item->threadData.id.raw()).arg(item->threadData.name));
});
- Internal::setThreadBoxContents(list, indexForThreadId(this, m_currentId));
+ m_engine->setThreadBoxContents(list, indexForThreadId(this, m_currentId));
}
ThreadData ThreadsHandler::thread(ThreadId id) const
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 3b72e428d8..6bd122e9ae 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -1298,7 +1298,7 @@ void WatchModel::timerEvent(QTimerEvent *event)
}
ungrabWidget();
}
- showMessage(msg, StatusBar);
+ m_engine->showMessage(msg, StatusBar);
} else {
WatchModelBase::timerEvent(event);
}
@@ -1951,8 +1951,10 @@ QString WatchModel::nameForFormat(int format)
///////////////////////////////////////////////////////////////////////
WatchHandler::WatchHandler(DebuggerEngine *engine)
+ : m_engine(engine)
{
m_model = new WatchModel(this, engine);
+ loadSessionDataForEngine();
}
WatchHandler::~WatchHandler()
@@ -2072,7 +2074,13 @@ void WatchHandler::resetValueCache()
void WatchHandler::resetWatchers()
{
- loadSessionData();
+ loadFormats();
+ theWatcherNames.clear();
+ theWatcherCount = 0;
+ const QStringList watchers = sessionValue("Watchers").toStringList();
+ m_model->m_watchRoot->removeChildren();
+ for (const QString &exp : watchers)
+ watchExpression(exp.trimmed());
}
void WatchHandler::notifyUpdateStarted(const UpdateParameters &updateParameters)
@@ -2173,7 +2181,7 @@ void WatchHandler::watchExpression(const QString &exp, const QString &name, bool
m_model->m_engine->updateWatchData(item->iname);
}
updateLocalsWindow();
- Internal::raiseWatchersWindow();
+ m_engine->raiseWatchersWindow();
}
void WatchHandler::updateWatchExpression(WatchItem *item, const QString &newExp)
@@ -2358,7 +2366,7 @@ void WatchHandler::updateLocalsWindow()
{
// Force show/hide of return view.
bool showReturn = m_model->m_returnRoot->childCount() != 0;
- Internal::updateLocalsWindow(showReturn);
+ m_engine->updateLocalsWindow(showReturn);
}
QStringList WatchHandler::watchedExpressions()
@@ -2383,6 +2391,11 @@ void WatchHandler::saveSessionData()
void WatchHandler::loadSessionData()
{
+ // Handled by loadSesseionDataForEngine.
+}
+
+void WatchHandler::loadSessionDataForEngine()
+{
loadFormats();
theWatcherNames.clear();
theWatcherCount = 0;
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index 9a289ef7c4..10e8825cdc 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -76,8 +76,10 @@ public:
WatchItem *findItem(const QString &iname) const;
const WatchItem *findCppLocalVariable(const QString &name) const;
- void loadSessionData();
- void saveSessionData();
+ void loadSessionDataForEngine();
+
+ static void loadSessionData();
+ static void saveSessionData();
bool isExpandedIName(const QString &iname) const;
QSet<QString> expandedINames() const;
@@ -120,6 +122,7 @@ public:
void recordTypeInfo(const GdbMi &typeInfo);
private:
+ DebuggerEngine * const m_engine; // Not owned
WatchModel *m_model; // Owned.
};