forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -282,12 +282,12 @@ ClangTidyClazyTool::ClangTidyClazyTool()
|
|||||||
action->setEnabled(m_startAction->isEnabled());
|
action->setEnabled(m_startAction->isEnabled());
|
||||||
});
|
});
|
||||||
|
|
||||||
perspective->addToolbarAction(m_startAction);
|
perspective->addToolBarAction(m_startAction);
|
||||||
perspective->addToolbarAction(m_stopAction);
|
perspective->addToolBarAction(m_stopAction);
|
||||||
perspective->addToolbarAction(m_goBack);
|
perspective->addToolBarAction(m_goBack);
|
||||||
perspective->addToolbarAction(m_goNext);
|
perspective->addToolBarAction(m_goNext);
|
||||||
perspective->addToolbarWidget(m_filterLineEdit);
|
perspective->addToolBarWidget(m_filterLineEdit);
|
||||||
perspective->addToolbarWidget(m_applyFixitsButton);
|
perspective->addToolBarWidget(m_applyFixitsButton);
|
||||||
|
|
||||||
Debugger::registerPerspective(perspective);
|
Debugger::registerPerspective(perspective);
|
||||||
|
|
||||||
|
@@ -32,9 +32,8 @@
|
|||||||
|
|
||||||
#include <projectexplorer/runconfiguration.h>
|
#include <projectexplorer/runconfiguration.h>
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
@@ -63,14 +62,11 @@ DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName);
|
|||||||
|
|
||||||
// Register a tool for a given start mode.
|
// Register a tool for a given start mode.
|
||||||
DEBUGGER_EXPORT void registerPerspective(Utils::Perspective *perspective);
|
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 void enableMainWindow(bool on);
|
||||||
DEBUGGER_EXPORT QWidget *mainWindow();
|
DEBUGGER_EXPORT QWidget *mainWindow();
|
||||||
|
|
||||||
DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId);
|
DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId);
|
||||||
DEBUGGER_EXPORT QByteArray currentPerspective();
|
|
||||||
|
|
||||||
// Convenience functions.
|
// Convenience functions.
|
||||||
DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000);
|
DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@
|
|||||||
#include "breakpoint.h"
|
#include "breakpoint.h"
|
||||||
#include "debuggerprotocol.h"
|
#include "debuggerprotocol.h"
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
#include <utils/treemodel.h>
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -38,203 +39,295 @@ namespace Utils { class ItemViewEvent; }
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class LocationItem;
|
|
||||||
class BreakpointItem;
|
class BreakpointItem;
|
||||||
|
class BreakpointMarker;
|
||||||
class BreakHandler;
|
class BreakHandler;
|
||||||
class DebuggerCommand;
|
class DebuggerCommand;
|
||||||
class DebuggerEngine;
|
class DebuggerEngine;
|
||||||
|
class BreakpointManager;
|
||||||
|
class GlobalBreakpointMarker;
|
||||||
|
|
||||||
// Non-owning "deletion-safe" wrapper around a BreakpointItem *
|
class SubBreakpointItem : public QObject, public Utils::TypedTreeItem<Utils::TreeItem, BreakpointItem>
|
||||||
class Breakpoint
|
{
|
||||||
|
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)
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Breakpoint() = default;
|
explicit GlobalBreakpointItem();
|
||||||
|
~GlobalBreakpointItem() override;
|
||||||
bool isValid() const;
|
|
||||||
operator const void *() const { return isValid() ? this : nullptr; }
|
|
||||||
bool operator!() const { return !isValid(); }
|
|
||||||
|
|
||||||
uint hash() const;
|
|
||||||
|
|
||||||
const BreakpointParameters ¶meters() const;
|
|
||||||
void addToCommand(DebuggerCommand *cmd) const;
|
|
||||||
|
|
||||||
BreakpointModelId id() const;
|
|
||||||
bool isLocatedAt(const QString &fileName, int lineNumber,
|
|
||||||
bool useMarkerPosition) const;
|
|
||||||
|
|
||||||
|
QVariant data(int column, int role) const override;
|
||||||
QIcon icon() const;
|
QIcon icon() const;
|
||||||
BreakpointState state() const;
|
|
||||||
void setEngine(DebuggerEngine *engine);
|
|
||||||
|
|
||||||
// State transitions.
|
void deleteBreakpoint();
|
||||||
void notifyBreakpointChangeAfterInsertNeeded();
|
void removeBreakpointFromModel();
|
||||||
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 ¶ms);
|
|
||||||
|
|
||||||
void update();
|
void updateLineNumber(int lineNumber);
|
||||||
|
void updateFileName(const Utils::FileName &fileName);
|
||||||
|
|
||||||
void gotoLocation() const;
|
bool isLocatedAt(const QString &fileName, int lineNumber, bool useMarkerPosition) const;
|
||||||
|
|
||||||
// Getter retrieves property value.
|
QString displayName() const;
|
||||||
// Setter sets property value and triggers update if changed.
|
QString markerFileName() const;
|
||||||
// Only use setters when it is safe to assume that the breakpoint still
|
QString toolTip() const;
|
||||||
// exist. That's not the case if the event loop could run after you
|
int markerLineNumber() const;
|
||||||
// obtained the BreakpointItem pointer.
|
int modelId() const;
|
||||||
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;
|
bool isEnabled() const { return m_params.enabled; }
|
||||||
void insertSubBreakpoint(const BreakpointResponse &data);
|
void setEnabled(bool enabled);
|
||||||
void removeAlienBreakpoint();
|
|
||||||
void removeBreakpoint() const;
|
|
||||||
|
|
||||||
QString msgWatchpointByAddressTriggered(int number, quint64 address) const;
|
const BreakpointParameters ¶meters() const { return m_params; }
|
||||||
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;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void gotoState(BreakpointState target, BreakpointState assumedCurrent);
|
|
||||||
|
|
||||||
friend class BreakHandler;
|
friend class BreakHandler;
|
||||||
explicit Breakpoint(BreakpointItem *b);
|
friend class BreakpointManager;
|
||||||
|
friend class BreakpointMarker;
|
||||||
|
friend class GlobalBreakpointMarker;
|
||||||
|
|
||||||
QPointer<BreakpointItem> b;
|
void updateMarker();
|
||||||
|
void updateMarkerIcon();
|
||||||
|
void destroyMarker();
|
||||||
|
void scheduleSynchronization();
|
||||||
|
QPointer<DebuggerEngine> usingEngine() const;
|
||||||
|
|
||||||
|
bool isEngineRunning() const;
|
||||||
|
|
||||||
|
const int m_modelId;
|
||||||
|
BreakpointParameters m_params;
|
||||||
|
GlobalBreakpointMarker *m_marker = nullptr; // The primary marker set by the user.
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint qHash(const Debugger::Internal::Breakpoint &b) { return b.hash(); }
|
using GlobalBreakpoint = QPointer<GlobalBreakpointItem>;
|
||||||
|
using GlobalBreakpoints = QList<GlobalBreakpoint>;
|
||||||
|
|
||||||
using Breakpoints = QList<Breakpoint>;
|
class BreakpointItem : public QObject, public Utils::TypedTreeItem<SubBreakpointItem>
|
||||||
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::BreakHandler)
|
||||||
|
|
||||||
using BreakModel = Utils::TreeModel<Utils::TypedTreeItem<BreakpointItem>, BreakpointItem, LocationItem>;
|
public:
|
||||||
|
explicit BreakpointItem(const GlobalBreakpoint &gbp);
|
||||||
|
~BreakpointItem() final;
|
||||||
|
|
||||||
class BreakHandler : public BreakModel
|
QVariant data(int column, int role) const final;
|
||||||
|
|
||||||
|
QIcon icon() const;
|
||||||
|
|
||||||
|
void setMarkerFileAndLine(const QString &fileName, int lineNumber);
|
||||||
|
bool needsChange() const;
|
||||||
|
|
||||||
|
SubBreakpoint findOrCreateSubBreakpoint(const QString &responseId);
|
||||||
|
QString markerFileName() const;
|
||||||
|
int markerLineNumber() 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;
|
||||||
|
|
||||||
|
void adjustMarker();
|
||||||
|
|
||||||
|
void deleteBreakpoint();
|
||||||
|
void deleteGlobalOrThisBreakpoint();
|
||||||
|
|
||||||
|
void updateLineNumber(int lineNumber);
|
||||||
|
void updateFileName(const Utils::FileName &fileName);
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Breakpoint = QPointer<BreakpointItem>;
|
||||||
|
using Breakpoints = const QList<Breakpoint>;
|
||||||
|
using SubBreakpoints = const QList<SubBreakpoint>;
|
||||||
|
|
||||||
|
using BreakHandlerModel = Utils::TreeModel<Utils::TypedTreeItem<BreakpointItem>, BreakpointItem, SubBreakpointItem>;
|
||||||
|
using BreakpointManagerModel = Utils::TreeModel<Utils::TypedTreeItem<GlobalBreakpointItem>, GlobalBreakpointItem>;
|
||||||
|
|
||||||
|
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 BreakHandlerModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BreakHandler();
|
explicit BreakHandler(DebuggerEngine *engine);
|
||||||
|
|
||||||
|
QAbstractItemModel *model() { return this; }
|
||||||
|
const Breakpoints breakpoints() const;
|
||||||
|
|
||||||
void loadSessionData();
|
void loadSessionData();
|
||||||
void saveSessionData();
|
void saveSessionData();
|
||||||
|
|
||||||
QAbstractItemModel *model() { return this; }
|
bool tryClaimBreakpoint(const GlobalBreakpoint &gbp);
|
||||||
|
void releaseAllBreakpoints();
|
||||||
|
|
||||||
// The only way to add a new breakpoint.
|
void handleAlienBreakpoint(const QString &responseId, const BreakpointParameters &response);
|
||||||
void appendBreakpoint(const BreakpointParameters &data);
|
void removeAlienBreakpoint(const QString &responseId);
|
||||||
void handleAlienBreakpoint(const BreakpointResponse &response, DebuggerEngine *engine);
|
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;
|
void removeBreakpoint(const Breakpoint &bp);
|
||||||
const Breakpoints engineBreakpoints(DebuggerEngine *engine) const;
|
void editBreakpoint(const Breakpoint &bp, QWidget *parent);
|
||||||
const Breakpoints unclaimedBreakpoints() const;
|
|
||||||
QStringList engineBreakpointPaths(DebuggerEngine *engine) const;
|
|
||||||
|
|
||||||
// Find a breakpoint matching approximately the data in needle.
|
Breakpoint findBreakpointByResponseId(const QString &responseId) const;
|
||||||
Breakpoint findSimilarBreakpoint(const BreakpointResponse &needle) const;
|
SubBreakpoint findSubBreakpointByResponseId(const QString &responseId) const;
|
||||||
Breakpoint findBreakpointByResponseId(const BreakpointResponseId &resultId) const;
|
|
||||||
Breakpoint findWatchpoint(const BreakpointParameters &data) const;
|
Breakpoint findWatchpoint(const BreakpointParameters &data) const;
|
||||||
Breakpoint findBreakpointByFunction(const QString &functionName) const;
|
Breakpoint findBreakpointByModelId(int modelId) const;
|
||||||
Breakpoint findBreakpointByIndex(const QModelIndex &index) const;
|
|
||||||
Breakpoints findBreakpointsByIndex(const QList<QModelIndex> &list) const;
|
|
||||||
void updateMarkers();
|
|
||||||
|
|
||||||
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 QString displayFromThreadSpec(int spec);
|
||||||
static int threadSpecFromDisplay(const QString &str);
|
static int threadSpecFromDisplay(const QString &str);
|
||||||
|
|
||||||
// Convenience.
|
// Convenience.
|
||||||
void setWatchpointAtAddress(quint64 address, unsigned size);
|
void setWatchpointAtAddress(quint64 address, unsigned size);
|
||||||
void setWatchpointAtExpression(const QString &exp);
|
void setWatchpointAtExpression(const QString &exp);
|
||||||
|
void setBreakpointEnabled(const Breakpoint &bp, bool on);
|
||||||
|
|
||||||
Breakpoint breakpointById(BreakpointModelId id) const;
|
void updateDisassemblerMarker(const Breakpoint &bp);
|
||||||
void editBreakpoint(Breakpoint bp, QWidget *parent);
|
void removeDisassemblerMarker(const Breakpoint &bp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariant data(const QModelIndex &idx, int role) const override;
|
Breakpoint findBreakpointByIndex(const QModelIndex &index) const;
|
||||||
bool setData(const QModelIndex &idx, const QVariant &value, int role) override;
|
Breakpoints findBreakpointsByIndex(const QList<QModelIndex> &list) const;
|
||||||
void timerEvent(QTimerEvent *event) override;
|
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);
|
bool contextMenuEvent(const Utils::ItemViewEvent &ev);
|
||||||
|
|
||||||
friend class BreakpointItem;
|
friend class BreakpointItem;
|
||||||
friend class Breakpoint;
|
|
||||||
|
|
||||||
void loadBreakpoints();
|
DebuggerEngine * const m_engine;
|
||||||
void saveBreakpoints();
|
};
|
||||||
|
|
||||||
void appendBreakpointInternal(const BreakpointParameters &data);
|
class BreakpointManager : public BreakpointManagerModel
|
||||||
void deleteBreakpoints(const Breakpoints &bps);
|
{
|
||||||
void deleteAllBreakpoints();
|
Q_OBJECT
|
||||||
void setBreakpointsEnabled(const Breakpoints &bps, bool enabled);
|
|
||||||
void addBreakpoint();
|
|
||||||
void editBreakpoints(const Breakpoints &bps, QWidget *parent);
|
|
||||||
|
|
||||||
Q_SLOT void changeLineNumberFromMarkerHelper(Debugger::Internal::BreakpointModelId id);
|
public:
|
||||||
Q_SLOT void deletionHelper(Debugger::Internal::BreakpointModelId id);
|
BreakpointManager();
|
||||||
|
|
||||||
void scheduleSynchronization();
|
static QAbstractItemModel *model();
|
||||||
|
|
||||||
int m_syncTimerId;
|
static const GlobalBreakpoints globalBreakpoints();
|
||||||
|
static void loadSessionData();
|
||||||
|
static void saveSessionData();
|
||||||
|
static void aboutToUnloadSession();
|
||||||
|
|
||||||
|
static GlobalBreakpoint createBreakpoint(const BreakpointParameters &data);
|
||||||
|
|
||||||
|
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 Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Debugger::Internal::Breakpoint)
|
|
||||||
|
@@ -25,89 +25,20 @@
|
|||||||
|
|
||||||
#include "breakpoint.h"
|
#include "breakpoint.h"
|
||||||
|
|
||||||
|
#include "debuggeractions.h"
|
||||||
|
#include "debuggercore.h"
|
||||||
|
#include "debuggerprotocol.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/abi.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
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
|
\class Debugger::Internal::BreakpointParameters
|
||||||
|
|
||||||
@@ -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
|
bool BreakpointParameters::isCppBreakpoint() const
|
||||||
{
|
{
|
||||||
// Qml specific breakpoint types.
|
// Qml specific breakpoint types.
|
||||||
if (type == BreakpointAtJavaScriptThrow
|
if (type == BreakpointAtJavaScriptThrow || type == BreakpointOnQmlSignalEmit)
|
||||||
|| type == BreakpointOnQmlSignalEmit)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Qml is currently only file.
|
// Qml is currently only file.
|
||||||
if (type == BreakpointByFileAndLine) {
|
if (type == BreakpointByFileAndLine)
|
||||||
auto qmlExtensionString = QString::fromLocal8Bit(qgetenv("QTC_QMLDEBUGGER_FILEEXTENSIONS"));
|
return !isQmlFileAndLineBreakpoint();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -283,55 +221,176 @@ QString BreakpointParameters::toString() const
|
|||||||
ts << " Command: " << command;
|
ts << " Command: " << command;
|
||||||
if (!message.isEmpty())
|
if (!message.isEmpty())
|
||||||
ts << " Message: " << message;
|
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)
|
if (pending)
|
||||||
ts << " [pending]";
|
ts << " [pending]";
|
||||||
if (!functionName.isEmpty())
|
if (!functionName.isEmpty())
|
||||||
ts << " Function: " << functionName;
|
ts << " Function: " << functionName;
|
||||||
if (multiple)
|
|
||||||
ts << " Multiple: " << multiple;
|
|
||||||
if (correctedLineNumber)
|
|
||||||
ts << " CorrectedLineNumber: " << correctedLineNumber;
|
|
||||||
ts << " Hit: " << hitCount << " times";
|
ts << " Hit: " << hitCount << " times";
|
||||||
ts << ' ';
|
ts << ' ';
|
||||||
return result + BreakpointParameters::toString();
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BreakpointResponse::fromParameters(const BreakpointParameters &p)
|
static QString cleanupFullName(const QString &fileName)
|
||||||
{
|
{
|
||||||
BreakpointParameters::operator=(p);
|
QString cleanFilePath = fileName;
|
||||||
id = BreakpointResponseId();
|
|
||||||
multiple = false;
|
// Gdb running on windows often delivers "fullnames" which
|
||||||
correctedLineNumber = 0;
|
// (a) have no drive letter and (b) are not normalized.
|
||||||
hitCount = 0;
|
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
|
} // namespace Internal
|
||||||
|
@@ -31,52 +31,7 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
class GdbMi;
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -86,7 +41,7 @@ public:
|
|||||||
|
|
||||||
//! \enum Debugger::Internal::BreakpointType
|
//! \enum Debugger::Internal::BreakpointType
|
||||||
|
|
||||||
// Note: Keep synchronized with similar definitions in bridge.py
|
// Note: Keep synchronized with similar definitions in dumper.py
|
||||||
enum BreakpointType
|
enum BreakpointType
|
||||||
{
|
{
|
||||||
UnknownBreakpointType,
|
UnknownBreakpointType,
|
||||||
@@ -110,11 +65,11 @@ enum BreakpointType
|
|||||||
enum BreakpointState
|
enum BreakpointState
|
||||||
{
|
{
|
||||||
BreakpointNew,
|
BreakpointNew,
|
||||||
BreakpointInsertRequested, //!< Inferior was told about bp, not ack'ed.
|
BreakpointInsertionRequested, //!< Inferior was told about bp, not ack'ed.
|
||||||
BreakpointInsertProceeding,
|
BreakpointInsertionProceeding,
|
||||||
BreakpointChangeRequested,
|
|
||||||
BreakpointChangeProceeding,
|
|
||||||
BreakpointInserted,
|
BreakpointInserted,
|
||||||
|
BreakpointUpdateRequested,
|
||||||
|
BreakpointUpdateProceeding,
|
||||||
BreakpointRemoveRequested,
|
BreakpointRemoveRequested,
|
||||||
BreakpointRemoveProceeding,
|
BreakpointRemoveProceeding,
|
||||||
BreakpointDead
|
BreakpointDead
|
||||||
@@ -185,12 +140,15 @@ public:
|
|||||||
bool conditionsMatch(const QString &other) const;
|
bool conditionsMatch(const QString &other) const;
|
||||||
bool isWatchpoint() const
|
bool isWatchpoint() const
|
||||||
{ return type == WatchpointAtAddress || type == WatchpointAtExpression; }
|
{ return type == WatchpointAtAddress || type == WatchpointAtExpression; }
|
||||||
|
bool isLocatedAt(const QString &fileName, int lineNumber, const QString &markerFileName) const;
|
||||||
// Enough for now.
|
// Enough for now.
|
||||||
bool isBreakpoint() const { return !isWatchpoint() && !isTracepoint(); }
|
bool isBreakpoint() const { return !isWatchpoint() && !isTracepoint(); }
|
||||||
bool isTracepoint() const { return tracepoint; }
|
bool isTracepoint() const { return tracepoint; }
|
||||||
bool isCppBreakpoint() const;
|
bool isCppBreakpoint() const;
|
||||||
|
bool isQmlFileAndLineBreakpoint() const;
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
void updateLocation(const QString &location); // file.cpp:42
|
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); }
|
||||||
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
|
QString message; //!< message
|
||||||
bool tracepoint;
|
bool tracepoint;
|
||||||
bool oneShot; //!< Should this breakpoint trigger only once?
|
bool oneShot; //!< Should this breakpoint trigger only once?
|
||||||
|
|
||||||
|
bool pending = true; //!< Breakpoint not fully resolved.
|
||||||
|
int hitCount = 0; //!< Number of times this has been hit.
|
||||||
};
|
};
|
||||||
|
|
||||||
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.
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint qHash(const Debugger::Internal::BreakpointModelId &id)
|
|
||||||
{
|
|
||||||
return id.toInternalId();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Debugger::Internal::BreakpointModelId)
|
|
||||||
Q_DECLARE_METATYPE(Debugger::Internal::BreakpointResponseId)
|
|
||||||
|
@@ -182,6 +182,7 @@ CdbEngine::CdbEngine() :
|
|||||||
m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT ".")
|
m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT ".")
|
||||||
{
|
{
|
||||||
setObjectName("CdbEngine");
|
setObjectName("CdbEngine");
|
||||||
|
setDebuggerName("CDB");
|
||||||
|
|
||||||
DisplayFormats stringFormats;
|
DisplayFormats stringFormats;
|
||||||
stringFormats.append(SimpleFormat);
|
stringFormats.append(SimpleFormat);
|
||||||
@@ -225,7 +226,7 @@ void CdbEngine::init()
|
|||||||
m_stopMode = NoStopRequested;
|
m_stopMode = NoStopRequested;
|
||||||
m_nextCommandToken = 0;
|
m_nextCommandToken = 0;
|
||||||
m_currentBuiltinResponseToken = -1;
|
m_currentBuiltinResponseToken = -1;
|
||||||
m_operateByInstruction = true;
|
m_operateByInstruction = action(OperateByInstruction)->isChecked();
|
||||||
m_hasDebuggee = false;
|
m_hasDebuggee = false;
|
||||||
m_sourceStepInto = false;
|
m_sourceStepInto = false;
|
||||||
m_watchPointX = m_watchPointY = 0;
|
m_watchPointX = m_watchPointY = 0;
|
||||||
@@ -238,8 +239,6 @@ void CdbEngine::init()
|
|||||||
m_currentBuiltinResponse.clear();
|
m_currentBuiltinResponse.clear();
|
||||||
m_extensionMessageBuffer.clear();
|
m_extensionMessageBuffer.clear();
|
||||||
m_pendingBreakpointMap.clear();
|
m_pendingBreakpointMap.clear();
|
||||||
m_insertSubBreakpointMap.clear();
|
|
||||||
m_pendingSubBreakpointMap.clear();
|
|
||||||
m_interrupCallbacks.clear();
|
m_interrupCallbacks.clear();
|
||||||
m_symbolAddressCache.clear();
|
m_symbolAddressCache.clear();
|
||||||
m_coreStopReason.reset();
|
m_coreStopReason.reset();
|
||||||
@@ -526,15 +525,17 @@ void CdbEngine::handleInitialSessionIdle()
|
|||||||
operateByInstructionTriggered(action(OperateByInstruction)->isChecked());
|
operateByInstructionTriggered(action(OperateByInstruction)->isChecked());
|
||||||
// QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
|
// QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
|
||||||
// (attemptBreakpointSynchronization() will be directly called then)
|
// (attemptBreakpointSynchronization() will be directly called then)
|
||||||
attemptBreakpointSynchronization();
|
|
||||||
if (rp.breakOnMain) {
|
if (rp.breakOnMain) {
|
||||||
const BreakpointParameters bp(BreakpointAtMain);
|
// FIXME:
|
||||||
BreakpointModelId id(quint16(-1));
|
// const BreakpointParameters bp(BreakpointAtMain);
|
||||||
QString function = cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true);
|
// BreakpointModelId id(quint16(-1));
|
||||||
runCommand({function, BuiltinCommand,
|
// QString function = cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true);
|
||||||
[this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); }});
|
// 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({".symopt+0x8000"}); // disable searching public symbol table - improving the symbol lookup speed
|
||||||
runCommand({"sxn 0x4000001f", NoFlags}); // Do not break on WowX86 exceptions.
|
runCommand({"sxn 0x4000001f", NoFlags}); // Do not break on WowX86 exceptions.
|
||||||
runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints.
|
runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints.
|
||||||
@@ -608,7 +609,7 @@ void CdbEngine::runEngine()
|
|||||||
runCommand({"sxe " + breakEvent, NoFlags});
|
runCommand({"sxe " + breakEvent, NoFlags});
|
||||||
// Break functions: each function must be fully qualified,
|
// Break functions: each function must be fully qualified,
|
||||||
// else the debugger will slow down considerably.
|
// 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)) {
|
if (boolSetting(CdbBreakOnCrtDbgReport)) {
|
||||||
Abi::OSFlavor flavor = runParameters().toolChainAbi.osFlavor();
|
Abi::OSFlavor flavor = runParameters().toolChainAbi.osFlavor();
|
||||||
// CrtDebugReport can not be safely resolved for vc 19
|
// 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);
|
showMessage(QString("Interrupting process %1...").arg(inferiorPid()), LogMisc);
|
||||||
QTC_ASSERT(!m_signalOperation, notifyInferiorStopFailed(); return);
|
QTC_ASSERT(!m_signalOperation, notifyInferiorStopFailed(); return);
|
||||||
if (DebuggerRunTool *rt = runTool()) {
|
QTC_ASSERT(device(), notifyInferiorRunFailed(); return);
|
||||||
IDevice::ConstPtr device = rt->device();
|
m_signalOperation = device()->signalOperation();
|
||||||
if (!device)
|
|
||||||
device = runParameters().inferior.device;
|
|
||||||
if (device)
|
|
||||||
m_signalOperation = device->signalOperation();
|
|
||||||
}
|
|
||||||
QTC_ASSERT(m_signalOperation, notifyInferiorStopFailed(); return;);
|
QTC_ASSERT(m_signalOperation, notifyInferiorStopFailed(); return;);
|
||||||
connect(m_signalOperation.data(), &DeviceProcessSignalOperation::finished,
|
connect(m_signalOperation.data(), &DeviceProcessSignalOperation::finished,
|
||||||
this, &CdbEngine::handleDoInterruptInferior);
|
this, &CdbEngine::handleDoInterruptInferior);
|
||||||
@@ -881,8 +877,8 @@ void CdbEngine::executeRunToLine(const ContextData &data)
|
|||||||
bp.lineNumber = data.lineNumber;
|
bp.lineNumber = data.lineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), BuiltinCommand,
|
runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, {}, true), BuiltinCommand,
|
||||||
[this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }});
|
[this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); }});
|
||||||
continueInferior();
|
continueInferior();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,8 +887,8 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
|
|||||||
// Add one-shot breakpoint
|
// Add one-shot breakpoint
|
||||||
BreakpointParameters bp(BreakpointByFunction);
|
BreakpointParameters bp(BreakpointByFunction);
|
||||||
bp.functionName = functionName;
|
bp.functionName = functionName;
|
||||||
runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), BuiltinCommand,
|
runCommand({cdbAddBreakpointCommand(bp, m_sourcePathMappings, {}, true), BuiltinCommand,
|
||||||
[this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }});
|
[this](const DebuggerResponse &r) { handleBreakInsert(r, Breakpoint()); }});
|
||||||
continueInferior();
|
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
|
// Post command to the cdb process
|
||||||
@@ -1465,8 +1460,7 @@ void CdbEngine::fetchMemory(MemoryAgent *agent, quint64 address, quint64 length)
|
|||||||
StringInputStream str(args);
|
StringInputStream str(args);
|
||||||
str << address << ' ' << length;
|
str << address << ' ' << length;
|
||||||
cmd.args = args;
|
cmd.args = args;
|
||||||
cmd.callback = [this, agent = QPointer<MemoryAgent>(agent), address, length]
|
cmd.callback = [&](const DebuggerResponse &response) {
|
||||||
(const DebuggerResponse &response) {
|
|
||||||
if (!agent)
|
if (!agent)
|
||||||
return;
|
return;
|
||||||
if (response.resultClass == ResultDone) {
|
if (response.resultClass == ResultDone) {
|
||||||
@@ -1507,7 +1501,8 @@ void CdbEngine::requestModuleSymbols(const QString &moduleName)
|
|||||||
|
|
||||||
void CdbEngine::reloadRegisters()
|
void CdbEngine::reloadRegisters()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(threadsHandler()->currentThreadIndex() >= 0, return);
|
if (!(threadsHandler()->currentThreadIndex() >= 0))
|
||||||
|
return;
|
||||||
runCommand({"registers", ExtensionCommand, CB(handleRegistersExt)});
|
runCommand({"registers", ExtensionCommand, CB(handleRegistersExt)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1680,19 +1675,18 @@ enum StopActionFlags
|
|||||||
StopShutdownInProgress = 0x80 // Shutdown in progress
|
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)
|
const QString &threadId)
|
||||||
{
|
{
|
||||||
return CdbEngine::tr("Trace point %1 (%2) in thread %3 triggered.")
|
return CdbEngine::tr("Trace point %1 in thread %2 triggered.")
|
||||||
.arg(id.toString()).arg(number).arg(threadId);
|
.arg(displayName).arg(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString msgCheckingConditionalBreakPoint(BreakpointModelId id, const int number,
|
static inline QString msgCheckingConditionalBreakPoint(const Breakpoint &bp, const QString &displayName,
|
||||||
const QString &condition,
|
|
||||||
const QString &threadId)
|
const QString &threadId)
|
||||||
{
|
{
|
||||||
return CdbEngine::tr("Conditional breakpoint %1 (%2) in thread %3 triggered, examining expression \"%4\".")
|
return CdbEngine::tr("Conditional breakpoint %1 in thread %2 triggered, examining expression \"%3\".")
|
||||||
.arg(id.toString()).arg(number).arg(threadId, condition);
|
.arg(displayName).arg(threadId, bp->condition());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
|
unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
|
||||||
@@ -1722,52 +1716,55 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
|
|||||||
if (reason == "breakpoint") {
|
if (reason == "breakpoint") {
|
||||||
// Note: Internal breakpoints (run to line) are reported with id=0.
|
// Note: Internal breakpoints (run to line) are reported with id=0.
|
||||||
// Step out creates temporary breakpoints with id 10000.
|
// Step out creates temporary breakpoints with id 10000.
|
||||||
int number = 0;
|
|
||||||
BreakpointModelId id = cdbIdToBreakpointModelId(stopReason["breakpointId"]);
|
|
||||||
Breakpoint bp = breakHandler()->breakpointById(id);
|
|
||||||
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;
|
const QString responseId = stopReason["breakpointId"].data();
|
||||||
}
|
QString displayName;
|
||||||
} else {
|
Breakpoint bp = breakHandler()->findBreakpointByResponseId(responseId);
|
||||||
bp = Breakpoint();
|
if (!bp) {
|
||||||
|
if (const SubBreakpoint sub = breakHandler()->findSubBreakpointByResponseId(responseId)) {
|
||||||
|
bp = sub->breakpoint();
|
||||||
|
displayName = sub->displayName;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
displayName = bp->displayName();
|
||||||
|
}
|
||||||
|
if (bp) {
|
||||||
|
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('"');
|
||||||
|
}
|
||||||
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
if (reason == "exception") {
|
if (reason == "exception") {
|
||||||
@@ -1881,11 +1878,11 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
|
|||||||
showMessage(stopReason["threaderror"].data(), LogError);
|
showMessage(stopReason["threaderror"].data(), LogError);
|
||||||
}
|
}
|
||||||
// Fire off remaining commands asynchronously
|
// Fire off remaining commands asynchronously
|
||||||
if (!m_pendingBreakpointMap.isEmpty() && !m_pendingSubBreakpointMap.isEmpty())
|
if (!m_pendingBreakpointMap.isEmpty())
|
||||||
listBreakpoints();
|
listBreakpoints();
|
||||||
if (Internal::isRegistersWindowVisible())
|
if (isRegistersWindowVisible())
|
||||||
reloadRegisters();
|
reloadRegisters();
|
||||||
if (Internal::isModulesWindowVisible())
|
if (isModulesWindowVisible())
|
||||||
reloadModules();
|
reloadModules();
|
||||||
}
|
}
|
||||||
// After the sequence has been sent off and CDB is pondering the commands,
|
// 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);
|
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');
|
const QStringList reply = response.data.data().split('\n');
|
||||||
if (reply.isEmpty())
|
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>::operator QString (__cdecl*)(void) (000007f6`be2f27b0)
|
||||||
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::<helper_func_vectorcall> (000007f6`be2f27d0)
|
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::<helper_func_vectorcall> (000007f6`be2f27d0)
|
||||||
// Matched: untitled123!<lambda_4956dbaf7bce78acbc6759af75f3884a>::operator QString (__vectorcall*)(void) (000007f6`be2f2850)
|
// 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`'
|
// ^ 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;
|
return;
|
||||||
Breakpoint bp = breakHandler()->breakpointById(bpId);
|
|
||||||
// add break point for every match
|
// add break point for every match
|
||||||
|
const int parentResponseId = bp->responseId().toInt();
|
||||||
quint16 subBreakPointID = 0;
|
quint16 subBreakPointID = 0;
|
||||||
|
const QLatin1String matchPrefix("Matched: ");
|
||||||
for (auto line = reply.constBegin(), end = reply.constEnd(); line != end; ++line) {
|
for (auto line = reply.constBegin(), end = reply.constEnd(); line != end; ++line) {
|
||||||
if (!line->startsWith("Matched: "))
|
if (!line->startsWith(matchPrefix))
|
||||||
continue;
|
continue;
|
||||||
const int addressStartPos = line->lastIndexOf('(') + 1;
|
const int addressStartPos = line->lastIndexOf('(') + 1;
|
||||||
const int addressEndPos = line->indexOf(')', addressStartPos);
|
const int addressEndPos = line->indexOf(')', addressStartPos);
|
||||||
@@ -1936,16 +1936,25 @@ void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const Breakp
|
|||||||
if (!ok)
|
if (!ok)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
BreakpointModelId id(bpId.majorPart(), ++subBreakPointID);
|
++subBreakPointID;
|
||||||
BreakpointResponse res = bp.response();
|
const QString responseId(QString::number(parentResponseId + subBreakPointID));
|
||||||
res.type = BreakpointByAddress;
|
SubBreakpoint sub = bp->findOrCreateSubBreakpoint(responseId);
|
||||||
res.address = address;
|
sub->responseId = responseId;
|
||||||
m_insertSubBreakpointMap.insert(id, res);
|
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)
|
void CdbEngine::handleCheckWow64(const DebuggerResponse &response, const GdbMi &stack)
|
||||||
@@ -2413,10 +2422,10 @@ bool CdbEngine::stateAcceptsBreakpointChanges() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdbEngine::acceptsBreakpoint(Breakpoint bp) const
|
bool CdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
|
||||||
{
|
{
|
||||||
if (bp.parameters().isCppBreakpoint()) {
|
if (bp.isCppBreakpoint()) {
|
||||||
switch (bp.type()) {
|
switch (bp.type) {
|
||||||
case UnknownBreakpointType:
|
case UnknownBreakpointType:
|
||||||
case LastBreakpointType:
|
case LastBreakpointType:
|
||||||
case BreakpointAtFork:
|
case BreakpointAtFork:
|
||||||
@@ -2490,139 +2499,90 @@ unsigned BreakpointCorrectionContext::fixLineNumber(const QString &fileName,
|
|||||||
return correctedLine;
|
return correctedLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbEngine::attemptBreakpointSynchronization()
|
void CdbEngine::insertBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
if (debug)
|
BreakpointParameters parameters = bp->requestedParameters();
|
||||||
qDebug("attemptBreakpointSynchronization in %s", qPrintable(stateName(state())));
|
const auto handleBreakInsertCB = [this, bp](const DebuggerResponse &r) { handleBreakInsert(r, bp); };
|
||||||
// Check if there is anything to be done at all.
|
BreakpointParameters response = parameters;
|
||||||
BreakHandler *handler = breakHandler();
|
auto responseId = QString::number(breakPointIdToCdbId(bp));
|
||||||
// Take ownership of the breakpoint. Requests insertion. TODO: Cpp only?
|
QScopedPointer<BreakpointCorrectionContext> lineCorrection(
|
||||||
for (Breakpoint bp : handler->unclaimedBreakpoints())
|
new BreakpointCorrectionContext(m_codeModelSnapshot, CppTools::CppModelManager::instance()->workingCopy()));
|
||||||
if (acceptsBreakpoint(bp))
|
if (!m_autoBreakPointCorrection
|
||||||
bp.setEngine(this);
|
&& parameters.type == BreakpointByFileAndLine
|
||||||
|
&& boolSetting(CdbBreakPointCorrection)) {
|
||||||
// Quick check: is there a need to change something? - Populate module cache
|
response.lineNumber = int(lineCorrection->fixLineNumber(
|
||||||
bool changed = !m_insertSubBreakpointMap.isEmpty();
|
parameters.fileName, unsigned(parameters.lineNumber)));
|
||||||
const Breakpoints bps = handler->engineBreakpoints(this);
|
QString cmd = cdbAddBreakpointCommand(response, m_sourcePathMappings, responseId, false);
|
||||||
if (!changed) {
|
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
|
||||||
for (Breakpoint bp : bps) {
|
} else {
|
||||||
switch (bp.state()) {
|
QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, responseId, false);
|
||||||
case BreakpointInsertRequested:
|
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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)
|
if (debugBreakpoints)
|
||||||
qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d",
|
qDebug("Adding %d %s\n", bp->modelId(), qPrintable(response.toString()));
|
||||||
elapsedLogTime(), m_accessible, qPrintable(stateName(state())), bps.size(), changed);
|
listBreakpoints();
|
||||||
if (!changed)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
// Add/Change breakpoints and store pending ones in map, since
|
void CdbEngine::removeBreakpoint(const Breakpoint &bp)
|
||||||
// Breakhandler::setResponse() on pending breakpoints clears the pending flag.
|
{
|
||||||
// handleBreakPoints will the complete that information and set it on the break handler.
|
runCommand({cdbClearBreakpointCommand(bp), NoFlags});
|
||||||
bool addedChanged = false;
|
notifyBreakpointRemoveProceeding(bp);
|
||||||
QScopedPointer<BreakpointCorrectionContext> lineCorrection;
|
notifyBreakpointRemoveOk(bp);
|
||||||
for (Breakpoint bp : bps) {
|
m_pendingBreakpointMap.remove(bp);
|
||||||
BreakpointParameters parameters = bp.parameters();
|
}
|
||||||
BreakpointModelId id = bp.id();
|
|
||||||
const auto handleBreakInsertCB = [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); };
|
static QString enableBreakpointCommand(const QString &responseId, bool on)
|
||||||
BreakpointResponse response;
|
{
|
||||||
response.fromParameters(parameters);
|
const QString command(on ? QString("be") : QString("bd"));
|
||||||
response.id = BreakpointResponseId(id.majorPart(), id.minorPart());
|
return command + ' ' + responseId;
|
||||||
// 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);
|
void CdbEngine::updateBreakpoint(const Breakpoint &bp)
|
||||||
if (it != m_fileNameModuleHash.constEnd())
|
{
|
||||||
parameters.module = it.value();
|
BreakpointParameters parameters = bp->requestedParameters();
|
||||||
}
|
const auto handleBreakInsertCB = [this, bp](const DebuggerResponse &r) { handleBreakInsert(r, bp); };
|
||||||
switch (bp.state()) {
|
BreakpointParameters response = parameters;
|
||||||
case BreakpointInsertRequested:
|
auto responseId = QString::number(breakPointIdToCdbId(bp));
|
||||||
if (!m_autoBreakPointCorrection
|
notifyBreakpointChangeProceeding(bp);
|
||||||
&& parameters.type == BreakpointByFileAndLine
|
if (debugBreakpoints)
|
||||||
&& boolSetting(CdbBreakPointCorrection)) {
|
qDebug("Changing %d:\n %s\nTo %s\n", bp->modelId(),
|
||||||
if (lineCorrection.isNull())
|
qPrintable(bp->parameters().toString()),
|
||||||
lineCorrection.reset(new BreakpointCorrectionContext(m_codeModelSnapshot,
|
qPrintable(parameters.toString()));
|
||||||
CppTools::CppModelManager::instance()->workingCopy()));
|
if (parameters.enabled != bp->isEnabled()) {
|
||||||
response.lineNumber = int(lineCorrection->fixLineNumber(
|
// Change enabled/disabled breakpoints without triggering update.
|
||||||
parameters.fileName, unsigned(parameters.lineNumber)));
|
bp->forFirstLevelChildren([this, parameters](SubBreakpointItem *sbp){
|
||||||
QString cmd = cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false);
|
breakHandler()->requestSubBreakpointEnabling({sbp}, parameters.enabled);
|
||||||
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
|
});
|
||||||
} else {
|
if (!bp->hasChildren())
|
||||||
QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false);
|
runCommand({enableBreakpointCommand(bp->responseId(), parameters.enabled), NoFlags});
|
||||||
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
|
response.pending = false;
|
||||||
}
|
response.enabled = parameters.enabled;
|
||||||
if (!parameters.enabled)
|
bp->setParameters(response);
|
||||||
runCommand({"bd " + QString::number(breakPointIdToCdbId(id)), NoFlags});
|
} else {
|
||||||
bp.notifyBreakpointInsertProceeding();
|
// Delete and re-add, triggering update
|
||||||
bp.notifyBreakpointInsertOk();
|
runCommand({cdbClearBreakpointCommand(bp), NoFlags});
|
||||||
m_pendingBreakpointMap.insert(id, response);
|
QString cmd = cdbAddBreakpointCommand(parameters, m_sourcePathMappings, responseId, false);
|
||||||
addedChanged = true;
|
runCommand({cmd, BuiltinCommand, handleBreakInsertCB});
|
||||||
// Ensure enabled/disabled is correct in handler and line number is there.
|
m_pendingBreakpointMap.insert(bp);
|
||||||
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)
|
|
||||||
listBreakpoints();
|
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
|
// 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;
|
int value = 0;
|
||||||
if (response.resultClass == ResultDone)
|
if (response.resultClass == ResultDone)
|
||||||
@@ -2862,9 +2822,9 @@ void CdbEngine::handleExpression(const DebuggerResponse &response, BreakpointMod
|
|||||||
// Is this a conditional breakpoint?
|
// Is this a conditional breakpoint?
|
||||||
const QString message = value ?
|
const QString message = value ?
|
||||||
tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
|
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.").
|
tr("Value 0 obtained from evaluating the condition of breakpoint %1, continuing.").
|
||||||
arg(id.toString());
|
arg(bp->displayName());
|
||||||
showMessage(message, LogMisc);
|
showMessage(message, LogMisc);
|
||||||
// Stop if evaluation is true, else continue
|
// Stop if evaluation is true, else continue
|
||||||
if (value)
|
if (value)
|
||||||
@@ -2905,10 +2865,9 @@ void CdbEngine::handleWidgetAt(const DebuggerResponse &response)
|
|||||||
m_watchPointX = m_watchPointY = 0;
|
m_watchPointX = m_watchPointY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void formatCdbBreakPointResponse(BreakpointModelId id, const BreakpointResponse &r,
|
static void formatCdbBreakPointResponse(int modelId, const QString &responseId, const BreakpointParameters &r, QTextStream &str)
|
||||||
QTextStream &str)
|
|
||||||
{
|
{
|
||||||
str << "Obtained breakpoint " << id << " (#" << r.id.majorPart() << ')';
|
str << "Obtained breakpoint " << modelId << " (#" << responseId << ')';
|
||||||
if (r.pending) {
|
if (r.pending) {
|
||||||
str << ", pending";
|
str << ", pending";
|
||||||
} else {
|
} else {
|
||||||
@@ -2946,46 +2905,62 @@ void CdbEngine::handleBreakPoints(const DebuggerResponse &response)
|
|||||||
QTextStream str(&message);
|
QTextStream str(&message);
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
foreach (const GdbMi &breakPointG, response.data.children()) {
|
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);
|
parseBreakPoint(breakPointG, &reportedResponse);
|
||||||
if (debugBreakpoints)
|
if (debugBreakpoints)
|
||||||
qDebug(" Parsed %d: pending=%d %s\n", reportedResponse.id.majorPart(),
|
qDebug(" Parsed %s: pending=%d %s\n", qPrintable(responseId),
|
||||||
reportedResponse.pending,
|
reportedResponse.pending,
|
||||||
qPrintable(reportedResponse.toString()));
|
qPrintable(reportedResponse.toString()));
|
||||||
if (reportedResponse.id.isValid() && !reportedResponse.pending) {
|
if (!responseId.isEmpty() && !reportedResponse.pending) {
|
||||||
Breakpoint bp = handler->findBreakpointByResponseId(reportedResponse.id);
|
Breakpoint bp = handler->findBreakpointByResponseId(responseId);
|
||||||
if (!bp && reportedResponse.type == BreakpointByFunction)
|
if (!bp && reportedResponse.type == BreakpointByFunction)
|
||||||
continue; // Breakpoints from options, CrtDbgReport() and others.
|
continue; // Breakpoints from options, CrtDbgReport() and others.
|
||||||
QTC_ASSERT(bp, continue);
|
|
||||||
const auto it = m_pendingBreakpointMap.find(bp.id());
|
if (bp) {
|
||||||
const auto subIt = m_pendingSubBreakpointMap.find(
|
if (!bp->isPending())
|
||||||
BreakpointModelId(reportedResponse.id.majorPart(),
|
continue;
|
||||||
reportedResponse.id.minorPart()));
|
QTC_ASSERT(m_pendingBreakpointMap.contains(bp), continue);
|
||||||
if (it != m_pendingBreakpointMap.end() || subIt != m_pendingSubBreakpointMap.end()) {
|
|
||||||
// Complete the response and set on handler.
|
// Complete the response and set on handler.
|
||||||
BreakpointResponse currentResponse = it != m_pendingBreakpointMap.end()
|
BreakpointParameters currentResponse = bp->parameters();
|
||||||
? it.value()
|
|
||||||
: subIt.value();
|
|
||||||
currentResponse.id = reportedResponse.id;
|
|
||||||
currentResponse.address = reportedResponse.address;
|
currentResponse.address = reportedResponse.address;
|
||||||
currentResponse.module = reportedResponse.module;
|
currentResponse.module = reportedResponse.module;
|
||||||
currentResponse.pending = reportedResponse.pending;
|
currentResponse.pending = reportedResponse.pending;
|
||||||
currentResponse.enabled = reportedResponse.enabled;
|
currentResponse.enabled = reportedResponse.enabled;
|
||||||
currentResponse.fileName = reportedResponse.fileName;
|
currentResponse.fileName = reportedResponse.fileName;
|
||||||
currentResponse.lineNumber = reportedResponse.lineNumber;
|
currentResponse.lineNumber = reportedResponse.lineNumber;
|
||||||
formatCdbBreakPointResponse(bp.id(), currentResponse, str);
|
formatCdbBreakPointResponse(bp->modelId(), responseId, currentResponse, str);
|
||||||
if (debugBreakpoints)
|
if (debugBreakpoints)
|
||||||
qDebug(" Setting for %d: %s\n", currentResponse.id.majorPart(),
|
qDebug(" Setting for %s: %s\n", qPrintable(responseId),
|
||||||
qPrintable(currentResponse.toString()));
|
qPrintable(currentResponse.toString()));
|
||||||
if (it != m_pendingBreakpointMap.end()) {
|
bp->setParameters(currentResponse);
|
||||||
bp.setResponse(currentResponse);
|
m_pendingBreakpointMap.remove(bp);
|
||||||
m_pendingBreakpointMap.erase(it);
|
continue;
|
||||||
}
|
|
||||||
if (subIt != m_pendingSubBreakpointMap.end()) {
|
|
||||||
bp.insertSubBreakpoint(currentResponse);
|
|
||||||
m_pendingSubBreakpointMap.erase(subIt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
} // not pending reported
|
||||||
} // foreach
|
} // foreach
|
||||||
if (m_pendingBreakpointMap.empty())
|
if (m_pendingBreakpointMap.empty())
|
||||||
|
@@ -52,12 +52,8 @@ public:
|
|||||||
explicit CdbEngine();
|
explicit CdbEngine();
|
||||||
~CdbEngine() override;
|
~CdbEngine() override;
|
||||||
|
|
||||||
// Factory function that returns 0 if the debug engine library cannot be found.
|
|
||||||
|
|
||||||
bool canHandleToolTip(const DebuggerToolTipContext &context) const override;
|
bool canHandleToolTip(const DebuggerToolTipContext &context) const override;
|
||||||
|
|
||||||
DebuggerEngine *cppEngine() override { return this; }
|
|
||||||
|
|
||||||
void setupEngine() override;
|
void setupEngine() override;
|
||||||
void runEngine() override;
|
void runEngine() override;
|
||||||
void shutdownInferior() override;
|
void shutdownInferior() override;
|
||||||
@@ -81,14 +77,18 @@ public:
|
|||||||
void executeRunToFunction(const QString &functionName) override;
|
void executeRunToFunction(const QString &functionName) override;
|
||||||
void executeJumpToLine(const ContextData &data) override;
|
void executeJumpToLine(const ContextData &data) override;
|
||||||
void assignValueInDebugger(WatchItem *w, const QString &expr, const QVariant &value) 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 activateFrame(int index) override;
|
||||||
void selectThread(ThreadId threadId) override;
|
void selectThread(ThreadId threadId) override;
|
||||||
|
|
||||||
bool stateAcceptsBreakpointChanges() const override;
|
bool stateAcceptsBreakpointChanges() const override;
|
||||||
bool acceptsBreakpoint(Breakpoint bp) const override;
|
bool acceptsBreakpoint(const BreakpointParameters ¶ms) const override;
|
||||||
void attemptBreakpointSynchronization() 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 fetchDisassembler(DisassemblerAgent *agent) override;
|
||||||
void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
|
void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
|
||||||
@@ -119,8 +119,7 @@ private:
|
|||||||
|
|
||||||
void handleDoInterruptInferior(const QString &errorMessage);
|
void handleDoInterruptInferior(const QString &errorMessage);
|
||||||
|
|
||||||
using PendingBreakPointMap = QHash<BreakpointModelId, BreakpointResponse>;
|
typedef QPair<QString, QString> SourcePathMapping;
|
||||||
using SourcePathMapping = QPair<QString, QString>;
|
|
||||||
struct NormalizedSourceFileName // Struct for caching mapped/normalized source files.
|
struct NormalizedSourceFileName // Struct for caching mapped/normalized source files.
|
||||||
{
|
{
|
||||||
NormalizedSourceFileName(const QString &fn = QString(), bool e = false) : fileName(fn), exists(e) {}
|
NormalizedSourceFileName(const QString &fn = QString(), bool e = false) : fileName(fn), exists(e) {}
|
||||||
@@ -176,10 +175,10 @@ private:
|
|||||||
void handleStackTrace(const DebuggerResponse &);
|
void handleStackTrace(const DebuggerResponse &);
|
||||||
void handleRegisters(const DebuggerResponse &);
|
void handleRegisters(const DebuggerResponse &);
|
||||||
void handleJumpToLineAddressResolution(const DebuggerResponse &response, const ContextData &context);
|
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 handleResolveSymbol(const DebuggerResponse &command, const QString &symbol, DisassemblerAgent *agent);
|
||||||
void handleResolveSymbolHelper(const QList<quint64> &addresses, 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 handleCheckWow64(const DebuggerResponse &response, const GdbMi &stack);
|
||||||
void ensureUsing32BitStackInWow64(const DebuggerResponse &response, const GdbMi &stack);
|
void ensureUsing32BitStackInWow64(const DebuggerResponse &response, const GdbMi &stack);
|
||||||
void handleSwitchWow64Stack(const DebuggerResponse &response);
|
void handleSwitchWow64Stack(const DebuggerResponse &response);
|
||||||
@@ -232,11 +231,8 @@ private:
|
|||||||
bool m_sourceStepInto = false;
|
bool m_sourceStepInto = false;
|
||||||
int m_watchPointX = 0;
|
int m_watchPointX = 0;
|
||||||
int m_watchPointY = 0;
|
int m_watchPointY = 0;
|
||||||
PendingBreakPointMap m_pendingBreakpointMap;
|
QSet<Breakpoint> m_pendingBreakpointMap;
|
||||||
PendingBreakPointMap m_insertSubBreakpointMap;
|
|
||||||
PendingBreakPointMap m_pendingSubBreakpointMap;
|
|
||||||
bool m_autoBreakPointCorrection = false;
|
bool m_autoBreakPointCorrection = false;
|
||||||
QHash<QString, QString> m_fileNameModuleHash;
|
|
||||||
QMultiHash<QString, quint64> m_symbolAddressCache;
|
QMultiHash<QString, quint64> m_symbolAddressCache;
|
||||||
bool m_ignoreCdbOutput = false;
|
bool m_ignoreCdbOutput = false;
|
||||||
QList<InterruptCallback> m_interrupCallbacks;
|
QList<InterruptCallback> m_interrupCallbacks;
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "stringinputstream.h"
|
#include "stringinputstream.h"
|
||||||
|
|
||||||
|
#include <debugger/breakhandler.h>
|
||||||
#include <debugger/debuggerprotocol.h>
|
#include <debugger/debuggerprotocol.h>
|
||||||
#include <debugger/disassemblerlines.h>
|
#include <debugger/disassemblerlines.h>
|
||||||
#include <debugger/shared/hostutils.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
|
// 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.
|
// is set, perform reverse lookup in the source path mappings.
|
||||||
static inline QString cdbBreakPointFileName(const BreakpointParameters &bp,
|
static inline QString cdbBreakPointFileName(const BreakpointParameters ¶ms,
|
||||||
const QList<QPair<QString, QString> > &sourcePathMapping)
|
const QList<QPair<QString, QString> > &sourcePathMapping)
|
||||||
{
|
{
|
||||||
if (bp.fileName.isEmpty())
|
if (params.fileName.isEmpty())
|
||||||
return bp.fileName;
|
return params.fileName;
|
||||||
if (bp.pathUsage == BreakpointUseShortPath)
|
if (params.pathUsage == BreakpointUseShortPath)
|
||||||
return Utils::FileName::fromString(bp.fileName).fileName();
|
return Utils::FileName::fromString(params.fileName).fileName();
|
||||||
return cdbSourcePathMapping(QDir::toNativeSeparators(bp.fileName), sourcePathMapping, SourceToDebugger);
|
return cdbSourcePathMapping(QDir::toNativeSeparators(params.fileName), sourcePathMapping, SourceToDebugger);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
|
static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
|
||||||
@@ -127,69 +128,46 @@ static BreakpointParameters fixWinMSVCBreakpoint(const BreakpointParameters &p)
|
|||||||
return 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>
|
//static int cdbIdToBreakpointModel(int cdbid)
|
||||||
inline ModelId cdbIdToBreakpointId(const int &id)
|
//{
|
||||||
{
|
// if (cdbid >= cdbBreakPointStartId) {
|
||||||
if (id >= cdbBreakPointStartId) {
|
// int major = (cdbid - cdbBreakPointStartId) / cdbBreakPointIdMinorPart;
|
||||||
int major = (id - cdbBreakPointStartId) / cdbBreakPointIdMinorPart;
|
// int minor = cdbid % cdbBreakPointIdMinorPart;
|
||||||
int minor = id % cdbBreakPointIdMinorPart;
|
// (void) minor;
|
||||||
if (minor)
|
// return major;
|
||||||
return ModelId(major, minor);
|
// }
|
||||||
else
|
// return 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
|
QString cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
|
||||||
const QList<QPair<QString, QString> > &sourcePathMapping,
|
const QList<QPair<QString, QString> > &sourcePathMapping,
|
||||||
BreakpointModelId id /* = BreakpointId() */,
|
const QString &responseId,
|
||||||
bool oneshot)
|
bool oneshot)
|
||||||
{
|
{
|
||||||
const BreakpointParameters bp = fixWinMSVCBreakpoint(bpIn);
|
const BreakpointParameters params = fixWinMSVCBreakpoint(bpIn);
|
||||||
QString rc;
|
QString rc;
|
||||||
StringInputStream str(rc);
|
StringInputStream str(rc);
|
||||||
|
|
||||||
if (bp.threadSpec >= 0)
|
if (params.threadSpec >= 0)
|
||||||
str << '~' << bp.threadSpec << ' ';
|
str << '~' << params.threadSpec << ' ';
|
||||||
|
|
||||||
// Currently use 'bu' so that the offset expression (including file name)
|
// Currently use 'bu' so that the offset expression (including file name)
|
||||||
// is kept when reporting back breakpoints (which is otherwise discarded
|
// is kept when reporting back breakpoints (which is otherwise discarded
|
||||||
// when resolving).
|
// when resolving).
|
||||||
str << (bp.type == WatchpointAtAddress ? "ba" : "bu");
|
str << (params.type == WatchpointAtAddress ? "ba" : "bu")
|
||||||
if (id.isValid())
|
<< responseId
|
||||||
str << breakPointIdToCdbId(id);
|
<< ' ';
|
||||||
str << ' ';
|
|
||||||
if (oneshot)
|
if (oneshot)
|
||||||
str << "/1 ";
|
str << "/1 ";
|
||||||
switch (bp.type) {
|
switch (params.type) {
|
||||||
case BreakpointAtFork:
|
case BreakpointAtFork:
|
||||||
case BreakpointAtExec:
|
case BreakpointAtExec:
|
||||||
case WatchpointAtExpression:
|
case WatchpointAtExpression:
|
||||||
@@ -204,39 +182,41 @@ QString cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
|
|||||||
QTC_ASSERT(false, return QString());
|
QTC_ASSERT(false, return QString());
|
||||||
break;
|
break;
|
||||||
case BreakpointByAddress:
|
case BreakpointByAddress:
|
||||||
str << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
|
str << hex << hexPrefixOn << params.address << hexPrefixOff << dec;
|
||||||
break;
|
break;
|
||||||
case BreakpointByFunction:
|
case BreakpointByFunction:
|
||||||
if (!bp.module.isEmpty())
|
if (!params.module.isEmpty())
|
||||||
str << bp.module << '!';
|
str << params.module << '!';
|
||||||
str << bp.functionName;
|
str << params.functionName;
|
||||||
break;
|
break;
|
||||||
case BreakpointByFileAndLine:
|
case BreakpointByFileAndLine:
|
||||||
str << '`';
|
str << '`';
|
||||||
if (!bp.module.isEmpty())
|
if (!params.module.isEmpty())
|
||||||
str << bp.module << '!';
|
str << params.module << '!';
|
||||||
str << cdbBreakPointFileName(bp, sourcePathMapping) << ':' << bp.lineNumber << '`';
|
str << cdbBreakPointFileName(params, sourcePathMapping) << ':' << params.lineNumber << '`';
|
||||||
break;
|
break;
|
||||||
case WatchpointAtAddress: { // Read/write, no space here
|
case WatchpointAtAddress: { // Read/write, no space here
|
||||||
const unsigned size = bp.size ? bp.size : 1;
|
const unsigned size = params.size ? params.size : 1;
|
||||||
str << 'r' << size << ' ' << hex << hexPrefixOn << bp.address << hexPrefixOff << dec;
|
str << 'r' << size << ' ' << hex << hexPrefixOn << params.address << hexPrefixOff << dec;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (bp.ignoreCount)
|
if (params.ignoreCount)
|
||||||
str << " 0n" << (bp.ignoreCount + 1);
|
str << " 0n" << (params.ignoreCount + 1);
|
||||||
// Condition currently unsupported.
|
// Condition currently unsupported.
|
||||||
if (!bp.command.isEmpty())
|
if (!params.command.isEmpty())
|
||||||
str << " \"" << bp.command << '"';
|
str << " \"" << params.command << '"';
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString cdbClearBreakpointCommand(const BreakpointModelId &id)
|
QString cdbClearBreakpointCommand(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
const int firstBreakPoint = breakPointIdToCdbId(id);
|
// FIME: Check
|
||||||
if (id.isMinor())
|
// const int firstBreakPoint = breakPointIdToCdbId(id);
|
||||||
return "bc " + QString::number(firstBreakPoint);
|
// if (id.isMinor())
|
||||||
|
// return "bc " + QString::number(firstBreakPoint);
|
||||||
// If this is a major break point we also want to delete all sub break points
|
// 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;
|
const int lastBreakPoint = firstBreakPoint + cdbBreakPointIdMinorPart - 1;
|
||||||
return "bc " + QString::number(firstBreakPoint) + '-' + QString::number(lastBreakPoint);
|
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.
|
// Parse extension command listing breakpoints.
|
||||||
// Note that not all fields are returned, since file, line, function are encoded
|
// 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).
|
// 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 */)
|
QString *expression /* = 0 */)
|
||||||
{
|
{
|
||||||
gdbmiChildToBool(gdbmi, "enabled", &(r->enabled));
|
gdbmiChildToBool(gdbmi, "enabled", &(r->enabled));
|
||||||
gdbmiChildToBool(gdbmi, "deferred", &(r->pending));
|
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"];
|
const GdbMi moduleG = gdbmi["module"];
|
||||||
if (moduleG.isValid())
|
if (moduleG.isValid())
|
||||||
r->module = moduleG.data();
|
r->module = moduleG.data();
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <debugger/breakpoint.h>
|
#include <debugger/breakhandler.h>
|
||||||
|
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
@@ -36,7 +36,6 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class BreakpointData;
|
|
||||||
class BreakpointParameters;
|
class BreakpointParameters;
|
||||||
struct ThreadData;
|
struct ThreadData;
|
||||||
class Register;
|
class Register;
|
||||||
@@ -54,19 +53,17 @@ QString cdbSourcePathMapping(QString fileName,
|
|||||||
enum { cdbBreakPointStartId = 100000,
|
enum { cdbBreakPointStartId = 100000,
|
||||||
cdbBreakPointIdMinorPart = 100};
|
cdbBreakPointIdMinorPart = 100};
|
||||||
|
|
||||||
int breakPointIdToCdbId(const BreakpointModelId &id);
|
int breakPointIdToCdbId(const Breakpoint &bp);
|
||||||
BreakpointModelId cdbIdToBreakpointModelId(const GdbMi &id);
|
|
||||||
BreakpointResponseId cdbIdToBreakpointResponseId(const GdbMi &id);
|
|
||||||
|
|
||||||
// Convert breakpoint in CDB syntax (applying source path mappings using native paths).
|
// Convert breakpoint in CDB syntax (applying source path mappings using native paths).
|
||||||
QString cdbAddBreakpointCommand(const BreakpointParameters &d,
|
QString cdbAddBreakpointCommand(const BreakpointParameters &d,
|
||||||
const QList<QPair<QString, QString> > &sourcePathMapping,
|
const QList<QPair<QString, QString> > &sourcePathMapping,
|
||||||
BreakpointModelId id = BreakpointModelId(quint16(-1)), bool oneshot = false);
|
const QString &responseId = QString(), bool oneshot = false);
|
||||||
QString cdbClearBreakpointCommand(const BreakpointModelId &id);
|
QString cdbClearBreakpointCommand(const Breakpoint &bp);
|
||||||
// Parse extension command listing breakpoints.
|
// Parse extension command listing breakpoints.
|
||||||
// Note that not all fields are returned, since file, line, function are encoded
|
// 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).
|
// 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 ...).
|
// Write memory (f ...).
|
||||||
QString cdbWriteMemoryCommand(quint64 addr, const QByteArray &data);
|
QString cdbWriteMemoryCommand(quint64 addr, const QByteArray &data);
|
||||||
|
@@ -41,7 +41,6 @@ HEADERS += \
|
|||||||
procinterrupt.h \
|
procinterrupt.h \
|
||||||
registerhandler.h \
|
registerhandler.h \
|
||||||
snapshothandler.h \
|
snapshothandler.h \
|
||||||
snapshotwindow.h \
|
|
||||||
sourceagent.h \
|
sourceagent.h \
|
||||||
sourcefileshandler.h \
|
sourcefileshandler.h \
|
||||||
sourceutils.h \
|
sourceutils.h \
|
||||||
@@ -89,7 +88,6 @@ SOURCES += \
|
|||||||
procinterrupt.cpp \
|
procinterrupt.cpp \
|
||||||
registerhandler.cpp \
|
registerhandler.cpp \
|
||||||
snapshothandler.cpp \
|
snapshothandler.cpp \
|
||||||
snapshotwindow.cpp \
|
|
||||||
sourceagent.cpp \
|
sourceagent.cpp \
|
||||||
sourcefileshandler.cpp \
|
sourcefileshandler.cpp \
|
||||||
sourceutils.cpp \
|
sourceutils.cpp \
|
||||||
|
@@ -72,7 +72,6 @@ Project {
|
|||||||
"procinterrupt.cpp", "procinterrupt.h",
|
"procinterrupt.cpp", "procinterrupt.h",
|
||||||
"registerhandler.cpp", "registerhandler.h",
|
"registerhandler.cpp", "registerhandler.h",
|
||||||
"snapshothandler.cpp", "snapshothandler.h",
|
"snapshothandler.cpp", "snapshothandler.h",
|
||||||
"snapshotwindow.cpp", "snapshotwindow.h",
|
|
||||||
"sourceagent.cpp", "sourceagent.h",
|
"sourceagent.cpp", "sourceagent.h",
|
||||||
"sourcefileshandler.cpp", "sourcefileshandler.h",
|
"sourcefileshandler.cpp", "sourcefileshandler.h",
|
||||||
"sourceutils.cpp", "sourceutils.h",
|
"sourceutils.cpp", "sourceutils.h",
|
||||||
@@ -143,7 +142,6 @@ Project {
|
|||||||
prefix: "qml/"
|
prefix: "qml/"
|
||||||
files: [
|
files: [
|
||||||
"interactiveinterpreter.cpp", "interactiveinterpreter.h",
|
"interactiveinterpreter.cpp", "interactiveinterpreter.h",
|
||||||
"qmlcppengine.cpp", "qmlcppengine.h",
|
|
||||||
"qmlengine.cpp", "qmlengine.h",
|
"qmlengine.cpp", "qmlengine.h",
|
||||||
"qmlengineutils.cpp", "qmlengineutils.h",
|
"qmlengineutils.cpp", "qmlengineutils.h",
|
||||||
"qmlinspectoragent.cpp", "qmlinspectoragent.h",
|
"qmlinspectoragent.cpp", "qmlinspectoragent.h",
|
||||||
|
@@ -101,8 +101,12 @@ void GlobalDebuggerOptions::fromSettings()
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static DebuggerSettings *theDebuggerSettings = nullptr;
|
||||||
|
|
||||||
DebuggerSettings::DebuggerSettings()
|
DebuggerSettings::DebuggerSettings()
|
||||||
{
|
{
|
||||||
|
theDebuggerSettings = this;
|
||||||
|
|
||||||
const QString debugModeGroup = QLatin1String(debugModeSettingsGroupC);
|
const QString debugModeGroup = QLatin1String(debugModeSettingsGroupC);
|
||||||
const QString cdbSettingsGroup = QLatin1String(cdbSettingsGroupC);
|
const QString cdbSettingsGroup = QLatin1String(cdbSettingsGroupC);
|
||||||
|
|
||||||
@@ -580,6 +584,7 @@ DebuggerSettings::DebuggerSettings()
|
|||||||
item->setText(tr("Enable Reverse Debugging"));
|
item->setText(tr("Enable Reverse Debugging"));
|
||||||
item->setCheckable(true);
|
item->setCheckable(true);
|
||||||
item->setDefaultValue(false);
|
item->setDefaultValue(false);
|
||||||
|
item->setIcon(Icons::REVERSE_MODE.icon());
|
||||||
insertItem(EnableReverseDebugging, item);
|
insertItem(EnableReverseDebugging, item);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -693,10 +698,10 @@ SavedAction *DebuggerSettings::item(int code) const
|
|||||||
return m_items.value(code, 0);
|
return m_items.value(code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DebuggerSettings::dump() const
|
QString DebuggerSettings::dump()
|
||||||
{
|
{
|
||||||
QStringList settings;
|
QStringList settings;
|
||||||
foreach (SavedAction *item, m_items) {
|
foreach (SavedAction *item, theDebuggerSettings->m_items) {
|
||||||
QString key = item->settingsKey();
|
QString key = item->settingsKey();
|
||||||
if (!key.isEmpty()) {
|
if (!key.isEmpty()) {
|
||||||
const QString current = item->value().toString();
|
const QString current = item->value().toString();
|
||||||
|
@@ -61,7 +61,7 @@ public:
|
|||||||
void insertItem(int code, Utils::SavedAction *item);
|
void insertItem(int code, Utils::SavedAction *item);
|
||||||
Utils::SavedAction *item(int code) const;
|
Utils::SavedAction *item(int code) const;
|
||||||
|
|
||||||
QString dump() const;
|
static QString dump();
|
||||||
|
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings() const;
|
void writeSettings() const;
|
||||||
|
@@ -38,8 +38,8 @@ const char C_DEBUGMODE[] = "Debugger.DebugMode";
|
|||||||
const char C_CPPDEBUGGER[] = "Gdb Debugger";
|
const char C_CPPDEBUGGER[] = "Gdb Debugger";
|
||||||
const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger";
|
const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger";
|
||||||
|
|
||||||
const char CppPerspectiveId[] = "Debugger.Perspective.Cpp";
|
const char PRESET_PERSPRECTIVE_ID[] = "Debugger.Perspective.Preset";
|
||||||
const char QmlPerspectiveId[] = "Debugger.Perspective.Qml";
|
const char PERSPECTIVE_ID[] = "Debugger.Perspective";
|
||||||
|
|
||||||
// Menu Groups
|
// Menu Groups
|
||||||
const char G_GENERAL[] = "Debugger.Group.General";
|
const char G_GENERAL[] = "Debugger.Group.General";
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "debuggerconstants.h"
|
#include "debuggerconstants.h"
|
||||||
|
|
||||||
|
#include <coreplugin/id.h>
|
||||||
#include <projectexplorer/abi.h>
|
#include <projectexplorer/abi.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -43,7 +44,10 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace CPlusPlus { class Snapshot; }
|
namespace CPlusPlus { class Snapshot; }
|
||||||
|
|
||||||
namespace Utils { class SavedAction; }
|
namespace Utils {
|
||||||
|
class BaseTreeView;
|
||||||
|
class SavedAction;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
|
|
||||||
@@ -51,12 +55,9 @@ class DebuggerRunTool;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class BreakHandler;
|
|
||||||
class DebuggerEngine;
|
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class Section;
|
class Section;
|
||||||
class GlobalDebuggerOptions;
|
class GlobalDebuggerOptions;
|
||||||
class WatchTreeView;
|
|
||||||
|
|
||||||
enum TestCases
|
enum TestCases
|
||||||
{
|
{
|
||||||
@@ -65,34 +66,14 @@ enum TestCases
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Some convenience.
|
// Some convenience.
|
||||||
void updateState(DebuggerRunTool *runTool);
|
|
||||||
void updateLocalsWindow(bool showReturn);
|
|
||||||
bool hasSnapshots();
|
|
||||||
void openTextEditor(const QString &titlePattern, const QString &contents);
|
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();
|
QWidget *mainWindow();
|
||||||
void raiseWatchersWindow();
|
|
||||||
bool isRegistersWindowVisible();
|
|
||||||
bool isModulesWindowVisible();
|
|
||||||
void showModuleSymbols(const QString &moduleName, const QVector<Internal::Symbol> &symbols);
|
void showModuleSymbols(const QString &moduleName, const QVector<Internal::Symbol> &symbols);
|
||||||
void showModuleSections(const QString &moduleName, const QVector<Internal::Section> §ions);
|
void showModuleSections(const QString &moduleName, const QVector<Internal::Section> §ions);
|
||||||
void openMemoryEditor();
|
|
||||||
|
|
||||||
void setThreadBoxContents(const QStringList &list, int index);
|
|
||||||
|
|
||||||
QSharedPointer<Internal::GlobalDebuggerOptions> globalDebuggerOptions();
|
QSharedPointer<Internal::GlobalDebuggerOptions> globalDebuggerOptions();
|
||||||
|
|
||||||
WatchTreeView *inspectorView();
|
|
||||||
QVariant sessionValue(const QByteArray &name);
|
QVariant sessionValue(const QByteArray &name);
|
||||||
void setSessionValue(const QByteArray &name, const QVariant &value);
|
void setSessionValue(const QByteArray &name, const QVariant &value);
|
||||||
QVariant configValue(const QString &name);
|
QVariant configValue(const QString &name);
|
||||||
@@ -105,9 +86,6 @@ bool boolSetting(int code);
|
|||||||
QString stringSetting(int code);
|
QString stringSetting(int code);
|
||||||
QStringList stringListSetting(int code);
|
QStringList stringListSetting(int code);
|
||||||
|
|
||||||
BreakHandler *breakHandler();
|
|
||||||
DebuggerEngine *currentEngine();
|
|
||||||
|
|
||||||
QMessageBox *showMessageBox(int icon, const QString &title,
|
QMessageBox *showMessageBox(int icon, const QString &title,
|
||||||
const QString &text, int buttons = 0);
|
const QString &text, int buttons = 0);
|
||||||
|
|
||||||
@@ -124,6 +102,7 @@ QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool c
|
|||||||
QStringList qtBuildPaths();
|
QStringList qtBuildPaths();
|
||||||
|
|
||||||
void addDebugInfoTask(unsigned id, const QString &cmd);
|
void addDebugInfoTask(unsigned id, const QString &cmd);
|
||||||
|
QWidget *addSearch(Utils::BaseTreeView *treeView);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,9 @@
|
|||||||
#include "debuggerconstants.h"
|
#include "debuggerconstants.h"
|
||||||
#include "debuggeritem.h"
|
#include "debuggeritem.h"
|
||||||
#include "debuggerprotocol.h"
|
#include "debuggerprotocol.h"
|
||||||
|
#include "breakhandler.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
#include <projectexplorer/devicesupport/idevice.h>
|
#include <projectexplorer/devicesupport/idevice.h>
|
||||||
#include <projectexplorer/runconfiguration.h>
|
#include <projectexplorer/runconfiguration.h>
|
||||||
#include <texteditor/textmark.h>
|
#include <texteditor/textmark.h>
|
||||||
@@ -41,12 +43,14 @@
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QDebug;
|
class QDebug;
|
||||||
class QPoint;
|
class QPoint;
|
||||||
class QAbstractItemModel;
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Core { class IOptionsPage; }
|
namespace Core { class IOptionsPage; }
|
||||||
|
|
||||||
namespace Utils { class MacroExpander; }
|
namespace Utils {
|
||||||
|
class MacroExpander;
|
||||||
|
class Perspective;
|
||||||
|
} // Utils
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
|
|
||||||
@@ -62,7 +66,9 @@ class DisassemblerAgent;
|
|||||||
class MemoryAgent;
|
class MemoryAgent;
|
||||||
class WatchItem;
|
class WatchItem;
|
||||||
class BreakHandler;
|
class BreakHandler;
|
||||||
|
class BreakpointParameters;
|
||||||
class LocationMark;
|
class LocationMark;
|
||||||
|
class LogWindow;
|
||||||
class ModulesHandler;
|
class ModulesHandler;
|
||||||
class RegisterHandler;
|
class RegisterHandler;
|
||||||
class StackHandler;
|
class StackHandler;
|
||||||
@@ -70,8 +76,7 @@ class StackFrame;
|
|||||||
class SourceFilesHandler;
|
class SourceFilesHandler;
|
||||||
class ThreadsHandler;
|
class ThreadsHandler;
|
||||||
class WatchHandler;
|
class WatchHandler;
|
||||||
class Breakpoint;
|
class WatchTreeView;
|
||||||
class QmlCppEngine;
|
|
||||||
class DebuggerToolTipContext;
|
class DebuggerToolTipContext;
|
||||||
class MemoryViewSetupData;
|
class MemoryViewSetupData;
|
||||||
class TerminalRunner;
|
class TerminalRunner;
|
||||||
@@ -157,7 +162,6 @@ public:
|
|||||||
|
|
||||||
bool isCppDebugging() const;
|
bool isCppDebugging() const;
|
||||||
bool isNativeMixedDebugging() const;
|
bool isNativeMixedDebugging() const;
|
||||||
void validateExecutable();
|
|
||||||
|
|
||||||
Utils::MacroExpander *macroExpander = nullptr;
|
Utils::MacroExpander *macroExpander = nullptr;
|
||||||
|
|
||||||
@@ -219,32 +223,21 @@ private:
|
|||||||
quint64 m_address = 0;
|
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
|
class DebuggerEngine : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DebuggerEngine();
|
DebuggerEngine();
|
||||||
~DebuggerEngine() override;
|
~DebuggerEngine() override;
|
||||||
|
|
||||||
const DebuggerRunParameters &runParameters() const;
|
void setRunTool(DebuggerRunTool *runTool);
|
||||||
|
void setRunParameters(const DebuggerRunParameters &runParameters);
|
||||||
|
|
||||||
virtual void setRunTool(DebuggerRunTool *runTool);
|
const DebuggerRunParameters &runParameters() const;
|
||||||
DebuggerRunTool *runTool() const;
|
bool isStartupRunConfiguration() const;
|
||||||
|
void setCompanionEngine(DebuggerEngine *engine);
|
||||||
|
void setSecondaryEngine();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
@@ -269,6 +262,7 @@ public:
|
|||||||
void updateWatchData(const QString &iname); // FIXME: Merge with above.
|
void updateWatchData(const QString &iname); // FIXME: Merge with above.
|
||||||
virtual void selectWatchData(const QString &iname);
|
virtual void selectWatchData(const QString &iname);
|
||||||
|
|
||||||
|
virtual void validateExecutable() {}
|
||||||
virtual void prepareForRestart() {}
|
virtual void prepareForRestart() {}
|
||||||
virtual void abortDebuggerProcess() {} // second attempt
|
virtual void abortDebuggerProcess() {} // second attempt
|
||||||
|
|
||||||
@@ -308,39 +302,39 @@ public:
|
|||||||
virtual void updateAll();
|
virtual void updateAll();
|
||||||
virtual void updateLocals();
|
virtual void updateLocals();
|
||||||
|
|
||||||
|
virtual Core::Context languageContext() const { return {}; }
|
||||||
|
virtual QString displayName() const;
|
||||||
|
|
||||||
virtual bool stateAcceptsBreakpointChanges() const { return true; }
|
virtual bool stateAcceptsBreakpointChanges() const { return true; }
|
||||||
virtual void attemptBreakpointSynchronization();
|
virtual bool acceptsBreakpoint(const BreakpointParameters &bp) const = 0;
|
||||||
virtual bool acceptsBreakpoint(Breakpoint bp) const = 0;
|
virtual void insertBreakpoint(const Breakpoint &bp) = 0;
|
||||||
virtual void insertBreakpoint(Breakpoint bp); // FIXME: make pure
|
virtual void removeBreakpoint(const Breakpoint &bp) = 0;
|
||||||
virtual void removeBreakpoint(Breakpoint bp); // FIXME: make pure
|
virtual void updateBreakpoint(const Breakpoint &bp) = 0;
|
||||||
virtual void changeBreakpoint(Breakpoint bp); // FIXME: make pure
|
virtual void enableSubBreakpoint(const SubBreakpoint &sbp, bool enabled);
|
||||||
virtual void enableSubBreakpoint(const QString &locid, bool on);
|
|
||||||
|
|
||||||
virtual bool acceptsDebuggerCommands() const { return true; }
|
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,
|
virtual void assignValueInDebugger(WatchItem *item,
|
||||||
const QString &expr, const QVariant &value);
|
const QString &expr, const QVariant &value);
|
||||||
virtual void selectThread(Internal::ThreadId threadId) = 0;
|
virtual void selectThread(Internal::ThreadId threadId) = 0;
|
||||||
|
|
||||||
virtual Internal::ModulesHandler *modulesHandler() const;
|
virtual void executeRecordReverse(bool) {}
|
||||||
virtual Internal::RegisterHandler *registerHandler() const;
|
virtual void executeReverse(bool) {}
|
||||||
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;
|
ModulesHandler *modulesHandler() const;
|
||||||
virtual QAbstractItemModel *registerModel() const;
|
RegisterHandler *registerHandler() const;
|
||||||
virtual QAbstractItemModel *stackModel() const;
|
StackHandler *stackHandler() const;
|
||||||
virtual QAbstractItemModel *threadsModel() const;
|
ThreadsHandler *threadsHandler() const;
|
||||||
virtual QAbstractItemModel *watchModel() const;
|
WatchHandler *watchHandler() const;
|
||||||
virtual QAbstractItemModel *sourceFilesModel() const;
|
SourceFilesHandler *sourceFilesHandler() const;
|
||||||
|
BreakHandler *breakHandler() const;
|
||||||
|
LogWindow *logWindow() const;
|
||||||
|
DisassemblerAgent *disassemblerAgent() const;
|
||||||
|
|
||||||
void progressPing();
|
void progressPing();
|
||||||
bool debuggerActionsEnabled() const;
|
bool debuggerActionsEnabled() const;
|
||||||
static bool debuggerActionsEnabled(DebuggerState state);
|
virtual bool companionPreventsActions() const;
|
||||||
|
|
||||||
DebuggerState state() const;
|
DebuggerState state() const;
|
||||||
bool isDying() const;
|
bool isDying() const;
|
||||||
@@ -349,7 +343,13 @@ public:
|
|||||||
|
|
||||||
void notifyInferiorPid(const Utils::ProcessHandle &pid);
|
void notifyInferiorPid(const Utils::ProcessHandle &pid);
|
||||||
qint64 inferiorPid() const;
|
qint64 inferiorPid() const;
|
||||||
|
|
||||||
bool isReverseDebugging() const;
|
bool isReverseDebugging() const;
|
||||||
|
void handleBeginOfRecordingReached();
|
||||||
|
void handleRecordingFailed();
|
||||||
|
void handleRecordReverse(bool);
|
||||||
|
void handleReverseDirection(bool);
|
||||||
|
|
||||||
void handleCommand(int role, const QVariant &value);
|
void handleCommand(int role, const QVariant &value);
|
||||||
|
|
||||||
// Convenience
|
// Convenience
|
||||||
@@ -359,30 +359,32 @@ public:
|
|||||||
|
|
||||||
virtual void resetLocation();
|
virtual void resetLocation();
|
||||||
virtual void gotoLocation(const Internal::Location &location);
|
virtual void gotoLocation(const Internal::Location &location);
|
||||||
|
void gotoCurrentLocation();
|
||||||
virtual void quitDebugger(); // called when pressing the stop button
|
virtual void quitDebugger(); // called when pressing the stop button
|
||||||
|
void abortDebugger();
|
||||||
|
|
||||||
void updateViews();
|
bool isPrimaryEngine() const;
|
||||||
bool isSlaveEngine() const;
|
|
||||||
bool isMasterEngine() const;
|
|
||||||
DebuggerEngine *masterEngine();
|
|
||||||
virtual DebuggerEngine *activeEngine() { return this; }
|
|
||||||
virtual DebuggerEngine *cppEngine() { return nullptr; }
|
|
||||||
|
|
||||||
virtual bool canDisplayTooltip() const;
|
virtual bool canDisplayTooltip() const;
|
||||||
|
|
||||||
virtual void notifyInferiorIll();
|
|
||||||
|
|
||||||
QString toFileInProject(const QUrl &fileUrl);
|
QString toFileInProject(const QUrl &fileUrl);
|
||||||
void updateBreakpointMarker(const Breakpoint &bp);
|
|
||||||
void removeBreakpointMarker(const Breakpoint &bp);
|
|
||||||
|
|
||||||
QString expand(const QString &string) const;
|
QString expand(const QString &string) const;
|
||||||
QString nativeStartupCommands() 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:
|
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 notifyEngineSetupOk();
|
||||||
void notifyEngineSetupFailed();
|
void notifyEngineSetupFailed();
|
||||||
void notifyEngineRunFailed();
|
void notifyEngineRunFailed();
|
||||||
@@ -398,14 +400,60 @@ protected:
|
|||||||
void notifyInferiorRunOk();
|
void notifyInferiorRunOk();
|
||||||
void notifyInferiorRunFailed();
|
void notifyInferiorRunFailed();
|
||||||
|
|
||||||
|
void notifyInferiorIll();
|
||||||
|
void notifyInferiorExited();
|
||||||
|
|
||||||
void notifyInferiorStopOk();
|
void notifyInferiorStopOk();
|
||||||
void notifyInferiorSpontaneousStop();
|
void notifyInferiorSpontaneousStop();
|
||||||
void notifyInferiorStopFailed();
|
void notifyInferiorStopFailed();
|
||||||
|
|
||||||
public: // FIXME: Remove, currently needed for Android.
|
public:
|
||||||
void notifyInferiorExited();
|
void updateState(bool alsoUpdateCompanion);
|
||||||
|
QString formatStartParameters() const;
|
||||||
|
WatchTreeView *inspectorView();
|
||||||
|
void updateLocalsWindow(bool showReturn);
|
||||||
|
void raiseWatchersWindow();
|
||||||
|
|
||||||
protected:
|
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:
|
||||||
|
void setDebuggerName(const QString &name);
|
||||||
void notifyDebuggerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus,
|
void notifyDebuggerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus,
|
||||||
const QString &backendName);
|
const QString &backendName);
|
||||||
|
|
||||||
@@ -424,29 +472,27 @@ protected:
|
|||||||
virtual void shutdownEngine() = 0;
|
virtual void shutdownEngine() = 0;
|
||||||
virtual void resetInferior() {}
|
virtual void resetInferior() {}
|
||||||
|
|
||||||
virtual void detachDebugger();
|
virtual void detachDebugger() {}
|
||||||
virtual void executeStep();
|
virtual void executeStep() {}
|
||||||
virtual void executeStepOut();
|
virtual void executeStepOut() {}
|
||||||
virtual void executeNext();
|
virtual void executeNext() {}
|
||||||
virtual void executeStepI();
|
virtual void executeStepI() {}
|
||||||
virtual void executeNextI();
|
virtual void executeNextI() {}
|
||||||
virtual void executeReturn();
|
virtual void executeReturn() {}
|
||||||
|
|
||||||
virtual void continueInferior();
|
virtual void continueInferior() {}
|
||||||
virtual void interruptInferior();
|
virtual void interruptInferior() {}
|
||||||
void requestInterruptInferior();
|
void requestInterruptInferior();
|
||||||
|
|
||||||
virtual void executeRunToLine(const Internal::ContextData &data);
|
virtual void executeRunToLine(const Internal::ContextData &) {}
|
||||||
virtual void executeRunToFunction(const QString &functionName);
|
virtual void executeRunToFunction(const QString &) {}
|
||||||
virtual void executeJumpToLine(const Internal::ContextData &data);
|
virtual void executeJumpToLine(const Internal::ContextData &) {}
|
||||||
|
|
||||||
virtual void frameUp();
|
virtual void frameUp();
|
||||||
virtual void frameDown();
|
virtual void frameDown();
|
||||||
|
|
||||||
virtual void doUpdateLocals(const UpdateParameters ¶ms);
|
virtual void doUpdateLocals(const UpdateParameters ¶ms);
|
||||||
|
|
||||||
void setMasterEngine(DebuggerEngine *masterEngine);
|
|
||||||
|
|
||||||
TerminalRunner *terminal() const;
|
TerminalRunner *terminal() const;
|
||||||
|
|
||||||
static QString msgStopped(const QString &reason = QString());
|
static QString msgStopped(const QString &reason = QString());
|
||||||
@@ -457,35 +503,43 @@ protected:
|
|||||||
bool showStoppedBySignalMessageBox(const QString meaning, QString name);
|
bool showStoppedBySignalMessageBox(const QString meaning, QString name);
|
||||||
void showStoppedByExceptionMessageBox(const QString &description);
|
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 updateLocalsView(const GdbMi &all);
|
||||||
void checkState(DebuggerState state, const char *file, int line);
|
void checkState(DebuggerState state, const char *file, int line);
|
||||||
bool isNativeMixedEnabled() const;
|
bool isNativeMixedEnabled() const;
|
||||||
bool isNativeMixedActive() const;
|
bool isNativeMixedActive() const;
|
||||||
bool isNativeMixedActiveFrame() const;
|
bool isNativeMixedActiveFrame() const;
|
||||||
|
void startDying() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DebuggerRunParameters &mutableRunParameters() const;
|
||||||
|
ProjectExplorer::IDevice::ConstPtr device() const;
|
||||||
|
DebuggerEngine *companionEngine() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Wrapper engine needs access to state of its subengines.
|
|
||||||
friend class QmlCppEngine;
|
|
||||||
friend class DebuggerPluginPrivate;
|
friend class DebuggerPluginPrivate;
|
||||||
|
|
||||||
friend class DebuggerEnginePrivate;
|
friend class DebuggerEnginePrivate;
|
||||||
friend class LocationMark;
|
friend class LocationMark;
|
||||||
DebuggerEnginePrivate *d;
|
DebuggerEnginePrivate *d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CppDebuggerEngine : public DebuggerEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CppDebuggerEngine() {}
|
||||||
|
~CppDebuggerEngine() override {}
|
||||||
|
|
||||||
|
void validateExecutable() override;
|
||||||
|
Core::Context languageContext() const override;
|
||||||
|
};
|
||||||
|
|
||||||
class LocationMark : public TextEditor::TextMark
|
class LocationMark : public TextEditor::TextMark
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LocationMark(DebuggerEngine *engine, const Utils::FileName &file, int line);
|
LocationMark(DebuggerEngine *engine, const Utils::FileName &file, int line);
|
||||||
void removedFromEditor() override { updateLineNumber(0); }
|
void removedFromEditor() override { updateLineNumber(0); }
|
||||||
|
|
||||||
|
void updateIcon();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isDraggable() const override;
|
bool isDraggable() const override;
|
||||||
void dragToLine(int line) override;
|
void dragToLine(int line) override;
|
||||||
|
@@ -81,9 +81,18 @@ const Icon DEBUG_EXIT_SMALL_TOOLBAR({
|
|||||||
const Icon LOCATION({
|
const Icon LOCATION({
|
||||||
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
{":/debugger/images/location_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
||||||
{":/debugger/images/location.png", Theme::IconsWarningToolBarColor}}, Icon::Tint);
|
{":/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({
|
const Icon REVERSE_MODE({
|
||||||
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
{":/debugger/images/debugger_reversemode_background.png", Theme::IconsCodeModelOverlayForegroundColor},
|
||||||
{":/debugger/images/debugger_reversemode.png", Theme::IconsInfoColor}}, Icon::Tint);
|
{":/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({
|
const Icon APP_ON_TOP({
|
||||||
{":/utils/images/app-on-top.png", Theme::PanelTextColorMid}}, Icon::MenuTintedStyle);
|
{":/utils/images/app-on-top.png", Theme::PanelTextColorMid}}, Icon::MenuTintedStyle);
|
||||||
const Icon APP_ON_TOP_TOOLBAR({
|
const Icon APP_ON_TOP_TOOLBAR({
|
||||||
|
@@ -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;
|
||||||
extern const Utils::Icon DEBUG_EXIT_SMALL_TOOLBAR;
|
extern const Utils::Icon DEBUG_EXIT_SMALL_TOOLBAR;
|
||||||
extern const Utils::Icon LOCATION;
|
extern const Utils::Icon LOCATION;
|
||||||
|
extern const Utils::Icon REVERSE_LOCATION;
|
||||||
extern const Utils::Icon REVERSE_MODE;
|
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;
|
||||||
extern const Utils::Icon APP_ON_TOP_TOOLBAR;
|
extern const Utils::Icon APP_ON_TOP_TOOLBAR;
|
||||||
extern const Utils::Icon SELECT;
|
extern const Utils::Icon SELECT;
|
||||||
|
@@ -31,16 +31,18 @@ namespace Debugger {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
// DebuggerMainWindow dock widget names
|
// DebuggerMainWindow dock widget names
|
||||||
const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";
|
const char DOCKWIDGET_BREAKPOINTMANAGER[] = "Debugger.Docks.BreakpointManager";
|
||||||
const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules";
|
const char DOCKWIDGET_ENGINEMANAGER[] = "Debugger.Docks.Snapshots";
|
||||||
const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register";
|
const char DOCKWIDGET_GLOBALLOG[] = "Debugger.Docks.GlobalLog";
|
||||||
const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output";
|
|
||||||
const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots";
|
const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";
|
||||||
const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack";
|
const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules";
|
||||||
const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles";
|
const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register";
|
||||||
const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads";
|
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_LOCALS_AND_INSPECTOR[] = "Debugger.Docks.LocalsAndInspector";
|
||||||
const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.Watchers";
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
|
@@ -49,6 +49,7 @@
|
|||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QDebug>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
@@ -64,196 +65,154 @@ namespace Utils {
|
|||||||
|
|
||||||
const char LAST_PERSPECTIVE_KEY[] = "LastPerspective";
|
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_centralWidgetStack = new QStackedWidget;
|
||||||
m_statusLabel = new Utils::StatusLabel;
|
m_statusLabel = new Utils::StatusLabel;
|
||||||
|
m_statusLabel->setProperty("panelwidget", true);
|
||||||
m_editorPlaceHolder = new EditorManagerPlaceHolder;
|
m_editorPlaceHolder = new EditorManagerPlaceHolder;
|
||||||
|
|
||||||
m_perspectiveChooser = new QComboBox;
|
m_perspectiveChooser = new QComboBox;
|
||||||
m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser"));
|
m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser"));
|
||||||
|
m_perspectiveChooser->setProperty("panelwidget", true);
|
||||||
connect(m_perspectiveChooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
|
connect(m_perspectiveChooser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
|
||||||
this, [this](int item) {
|
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);
|
setDockNestingEnabled(true);
|
||||||
setDockActionsVisible(false);
|
setDockActionsVisible(false);
|
||||||
setDocumentMode(true);
|
setDocumentMode(true);
|
||||||
|
|
||||||
connect(this, &FancyMainWindow::resetLayout,
|
connect(this, &FancyMainWindow::resetLayout,
|
||||||
this, &DebuggerMainWindow::resetCurrentPerspective);
|
d, &DebuggerMainWindowPrivate::resetCurrentPerspective);
|
||||||
}
|
|
||||||
|
|
||||||
DebuggerMainWindow::~DebuggerMainWindow()
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
m_perspectives.append(perspective);
|
|
||||||
QByteArray parentPerspective = perspective->parentPerspective();
|
|
||||||
// Add "main" perspectives to the chooser.
|
|
||||||
if (parentPerspective.isEmpty()) {
|
|
||||||
m_perspectiveChooser->addItem(perspective->name(), perspective->m_id);
|
|
||||||
increaseChooserWidthIfNecessary(perspective->name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::increaseChooserWidthIfNecessary(const QString &visibleName)
|
|
||||||
{
|
|
||||||
const int oldWidth = m_perspectiveChooser->width();
|
|
||||||
const int contentWidth = m_perspectiveChooser->fontMetrics().width(visibleName);
|
|
||||||
QStyleOptionComboBox option;
|
|
||||||
option.initFrom(m_perspectiveChooser);
|
|
||||||
const QSize sz(contentWidth, 1);
|
|
||||||
const int width = m_perspectiveChooser->style()->sizeFromContents(
|
|
||||||
QStyle::CT_ComboBox, &option, sz).width();
|
|
||||||
if (width > oldWidth)
|
|
||||||
m_perspectiveChooser->setFixedWidth(width);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::destroyDynamicPerspective(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));
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::onModeChanged(Core::Id mode)
|
|
||||||
{
|
|
||||||
if (mode == Debugger::Constants::MODE_DEBUG) {
|
|
||||||
setDockActionsVisible(true);
|
|
||||||
restorePerspective(nullptr);
|
|
||||||
} else {
|
|
||||||
setDockActionsVisible(false);
|
|
||||||
|
|
||||||
// Hide dock widgets manually in case they are floating.
|
|
||||||
foreach (QDockWidget *dockWidget, dockWidgets()) {
|
|
||||||
if (dockWidget->isFloating())
|
|
||||||
dockWidget->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::setPerspectiveEnabled(const QByteArray &perspectiveId, bool enabled)
|
|
||||||
{
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
Perspective *DebuggerMainWindow::findPerspective(const QByteArray &perspectiveId) const
|
|
||||||
{
|
|
||||||
return Utils::findOr(m_perspectives, nullptr, [&](Perspective *perspective) {
|
|
||||||
return perspective->m_id == perspectiveId;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::resetCurrentPerspective()
|
|
||||||
{
|
|
||||||
loadPerspectiveHelper(m_currentPerspective, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DebuggerMainWindow::indexInChooser(Perspective *perspective) const
|
|
||||||
{
|
|
||||||
return perspective ? m_perspectiveChooser->findData(perspective->m_id) : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::restorePerspective(Perspective *perspective)
|
|
||||||
{
|
|
||||||
loadPerspectiveHelper(perspective, true);
|
|
||||||
|
|
||||||
const int index = indexInChooser(m_currentPerspective);
|
|
||||||
if (index != -1)
|
|
||||||
m_perspectiveChooser->setCurrentIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::finalizeSetup()
|
|
||||||
{
|
|
||||||
auto viewButton = new QToolButton;
|
|
||||||
viewButton->setText(tr("&Views"));
|
|
||||||
|
|
||||||
auto closeButton = new QToolButton();
|
|
||||||
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);
|
|
||||||
hbox->setMargin(0);
|
|
||||||
hbox->setSpacing(0);
|
|
||||||
hbox->addWidget(m_perspectiveChooser);
|
|
||||||
hbox->addWidget(toolbuttonBox);
|
|
||||||
hbox->addStretch(3);
|
|
||||||
hbox->addWidget(m_statusLabel);
|
|
||||||
hbox->addStretch(1);
|
|
||||||
hbox->addWidget(new Utils::StyledSeparator);
|
|
||||||
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);
|
Context debugcontext(Debugger::Constants::C_DEBUGMODE);
|
||||||
|
|
||||||
@@ -279,6 +238,156 @@ void DebuggerMainWindow::finalizeSetup()
|
|||||||
"Debugger.Views.ResetSimple", debugcontext);
|
"Debugger.Views.ResetSimple", debugcontext);
|
||||||
cmd->setAttribute(Command::CA_Hide);
|
cmd->setAttribute(Command::CA_Hide);
|
||||||
viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindow::registerPerspective(Perspective *perspective)
|
||||||
|
{
|
||||||
|
d->registerPerspective(perspective);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::registerPerspective(Perspective *perspective)
|
||||||
|
{
|
||||||
|
m_perspectives.append(perspective);
|
||||||
|
QByteArray parentPerspective = perspective->d->m_parentPerspective;
|
||||||
|
// Add "main" perspectives to the chooser.
|
||||||
|
if (parentPerspective.isEmpty()) {
|
||||||
|
m_perspectiveChooser->addItem(perspective->name(), perspective->id());
|
||||||
|
increaseChooserWidthIfNecessary(perspective->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::increaseChooserWidthIfNecessary(const QString &visibleName)
|
||||||
|
{
|
||||||
|
const int oldWidth = m_perspectiveChooser->width();
|
||||||
|
const int contentWidth = m_perspectiveChooser->fontMetrics().width(visibleName);
|
||||||
|
QStyleOptionComboBox option;
|
||||||
|
option.initFrom(m_perspectiveChooser);
|
||||||
|
const QSize sz(contentWidth, 1);
|
||||||
|
const int width = m_perspectiveChooser->style()->sizeFromContents(
|
||||||
|
QStyle::CT_ComboBox, &option, sz).width();
|
||||||
|
if (width > oldWidth)
|
||||||
|
m_perspectiveChooser->setFixedWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::destroyPerspective(Perspective *perspective)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
// All dynamic perspectives currently have a static parent perspective.
|
||||||
|
// This might change in the future, make sure we notice.
|
||||||
|
QTC_CHECK(!perspective->d->m_parentPerspective.isEmpty());
|
||||||
|
restorePerspective(findPerspective(perspective->d->m_parentPerspective));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS)
|
||||||
|
{
|
||||||
|
d->m_statusLabel->showStatusMessage(message, timeoutMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindow::onModeChanged(Core::Id mode)
|
||||||
|
{
|
||||||
|
if (mode == Debugger::Constants::MODE_DEBUG) {
|
||||||
|
setDockActionsVisible(true);
|
||||||
|
d->restorePerspective(nullptr);
|
||||||
|
} else {
|
||||||
|
setDockActionsVisible(false);
|
||||||
|
|
||||||
|
// Hide dock widgets manually in case they are floating.
|
||||||
|
foreach (QDockWidget *dockWidget, dockWidgets()) {
|
||||||
|
if (dockWidget->isFloating())
|
||||||
|
dockWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Perspective *DebuggerMainWindow::findPerspective(const QByteArray &perspectiveId) const
|
||||||
|
{
|
||||||
|
return d->findPerspective(perspectiveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *DebuggerMainWindow::centralWidgetStack()
|
||||||
|
{
|
||||||
|
return d->m_centralWidgetStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
Perspective *DebuggerMainWindowPrivate::findPerspective(const QByteArray &perspectiveId) const
|
||||||
|
{
|
||||||
|
return Utils::findOr(m_perspectives, nullptr, [&](Perspective *perspective) {
|
||||||
|
return perspective->d->m_id.toUtf8() == perspectiveId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindow::closeEvent(QCloseEvent *)
|
||||||
|
{
|
||||||
|
d->savePerspectiveHelper(d->m_currentPerspective);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::resetCurrentPerspective()
|
||||||
|
{
|
||||||
|
loadPerspectiveHelper(m_currentPerspective, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DebuggerMainWindowPrivate::indexInChooser(Perspective *perspective) const
|
||||||
|
{
|
||||||
|
return perspective ? m_perspectiveChooser->findData(perspective->d->m_id) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::restorePerspective(Perspective *perspective)
|
||||||
|
{
|
||||||
|
loadPerspectiveHelper(perspective, true);
|
||||||
|
|
||||||
|
const int index = indexInChooser(m_currentPerspective);
|
||||||
|
if (index != -1)
|
||||||
|
m_perspectiveChooser->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerMainWindowPrivate::ensureToolBarDockExists()
|
||||||
|
{
|
||||||
|
if (m_toolBarDock)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto viewButton = new QToolButton;
|
||||||
|
viewButton->setText(tr("&Views"));
|
||||||
|
|
||||||
|
auto closeButton = new QToolButton();
|
||||||
|
closeButton->setIcon(Utils::Icons::CLOSE_SPLIT_BOTTOM.icon());
|
||||||
|
closeButton->setToolTip(tr("Leave Debug Mode"));
|
||||||
|
|
||||||
|
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);
|
||||||
|
// <- 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);
|
||||||
|
hbox->addWidget(new Utils::StyledSeparator);
|
||||||
|
hbox->addWidget(viewButton);
|
||||||
|
hbox->addWidget(closeButton);
|
||||||
|
|
||||||
auto dock = new QDockWidget(tr("Toolbar"));
|
auto dock = new QDockWidget(tr("Toolbar"));
|
||||||
dock->setObjectName(QLatin1String("Toolbar"));
|
dock->setObjectName(QLatin1String("Toolbar"));
|
||||||
@@ -287,9 +396,18 @@ void DebuggerMainWindow::finalizeSetup()
|
|||||||
dock->setTitleBarWidget(new QWidget(dock)); // hide title bar
|
dock->setTitleBarWidget(new QWidget(dock)); // hide title bar
|
||||||
dock->setProperty("managed_dockwidget", QLatin1String("true"));
|
dock->setProperty("managed_dockwidget", QLatin1String("true"));
|
||||||
dock->setWidget(toolbar);
|
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)
|
QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow)
|
||||||
@@ -342,13 +460,12 @@ QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow)
|
|||||||
return splitter;
|
return splitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings)
|
void DebuggerMainWindowPrivate::loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings)
|
||||||
{
|
{
|
||||||
// Clean up old perspective.
|
// Clean up old perspective.
|
||||||
if (m_currentPerspective) {
|
if (m_currentPerspective) {
|
||||||
savePerspectiveHelper(m_currentPerspective);
|
savePerspectiveHelper(m_currentPerspective);
|
||||||
for (QDockWidget *dock : m_dockForDockId) {
|
for (QDockWidget *dock : m_dockForDockId) {
|
||||||
QTC_ASSERT(dock, continue);
|
|
||||||
dock->setParent(nullptr);
|
dock->setParent(nullptr);
|
||||||
dock->widget()->setParent(nullptr);
|
dock->widget()->setParent(nullptr);
|
||||||
ActionManager::unregisterAction(dock->toggleViewAction(),
|
ActionManager::unregisterAction(dock->toggleViewAction(),
|
||||||
@@ -357,22 +474,11 @@ void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fr
|
|||||||
}
|
}
|
||||||
m_dockForDockId.clear();
|
m_dockForDockId.clear();
|
||||||
|
|
||||||
ICore::removeAdditionalContext(Context(Id::fromName(m_currentPerspective->m_id)));
|
ICore::removeAdditionalContext(m_currentPerspective->context());
|
||||||
QWidget *central = m_currentPerspective->centralWidget();
|
QWidget *central = m_currentPerspective->centralWidget();
|
||||||
m_centralWidgetStack->removeWidget(central ? central : m_editorPlaceHolder);
|
m_centralWidgetStack->removeWidget(central ? central : m_editorPlaceHolder);
|
||||||
|
|
||||||
// Detach potentially re-used widgets to prevent deletion.
|
m_currentPerspective->d->destroyToolBar();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perspective) {
|
if (perspective) {
|
||||||
@@ -380,201 +486,294 @@ void DebuggerMainWindow::loadPerspectiveHelper(Perspective *perspective, bool fr
|
|||||||
} else {
|
} else {
|
||||||
const QSettings *settings = ICore::settings();
|
const QSettings *settings = ICore::settings();
|
||||||
m_currentPerspective = findPerspective(settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray());
|
m_currentPerspective = findPerspective(settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray());
|
||||||
if (!m_currentPerspective)
|
// If we don't find a perspective with the stored name, pick any.
|
||||||
m_currentPerspective = findPerspective(Debugger::Constants::CppPerspectiveId);
|
// 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())
|
if (!m_currentPerspective && !m_perspectives.isEmpty())
|
||||||
m_currentPerspective = m_perspectives.first();
|
m_currentPerspective = m_perspectives.first();
|
||||||
}
|
}
|
||||||
QTC_ASSERT(m_currentPerspective, return);
|
QTC_ASSERT(m_currentPerspective, return);
|
||||||
|
|
||||||
ICore::addAdditionalContext(Context(Id::fromName(m_currentPerspective->m_id)));
|
ICore::addAdditionalContext(m_currentPerspective->context());
|
||||||
|
|
||||||
m_currentPerspective->aboutToActivate();
|
m_currentPerspective->aboutToActivate();
|
||||||
|
|
||||||
for (const Perspective::ToolbarOperation &op : m_currentPerspective->m_toolbarOperations) {
|
for (const DockOperation &op : m_currentPerspective->d->m_dockOperations) {
|
||||||
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) {
|
|
||||||
QTC_ASSERT(op.widget, continue);
|
QTC_ASSERT(op.widget, continue);
|
||||||
const QByteArray dockId = op.widget->objectName().toUtf8();
|
const QByteArray dockId = op.widget->objectName().toUtf8();
|
||||||
QDockWidget *dock = m_dockForDockId.value(dockId);
|
QDockWidget *dock = m_dockForDockId.value(dockId);
|
||||||
if (!dock) {
|
if (!dock) {
|
||||||
QTC_CHECK(!dockId.isEmpty());
|
QTC_CHECK(!dockId.isEmpty());
|
||||||
dock = addDockForWidget(op.widget);
|
dock = q->addDockForWidget(op.widget);
|
||||||
m_dockForDockId[dockId] = dock;
|
m_dockForDockId[dockId] = dock;
|
||||||
|
|
||||||
QAction *toggleViewAction = dock->toggleViewAction();
|
QAction *toggleViewAction = dock->toggleViewAction();
|
||||||
toggleViewAction->setText(dock->windowTitle());
|
toggleViewAction->setText(dock->windowTitle());
|
||||||
|
|
||||||
Command *cmd = ActionManager::registerAction(toggleViewAction,
|
Command *cmd = ActionManager::registerAction(toggleViewAction,
|
||||||
Id("Dock.").withSuffix(dock->objectName()),
|
Id("Dock.").withSuffix(dock->objectName()),
|
||||||
Context(Id::fromName(m_currentPerspective->m_id)));
|
m_currentPerspective->context());
|
||||||
cmd->setAttribute(Command::CA_Hide);
|
cmd->setAttribute(Command::CA_Hide);
|
||||||
|
|
||||||
ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd);
|
ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd);
|
||||||
}
|
}
|
||||||
// Restore parent/child relation, so that the widget hierarchy is clear.
|
// Restore parent/child relation, so that the widget hierarchy is clear.
|
||||||
dock->setParent(this);
|
dock->setParent(q);
|
||||||
if (op.operationType == Perspective::Raise) {
|
if (op.operationType == Perspective::Raise) {
|
||||||
dock->raise();
|
dock->raise();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addDockWidget(op.area, dock);
|
q->addDockWidget(op.area, dock);
|
||||||
QDockWidget *anchor = m_dockForDockId.value(op.anchorDockId);
|
QDockWidget *anchor = m_dockForDockId.value(op.anchorDockId);
|
||||||
if (!anchor && op.area == Qt::BottomDockWidgetArea)
|
if (!anchor && op.area == Qt::BottomDockWidgetArea) {
|
||||||
anchor = m_toolbarDock;
|
ensureToolBarDockExists();
|
||||||
|
anchor = m_toolBarDock;
|
||||||
|
}
|
||||||
|
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
switch (op.operationType) {
|
switch (op.operationType) {
|
||||||
case Perspective::AddToTab:
|
case Perspective::AddToTab:
|
||||||
tabifyDockWidget(anchor, dock);
|
q->tabifyDockWidget(anchor, dock);
|
||||||
break;
|
break;
|
||||||
case Perspective::SplitHorizontal:
|
case Perspective::SplitHorizontal:
|
||||||
splitDockWidget(anchor, dock, Qt::Horizontal);
|
q->splitDockWidget(anchor, dock, Qt::Horizontal);
|
||||||
break;
|
break;
|
||||||
case Perspective::SplitVertical:
|
case Perspective::SplitVertical:
|
||||||
splitDockWidget(anchor, dock, Qt::Vertical);
|
q->splitDockWidget(anchor, dock, Qt::Vertical);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!op.visibleByDefault)
|
dock->setVisible(op.visibleByDefault);
|
||||||
dock->hide();
|
|
||||||
else
|
|
||||||
dock->show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_currentPerspective->d->showToolBar();
|
||||||
|
|
||||||
if (fromStoredSettings) {
|
if (fromStoredSettings) {
|
||||||
QSettings *settings = ICore::settings();
|
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())
|
if (settings->value(QLatin1String("ToolSettingsSaved"), false).toBool())
|
||||||
restoreSettings(settings);
|
q->restoreSettings(settings);
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
} else {
|
} else {
|
||||||
// By default, show the central widget
|
// By default, show the central widget
|
||||||
showCentralWidgetAction()->setChecked(true);
|
q->showCentralWidgetAction()->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *central = m_currentPerspective->centralWidget();
|
QWidget *central = m_currentPerspective->centralWidget();
|
||||||
m_centralWidgetStack->addWidget(central ? central : m_editorPlaceHolder);
|
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();
|
m_statusLabel->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerMainWindow::savePerspectiveHelper(const Perspective *perspective)
|
void DebuggerMainWindowPrivate::savePerspectiveHelper(const Perspective *perspective)
|
||||||
{
|
{
|
||||||
if (!perspective)
|
if (!perspective)
|
||||||
return;
|
return;
|
||||||
QSettings *settings = ICore::settings();
|
QSettings *settings = ICore::settings();
|
||||||
settings->beginGroup(QString::fromLatin1(perspective->m_id));
|
settings->beginGroup(perspective->d->m_id);
|
||||||
saveSettings(settings);
|
q->saveSettings(settings);
|
||||||
settings->setValue(QLatin1String("ToolSettingsSaved"), true);
|
settings->setValue(QLatin1String("ToolSettingsSaved"), true);
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), perspective->m_id);
|
settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), perspective->d->m_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perspective
|
// Perspective
|
||||||
|
|
||||||
Perspective::Perspective(const QByteArray &id, const QString &name)
|
Perspective::Perspective(const QString &id, const QString &name)
|
||||||
: m_id(id), m_name(name)
|
: d(new PerspectivePrivate)
|
||||||
{
|
{
|
||||||
|
d->m_id = id;
|
||||||
|
d->m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Perspective::~Perspective()
|
Perspective::~Perspective()
|
||||||
{
|
{
|
||||||
for (const ToolbarOperation &op : m_toolbarOperations) {
|
delete d;
|
||||||
// op.widget and op.actions are owned by the plugins
|
|
||||||
delete op.toolbutton;
|
|
||||||
delete op.separator;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::setCentralWidget(QWidget *centralWidget)
|
void Perspective::setCentralWidget(QWidget *centralWidget)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_centralWidget == nullptr, return);
|
QTC_ASSERT(d->m_centralWidget == nullptr, return);
|
||||||
m_centralWidget = centralWidget;
|
d->m_centralWidget = centralWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Perspective::name() const
|
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)
|
void Perspective::setAboutToActivateCallback(const Perspective::Callback &cb)
|
||||||
{
|
{
|
||||||
m_aboutToActivateCallback = cb;
|
d->m_aboutToActivateCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::aboutToActivate() const
|
void Perspective::aboutToActivate() const
|
||||||
{
|
{
|
||||||
if (m_aboutToActivateCallback)
|
if (d->m_aboutToActivateCallback)
|
||||||
m_aboutToActivateCallback();
|
d->m_aboutToActivateCallback();
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray Perspective::parentPerspective() const
|
|
||||||
{
|
|
||||||
return m_parentPerspective;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::setParentPerspective(const QByteArray &parentPerspective)
|
void Perspective::setParentPerspective(const QByteArray &parentPerspective)
|
||||||
{
|
{
|
||||||
m_parentPerspective = parentPerspective;
|
d->m_parentPerspective = parentPerspective;
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton *Perspective::addToolbarAction(QAction *action, const QIcon &toolbarIcon)
|
void Perspective::setEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
ToolbarOperation op;
|
const int index = theMainWindow->d->indexInChooser(this);
|
||||||
op.action = action;
|
QTC_ASSERT(index != -1, return);
|
||||||
op.icon = toolbarIcon;
|
auto model = qobject_cast<QStandardItemModel*>(theMainWindow->d->m_perspectiveChooser->model());
|
||||||
op.toolbutton = new QToolButton;
|
QTC_ASSERT(model, return);
|
||||||
// QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget
|
QStandardItem *item = model->item(index, 0);
|
||||||
op.toolbutton->setProperty("panelwidget", true);
|
item->setFlags(enabled ? item->flags() | Qt::ItemIsEnabled : item->flags() & ~Qt::ItemIsEnabled );
|
||||||
op.toolbutton->setDefaultAction(toolbarIcon.isNull()
|
|
||||||
? action : ProxyAction::proxyActionWithIcon(action, toolbarIcon));
|
|
||||||
m_toolbarOperations.append(op);
|
|
||||||
|
|
||||||
return op.toolbutton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::addToolbarWidget(QWidget *widget)
|
void Perspective::addToolBarAction(QAction *action)
|
||||||
|
{
|
||||||
|
auto toolButton = new QToolButton;
|
||||||
|
ToolbarOperation op;
|
||||||
|
op.toolBarPlainAction = action;
|
||||||
|
op.toolBarPlainActionButton = toolButton;
|
||||||
|
d->m_toolBarOperations.append(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Perspective::addToolBarAction(OptionalAction *action)
|
||||||
{
|
{
|
||||||
ToolbarOperation op;
|
ToolbarOperation op;
|
||||||
op.widget = widget;
|
op.toolBarAction = action;
|
||||||
|
d->m_toolBarOperations.append(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Perspective::addToolBarWidget(QWidget *widget)
|
||||||
|
{
|
||||||
|
ToolbarOperation op;
|
||||||
|
op.toolBarWidget = widget;
|
||||||
// QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget
|
// QStyle::polish is called before it is added to the toolbar, explicitly make it a panel widget
|
||||||
op.widget->setProperty("panelwidget", true);
|
op.toolBarWidget->setProperty("panelwidget", true);
|
||||||
m_toolbarOperations.append(op);
|
d->m_toolBarOperations.append(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::addToolbarSeparator()
|
void Perspective::addToolbarSeparator()
|
||||||
{
|
{
|
||||||
ToolbarOperation op;
|
ToolbarOperation op;
|
||||||
op.separator = new StyledSeparator;
|
op.separator = new StyledSeparator;
|
||||||
m_toolbarOperations.append(op);
|
d->m_toolBarOperations.append(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *Perspective::centralWidget() const
|
QWidget *Perspective::centralWidget() const
|
||||||
{
|
{
|
||||||
return m_centralWidget;
|
return d->m_centralWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Perspective::addWindow(QWidget *widget, OperationType type, QWidget *anchorWidget,
|
void Perspective::destroy()
|
||||||
bool visibleByDefault, Qt::DockWidgetArea area)
|
|
||||||
{
|
{
|
||||||
Operation op;
|
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 PerspectivePrivate::hideToolBar()
|
||||||
|
{
|
||||||
|
if (m_toolButtonBox)
|
||||||
|
m_toolButtonBox->setVisible(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
void PerspectivePrivate::destroyToolBar()
|
||||||
|
{
|
||||||
|
// 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;
|
op.widget = widget;
|
||||||
if (anchorWidget)
|
if (anchorWidget)
|
||||||
op.anchorDockId = anchorWidget->objectName().toUtf8();
|
op.anchorDockId = anchorWidget->objectName().toUtf8();
|
||||||
op.operationType = type;
|
op.operationType = type;
|
||||||
op.visibleByDefault = visibleByDefault;
|
op.visibleByDefault = visibleByDefault;
|
||||||
op.area = area;
|
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
|
} // Utils
|
||||||
|
@@ -30,28 +30,44 @@
|
|||||||
#include <utils/fancymainwindow.h>
|
#include <utils/fancymainwindow.h>
|
||||||
#include <utils/statuslabel.h>
|
#include <utils/statuslabel.h>
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QAction>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSet>
|
#include <QToolButton>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
namespace Core {
|
||||||
class QComboBox;
|
class Context;
|
||||||
class QToolButton;
|
class Id;
|
||||||
class QStackedWidget;
|
} // Core
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace Core { class Id; }
|
|
||||||
|
|
||||||
namespace Utils {
|
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:
|
public:
|
||||||
enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise };
|
enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise };
|
||||||
|
|
||||||
explicit Perspective(const QByteArray &id, const QString &name);
|
explicit Perspective(const QString &id, const QString &name);
|
||||||
~Perspective();
|
~Perspective();
|
||||||
|
|
||||||
void setCentralWidget(QWidget *centralWidget);
|
void setCentralWidget(QWidget *centralWidget);
|
||||||
@@ -61,54 +77,36 @@ public:
|
|||||||
bool visibleByDefault = true,
|
bool visibleByDefault = true,
|
||||||
Qt::DockWidgetArea area = Qt::BottomDockWidgetArea);
|
Qt::DockWidgetArea area = Qt::BottomDockWidgetArea);
|
||||||
|
|
||||||
QToolButton *addToolbarAction(QAction *action, const QIcon &toolbarIcon = QIcon());
|
void addToolBarAction(QAction *action);
|
||||||
void addToolbarWidget(QWidget *widget);
|
void addToolBarAction(OptionalAction *action);
|
||||||
|
void addToolBarWidget(QWidget *widget);
|
||||||
void addToolbarSeparator();
|
void addToolbarSeparator();
|
||||||
|
|
||||||
QWidget *centralWidget() const;
|
QWidget *centralWidget() const;
|
||||||
|
|
||||||
QString name() const;
|
QString name() const;
|
||||||
|
QString id() const;
|
||||||
|
|
||||||
using Callback = std::function<void()>;
|
using Callback = std::function<void()>;
|
||||||
void setAboutToActivateCallback(const Callback &cb);
|
void setAboutToActivateCallback(const Callback &cb);
|
||||||
void aboutToActivate() const;
|
void aboutToActivate() const;
|
||||||
|
|
||||||
QByteArray parentPerspective() const;
|
|
||||||
void setParentPerspective(const QByteArray &parentPerspective);
|
void setParentPerspective(const QByteArray &parentPerspective);
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
void select();
|
||||||
|
static Perspective *currentPerspective();
|
||||||
|
|
||||||
|
Core::Context context() const;
|
||||||
|
|
||||||
|
void showToolBar();
|
||||||
|
void hideToolBar();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Perspective(const Perspective &) = delete;
|
|
||||||
void operator=(const Perspective &) = delete;
|
|
||||||
|
|
||||||
friend class DebuggerMainWindow;
|
friend class DebuggerMainWindow;
|
||||||
|
friend class DebuggerMainWindowPrivate;
|
||||||
class PerspectivePrivate *d = nullptr;
|
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
|
class DEBUGGER_EXPORT DebuggerMainWindow : public FancyMainWindow
|
||||||
@@ -120,42 +118,18 @@ public:
|
|||||||
~DebuggerMainWindow() override;
|
~DebuggerMainWindow() override;
|
||||||
|
|
||||||
void registerPerspective(Perspective *perspective);
|
void registerPerspective(Perspective *perspective);
|
||||||
void destroyDynamicPerspective(Perspective *perspective);
|
|
||||||
|
|
||||||
void resetCurrentPerspective();
|
|
||||||
void restorePerspective(Perspective *perspective);
|
|
||||||
|
|
||||||
void finalizeSetup();
|
|
||||||
|
|
||||||
void showStatusMessage(const QString &message, int timeoutMS);
|
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 onModeChanged(Core::Id mode);
|
||||||
|
|
||||||
void setPerspectiveEnabled(const QByteArray &perspectiveId, bool enabled);
|
|
||||||
|
|
||||||
Perspective *findPerspective(const QByteArray &perspectiveId) const;
|
Perspective *findPerspective(const QByteArray &perspectiveId) const;
|
||||||
|
QWidget *centralWidgetStack();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void closeEvent(QCloseEvent *) final { savePerspectiveHelper(m_currentPerspective); }
|
void closeEvent(QCloseEvent *) final;
|
||||||
|
|
||||||
void loadPerspectiveHelper(Perspective *perspective, bool fromStoredSettings = true);
|
friend class Perspective;
|
||||||
void savePerspectiveHelper(const Perspective *perspective);
|
friend class PerspectivePrivate;
|
||||||
void increaseChooserWidthIfNecessary(const QString &visibleName);
|
class DebuggerMainWindowPrivate *d = nullptr;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEBUGGER_EXPORT QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow);
|
DEBUGGER_EXPORT QWidget *createModeWindow(const Core::Id &mode, DebuggerMainWindow *mainWindow);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -301,6 +301,20 @@ const char DisplayImageFile[] = "imagefile:separate";
|
|||||||
const char DisplayPlotData[] = "plotdata:separate";
|
const char DisplayPlotData[] = "plotdata:separate";
|
||||||
const char DisplayArrayData[] = "arraydata: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 Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "debuggerrunconfigurationaspect.h"
|
#include "debuggerrunconfigurationaspect.h"
|
||||||
#include "breakhandler.h"
|
#include "breakhandler.h"
|
||||||
#include "shared/peutils.h"
|
#include "shared/peutils.h"
|
||||||
|
#include "snapshothandler.h"
|
||||||
|
|
||||||
#include <projectexplorer/buildconfiguration.h>
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
|
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
|
||||||
@@ -60,9 +61,11 @@
|
|||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
#include <utils/url.h>
|
#include <utils/url.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/messagebox.h>
|
#include <coreplugin/messagebox.h>
|
||||||
|
|
||||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||||
|
|
||||||
#include <qtsupport/qtkitinformation.h>
|
#include <qtsupport/qtkitinformation.h>
|
||||||
@@ -70,7 +73,9 @@
|
|||||||
#include <ssh/sshconnection.h>
|
#include <ssh/sshconnection.h>
|
||||||
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
using namespace Debugger::Internal;
|
using namespace Debugger::Internal;
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
@@ -84,7 +89,6 @@ DebuggerEngine *createCdbEngine();
|
|||||||
DebuggerEngine *createGdbEngine();
|
DebuggerEngine *createGdbEngine();
|
||||||
DebuggerEngine *createPdbEngine();
|
DebuggerEngine *createPdbEngine();
|
||||||
DebuggerEngine *createQmlEngine();
|
DebuggerEngine *createQmlEngine();
|
||||||
DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine);
|
|
||||||
DebuggerEngine *createLldbEngine();
|
DebuggerEngine *createLldbEngine();
|
||||||
|
|
||||||
class LocalProcessRunner : public RunWorker
|
class LocalProcessRunner : public RunWorker
|
||||||
@@ -92,8 +96,8 @@ class LocalProcessRunner : public RunWorker
|
|||||||
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::LocalProcessRunner)
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::LocalProcessRunner)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LocalProcessRunner(RunControl *runControl, const Runnable &runnable)
|
LocalProcessRunner(DebuggerRunTool *runTool, const Runnable &runnable)
|
||||||
: RunWorker(runControl), m_runnable(runnable)
|
: RunWorker(runTool->runControl()), m_runTool(runTool), m_runnable(runnable)
|
||||||
{
|
{
|
||||||
connect(&m_proc, &QProcess::errorOccurred,
|
connect(&m_proc, &QProcess::errorOccurred,
|
||||||
this, &LocalProcessRunner::handleError);
|
this, &LocalProcessRunner::handleError);
|
||||||
@@ -120,16 +124,14 @@ public:
|
|||||||
{
|
{
|
||||||
const QByteArray ba = m_proc.readAllStandardOutput();
|
const QByteArray ba = m_proc.readAllStandardOutput();
|
||||||
const QString msg = QString::fromLocal8Bit(ba, ba.length());
|
const QString msg = QString::fromLocal8Bit(ba, ba.length());
|
||||||
showMessage(msg, LogOutput);
|
m_runTool->appendMessage(msg, StdOutFormatSameLine);
|
||||||
showMessage(msg, AppOutput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleStandardError()
|
void handleStandardError()
|
||||||
{
|
{
|
||||||
const QByteArray ba = m_proc.readAllStandardError();
|
const QByteArray ba = m_proc.readAllStandardError();
|
||||||
const QString msg = QString::fromLocal8Bit(ba, ba.length());
|
const QString msg = QString::fromLocal8Bit(ba, ba.length());
|
||||||
showMessage(msg, LogOutput);
|
m_runTool->appendMessage(msg, StdErrFormatSameLine);
|
||||||
showMessage(msg, AppError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFinished()
|
void handleFinished()
|
||||||
@@ -172,10 +174,11 @@ public:
|
|||||||
"This is the default return value of error().");
|
"This is the default return value of error().");
|
||||||
}
|
}
|
||||||
|
|
||||||
showMessage(msg, StatusBar);
|
m_runTool->showMessage(msg, StatusBar);
|
||||||
Core::AsynchronousMessageBox::critical(tr("Error"), msg);
|
Core::AsynchronousMessageBox::critical(tr("Error"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPointer<DebuggerRunTool> m_runTool;
|
||||||
Runnable m_runnable;
|
Runnable m_runnable;
|
||||||
Utils::QtcProcess m_proc;
|
Utils::QtcProcess m_proc;
|
||||||
};
|
};
|
||||||
@@ -245,10 +248,14 @@ private:
|
|||||||
class DebuggerRunToolPrivate
|
class DebuggerRunToolPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QPointer<TerminalRunner> terminalRunner;
|
bool useTerminal = false;
|
||||||
QPointer<CoreUnpacker> coreUnpacker;
|
QPointer<CoreUnpacker> coreUnpacker;
|
||||||
QPointer<GdbServerPortsGatherer> portsGatherer;
|
QPointer<GdbServerPortsGatherer> portsGatherer;
|
||||||
bool addQmlServerInferiorCommandLineArgumentIfNeeded = false;
|
bool addQmlServerInferiorCommandLineArgumentIfNeeded = false;
|
||||||
|
TerminalRunner *terminalRunner = nullptr;
|
||||||
|
int snapshotCounter = 0;
|
||||||
|
int engineStartsNeeded = 0;
|
||||||
|
int engineStopsNeeded = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
@@ -372,7 +379,7 @@ void DebuggerRunTool::setUseTerminal(bool on)
|
|||||||
&& boolSetting(UseCdbConsole);
|
&& boolSetting(UseCdbConsole);
|
||||||
|
|
||||||
if (on && !d->terminalRunner && !useCdbConsole) {
|
if (on && !d->terminalRunner && !useCdbConsole) {
|
||||||
d->terminalRunner = new TerminalRunner(this);
|
d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
|
||||||
addStartDependency(d->terminalRunner);
|
addStartDependency(d->terminalRunner);
|
||||||
}
|
}
|
||||||
if (!on && d->terminalRunner) {
|
if (!on && d->terminalRunner) {
|
||||||
@@ -398,7 +405,7 @@ void DebuggerRunTool::setServerStartScript(const QString &serverStartScript)
|
|||||||
serverStarter.executable = serverStartScript;
|
serverStarter.executable = serverStartScript;
|
||||||
QtcProcess::addArg(&serverStarter.commandLineArguments, m_runParameters.inferior.executable);
|
QtcProcess::addArg(&serverStarter.commandLineArguments, m_runParameters.inferior.executable);
|
||||||
QtcProcess::addArg(&serverStarter.commandLineArguments, m_runParameters.remoteChannel);
|
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()
|
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_DEBUGINFO);
|
||||||
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
|
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
|
||||||
|
|
||||||
@@ -560,25 +565,25 @@ void DebuggerRunTool::start()
|
|||||||
|
|
||||||
runControl()->setDisplayName(m_runParameters.displayName);
|
runControl()->setDisplayName(m_runParameters.displayName);
|
||||||
|
|
||||||
DebuggerEngine *cppEngine = nullptr;
|
|
||||||
if (!m_engine) {
|
if (!m_engine) {
|
||||||
if (m_runParameters.isCppDebugging()) {
|
if (m_runParameters.isCppDebugging()) {
|
||||||
switch (m_runParameters.cppEngineType) {
|
switch (m_runParameters.cppEngineType) {
|
||||||
case GdbEngineType:
|
case GdbEngineType:
|
||||||
cppEngine = createGdbEngine();
|
m_engine = createGdbEngine();
|
||||||
break;
|
break;
|
||||||
case CdbEngineType:
|
case CdbEngineType:
|
||||||
if (!HostOsInfo::isWindowsHost()) {
|
if (!HostOsInfo::isWindowsHost()) {
|
||||||
reportFailure(tr("Unsupported CDB host system."));
|
reportFailure(tr("Unsupported CDB host system."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cppEngine = createCdbEngine();
|
m_engine = createCdbEngine();
|
||||||
break;
|
break;
|
||||||
case LldbEngineType:
|
case LldbEngineType:
|
||||||
cppEngine = createLldbEngine();
|
m_engine = createLldbEngine();
|
||||||
break;
|
break;
|
||||||
case PdbEngineType: // FIXME: Yes, Python counts as C++...
|
case PdbEngineType: // FIXME: Yes, Python counts as C++...
|
||||||
cppEngine = createPdbEngine();
|
QTC_CHECK(false); // Called from DebuggerRunTool constructor already.
|
||||||
|
// m_engine = createPdbEngine();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!m_runParameters.isQmlDebugging) {
|
if (!m_runParameters.isQmlDebugging) {
|
||||||
@@ -592,12 +597,11 @@ void DebuggerRunTool::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_runParameters.isQmlDebugging) {
|
if (m_runParameters.isQmlDebugging) {
|
||||||
if (cppEngine)
|
if (m_engine) {
|
||||||
m_engine = createQmlCppEngine(cppEngine);
|
m_engine2 = createQmlEngine();
|
||||||
else
|
} else {
|
||||||
m_engine = createQmlEngine();
|
m_engine = createQmlEngine();
|
||||||
} else {
|
}
|
||||||
m_engine = cppEngine;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,12 +611,57 @@ void DebuggerRunTool::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_engine->setRunTool(this);
|
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) {
|
if (m_runParameters.startMode == StartInternal) {
|
||||||
QStringList unhandledIds;
|
QStringList unhandledIds;
|
||||||
for (const Breakpoint &bp : breakHandler()->allBreakpoints()) {
|
for (const GlobalBreakpoint bp : BreakpointManager::globalBreakpoints()) {
|
||||||
if (bp.isEnabled() && !m_engine->acceptsBreakpoint(bp))
|
// if (bp->isEnabled() && !m_engine->acceptsBreakpoint(bp))
|
||||||
unhandledIds.append(bp.id().toString());
|
// unhandledIds.append(bp.id().toString());
|
||||||
}
|
}
|
||||||
if (!unhandledIds.isEmpty()) {
|
if (!unhandledIds.isEmpty()) {
|
||||||
QString warningMessage =
|
QString warningMessage =
|
||||||
@@ -621,7 +670,7 @@ void DebuggerRunTool::start()
|
|||||||
"Affected are breakpoints %1")
|
"Affected are breakpoints %1")
|
||||||
.arg(unhandledIds.join(QLatin1String(", ")));
|
.arg(unhandledIds.join(QLatin1String(", ")));
|
||||||
|
|
||||||
Internal::showMessage(warningMessage, LogWarning);
|
showMessage(warningMessage, LogWarning);
|
||||||
|
|
||||||
static bool checked = true;
|
static bool checked = true;
|
||||||
if (checked)
|
if (checked)
|
||||||
@@ -634,20 +683,53 @@ void DebuggerRunTool::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
appendMessage(tr("Debugging starts"), NormalMessageFormat);
|
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();
|
m_engine->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerRunTool::stop()
|
void DebuggerRunTool::stop()
|
||||||
{
|
{
|
||||||
m_isDying = true;
|
|
||||||
QTC_ASSERT(m_engine, reportStopped(); return);
|
QTC_ASSERT(m_engine, reportStopped(); return);
|
||||||
|
if (m_engine2)
|
||||||
|
m_engine2->quitDebugger();
|
||||||
m_engine->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
|
bool DebuggerRunTool::isCppDebugging() const
|
||||||
@@ -684,36 +766,9 @@ void DebuggerRunTool::setSolibSearchPath(const QStringList &list)
|
|||||||
m_runParameters.solibSearchPath = list;
|
m_runParameters.solibSearchPath = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerRunTool::notifyInferiorIll()
|
|
||||||
{
|
|
||||||
m_engine->notifyInferiorIll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerRunTool::notifyInferiorExited()
|
|
||||||
{
|
|
||||||
m_engine->notifyInferiorExited();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerRunTool::quitDebugger()
|
void DebuggerRunTool::quitDebugger()
|
||||||
{
|
{
|
||||||
m_isDying = true;
|
initiateStop();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerRunTool::fixupParameters()
|
bool DebuggerRunTool::fixupParameters()
|
||||||
@@ -807,9 +862,6 @@ bool DebuggerRunTool::fixupParameters()
|
|||||||
if (rp.isNativeMixedDebugging())
|
if (rp.isNativeMixedDebugging())
|
||||||
rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
|
rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1");
|
||||||
|
|
||||||
if (rp.isCppDebugging() && !rp.skipExecutableValidation)
|
|
||||||
rp.validateExecutable();
|
|
||||||
|
|
||||||
return true;
|
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()
|
void DebuggerRunTool::startRunControl()
|
||||||
{
|
{
|
||||||
ProjectExplorerPlugin::startRunControl(runControl());
|
ProjectExplorerPlugin::startRunControl(runControl());
|
||||||
@@ -931,13 +978,14 @@ void DebuggerRunTool::addSolibSearchDir(const QString &str)
|
|||||||
|
|
||||||
DebuggerRunTool::~DebuggerRunTool()
|
DebuggerRunTool::~DebuggerRunTool()
|
||||||
{
|
{
|
||||||
disconnect();
|
if (m_runParameters.isSnapshot && !m_runParameters.coreFile.isEmpty())
|
||||||
if (m_engine) {
|
QFile::remove(m_runParameters.coreFile);
|
||||||
DebuggerEngine *engine = m_engine;
|
|
||||||
m_engine = nullptr;
|
delete m_engine2;
|
||||||
engine->disconnect();
|
m_engine2 = nullptr;
|
||||||
delete engine;
|
delete m_engine;
|
||||||
}
|
m_engine = nullptr;
|
||||||
|
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -946,7 +994,9 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
|
|||||||
if (channel == ConsoleOutput)
|
if (channel == ConsoleOutput)
|
||||||
debuggerConsole()->printItem(ConsoleItem::DefaultType, msg);
|
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) {
|
switch (channel) {
|
||||||
case AppOutput:
|
case AppOutput:
|
||||||
appendMessage(msg, StdOutFormatSameLine);
|
appendMessage(msg, StdOutFormatSameLine);
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "debugger_global.h"
|
#include "debugger_global.h"
|
||||||
#include "debuggerconstants.h"
|
#include "debuggerconstants.h"
|
||||||
#include "debuggerengine.h"
|
#include "debuggerengine.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
#include <projectexplorer/runconfiguration.h>
|
#include <projectexplorer/runconfiguration.h>
|
||||||
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
|
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
|
||||||
@@ -51,9 +52,6 @@ public:
|
|||||||
bool allowTerminal = true);
|
bool allowTerminal = true);
|
||||||
~DebuggerRunTool() override;
|
~DebuggerRunTool() override;
|
||||||
|
|
||||||
Internal::DebuggerEngine *engine() const { return m_engine; }
|
|
||||||
Internal::DebuggerEngine *activeEngine() const;
|
|
||||||
|
|
||||||
void startRunControl();
|
void startRunControl();
|
||||||
|
|
||||||
void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1);
|
void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1);
|
||||||
@@ -61,15 +59,8 @@ public:
|
|||||||
void start() override;
|
void start() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
void notifyInferiorIll();
|
|
||||||
Q_SLOT void notifyInferiorExited(); // Called from Android.
|
|
||||||
void quitDebugger();
|
void quitDebugger();
|
||||||
void abortDebugger();
|
|
||||||
|
|
||||||
const Internal::DebuggerRunParameters &runParameters() const;
|
|
||||||
|
|
||||||
void startDying() { m_isDying = true; }
|
|
||||||
bool isDying() const { return m_isDying; }
|
|
||||||
bool isCppDebugging() const;
|
bool isCppDebugging() const;
|
||||||
bool isQmlDebugging() const;
|
bool isQmlDebugging() const;
|
||||||
int portsUsedByDebugger() const;
|
int portsUsedByDebugger() const;
|
||||||
@@ -138,11 +129,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool fixupParameters();
|
bool fixupParameters();
|
||||||
|
void handleEngineStarted(Internal::DebuggerEngine *engine);
|
||||||
|
void handleEngineFinished(Internal::DebuggerEngine *engine);
|
||||||
|
|
||||||
Internal::DebuggerRunToolPrivate *d;
|
Internal::DebuggerRunToolPrivate *d;
|
||||||
QPointer<Internal::DebuggerEngine> m_engine; // Master engine
|
QPointer<Internal::DebuggerEngine> m_engine;
|
||||||
|
QPointer<Internal::DebuggerEngine> m_engine2;
|
||||||
Internal::DebuggerRunParameters m_runParameters;
|
Internal::DebuggerRunParameters m_runParameters;
|
||||||
bool m_isDying = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::ChannelProvider
|
class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::ChannelProvider
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "debuggerengine.h"
|
#include "debuggerengine.h"
|
||||||
#include "debuggerprotocol.h"
|
#include "debuggerprotocol.h"
|
||||||
#include "debuggeractions.h"
|
#include "debuggeractions.h"
|
||||||
|
#include "snapshothandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
#include "debuggercore.h"
|
#include "debuggercore.h"
|
||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
@@ -1138,7 +1139,7 @@ static void slotTooltipOverrideRequested
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const TextDocument *document = editorWidget->textDocument();
|
const TextDocument *document = editorWidget->textDocument();
|
||||||
DebuggerEngine *engine = currentEngine();
|
DebuggerEngine *engine = EngineManager::currentEngine();
|
||||||
if (!engine || !engine->canDisplayTooltip())
|
if (!engine || !engine->canDisplayTooltip())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -68,12 +68,17 @@ public:
|
|||||||
DisassemblerBreakpointMarker(const Breakpoint &bp, int lineNumber)
|
DisassemblerBreakpointMarker(const Breakpoint &bp, int lineNumber)
|
||||||
: TextMark(Utils::FileName(), lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_bp(bp)
|
: TextMark(Utils::FileName(), lineNumber, Constants::TEXT_MARK_CATEGORY_BREAKPOINT), m_bp(bp)
|
||||||
{
|
{
|
||||||
setIcon(bp.icon());
|
setIcon(bp->icon());
|
||||||
setPriority(TextMark::NormalPriority);
|
setPriority(TextMark::NormalPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isClickable() const override { return true; }
|
bool isClickable() const final { return true; }
|
||||||
void clicked() override { m_bp.removeBreakpoint(); }
|
|
||||||
|
void clicked() final
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_bp, return);
|
||||||
|
m_bp->deleteGlobalOrThisBreakpoint();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Breakpoint m_bp;
|
Breakpoint m_bp;
|
||||||
@@ -331,8 +336,8 @@ void DisassemblerAgent::setContentsToDocument(const DisassemblerLines &contents)
|
|||||||
d->document->setPreferredDisplayName(QString("Disassembler (%1)")
|
d->document->setPreferredDisplayName(QString("Disassembler (%1)")
|
||||||
.arg(d->location.functionName()));
|
.arg(d->location.functionName()));
|
||||||
|
|
||||||
const Breakpoints bps = breakHandler()->engineBreakpoints(d->engine);
|
const Breakpoints bps = d->engine->breakHandler()->breakpoints();
|
||||||
for (Breakpoint bp : bps)
|
for (const Breakpoint bp : bps)
|
||||||
updateBreakpointMarker(bp);
|
updateBreakpointMarker(bp);
|
||||||
|
|
||||||
updateLocationMarker();
|
updateLocationMarker();
|
||||||
@@ -340,7 +345,9 @@ void DisassemblerAgent::setContentsToDocument(const DisassemblerLines &contents)
|
|||||||
|
|
||||||
void DisassemblerAgent::updateLocationMarker()
|
void DisassemblerAgent::updateLocationMarker()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(d->document, return);
|
if (!d->document)
|
||||||
|
return;
|
||||||
|
|
||||||
int lineNumber = d->lineForAddress(d->location.address());
|
int lineNumber = d->lineForAddress(d->location.address());
|
||||||
if (d->location.needsMarker()) {
|
if (d->location.needsMarker()) {
|
||||||
d->document->removeMark(&d->locationMark);
|
d->document->removeMark(&d->locationMark);
|
||||||
@@ -348,6 +355,8 @@ void DisassemblerAgent::updateLocationMarker()
|
|||||||
d->document->addMark(&d->locationMark);
|
d->document->addMark(&d->locationMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->locationMark.updateIcon();
|
||||||
|
|
||||||
// Center cursor.
|
// Center cursor.
|
||||||
if (EditorManager::currentDocument() == d->document)
|
if (EditorManager::currentDocument() == d->document)
|
||||||
if (auto textEditor = qobject_cast<BaseTextEditor *>(EditorManager::currentEditor()))
|
if (auto textEditor = qobject_cast<BaseTextEditor *>(EditorManager::currentEditor()))
|
||||||
@@ -359,9 +368,8 @@ void DisassemblerAgent::removeBreakpointMarker(const Breakpoint &bp)
|
|||||||
if (!d->document)
|
if (!d->document)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BreakpointModelId id = bp.id();
|
for (DisassemblerBreakpointMarker *marker : d->breakpointMarks) {
|
||||||
foreach (DisassemblerBreakpointMarker *marker, d->breakpointMarks) {
|
if (marker->m_bp == bp) {
|
||||||
if (marker->m_bp.id() == id) {
|
|
||||||
d->breakpointMarks.removeOne(marker);
|
d->breakpointMarks.removeOne(marker);
|
||||||
d->document->removeMark(marker);
|
d->document->removeMark(marker);
|
||||||
delete marker;
|
delete marker;
|
||||||
@@ -373,7 +381,7 @@ void DisassemblerAgent::removeBreakpointMarker(const Breakpoint &bp)
|
|||||||
void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
|
void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
removeBreakpointMarker(bp);
|
removeBreakpointMarker(bp);
|
||||||
const quint64 address = bp.response().address;
|
const quint64 address = bp->address();
|
||||||
if (!address)
|
if (!address)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -384,7 +392,7 @@ void DisassemblerAgent::updateBreakpointMarker(const Breakpoint &bp)
|
|||||||
// HACK: If it's a FileAndLine breakpoint, and there's a source line
|
// HACK: If it's a FileAndLine breakpoint, and there's a source line
|
||||||
// above, move the marker up there. That allows setting and removing
|
// above, move the marker up there. That allows setting and removing
|
||||||
// normal breakpoints from within the disassembler view.
|
// normal breakpoints from within the disassembler view.
|
||||||
if (bp.type() == BreakpointByFileAndLine) {
|
if (bp->type() == BreakpointByFileAndLine) {
|
||||||
ContextData context = getLocationContext(d->document, lineNumber - 1);
|
ContextData context = getLocationContext(d->document, lineNumber - 1);
|
||||||
if (context.type == LocationByFile)
|
if (context.type == LocationByFile)
|
||||||
--lineNumber;
|
--lineNumber;
|
||||||
|
@@ -25,12 +25,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "breakhandler.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class Breakpoint;
|
|
||||||
class DebuggerEngine;
|
class DebuggerEngine;
|
||||||
class DisassemblerAgentPrivate;
|
class DisassemblerAgentPrivate;
|
||||||
class DisassemblerLines;
|
class DisassemblerLines;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,6 @@ namespace Debugger {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class BreakpointParameters;
|
class BreakpointParameters;
|
||||||
class BreakpointResponse;
|
|
||||||
class DebugInfoTask;
|
class DebugInfoTask;
|
||||||
class DebugInfoTaskHandler;
|
class DebugInfoTaskHandler;
|
||||||
class DebuggerResponse;
|
class DebuggerResponse;
|
||||||
@@ -65,7 +64,7 @@ struct CoreInfo
|
|||||||
const QString &coreFile);
|
const QString &coreFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GdbEngine : public DebuggerEngine
|
class GdbEngine : public CppDebuggerEngine
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -74,8 +73,6 @@ public:
|
|||||||
~GdbEngine() final;
|
~GdbEngine() final;
|
||||||
|
|
||||||
private: ////////// General Interface //////////
|
private: ////////// General Interface //////////
|
||||||
DebuggerEngine *cppEngine() final { return this; }
|
|
||||||
|
|
||||||
void handleGdbStartFailed();
|
void handleGdbStartFailed();
|
||||||
void prepareForRestart() final;
|
void prepareForRestart() final;
|
||||||
|
|
||||||
@@ -86,7 +83,7 @@ private: ////////// General Interface //////////
|
|||||||
void resetInferior() final;
|
void resetInferior() final;
|
||||||
|
|
||||||
bool acceptsDebuggerCommands() const final;
|
bool acceptsDebuggerCommands() const final;
|
||||||
void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) final;
|
void executeDebuggerCommand(const QString &command) final;
|
||||||
|
|
||||||
////////// General State //////////
|
////////// General State //////////
|
||||||
|
|
||||||
@@ -189,11 +186,11 @@ private: ////////// General Interface //////////
|
|||||||
|
|
||||||
// This should be always the last call in a function.
|
// This should be always the last call in a function.
|
||||||
bool stateAcceptsBreakpointChanges() const final;
|
bool stateAcceptsBreakpointChanges() const final;
|
||||||
bool acceptsBreakpoint(Breakpoint bp) const final;
|
bool acceptsBreakpoint(const BreakpointParameters &bp) const final;
|
||||||
void insertBreakpoint(Breakpoint bp) final;
|
void insertBreakpoint(const Breakpoint &bp) final;
|
||||||
void removeBreakpoint(Breakpoint bp) final;
|
void removeBreakpoint(const Breakpoint &bp) final;
|
||||||
void changeBreakpoint(Breakpoint bp) final;
|
void updateBreakpoint(const Breakpoint &bp) final;
|
||||||
void enableSubBreakpoint(const QString &locId, bool on) final;
|
void enableSubBreakpoint(const SubBreakpoint &sbp, bool on) final;
|
||||||
|
|
||||||
void executeStep() final;
|
void executeStep() final;
|
||||||
void executeStepOut() final;
|
void executeStepOut() final;
|
||||||
@@ -209,6 +206,7 @@ private: ////////// General Interface //////////
|
|||||||
void executeRunToFunction(const QString &functionName) final;
|
void executeRunToFunction(const QString &functionName) final;
|
||||||
void executeJumpToLine(const ContextData &data) final;
|
void executeJumpToLine(const ContextData &data) final;
|
||||||
void executeReturn() final;
|
void executeReturn() final;
|
||||||
|
void executeRecordReverse(bool reverse);
|
||||||
|
|
||||||
void handleExecuteContinue(const DebuggerResponse &response);
|
void handleExecuteContinue(const DebuggerResponse &response);
|
||||||
void handleExecuteStep(const DebuggerResponse &response);
|
void handleExecuteStep(const DebuggerResponse &response);
|
||||||
@@ -223,26 +221,24 @@ private: ////////// General Interface //////////
|
|||||||
|
|
||||||
void selectThread(ThreadId threadId) final;
|
void selectThread(ThreadId threadId) final;
|
||||||
void activateFrame(int index) final;
|
void activateFrame(int index) final;
|
||||||
void handleAutoContinueInferior();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Breakpoint specific stuff
|
// Breakpoint specific stuff
|
||||||
//
|
//
|
||||||
void handleBreakModifications(const GdbMi &bkpts);
|
void handleBreakModifications(const GdbMi &bkpts);
|
||||||
void handleBreakIgnore(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakIgnore(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakDisable(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakDisable(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakEnable(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakEnable(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakInsert1(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakInsert2(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakInsert2(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakCondition(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakCondition(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakThreadSpec(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakLineNumber(const DebuggerResponse &response, Breakpoint bp);
|
void handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, Breakpoint bp);
|
void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleInterpreterBreakpointModified(const GdbMi &data);
|
void handleInterpreterBreakpointModified(const GdbMi &data);
|
||||||
void handleWatchInsert(const DebuggerResponse &response, Breakpoint bp);
|
void handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleCatchInsert(const DebuggerResponse &response, Breakpoint bp);
|
void handleCatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBkpt(const GdbMi &bkpt, Breakpoint bp);
|
void handleBkpt(const GdbMi &bkpt, const Breakpoint &bp);
|
||||||
void updateResponse(BreakpointResponse &response, const GdbMi &bkpt);
|
|
||||||
QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
|
QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
|
||||||
QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
|
QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
|
||||||
QString breakLocation(const QString &file) const;
|
QString breakLocation(const QString &file) const;
|
||||||
|
@@ -84,6 +84,7 @@ static int ¤tToken()
|
|||||||
LldbEngine::LldbEngine()
|
LldbEngine::LldbEngine()
|
||||||
{
|
{
|
||||||
setObjectName("LldbEngine");
|
setObjectName("LldbEngine");
|
||||||
|
setDebuggerName("LLDB");
|
||||||
|
|
||||||
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
|
connect(action(AutoDerefPointers), &SavedAction::valueChanged,
|
||||||
this, &LldbEngine::updateLocals);
|
this, &LldbEngine::updateLocals);
|
||||||
@@ -114,7 +115,7 @@ LldbEngine::~LldbEngine()
|
|||||||
m_lldbProc.disconnect();
|
m_lldbProc.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
|
void LldbEngine::executeDebuggerCommand(const QString &command)
|
||||||
{
|
{
|
||||||
DebuggerCommand cmd("executeDebuggerCommand");
|
DebuggerCommand cmd("executeDebuggerCommand");
|
||||||
cmd.arg("command", command);
|
cmd.arg("command", command);
|
||||||
@@ -175,13 +176,18 @@ void LldbEngine::shutdownInferior()
|
|||||||
void LldbEngine::shutdownEngine()
|
void LldbEngine::shutdownEngine()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
|
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
|
||||||
m_lldbProc.kill();
|
if (m_lldbProc.state() == QProcess::Running)
|
||||||
notifyEngineShutdownFinished();
|
m_lldbProc.terminate();
|
||||||
|
else
|
||||||
|
notifyEngineShutdownFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::abortDebuggerProcess()
|
void LldbEngine::abortDebuggerProcess()
|
||||||
{
|
{
|
||||||
m_lldbProc.kill();
|
if (m_lldbProc.state() == QProcess::Running)
|
||||||
|
m_lldbProc.kill();
|
||||||
|
else
|
||||||
|
notifyEngineShutdownFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::setupEngine()
|
void LldbEngine::setupEngine()
|
||||||
@@ -290,17 +296,9 @@ void LldbEngine::setupEngine()
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd2.callback = [this](const DebuggerResponse &response) {
|
cmd2.callback = [this](const DebuggerResponse &response) {
|
||||||
bool success = response.data["success"].toInt();
|
const bool success = response.data["success"].toInt();
|
||||||
if (success) {
|
if (success) {
|
||||||
for (Breakpoint bp : breakHandler()->unclaimedBreakpoints()) {
|
BreakpointManager::claimBreakpointsForEngine(this);
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
notifyEngineSetupFailed();
|
notifyEngineSetupFailed();
|
||||||
}
|
}
|
||||||
@@ -442,7 +440,7 @@ void LldbEngine::activateFrame(int frameIndex)
|
|||||||
|
|
||||||
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
QTC_ASSERT(frameIndex < handler->stackSize(), return);
|
||||||
handler->setCurrentIndex(frameIndex);
|
handler->setCurrentIndex(frameIndex);
|
||||||
gotoLocation(handler->currentFrame());
|
gotoCurrentLocation();
|
||||||
|
|
||||||
DebuggerCommand cmd("activateFrame");
|
DebuggerCommand cmd("activateFrame");
|
||||||
cmd.arg("index", frameIndex);
|
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)
|
if (runParameters().startMode == AttachCore)
|
||||||
return false;
|
return false;
|
||||||
if (bp.parameters().isCppBreakpoint())
|
if (bp.isCppBreakpoint())
|
||||||
return true;
|
return true;
|
||||||
return isNativeMixedEnabled();
|
return isNativeMixedEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::insertBreakpoint(Breakpoint bp)
|
void LldbEngine::insertBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
|
QTC_ASSERT(bp, return);
|
||||||
DebuggerCommand cmd("insertBreakpoint");
|
DebuggerCommand cmd("insertBreakpoint");
|
||||||
cmd.callback = [this, bp](const DebuggerResponse &response) {
|
cmd.callback = [this, bp](const DebuggerResponse &response) {
|
||||||
QTC_CHECK(bp.state() == BreakpointInsertProceeding);
|
QTC_CHECK(bp && bp->state() == BreakpointInsertionProceeding);
|
||||||
updateBreakpointData(bp, response.data, true);
|
updateBreakpointData(bp, response.data, true);
|
||||||
};
|
};
|
||||||
bp.addToCommand(&cmd);
|
bp->addToCommand(&cmd);
|
||||||
bp.notifyBreakpointInsertProceeding();
|
notifyBreakpointInsertProceeding(bp);
|
||||||
runCommand(cmd);
|
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");
|
DebuggerCommand cmd("changeBreakpoint");
|
||||||
cmd.arg("lldbid", response.id.toString());
|
cmd.arg("lldbid", bp->responseId());
|
||||||
cmd.callback = [this, bp](const DebuggerResponse &response) {
|
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);
|
updateBreakpointData(bp, response.data, false);
|
||||||
};
|
};
|
||||||
bp.addToCommand(&cmd);
|
bp->addToCommand(&cmd);
|
||||||
bp.notifyBreakpointChangeProceeding();
|
notifyBreakpointChangeProceeding(bp);
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::removeBreakpoint(Breakpoint bp)
|
void LldbEngine::removeBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
const BreakpointResponse &response = bp.response();
|
QTC_ASSERT(bp, return);
|
||||||
if (response.id.isValid()) {
|
if (!bp->responseId().isEmpty()) {
|
||||||
DebuggerCommand cmd("removeBreakpoint");
|
DebuggerCommand cmd("removeBreakpoint");
|
||||||
cmd.arg("lldbid", response.id.toString());
|
cmd.arg("lldbid", bp->responseId());
|
||||||
cmd.callback = [bp](const DebuggerResponse &) {
|
notifyBreakpointRemoveProceeding(bp);
|
||||||
QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
|
|
||||||
Breakpoint bp0 = bp;
|
|
||||||
bp0.notifyBreakpointRemoveOk();
|
|
||||||
};
|
|
||||||
bp.notifyBreakpointRemoveProceeding();
|
|
||||||
runCommand(cmd);
|
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();
|
QTC_ASSERT(bp, return);
|
||||||
BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
|
QString rid = bkpt["lldbid"].data();
|
||||||
if (!bp.isValid())
|
QTC_ASSERT(bp, return);
|
||||||
bp = handler->findBreakpointByResponseId(rid);
|
|
||||||
BreakpointResponse response = bp.response();
|
|
||||||
if (added)
|
if (added)
|
||||||
response.id = rid;
|
bp->setResponseId(rid);
|
||||||
QTC_CHECK(response.id == rid);
|
QTC_CHECK(bp->responseId() == rid);
|
||||||
response.address = 0;
|
bp->setAddress(0);
|
||||||
response.enabled = bkpt["enabled"].toInt();
|
bp->setEnabled(bkpt["enabled"].toInt());
|
||||||
response.ignoreCount = bkpt["ignorecount"].toInt();
|
bp->setIgnoreCount(bkpt["ignorecount"].toInt());
|
||||||
response.condition = fromHex(bkpt["condition"].data());
|
bp->setCondition(fromHex(bkpt["condition"].data()));
|
||||||
response.hitCount = bkpt["hitcount"].toInt();
|
bp->setHitCount(bkpt["hitcount"].toInt());
|
||||||
response.fileName = bkpt["file"].data();
|
bp->setFileName(bkpt["file"].data());
|
||||||
response.lineNumber = bkpt["line"].toInt();
|
bp->setLineNumber(bkpt["line"].toInt());
|
||||||
|
|
||||||
GdbMi locations = bkpt["locations"];
|
GdbMi locations = bkpt["locations"];
|
||||||
const int numChild = int(locations.children().size());
|
const int numChild = int(locations.children().size());
|
||||||
if (numChild > 1) {
|
if (numChild > 1) {
|
||||||
for (const GdbMi &location : locations.children()) {
|
for (const GdbMi &location : locations.children()) {
|
||||||
const int locid = location["locid"].toInt();
|
const QString locid = QString("%1.%2").arg(rid).arg(location["locid"].data());
|
||||||
BreakpointResponse sub;
|
SubBreakpoint loc = bp->findOrCreateSubBreakpoint(locid);
|
||||||
sub.id = BreakpointResponseId(rid.majorPart(), locid);
|
QTC_ASSERT(loc, continue);
|
||||||
sub.type = response.type;
|
loc->params.type = bp->type();
|
||||||
sub.address = location["addr"].toAddress();
|
loc->params.address = location["addr"].toAddress();
|
||||||
sub.functionName = location["func"].data();
|
loc->params.functionName = location["function"].data();
|
||||||
sub.fileName = location["file"].data();
|
loc->params.fileName = location["file"].data();
|
||||||
sub.lineNumber = location["line"].toInt();
|
loc->params.lineNumber = location["line"].toInt();
|
||||||
bp.insertSubBreakpoint(sub);
|
|
||||||
}
|
}
|
||||||
response.pending = false;
|
bp->setPending(false);
|
||||||
} else if (numChild == 1) {
|
} else if (numChild == 1) {
|
||||||
const GdbMi location = locations.childAt(0);
|
const GdbMi location = locations.childAt(0);
|
||||||
response.address = location["addr"].toAddress();
|
bp->setAddress(location["addr"].toAddress());
|
||||||
response.functionName = location["func"].data();
|
bp->setFunctionName(location["function"].data());
|
||||||
response.pending = false;
|
bp->setPending(false);
|
||||||
} else {
|
} else {
|
||||||
// This can happen for pending breakpoints.
|
// 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)
|
if (added)
|
||||||
bp.notifyBreakpointInsertOk();
|
notifyBreakpointInsertOk(bp);
|
||||||
else
|
else
|
||||||
bp.notifyBreakpointChangeOk();
|
notifyBreakpointChangeOk(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::handleOutputNotification(const GdbMi &output)
|
void LldbEngine::handleOutputNotification(const GdbMi &output)
|
||||||
@@ -896,7 +893,7 @@ void LldbEngine::handleLocationNotification(const GdbMi &reportedLocation)
|
|||||||
|
|
||||||
void LldbEngine::reloadRegisters()
|
void LldbEngine::reloadRegisters()
|
||||||
{
|
{
|
||||||
if (!Internal::isRegistersWindowVisible())
|
if (!isRegistersWindowVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
||||||
@@ -1012,7 +1009,8 @@ void LldbEngine::setRegisterValue(const QString &name, const QString &value)
|
|||||||
|
|
||||||
bool LldbEngine::hasCapability(unsigned cap) const
|
bool LldbEngine::hasCapability(unsigned cap) const
|
||||||
{
|
{
|
||||||
if (cap & (ReverseSteppingCapability
|
if (cap & (0
|
||||||
|
//| ReverseSteppingCapability
|
||||||
| AutoDerefPointersCapability
|
| AutoDerefPointersCapability
|
||||||
| DisassemblerCapability
|
| DisassemblerCapability
|
||||||
| RegisterCapability
|
| RegisterCapability
|
||||||
|
@@ -41,17 +41,14 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class GdbMi;
|
|
||||||
|
|
||||||
/* A debugger engine interfacing the LLDB debugger
|
/* A debugger engine interfacing the LLDB debugger
|
||||||
* using its Python interface.
|
* using its Python interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class LldbEngine : public DebuggerEngine
|
class LldbEngine : public CppDebuggerEngine
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -63,8 +60,6 @@ signals:
|
|||||||
void outputReady(const QString &data);
|
void outputReady(const QString &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DebuggerEngine *cppEngine() override { return this; }
|
|
||||||
|
|
||||||
void executeStep() override;
|
void executeStep() override;
|
||||||
void executeStepOut() override;
|
void executeStepOut() override;
|
||||||
void executeNext() override;
|
void executeNext() override;
|
||||||
@@ -92,13 +87,13 @@ private:
|
|||||||
|
|
||||||
// This should be always the last call in a function.
|
// This should be always the last call in a function.
|
||||||
bool stateAcceptsBreakpointChanges() const override;
|
bool stateAcceptsBreakpointChanges() const override;
|
||||||
bool acceptsBreakpoint(Breakpoint bp) const override;
|
bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
|
||||||
void insertBreakpoint(Breakpoint bp) override;
|
void insertBreakpoint(const Breakpoint &bp) override;
|
||||||
void removeBreakpoint(Breakpoint bp) override;
|
void removeBreakpoint(const Breakpoint &bp) override;
|
||||||
void changeBreakpoint(Breakpoint bp) override;
|
void updateBreakpoint(const Breakpoint &bp) override;
|
||||||
|
|
||||||
void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value) 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 loadSymbols(const QString &moduleName) override;
|
||||||
void loadAllSymbols() override;
|
void loadAllSymbols() override;
|
||||||
@@ -130,7 +125,7 @@ private:
|
|||||||
void handleResponse(const QString &data);
|
void handleResponse(const QString &data);
|
||||||
void updateAll() override;
|
void updateAll() override;
|
||||||
void doUpdateLocals(const UpdateParameters ¶ms) override;
|
void doUpdateLocals(const UpdateParameters ¶ms) 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 fetchStack(int limit);
|
||||||
|
|
||||||
void runCommand(const DebuggerCommand &cmd) override;
|
void runCommand(const DebuggerCommand &cmd) override;
|
||||||
|
@@ -58,6 +58,52 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
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
|
// OutputHighlighter
|
||||||
@@ -77,7 +123,7 @@ private:
|
|||||||
using Utils::Theme;
|
using Utils::Theme;
|
||||||
QTextCharFormat format;
|
QTextCharFormat format;
|
||||||
Theme *theme = Utils::creatorTheme();
|
Theme *theme = Utils::creatorTheme();
|
||||||
switch (LogWindow::channelForChar(text.isEmpty() ? QChar() : text.at(0))) {
|
switch (channelForChar(text.isEmpty() ? QChar() : text.at(0))) {
|
||||||
case LogInput:
|
case LogInput:
|
||||||
format.setForeground(theme->color(Theme::Debugger_LogWindow_LogInput));
|
format.setForeground(theme->color(Theme::Debugger_LogWindow_LogInput));
|
||||||
setFormat(1, text.size(), format);
|
setFormat(1, text.size(), format);
|
||||||
@@ -149,15 +195,14 @@ class DebuggerPane : public QPlainTextEdit
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DebuggerPane(LogWindow *parent)
|
explicit DebuggerPane()
|
||||||
: QPlainTextEdit(parent)
|
|
||||||
{
|
{
|
||||||
setFrameStyle(QFrame::NoFrame);
|
setFrameStyle(QFrame::NoFrame);
|
||||||
|
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||||
|
|
||||||
m_clearContentsAction = new QAction(this);
|
m_clearContentsAction = new QAction(this);
|
||||||
m_clearContentsAction->setText(tr("Clear Contents"));
|
m_clearContentsAction->setText(tr("Clear Contents"));
|
||||||
m_clearContentsAction->setEnabled(true);
|
m_clearContentsAction->setEnabled(true);
|
||||||
connect(m_clearContentsAction, &QAction::triggered,
|
|
||||||
parent, &LogWindow::clearContents);
|
|
||||||
|
|
||||||
m_saveContentsAction = new QAction(this);
|
m_saveContentsAction = new QAction(this);
|
||||||
m_saveContentsAction->setText(tr("Save Contents"));
|
m_saveContentsAction->setText(tr("Save Contents"));
|
||||||
@@ -168,8 +213,6 @@ public:
|
|||||||
m_reloadDebuggingHelpersAction = new QAction(this);
|
m_reloadDebuggingHelpersAction = new QAction(this);
|
||||||
m_reloadDebuggingHelpersAction->setText(tr("Reload Debugging Helpers"));
|
m_reloadDebuggingHelpersAction->setText(tr("Reload Debugging Helpers"));
|
||||||
m_reloadDebuggingHelpersAction->setEnabled(true);
|
m_reloadDebuggingHelpersAction->setEnabled(true);
|
||||||
connect(m_reloadDebuggingHelpersAction, &QAction::triggered,
|
|
||||||
this, &DebuggerPane::reloadDebuggingHelpers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void contextMenuEvent(QContextMenuEvent *ev) override
|
void contextMenuEvent(QContextMenuEvent *ev) override
|
||||||
@@ -212,24 +255,18 @@ public:
|
|||||||
setUndoRedoEnabled(true);
|
setUndoRedoEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QAction *clearContentsAction() const { return m_clearContentsAction; }
|
||||||
|
QAction *reloadDebuggingHelpersAction() const { return m_reloadDebuggingHelpersAction; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void saveContents();
|
void saveContents() { writeLogContents(this, this); }
|
||||||
void reloadDebuggingHelpers();
|
|
||||||
|
|
||||||
QAction *m_clearContentsAction;
|
QAction *m_clearContentsAction;
|
||||||
QAction *m_saveContentsAction;
|
QAction *m_saveContentsAction;
|
||||||
QAction *m_reloadDebuggingHelpersAction;
|
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
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
InputPane(LogWindow *parent)
|
InputPane(LogWindow *logWindow)
|
||||||
: DebuggerPane(parent)
|
|
||||||
{
|
{
|
||||||
|
connect(clearContentsAction(), &QAction::triggered,
|
||||||
|
logWindow, &LogWindow::clearContents);
|
||||||
|
connect(reloadDebuggingHelpersAction(), &QAction::triggered,
|
||||||
|
logWindow->engine(), &DebuggerEngine::reloadDebuggingHelpers);
|
||||||
(void) new InputHighlighter(this);
|
(void) new InputHighlighter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,10 +347,13 @@ class CombinedPane : public DebuggerPane
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
CombinedPane(LogWindow *parent)
|
CombinedPane(LogWindow *logWindow)
|
||||||
: DebuggerPane(parent)
|
|
||||||
{
|
{
|
||||||
(void) new OutputHighlighter(this);
|
(void) new OutputHighlighter(this);
|
||||||
|
connect(clearContentsAction(), &QAction::triggered,
|
||||||
|
logWindow, &LogWindow::clearContents);
|
||||||
|
connect(reloadDebuggingHelpersAction(), &QAction::triggered,
|
||||||
|
logWindow->engine(), &DebuggerEngine::reloadDebuggingHelpers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gotoResult(int i)
|
void gotoResult(int i)
|
||||||
@@ -347,8 +390,8 @@ public:
|
|||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LogWindow::LogWindow(QWidget *parent)
|
LogWindow::LogWindow(DebuggerEngine *engine)
|
||||||
: QWidget(parent)
|
: m_engine(engine)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Debugger &Log"));
|
setWindowTitle(tr("Debugger &Log"));
|
||||||
setObjectName(QLatin1String("Log"));
|
setObjectName(QLatin1String("Log"));
|
||||||
@@ -362,14 +405,10 @@ LogWindow::LogWindow(QWidget *parent)
|
|||||||
m_combinedText = new CombinedPane(this);
|
m_combinedText = new CombinedPane(this);
|
||||||
m_combinedText->setReadOnly(true);
|
m_combinedText->setReadOnly(true);
|
||||||
m_combinedText->setReadOnly(false);
|
m_combinedText->setReadOnly(false);
|
||||||
m_combinedText->setSizePolicy(QSizePolicy::MinimumExpanding,
|
|
||||||
QSizePolicy::MinimumExpanding);
|
|
||||||
|
|
||||||
// Input only.
|
// Input only.
|
||||||
m_inputText = new InputPane(this);
|
m_inputText = new InputPane(this);
|
||||||
m_inputText->setReadOnly(false);
|
m_inputText->setReadOnly(false);
|
||||||
m_inputText->setSizePolicy(QSizePolicy::MinimumExpanding,
|
|
||||||
QSizePolicy::MinimumExpanding);
|
|
||||||
|
|
||||||
m_commandEdit = new Utils::FancyLineEdit(this);
|
m_commandEdit = new Utils::FancyLineEdit(this);
|
||||||
m_commandEdit->setFrame(false);
|
m_commandEdit->setFrame(false);
|
||||||
@@ -445,23 +484,33 @@ LogWindow::LogWindow(QWidget *parent)
|
|||||||
.arg(Core::Constants::IDE_DISPLAY_NAME));
|
.arg(Core::Constants::IDE_DISPLAY_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogWindow::~LogWindow()
|
||||||
|
{
|
||||||
|
disconnect(&m_outputTimer, &QTimer::timeout, this, &LogWindow::doOutput);
|
||||||
|
m_outputTimer.stop();
|
||||||
|
doOutput();
|
||||||
|
}
|
||||||
|
|
||||||
void LogWindow::executeLine()
|
void LogWindow::executeLine()
|
||||||
{
|
{
|
||||||
m_ignoreNextInputEcho = true;
|
m_ignoreNextInputEcho = true;
|
||||||
currentEngine()->
|
m_engine->executeDebuggerCommand(m_inputText->textCursor().block().text());
|
||||||
executeDebuggerCommand(m_inputText->textCursor().block().text(), CppLanguage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWindow::repeatLastCommand()
|
void LogWindow::repeatLastCommand()
|
||||||
{
|
{
|
||||||
currentEngine()->debugLastCommand();
|
m_engine->debugLastCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
DebuggerEngine *LogWindow::engine() const
|
||||||
|
{
|
||||||
|
return m_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWindow::sendCommand()
|
void LogWindow::sendCommand()
|
||||||
{
|
{
|
||||||
DebuggerEngine *engine = currentEngine();
|
if (m_engine->acceptsDebuggerCommands())
|
||||||
if (engine->acceptsDebuggerCommands())
|
m_engine->executeDebuggerCommand(m_commandEdit->text());
|
||||||
engine->executeDebuggerCommand(m_commandEdit->text(), CppLanguage);
|
|
||||||
else
|
else
|
||||||
showOutput(LogError, tr("User commands are not accepted in the current state."));
|
showOutput(LogError, tr("User commands are not accepted in the current state."));
|
||||||
}
|
}
|
||||||
@@ -512,6 +561,8 @@ void LogWindow::doOutput()
|
|||||||
if (m_queuedOutput.isEmpty())
|
if (m_queuedOutput.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
theGlobalLog->doOutput(m_queuedOutput);
|
||||||
|
|
||||||
QTextCursor cursor = m_combinedText->textCursor();
|
QTextCursor cursor = m_combinedText->textCursor();
|
||||||
const bool atEnd = cursor.atEnd();
|
const bool atEnd = cursor.atEnd();
|
||||||
|
|
||||||
@@ -543,6 +594,8 @@ void LogWindow::showInput(int channel, const QString &input)
|
|||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
m_inputText->setTextCursor(cursor);
|
m_inputText->setTextCursor(cursor);
|
||||||
m_inputText->ensureCursorVisible();
|
m_inputText->ensureCursorVisible();
|
||||||
|
|
||||||
|
theGlobalLog->doInput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogWindow::clearContents()
|
void LogWindow::clearContents()
|
||||||
@@ -597,48 +650,100 @@ QString LogWindow::logTimeStamp()
|
|||||||
return lastTimeStamp;
|
return lastTimeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LogWindow::writeLogContents(const QPlainTextEdit *editor, QWidget *parent)
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// GlobalLogWindow
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GlobalLogWindow::GlobalLogWindow()
|
||||||
{
|
{
|
||||||
bool success = false;
|
theGlobalLog = this;
|
||||||
while (!success) {
|
|
||||||
const QString fileName = QFileDialog::getSaveFileName(parent, tr("Log File"));
|
setWindowTitle(tr("Global Debugger &Log"));
|
||||||
if (fileName.isEmpty())
|
setObjectName("GlobalLog");
|
||||||
break;
|
|
||||||
Utils::FileSaver saver(fileName, QIODevice::Text);
|
auto m_splitter = new Core::MiniSplitter(Qt::Horizontal);
|
||||||
saver.write(editor->toPlainText().toUtf8());
|
m_splitter->setParent(this);
|
||||||
if (saver.finalize(parent))
|
|
||||||
success = true;
|
m_rightPane = new DebuggerPane;
|
||||||
}
|
m_rightPane->setReadOnly(true);
|
||||||
return success;
|
|
||||||
|
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');
|
void GlobalLogWindow::doOutput(const QString &output)
|
||||||
case LogError: return QLatin1Char('e');
|
{
|
||||||
case LogInput: return QLatin1Char('<');
|
QTextCursor cursor = m_rightPane->textCursor();
|
||||||
case LogOutput: return QLatin1Char('>');
|
const bool atEnd = cursor.atEnd();
|
||||||
case LogStatus: return QLatin1Char('s');
|
|
||||||
case LogTime: return QLatin1Char('t');
|
m_rightPane->append(output);
|
||||||
case LogMisc:
|
|
||||||
default: return QLatin1Char(' ');
|
if (atEnd) {
|
||||||
|
cursor.movePosition(QTextCursor::End);
|
||||||
|
m_rightPane->setTextCursor(cursor);
|
||||||
|
m_rightPane->ensureCursorVisible();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogChannel LogWindow::channelForChar(QChar c)
|
void GlobalLogWindow::doInput(const QString &input)
|
||||||
{
|
{
|
||||||
switch (c.unicode()) {
|
if (boolSetting(LogTimeStamps))
|
||||||
case 'd': return LogDebug;
|
m_leftPane->append(LogWindow::logTimeStamp());
|
||||||
case 'w': return LogWarning;
|
m_leftPane->append(input);
|
||||||
case 'e': return LogError;
|
QTextCursor cursor = m_leftPane->textCursor();
|
||||||
case '<': return LogInput;
|
cursor.movePosition(QTextCursor::End);
|
||||||
case '>': return LogOutput;
|
m_leftPane->setTextCursor(cursor);
|
||||||
case 's': return LogStatus;
|
m_leftPane->ensureCursorVisible();
|
||||||
case 't': return LogTime;
|
}
|
||||||
default: return LogMisc;
|
|
||||||
}
|
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 Internal
|
||||||
|
@@ -40,6 +40,8 @@ namespace Utils { class FancyLineEdit; }
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class DebuggerEngine;
|
||||||
|
class DebuggerPane;
|
||||||
class CombinedPane;
|
class CombinedPane;
|
||||||
class InputPane;
|
class InputPane;
|
||||||
|
|
||||||
@@ -48,7 +50,10 @@ class LogWindow : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LogWindow(QWidget *parent = nullptr);
|
explicit LogWindow(DebuggerEngine *engine);
|
||||||
|
~LogWindow() final;
|
||||||
|
|
||||||
|
DebuggerEngine *engine() const;
|
||||||
|
|
||||||
void setCursor(const QCursor &cursor);
|
void setCursor(const QCursor &cursor);
|
||||||
|
|
||||||
@@ -59,11 +64,6 @@ public:
|
|||||||
|
|
||||||
static QString logTimeStamp();
|
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 clearContents();
|
||||||
void sendCommand();
|
void sendCommand();
|
||||||
void executeLine();
|
void executeLine();
|
||||||
@@ -73,7 +73,6 @@ public:
|
|||||||
void repeatLastCommand();
|
void repeatLastCommand();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void showPage();
|
|
||||||
void statusMessageRequested(const QString &msg, int);
|
void statusMessageRequested(const QString &msg, int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -83,6 +82,27 @@ private:
|
|||||||
QString m_queuedOutput;
|
QString m_queuedOutput;
|
||||||
Utils::FancyLineEdit *m_commandEdit;
|
Utils::FancyLineEdit *m_commandEdit;
|
||||||
bool m_ignoreNextInputEcho;
|
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
|
} // namespace Internal
|
||||||
|
@@ -65,12 +65,11 @@ namespace Internal {
|
|||||||
PdbEngine::PdbEngine()
|
PdbEngine::PdbEngine()
|
||||||
{
|
{
|
||||||
setObjectName("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());
|
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
||||||
if (state() == DebuggerNotReady) {
|
if (state() == DebuggerNotReady) {
|
||||||
showMessage("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + command);
|
showMessage("PDB PROCESS NOT RUNNING, PLAIN CMD IGNORED: " + command);
|
||||||
@@ -157,7 +156,7 @@ void PdbEngine::runEngine()
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
||||||
showStatusMessage(tr("Running requested..."), 5000);
|
showStatusMessage(tr("Running requested..."), 5000);
|
||||||
attemptBreakpointSynchronization();
|
BreakpointManager::claimBreakpointsForEngine(this);
|
||||||
notifyEngineRunAndInferiorStopOk();
|
notifyEngineRunAndInferiorStopOk();
|
||||||
updateAll();
|
updateAll();
|
||||||
}
|
}
|
||||||
@@ -246,35 +245,44 @@ void PdbEngine::selectThread(ThreadId threadId)
|
|||||||
Q_UNUSED(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");
|
return fileName.endsWith(".py");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PdbEngine::insertBreakpoint(Breakpoint bp)
|
void PdbEngine::insertBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
QTC_CHECK(bp.state() == BreakpointInsertRequested);
|
QTC_ASSERT(bp, return);
|
||||||
bp.notifyBreakpointInsertProceeding();
|
QTC_CHECK(bp->state() == BreakpointInsertionRequested);
|
||||||
|
notifyBreakpointInsertProceeding(bp);
|
||||||
|
|
||||||
QString loc;
|
QString loc;
|
||||||
if (bp.type() == BreakpointByFunction)
|
const BreakpointParameters ¶ms = bp->requestedParameters();
|
||||||
loc = bp.functionName();
|
if (params.type == BreakpointByFunction)
|
||||||
|
loc = params.functionName;
|
||||||
else
|
else
|
||||||
loc = bp.fileName() + ':' + QString::number(bp.lineNumber());
|
loc = params.fileName + ':' + QString::number(params.lineNumber);
|
||||||
|
|
||||||
postDirectCommand("break " + loc);
|
postDirectCommand("break " + loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PdbEngine::removeBreakpoint(Breakpoint bp)
|
void PdbEngine::updateBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
QTC_CHECK(bp.state() == BreakpointRemoveRequested);
|
Q_UNUSED(bp);
|
||||||
bp.notifyBreakpointRemoveProceeding();
|
QTC_CHECK(false);
|
||||||
BreakpointResponse br = bp.response();
|
}
|
||||||
showMessage(QString("DELETING BP %1 IN %2").arg(br.id.toString()).arg(bp.fileName()));
|
|
||||||
postDirectCommand("clear " + br.id.toString());
|
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.
|
// Pretend it succeeds without waiting for response.
|
||||||
bp.notifyBreakpointRemoveOk();
|
notifyBreakpointRemoveOk(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PdbEngine::loadSymbols(const QString &moduleName)
|
void PdbEngine::loadSymbols(const QString &moduleName)
|
||||||
@@ -459,8 +467,8 @@ void PdbEngine::handleOutput(const QString &data)
|
|||||||
|
|
||||||
void PdbEngine::handleOutput2(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;
|
GdbMi item;
|
||||||
item.fromString(line);
|
item.fromString(line);
|
||||||
|
|
||||||
@@ -479,21 +487,25 @@ void PdbEngine::handleOutput2(const QString &data)
|
|||||||
} else if (line.startsWith("state=")) {
|
} else if (line.startsWith("state=")) {
|
||||||
refreshState(item);
|
refreshState(item);
|
||||||
} else if (line.startsWith("Breakpoint")) {
|
} else if (line.startsWith("Breakpoint")) {
|
||||||
int pos1 = line.indexOf(" at ");
|
const int pos1 = line.indexOf(" at ");
|
||||||
QTC_ASSERT(pos1 != -1, continue);
|
QTC_ASSERT(pos1 != -1, continue);
|
||||||
QString bpnr = line.mid(11, pos1 - 11);
|
const QString bpnr = line.mid(11, pos1 - 11);
|
||||||
int pos2 = line.lastIndexOf(':');
|
const int pos2 = line.lastIndexOf(':');
|
||||||
QTC_ASSERT(pos2 != -1, continue);
|
QTC_ASSERT(pos2 != -1, continue);
|
||||||
BreakpointResponse br;
|
const QString fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
|
||||||
br.id = BreakpointResponseId(bpnr);
|
const int lineNumber = line.mid(pos2 + 1).toInt();
|
||||||
br.fileName = line.mid(pos1 + 4, pos2 - pos1 - 4);
|
const Breakpoint bp = Utils::findOrDefault(breakHandler()->breakpoints(), [&](const Breakpoint &bp) {
|
||||||
br.lineNumber = line.mid(pos2 + 1).toInt();
|
return bp->parameters().isLocatedAt(fileName, lineNumber, bp->markerFileName())
|
||||||
Breakpoint bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
|
|| bp->requestedParameters().isLocatedAt(fileName, lineNumber, bp->markerFileName());
|
||||||
if (bp.isValid()) {
|
});
|
||||||
bp.setResponse(br);
|
QTC_ASSERT(bp, continue);
|
||||||
QTC_CHECK(!bp.needsChange());
|
bp->setResponseId(bpnr);
|
||||||
bp.notifyBreakpointInsertOk();
|
bp->setFileName(fileName);
|
||||||
}
|
bp->setLineNumber(lineNumber);
|
||||||
|
bp->adjustMarker();
|
||||||
|
bp->setPending(false);
|
||||||
|
QTC_CHECK(!bp->needsChange());
|
||||||
|
notifyBreakpointInsertOk(bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -71,13 +71,14 @@ private:
|
|||||||
void activateFrame(int index) override;
|
void activateFrame(int index) override;
|
||||||
void selectThread(ThreadId threadId) override;
|
void selectThread(ThreadId threadId) override;
|
||||||
|
|
||||||
bool acceptsBreakpoint(Breakpoint bp) const override;
|
bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
|
||||||
void insertBreakpoint(Breakpoint bp) override;
|
void insertBreakpoint(const Breakpoint &bp) override;
|
||||||
void removeBreakpoint(Breakpoint bp) override;
|
void updateBreakpoint(const Breakpoint &bp) override;
|
||||||
|
void removeBreakpoint(const Breakpoint &bp) override;
|
||||||
|
|
||||||
void assignValueInDebugger(WatchItem *item,
|
void assignValueInDebugger(WatchItem *item,
|
||||||
const QString &expr, const QVariant &value) override;
|
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 loadSymbols(const QString &moduleName) override;
|
||||||
void loadAllSymbols() override;
|
void loadAllSymbols() override;
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/qmlengine.h \
|
$$PWD/qmlengine.h \
|
||||||
$$PWD/qmlengineutils.h \
|
$$PWD/qmlengineutils.h \
|
||||||
$$PWD/qmlcppengine.h \
|
|
||||||
$$PWD/interactiveinterpreter.h \
|
$$PWD/interactiveinterpreter.h \
|
||||||
$$PWD/qmlv8debuggerclientconstants.h \
|
$$PWD/qmlv8debuggerclientconstants.h \
|
||||||
$$PWD/qmlinspectoragent.h
|
$$PWD/qmlinspectoragent.h
|
||||||
@@ -9,6 +8,5 @@ HEADERS += \
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/qmlengine.cpp \
|
$$PWD/qmlengine.cpp \
|
||||||
$$PWD/qmlengineutils.cpp \
|
$$PWD/qmlengineutils.cpp \
|
||||||
$$PWD/qmlcppengine.cpp \
|
|
||||||
$$PWD/interactiveinterpreter.cpp \
|
$$PWD/interactiveinterpreter.cpp \
|
||||||
$$PWD/qmlinspectoragent.cpp
|
$$PWD/qmlinspectoragent.cpp
|
||||||
|
@@ -169,10 +169,10 @@ public:
|
|||||||
void setBreakpoint(const QString type, const QString target,
|
void setBreakpoint(const QString type, const QString target,
|
||||||
bool enabled = true,int line = 0, int column = 0,
|
bool enabled = true,int line = 0, int column = 0,
|
||||||
const QString condition = QString(), int ignoreCount = -1);
|
const QString condition = QString(), int ignoreCount = -1);
|
||||||
void clearBreakpoint(int breakpoint);
|
void clearBreakpoint(const Breakpoint &bp);
|
||||||
|
|
||||||
bool canChangeBreakpoint() const;
|
bool canChangeBreakpoint() const;
|
||||||
void changeBreakpoint(int breakpoint, bool enabled);
|
void changeBreakpoint(const Breakpoint &bp, bool enabled);
|
||||||
|
|
||||||
void setExceptionBreak(Exceptions type, bool enabled = false);
|
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.
|
QHash<int, QmlV8ObjectData> refVals; // The mapping of target object handles to retrieved values.
|
||||||
int sequence = -1;
|
int sequence = -1;
|
||||||
QmlEngine *engine;
|
QmlEngine *engine;
|
||||||
QHash<BreakpointModelId, int> breakpoints;
|
QHash<int, Breakpoint> breakpointsSync;
|
||||||
QHash<int, BreakpointModelId> breakpointsSync;
|
QList<QString> breakpointsTemp;
|
||||||
QList<int> breakpointsTemp;
|
|
||||||
|
|
||||||
LookupItems currentlyLookingUp; // Id -> inames
|
LookupItems currentlyLookingUp; // Id -> inames
|
||||||
|
|
||||||
@@ -260,14 +259,14 @@ QmlEngine::QmlEngine()
|
|||||||
: d(new QmlEnginePrivate(this, new QmlDebugConnection(this)))
|
: d(new QmlEnginePrivate(this, new QmlDebugConnection(this)))
|
||||||
{
|
{
|
||||||
setObjectName("QmlEngine");
|
setObjectName("QmlEngine");
|
||||||
|
setDebuggerName(tr("QML Debugger"));
|
||||||
|
|
||||||
QmlDebugConnection *connection = d->connection();
|
QmlDebugConnection *connection = d->connection();
|
||||||
|
|
||||||
connect(stackHandler(), &StackHandler::stackChanged,
|
connect(stackHandler(), &StackHandler::stackChanged,
|
||||||
this, &QmlEngine::updateCurrentContext);
|
this, &QmlEngine::updateCurrentContext);
|
||||||
connect(stackHandler(), &StackHandler::currentIndexChanged,
|
connect(stackHandler(), &StackHandler::currentIndexChanged,
|
||||||
this, &QmlEngine::updateCurrentContext);
|
this, &QmlEngine::updateCurrentContext);
|
||||||
connect(inspectorView(), &WatchTreeView::currentIndexChanged,
|
|
||||||
this, &QmlEngine::updateCurrentContext);
|
|
||||||
|
|
||||||
connect(&d->applicationLauncher, &ApplicationLauncher::processExited,
|
connect(&d->applicationLauncher, &ApplicationLauncher::processExited,
|
||||||
this, &QmlEngine::disconnected);
|
this, &QmlEngine::disconnected);
|
||||||
@@ -278,7 +277,7 @@ QmlEngine::QmlEngine()
|
|||||||
|
|
||||||
debuggerConsole()->populateFileFinder();
|
debuggerConsole()->populateFileFinder();
|
||||||
debuggerConsole()->setScriptEvaluator([this](const QString &expr) {
|
debuggerConsole()->setScriptEvaluator([this](const QString &expr) {
|
||||||
executeDebuggerCommand(expr, QmlLanguage);
|
executeDebuggerCommand(expr);
|
||||||
});
|
});
|
||||||
|
|
||||||
d->connectionTimer.setInterval(4000);
|
d->connectionTimer.setInterval(4000);
|
||||||
@@ -336,7 +335,7 @@ void QmlEngine::handleLauncherStarted()
|
|||||||
{
|
{
|
||||||
// FIXME: The QmlEngine never calls notifyInferiorPid() triggering the
|
// FIXME: The QmlEngine never calls notifyInferiorPid() triggering the
|
||||||
// raising, so do it here manually for now.
|
// raising, so do it here manually for now.
|
||||||
runTool()->runControl()->applicationProcessHandle().activate();
|
ProcessHandle(inferiorPid()).activate();
|
||||||
tryToConnect();
|
tryToConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +346,10 @@ void QmlEngine::appMessage(const QString &msg, Utils::OutputFormat /* format */)
|
|||||||
|
|
||||||
void QmlEngine::connectionEstablished()
|
void QmlEngine::connectionEstablished()
|
||||||
{
|
{
|
||||||
attemptBreakpointSynchronization();
|
connect(inspectorView(), &WatchTreeView::currentIndexChanged,
|
||||||
|
this, &QmlEngine::updateCurrentContext);
|
||||||
|
|
||||||
|
BreakpointManager::claimBreakpointsForEngine(this);
|
||||||
|
|
||||||
if (state() == EngineRunRequested)
|
if (state() == EngineRunRequested)
|
||||||
notifyEngineRunAndInferiorRunOk();
|
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);
|
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());
|
auto infoBox = new QMessageBox(ICore::mainWindow());
|
||||||
infoBox->setIcon(QMessageBox::Critical);
|
infoBox->setIcon(QMessageBox::Critical);
|
||||||
infoBox->setWindowTitle(Core::Constants::IDE_DISPLAY_NAME);
|
infoBox->setWindowTitle(Core::Constants::IDE_DISPLAY_NAME);
|
||||||
@@ -522,7 +524,8 @@ void QmlEngine::runEngine()
|
|||||||
|
|
||||||
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
|
||||||
|
|
||||||
if (!isSlaveEngine()) {
|
if (isPrimaryEngine()) {
|
||||||
|
// QML only.
|
||||||
if (runParameters().startMode == AttachToRemoteServer)
|
if (runParameters().startMode == AttachToRemoteServer)
|
||||||
tryToConnect();
|
tryToConnect();
|
||||||
else if (runParameters().startMode == AttachToRemoteProcess)
|
else if (runParameters().startMode == AttachToRemoteProcess)
|
||||||
@@ -538,10 +541,9 @@ void QmlEngine::startApplicationLauncher()
|
|||||||
{
|
{
|
||||||
if (!d->applicationLauncher.isRunning()) {
|
if (!d->applicationLauncher.isRunning()) {
|
||||||
const Runnable runnable = runParameters().inferior;
|
const Runnable runnable = runParameters().inferior;
|
||||||
runTool()->appendMessage(tr("Starting %1 %2").arg(
|
showMessage(tr("Starting %1 %2").arg(QDir::toNativeSeparators(runnable.executable),
|
||||||
QDir::toNativeSeparators(runnable.executable),
|
runnable.commandLineArguments),
|
||||||
runnable.commandLineArguments),
|
Utils::NormalMessageFormat);
|
||||||
Utils::NormalMessageFormat);
|
|
||||||
d->applicationLauncher.start(runnable);
|
d->applicationLauncher.start(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,8 +567,7 @@ void QmlEngine::shutdownInferior()
|
|||||||
// }
|
// }
|
||||||
d->runCommand({DISCONNECT});
|
d->runCommand({DISCONNECT});
|
||||||
|
|
||||||
if (isSlaveEngine())
|
resetLocation();
|
||||||
resetLocation();
|
|
||||||
stopApplicationLauncher();
|
stopApplicationLauncher();
|
||||||
closeConnection();
|
closeConnection();
|
||||||
|
|
||||||
@@ -583,8 +584,7 @@ void QmlEngine::shutdownEngine()
|
|||||||
stopApplicationLauncher();
|
stopApplicationLauncher();
|
||||||
|
|
||||||
notifyEngineShutdownFinished();
|
notifyEngineShutdownFinished();
|
||||||
if (!isSlaveEngine())
|
showMessage(QString(), StatusBar);
|
||||||
showMessage(QString(), StatusBar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::setupEngine()
|
void QmlEngine::setupEngine()
|
||||||
@@ -689,34 +689,31 @@ void QmlEngine::selectThread(ThreadId threadId)
|
|||||||
Q_UNUSED(threadId)
|
Q_UNUSED(threadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::insertBreakpoint(Breakpoint bp)
|
void QmlEngine::insertBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
BreakpointState state = bp.state();
|
QTC_ASSERT(bp, return);
|
||||||
QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << bp << this << state);
|
const BreakpointState state = bp->state();
|
||||||
bp.notifyBreakpointInsertProceeding();
|
QTC_ASSERT(state == BreakpointInsertionRequested, qDebug() << bp << this << state);
|
||||||
|
notifyBreakpointInsertProceeding(bp);
|
||||||
|
|
||||||
const BreakpointParameters ¶ms = bp.parameters();
|
const BreakpointParameters &requested = bp->requestedParameters();
|
||||||
if (params.type == BreakpointAtJavaScriptThrow) {
|
if (requested.type == BreakpointAtJavaScriptThrow) {
|
||||||
BreakpointResponse br = bp.response();
|
bp->setPending(false);
|
||||||
br.pending = false;
|
notifyBreakpointInsertOk(bp);
|
||||||
bp.setResponse(br);
|
d->setExceptionBreak(AllExceptions, requested.enabled);
|
||||||
bp.notifyBreakpointInsertOk();
|
|
||||||
d->setExceptionBreak(AllExceptions, params.enabled);
|
|
||||||
|
|
||||||
} else if (params.type == BreakpointByFileAndLine) {
|
} else if (requested.type == BreakpointByFileAndLine) {
|
||||||
d->setBreakpoint(SCRIPTREGEXP, params.fileName,
|
d->setBreakpoint(SCRIPTREGEXP, requested.fileName,
|
||||||
params.enabled, params.lineNumber, 0,
|
requested.enabled, requested.lineNumber, 0,
|
||||||
params.condition, params.ignoreCount);
|
requested.condition, requested.ignoreCount);
|
||||||
|
|
||||||
} else if (params.type == BreakpointOnQmlSignalEmit) {
|
} else if (requested.type == BreakpointOnQmlSignalEmit) {
|
||||||
d->setBreakpoint(EVENT, params.functionName, params.enabled);
|
d->setBreakpoint(EVENT, requested.functionName, requested.enabled);
|
||||||
BreakpointResponse br = bp.response();
|
bp->setPending(false);
|
||||||
br.pending = false;
|
notifyBreakpointInsertOk(bp);
|
||||||
bp.setResponse(br);
|
|
||||||
bp.notifyBreakpointInsertOk();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d->breakpointsSync.insert(d->sequence, bp.id());
|
d->breakpointsSync.insert(d->sequence, bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::resetLocation()
|
void QmlEngine::resetLocation()
|
||||||
@@ -725,114 +722,64 @@ void QmlEngine::resetLocation()
|
|||||||
d->currentlyLookingUp.clear();
|
d->currentlyLookingUp.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::removeBreakpoint(Breakpoint bp)
|
void QmlEngine::removeBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
const BreakpointParameters ¶ms = bp.parameters();
|
QTC_ASSERT(bp, return);
|
||||||
|
const BreakpointParameters ¶ms = bp->requestedParameters();
|
||||||
|
|
||||||
BreakpointState state = bp.state();
|
const BreakpointState state = bp->state();
|
||||||
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << bp << this << state);
|
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << bp << this << state);
|
||||||
bp.notifyBreakpointRemoveProceeding();
|
notifyBreakpointRemoveProceeding(bp);
|
||||||
|
|
||||||
int breakpoint = d->breakpoints.value(bp.id());
|
|
||||||
d->breakpoints.remove(bp.id());
|
|
||||||
|
|
||||||
if (params.type == BreakpointAtJavaScriptThrow)
|
if (params.type == BreakpointAtJavaScriptThrow)
|
||||||
d->setExceptionBreak(AllExceptions);
|
d->setExceptionBreak(AllExceptions);
|
||||||
else if (params.type == BreakpointOnQmlSignalEmit)
|
else if (params.type == BreakpointOnQmlSignalEmit)
|
||||||
d->setBreakpoint(EVENT, params.functionName, false);
|
d->setBreakpoint(EVENT, params.functionName, false);
|
||||||
else
|
else
|
||||||
d->clearBreakpoint(breakpoint);
|
d->clearBreakpoint(bp);
|
||||||
|
|
||||||
if (bp.state() == BreakpointRemoveProceeding)
|
if (bp->state() == BreakpointRemoveProceeding)
|
||||||
bp.notifyBreakpointRemoveOk();
|
notifyBreakpointRemoveOk(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::changeBreakpoint(Breakpoint bp)
|
void QmlEngine::updateBreakpoint(const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
BreakpointState state = bp.state();
|
QTC_ASSERT(bp, return);
|
||||||
QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << bp << this << state);
|
const BreakpointState state = bp->state();
|
||||||
bp.notifyBreakpointChangeProceeding();
|
QTC_ASSERT(state == BreakpointUpdateRequested, qDebug() << bp << this << state);
|
||||||
|
notifyBreakpointChangeProceeding(bp);
|
||||||
|
|
||||||
const BreakpointParameters ¶ms = bp.parameters();
|
const BreakpointParameters &requested = bp->requestedParameters();
|
||||||
|
|
||||||
BreakpointResponse br = bp.response();
|
if (requested.type == BreakpointAtJavaScriptThrow) {
|
||||||
if (params.type == BreakpointAtJavaScriptThrow) {
|
d->setExceptionBreak(AllExceptions, requested.enabled);
|
||||||
d->setExceptionBreak(AllExceptions, params.enabled);
|
bp->setEnabled(requested.enabled);
|
||||||
} else if (params.type == BreakpointOnQmlSignalEmit) {
|
} else if (requested.type == BreakpointOnQmlSignalEmit) {
|
||||||
d->setBreakpoint(EVENT, params.functionName, params.enabled);
|
d->setBreakpoint(EVENT, requested.functionName, requested.enabled);
|
||||||
|
bp->setEnabled(requested.enabled);
|
||||||
} else if (d->canChangeBreakpoint()) {
|
} else if (d->canChangeBreakpoint()) {
|
||||||
d->changeBreakpoint(d->breakpoints.value(bp.id()), params.enabled);
|
d->changeBreakpoint(bp, requested.enabled);
|
||||||
} else {
|
} else {
|
||||||
d->clearBreakpoint(d->breakpoints.take(bp.id()));
|
d->clearBreakpoint(bp);
|
||||||
d->setBreakpoint(SCRIPTREGEXP, params.fileName,
|
d->setBreakpoint(SCRIPTREGEXP, requested.fileName,
|
||||||
params.enabled, params.lineNumber, 0,
|
requested.enabled, requested.lineNumber, 0,
|
||||||
params.condition, params.ignoreCount);
|
requested.condition, requested.ignoreCount);
|
||||||
d->breakpointsSync.insert(d->sequence, bp.id());
|
d->breakpointsSync.insert(d->sequence, bp);
|
||||||
}
|
}
|
||||||
br.enabled = params.enabled;
|
|
||||||
bp.setResponse(br);
|
|
||||||
|
|
||||||
if (bp.state() == BreakpointChangeProceeding)
|
if (bp->state() == BreakpointUpdateProceeding)
|
||||||
bp.notifyBreakpointChangeOk();
|
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
|
//TODO: enable setting of breakpoints before start of debug session
|
||||||
//For now, the event breakpoint can be set after the activeDebuggerClient is known
|
//For now, the event breakpoint can be set after the activeDebuggerClient is known
|
||||||
//This is because the older client does not support BreakpointOnQmlSignalHandler
|
//This is because the older client does not support BreakpointOnQmlSignalHandler
|
||||||
BreakpointType type = bp.type();
|
if (bp.type == BreakpointOnQmlSignalEmit || bp.type == BreakpointAtJavaScriptThrow)
|
||||||
return type == BreakpointOnQmlSignalEmit
|
return true;
|
||||||
|| type == BreakpointByFileAndLine
|
|
||||||
|| type == BreakpointAtJavaScriptThrow;
|
return bp.isQmlFileAndLineBreakpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEngine::loadSymbols(const QString &moduleName)
|
void QmlEngine::loadSymbols(const QString &moduleName)
|
||||||
@@ -1041,6 +988,11 @@ void QmlEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
d->updateLocals();
|
d->updateLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context QmlEngine::languageContext() const
|
||||||
|
{
|
||||||
|
return Context(Constants::C_QMLDEBUGGER);
|
||||||
|
}
|
||||||
|
|
||||||
void QmlEngine::disconnected()
|
void QmlEngine::disconnected()
|
||||||
{
|
{
|
||||||
showMessage(tr("QML Debugger disconnected."), StatusBar);
|
showMessage(tr("QML Debugger disconnected."), StatusBar);
|
||||||
@@ -1084,11 +1036,8 @@ void QmlEngine::updateCurrentContext()
|
|||||||
+ (context.isEmpty() ? tr("Global QML Context") : context));
|
+ (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) {
|
if (state() == InferiorStopOk) {
|
||||||
StackHandler *handler = stackHandler();
|
StackHandler *handler = stackHandler();
|
||||||
if (handler->isContentsValid() && handler->currentFrame().isUsable()) {
|
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,
|
void QmlEnginePrivate::updateScriptSource(const QString &fileName, int lineOffset, int columnOffset,
|
||||||
const QString &source)
|
const QString &source)
|
||||||
{
|
{
|
||||||
@@ -1181,11 +1140,8 @@ void QmlEngine::connectionFailed()
|
|||||||
// this is only an error if we are already connected and something goes wrong.
|
// this is only an error if we are already connected and something goes wrong.
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
showMessage(tr("QML Debugger: Connection failed."), StatusBar);
|
showMessage(tr("QML Debugger: Connection failed."), StatusBar);
|
||||||
|
notifyInferiorSpontaneousStop();
|
||||||
if (!isSlaveEngine()) { // normal flow for slave engine when gdb exits
|
notifyInferiorIll();
|
||||||
notifyInferiorSpontaneousStop();
|
|
||||||
notifyInferiorIll();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
d->connectionTimer.stop();
|
d->connectionTimer.stop();
|
||||||
connectionStartupFailed();
|
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>,
|
// { "seq" : <number>,
|
||||||
// "type" : "request",
|
// "type" : "request",
|
||||||
@@ -1502,7 +1458,7 @@ void QmlEnginePrivate::clearBreakpoint(int breakpoint)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
DebuggerCommand cmd(CLEARBREAKPOINT);
|
DebuggerCommand cmd(CLEARBREAKPOINT);
|
||||||
cmd.arg(BREAKPOINT, breakpoint);
|
cmd.arg(BREAKPOINT, bp->responseId().toInt());
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1511,10 +1467,10 @@ bool QmlEnginePrivate::canChangeBreakpoint() const
|
|||||||
return supportChangeBreakpoint;
|
return supportChangeBreakpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlEnginePrivate::changeBreakpoint(int breakpoint, bool enabled)
|
void QmlEnginePrivate::changeBreakpoint(const Breakpoint &bp, bool enabled)
|
||||||
{
|
{
|
||||||
DebuggerCommand cmd(CHANGEBREAKPOINT);
|
DebuggerCommand cmd(CHANGEBREAKPOINT);
|
||||||
cmd.arg(BREAKPOINT, breakpoint);
|
cmd.arg(BREAKPOINT, bp->responseId().toInt());
|
||||||
cmd.arg(ENABLED, enabled);
|
cmd.arg(ENABLED, enabled);
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
}
|
}
|
||||||
@@ -1780,27 +1736,26 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
|
|||||||
|
|
||||||
int seq = resp.value("request_seq").toInt();
|
int seq = resp.value("request_seq").toInt();
|
||||||
const QVariantMap breakpointData = resp.value(BODY).toMap();
|
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)) {
|
if (breakpointsSync.contains(seq)) {
|
||||||
BreakpointModelId id = breakpointsSync.take(seq);
|
Breakpoint bp = breakpointsSync.take(seq);
|
||||||
breakpoints.insert(id, index);
|
QTC_ASSERT(bp, return);
|
||||||
|
bp->setParameters(bp->requestedParameters()); // Assume it worked.
|
||||||
|
bp->setResponseId(index);
|
||||||
|
|
||||||
//Is actual position info present? Then breakpoint was
|
//Is actual position info present? Then breakpoint was
|
||||||
//accepted
|
//accepted
|
||||||
const QVariantList actualLocations =
|
const QVariantList actualLocations =
|
||||||
breakpointData.value("actual_locations").toList();
|
breakpointData.value("actual_locations").toList();
|
||||||
|
const int line = breakpointData.value("line").toInt() + 1;
|
||||||
if (actualLocations.count()) {
|
if (actualLocations.count()) {
|
||||||
//The breakpoint requested line should be same as
|
//The breakpoint requested line should be same as
|
||||||
//actual line
|
//actual line
|
||||||
BreakHandler *handler = engine->breakHandler();
|
if (bp && bp->state() != BreakpointInserted) {
|
||||||
Breakpoint bp = handler->breakpointById(id);
|
bp->setLineNumber(line);
|
||||||
if (bp.state() != BreakpointInserted) {
|
bp->setPending(false);
|
||||||
BreakpointResponse br = bp.response();
|
engine->notifyBreakpointInsertOk(bp);
|
||||||
br.lineNumber = breakpointData.value("line").toInt() + 1;
|
|
||||||
br.pending = false;
|
|
||||||
bp.setResponse(br);
|
|
||||||
bp.notifyBreakpointInsertOk();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1900,14 +1855,18 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
|
|||||||
|
|
||||||
bool inferiorStop = true;
|
bool inferiorStop = true;
|
||||||
|
|
||||||
QList<int> v8BreakpointIds;
|
QList<Breakpoint> v8Breakpoints;
|
||||||
{
|
|
||||||
const QVariantList v8BreakpointIdList = breakData.value("breakpoints").toList();
|
const QVariantList v8BreakpointIdList = breakData.value("breakpoints").toList();
|
||||||
for (const QVariant &breakpointId : v8BreakpointIdList)
|
for (const QVariant &breakpointId : v8BreakpointIdList) {
|
||||||
v8BreakpointIds << breakpointId.toInt();
|
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")
|
&& scriptUrl.endsWith(".qml")
|
||||||
&& sourceLineText.trimmed().startsWith('(')) {
|
&& sourceLineText.trimmed().startsWith('(')) {
|
||||||
|
|
||||||
@@ -1915,24 +1874,20 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
|
|||||||
// -> relocate the breakpoint to column: 1 and continue
|
// -> relocate the breakpoint to column: 1 and continue
|
||||||
|
|
||||||
int newColumn = sourceLineText.indexOf('(') + 1;
|
int newColumn = sourceLineText.indexOf('(') + 1;
|
||||||
BreakHandler *handler = engine->breakHandler();
|
|
||||||
|
|
||||||
for (int v8Id : v8BreakpointIds) {
|
for (const Breakpoint &bp : v8Breakpoints) {
|
||||||
const BreakpointModelId id = breakpoints.key(v8Id);
|
QTC_ASSERT(bp, continue);
|
||||||
Breakpoint bp = handler->breakpointById(id);
|
const BreakpointParameters ¶ms = bp->requestedParameters();
|
||||||
if (bp.isValid()) {
|
|
||||||
const BreakpointParameters ¶ms = bp.parameters();
|
|
||||||
|
|
||||||
clearBreakpoint(v8Id);
|
clearBreakpoint(bp);
|
||||||
setBreakpoint(SCRIPTREGEXP,
|
setBreakpoint(SCRIPTREGEXP,
|
||||||
params.fileName,
|
params.fileName,
|
||||||
params.enabled,
|
params.enabled,
|
||||||
params.lineNumber,
|
params.lineNumber,
|
||||||
newColumn,
|
newColumn,
|
||||||
params.condition,
|
params.condition,
|
||||||
params.ignoreCount);
|
params.ignoreCount);
|
||||||
breakpointsSync.insert(sequence, id);
|
breakpointsSync.insert(sequence, bp);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continueDebugging(Continue);
|
continueDebugging(Continue);
|
||||||
inferiorStop = false;
|
inferiorStop = false;
|
||||||
@@ -1946,29 +1901,23 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data)
|
|||||||
|
|
||||||
if (inferiorStop) {
|
if (inferiorStop) {
|
||||||
//Update breakpoint data
|
//Update breakpoint data
|
||||||
BreakHandler *handler = engine->breakHandler();
|
for (const Breakpoint &bp : v8Breakpoints) {
|
||||||
for (int v8Id : v8BreakpointIds) {
|
QTC_ASSERT(bp, continue);
|
||||||
const BreakpointModelId id = breakpoints.key(v8Id);
|
if (bp->functionName().isEmpty()) {
|
||||||
Breakpoint bp = handler->breakpointById(id);
|
bp->setFunctionName(invocationText);
|
||||||
if (bp) {
|
}
|
||||||
BreakpointResponse br = bp.response();
|
if (bp->state() != BreakpointInserted) {
|
||||||
if (br.functionName.isEmpty()) {
|
bp->setLineNumber(breakData.value("sourceLine").toInt() + 1);
|
||||||
br.functionName = invocationText;
|
bp->setPending(false);
|
||||||
bp.setResponse(br);
|
engine->notifyBreakpointInsertOk(bp);
|
||||||
}
|
|
||||||
if (bp.state() != BreakpointInserted) {
|
|
||||||
br.lineNumber = breakData.value("sourceLine").toInt() + 1;
|
|
||||||
br.pending = false;
|
|
||||||
bp.setResponse(br);
|
|
||||||
bp.notifyBreakpointInsertOk();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine->state() == InferiorRunOk) {
|
if (engine->state() == InferiorRunOk) {
|
||||||
for (const QVariant &breakpointId : v8BreakpointIds) {
|
for (const Breakpoint &bp : v8Breakpoints) {
|
||||||
if (breakpointsTemp.contains(breakpointId.toInt()))
|
QTC_ASSERT(bp, continue);
|
||||||
clearBreakpoint(breakpointId.toInt());
|
if (breakpointsTemp.contains(bp->responseId()))
|
||||||
|
clearBreakpoint(bp);
|
||||||
}
|
}
|
||||||
engine->notifyInferiorSpontaneousStop();
|
engine->notifyInferiorSpontaneousStop();
|
||||||
backtrace();
|
backtrace();
|
||||||
|
@@ -34,7 +34,6 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class WatchItem;
|
|
||||||
class QmlEnginePrivate;
|
class QmlEnginePrivate;
|
||||||
class QmlInspectorAgent;
|
class QmlInspectorAgent;
|
||||||
|
|
||||||
@@ -68,7 +67,6 @@ private:
|
|||||||
void setState(DebuggerState state, bool forced) override;
|
void setState(DebuggerState state, bool forced) override;
|
||||||
|
|
||||||
void gotoLocation(const Internal::Location &location) override;
|
void gotoLocation(const Internal::Location &location) override;
|
||||||
void insertBreakpoint(Breakpoint bp) override;
|
|
||||||
|
|
||||||
bool canDisplayTooltip() const override { return false; }
|
bool canDisplayTooltip() const override { return false; }
|
||||||
|
|
||||||
@@ -97,10 +95,10 @@ private:
|
|||||||
void activateFrame(int index) override;
|
void activateFrame(int index) override;
|
||||||
void selectThread(ThreadId threadId) override;
|
void selectThread(ThreadId threadId) override;
|
||||||
|
|
||||||
void attemptBreakpointSynchronization() override;
|
bool acceptsBreakpoint(const BreakpointParameters &bp) const final;
|
||||||
void removeBreakpoint(Breakpoint bp) override;
|
void insertBreakpoint(const Breakpoint &bp) final;
|
||||||
void changeBreakpoint(Breakpoint bp) override;
|
void removeBreakpoint(const Breakpoint &bp) final;
|
||||||
bool acceptsBreakpoint(Breakpoint bp) const override;
|
void updateBreakpoint(const Breakpoint &bp) final;
|
||||||
|
|
||||||
void assignValueInDebugger(WatchItem *item,
|
void assignValueInDebugger(WatchItem *item,
|
||||||
const QString &expr, const QVariant &value) override;
|
const QString &expr, const QVariant &value) override;
|
||||||
@@ -117,12 +115,14 @@ private:
|
|||||||
void updateItem(const QString &iname) override;
|
void updateItem(const QString &iname) override;
|
||||||
void expandItem(const QString &iname) override;
|
void expandItem(const QString &iname) override;
|
||||||
void selectWatchData(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;
|
bool hasCapability(unsigned) const override;
|
||||||
void quitDebugger() override;
|
void quitDebugger() override;
|
||||||
|
|
||||||
void doUpdateLocals(const UpdateParameters ¶ms) override;
|
void doUpdateLocals(const UpdateParameters ¶ms) override;
|
||||||
|
Core::Context languageContext() const override;
|
||||||
|
|
||||||
void closeConnection();
|
void closeConnection();
|
||||||
void startApplicationLauncher();
|
void startApplicationLauncher();
|
||||||
@@ -135,7 +135,6 @@ private:
|
|||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QmlCppEngine;
|
|
||||||
friend class QmlEnginePrivate;
|
friend class QmlEnginePrivate;
|
||||||
friend class QmlInspectorAgent;
|
friend class QmlInspectorAgent;
|
||||||
QmlEnginePrivate *d;
|
QmlEnginePrivate *d;
|
||||||
|
@@ -67,7 +67,8 @@ Q_LOGGING_CATEGORY(qmlInspectorLog, "qtc.dbg.qmlinspector")
|
|||||||
QmlInspectorAgent::QmlInspectorAgent(QmlEngine *engine, QmlDebugConnection *connection)
|
QmlInspectorAgent::QmlInspectorAgent(QmlEngine *engine, QmlDebugConnection *connection)
|
||||||
: m_qmlEngine(engine)
|
: m_qmlEngine(engine)
|
||||||
, m_objectToSelect(WatchItem::InvalidId)
|
, m_objectToSelect(WatchItem::InvalidId)
|
||||||
, m_masterEngine(engine->masterEngine())
|
, m_toolsClient(nullptr)
|
||||||
|
, m_targetToSync(NoTarget)
|
||||||
, m_debugIdToSelect(WatchItem::InvalidId)
|
, m_debugIdToSelect(WatchItem::InvalidId)
|
||||||
, m_currentSelectedDebugId(WatchItem::InvalidId)
|
, m_currentSelectedDebugId(WatchItem::InvalidId)
|
||||||
, m_inspectorToolsContext("Debugger.QmlInspector")
|
, m_inspectorToolsContext("Debugger.QmlInspector")
|
||||||
@@ -786,7 +787,7 @@ void QmlInspectorAgent::toolsClientStateChanged(QmlDebugClient::State state)
|
|||||||
Core::ICore::addAdditionalContext(m_inspectorToolsContext);
|
Core::ICore::addAdditionalContext(m_inspectorToolsContext);
|
||||||
|
|
||||||
m_toolsClientConnected = true;
|
m_toolsClientConnected = true;
|
||||||
enableTools(m_masterEngine->state() == InferiorRunOk);
|
enableTools(m_qmlEngine->state() == InferiorRunOk);
|
||||||
if (m_showAppOnTopAction->isChecked())
|
if (m_showAppOnTopAction->isChecked())
|
||||||
m_toolsClient->showAppOnTop(true);
|
m_toolsClient->showAppOnTop(true);
|
||||||
|
|
||||||
@@ -901,7 +902,7 @@ void QmlInspectorAgent::setActiveEngineClient(BaseEngineDebugClient *client)
|
|||||||
void QmlInspectorAgent::jumpToObjectDefinitionInEditor(
|
void QmlInspectorAgent::jumpToObjectDefinitionInEditor(
|
||||||
const FileReference &objSource, int debugId)
|
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());
|
Core::EditorManager::openEditorAt(fileName, objSource.lineNumber());
|
||||||
if (debugId != WatchItem::InvalidId && debugId != m_currentSelectedDebugId) {
|
if (debugId != WatchItem::InvalidId && debugId != m_currentSelectedDebugId) {
|
||||||
|
@@ -134,7 +134,6 @@ private:
|
|||||||
QList<int> m_fetchDataIds;
|
QList<int> m_fetchDataIds;
|
||||||
QTimer m_delayQueryTimer;
|
QTimer m_delayQueryTimer;
|
||||||
|
|
||||||
DebuggerEngine *m_masterEngine;
|
|
||||||
QHash<QString, QmlDebug::BaseEngineDebugClient*> m_engineClients;
|
QHash<QString, QmlDebug::BaseEngineDebugClient*> m_engineClients;
|
||||||
QmlDebug::BaseToolsClient *m_toolsClient = nullptr;
|
QmlDebug::BaseToolsClient *m_toolsClient = nullptr;
|
||||||
|
|
||||||
|
@@ -676,8 +676,8 @@ bool RegisterHandler::setData(const QModelIndex &idx, const QVariant &data, int
|
|||||||
|
|
||||||
bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
|
bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
|
||||||
{
|
{
|
||||||
const bool actionsEnabled = m_engine->debuggerActionsEnabled();
|
|
||||||
const DebuggerState state = m_engine->state();
|
const DebuggerState state = m_engine->state();
|
||||||
|
const bool actionsEnabled = m_engine->debuggerActionsEnabled();
|
||||||
|
|
||||||
RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.index());
|
RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.index());
|
||||||
RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.index());
|
RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.index());
|
||||||
|
@@ -25,15 +25,28 @@
|
|||||||
|
|
||||||
#include "snapshothandler.h"
|
#include "snapshothandler.h"
|
||||||
|
|
||||||
|
#include "analyzer/analyzermanager.h"
|
||||||
|
#include "debuggeractions.h"
|
||||||
#include "debuggerinternalconstants.h"
|
#include "debuggerinternalconstants.h"
|
||||||
#include "debuggericons.h"
|
#include "debuggericons.h"
|
||||||
#include "debuggercore.h"
|
#include "debuggercore.h"
|
||||||
#include "debuggerruncontrol.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 <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QMenu>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -102,177 +115,300 @@ QDebug operator<<(QDebug d, const SnapshotData &f)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
\class Debugger::Internal::EngineManager
|
||||||
\brief The SnapshotHandler class provides a model to represent the
|
\brief The EngineManager manages running debugger engines.
|
||||||
snapshots in a QTreeView.
|
|
||||||
|
|
||||||
A snapshot represents a debugging session.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SnapshotHandler::SnapshotHandler() = default;
|
static EngineManager *theEngineManager = nullptr;
|
||||||
|
static EngineManagerPrivate *d = nullptr;
|
||||||
|
|
||||||
SnapshotHandler::~SnapshotHandler()
|
EngineManager::EngineManager()
|
||||||
{
|
{
|
||||||
for (int i = m_snapshots.size(); --i >= 0; ) {
|
theEngineManager = this;
|
||||||
if (DebuggerRunTool *runTool = at(i)) {
|
d = new EngineManagerPrivate;
|
||||||
const DebuggerRunParameters &rp = runTool->runParameters();
|
}
|
||||||
if (rp.isSnapshot && !rp.coreFile.isEmpty())
|
|
||||||
QFile::remove(rp.coreFile);
|
QWidget *EngineManager::engineChooser()
|
||||||
|
{
|
||||||
|
return d->m_engineChooser;
|
||||||
|
}
|
||||||
|
|
||||||
|
EngineManager::~EngineManager()
|
||||||
|
{
|
||||||
|
theEngineManager = nullptr;
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
EngineManager *EngineManager::instance()
|
||||||
|
{
|
||||||
|
return theEngineManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemModel *EngineManager::model()
|
||||||
|
{
|
||||||
|
return &d->m_engineModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EngineManager::activateEngine(DebuggerEngine *engine)
|
||||||
|
{
|
||||||
|
d->activateEngine(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
int SnapshotHandler::rowCount(const QModelIndex &parent) const
|
return EngineManager::tr("Debugger Preset");
|
||||||
{
|
default:
|
||||||
// Since the stack is not a tree, row count is 0 for any valid parent
|
break;
|
||||||
return parent.isValid() ? 0 : m_snapshots.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SnapshotHandler::columnCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return parent.isValid() ? 0 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant SnapshotHandler::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid() || index.row() >= m_snapshots.size())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
const DebuggerRunTool *runTool = at(index.row());
|
|
||||||
|
|
||||||
if (role == SnapshotCapabilityRole)
|
|
||||||
return runTool && runTool->activeEngine()->hasCapability(SnapshotCapability);
|
|
||||||
|
|
||||||
if (!runTool)
|
|
||||||
return QLatin1String("<finished>");
|
|
||||||
|
|
||||||
const DebuggerRunParameters &rp = runTool->runParameters();
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
case Qt::ToolTipRole:
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant SnapshotHandler::headerData(int section, Qt::Orientation orientation, int role) const
|
bool EngineItem::setData(int row, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
Q_UNUSED(row);
|
||||||
switch (section) {
|
if (!m_engine)
|
||||||
case 0: return tr("Name");
|
return false;
|
||||||
case 1: return tr("File");
|
|
||||||
};
|
if (role == BaseTreeView::ItemActivatedRole) {
|
||||||
|
EngineItem *engineItem = d->findEngineItem(m_engine);
|
||||||
|
d->activateEngineItem(engineItem);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return QVariant();
|
|
||||||
|
if (role == BaseTreeView::ItemViewEventRole) {
|
||||||
|
ItemViewEvent ev = value.value<ItemViewEvent>();
|
||||||
|
|
||||||
|
if (auto cmev = ev.as<QContextMenuEvent>()) {
|
||||||
|
|
||||||
|
auto menu = new QMenu(ev.view());
|
||||||
|
|
||||||
|
QAction *actCreate = menu->addAction(tr("Create Snapshot"));
|
||||||
|
actCreate->setEnabled(m_engine->hasCapability(SnapshotCapabilityRole));
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
|
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 false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags SnapshotHandler::flags(const QModelIndex &index) const
|
void EngineManagerPrivate::activateEngineByIndex(int index)
|
||||||
{
|
{
|
||||||
if (index.row() >= m_snapshots.size())
|
activateEngineItem(m_engineModel.rootItem()->childAt(index));
|
||||||
return nullptr;
|
|
||||||
if (index.row() == m_snapshots.size())
|
|
||||||
return QAbstractTableModel::flags(index);
|
|
||||||
return true ? QAbstractTableModel::flags(index) : Qt::ItemFlags({});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotHandler::activateSnapshot(int index)
|
void EngineManagerPrivate::activateEngineItem(EngineItem *engineItem)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
if (m_currentItem) {
|
||||||
m_currentIndex = index;
|
if (DebuggerEngine *engine = m_currentItem->m_engine) {
|
||||||
//qDebug() << "ACTIVATING INDEX: " << m_currentIndex << " OF " << size();
|
const Context context = engine->languageContext();
|
||||||
Internal::displayDebugger(at(index));
|
ICore::removeAdditionalContext(context);
|
||||||
endResetModel();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentItem = engineItem;
|
||||||
|
|
||||||
|
if (m_currentItem) {
|
||||||
|
if (DebuggerEngine *engine = m_currentItem->m_engine) {
|
||||||
|
const Context context = engine->languageContext();
|
||||||
|
ICore::addAdditionalContext(context);
|
||||||
|
engine->gotoCurrentLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectUiForCurrentEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotHandler::createSnapshot(int index)
|
void EngineManagerPrivate::selectUiForCurrentEngine()
|
||||||
{
|
{
|
||||||
DebuggerRunTool *runTool = at(index);
|
Perspective *perspective = nullptr;
|
||||||
QTC_ASSERT(runTool, return);
|
int row = 0;
|
||||||
runTool->engine()->createSnapshot();
|
|
||||||
|
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::removeSnapshot(int index)
|
void EngineManager::selectUiForCurrentEngine()
|
||||||
{
|
{
|
||||||
DebuggerRunTool *runTool = at(index);
|
d->selectUiForCurrentEngine();
|
||||||
//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 *EngineManagerPrivate::findEngineItem(DebuggerEngine *engine)
|
||||||
void SnapshotHandler::removeAll()
|
|
||||||
{
|
{
|
||||||
beginResetModel();
|
return m_engineModel.rootItem()->findFirstLevelChild([engine](EngineItem *engineItem) {
|
||||||
m_snapshots.clear();
|
return engineItem->m_engine == engine;
|
||||||
m_currentIndex = -1;
|
});
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotHandler::appendSnapshot(DebuggerRunTool *runTool)
|
void EngineManagerPrivate::activateEngine(DebuggerEngine *engine)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
EngineItem *engineItem = findEngineItem(engine);
|
||||||
m_snapshots.append(runTool);
|
activateEngineItem(engineItem);
|
||||||
m_currentIndex = size() - 1;
|
|
||||||
endResetModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotHandler::removeSnapshot(DebuggerRunTool *runTool)
|
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 EngineManager::registerEngine(DebuggerEngine *engine)
|
||||||
|
{
|
||||||
|
auto engineItem = new EngineItem;
|
||||||
|
engineItem->m_engine = engine;
|
||||||
|
d->m_engineModel.rootItem()->appendChild(engineItem);
|
||||||
|
d->updateEngineChooserVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EngineManager::activateDebugMode()
|
||||||
|
{
|
||||||
|
if (ModeManager::currentModeId() != Constants::MODE_DEBUG) {
|
||||||
|
d->m_previousMode = ModeManager::currentModeId();
|
||||||
|
ModeManager::activateMode(Constants::MODE_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EngineManager::unregisterEngine(DebuggerEngine *engine)
|
||||||
{
|
{
|
||||||
// Could be that the run controls died before it was appended.
|
// Could be that the run controls died before it was appended.
|
||||||
int index = m_snapshots.indexOf(runTool);
|
if (auto engineItem = d->findEngineItem(engine))
|
||||||
if (index != -1)
|
d->m_engineModel.destroyItem(engineItem);
|
||||||
removeSnapshot(index);
|
|
||||||
|
d->updateEngineChooserVisibility();
|
||||||
|
emit theEngineManager->currentEngineChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotHandler::setCurrentIndex(int index)
|
QList<QPointer<DebuggerEngine>> EngineManager::engines()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
QList<QPointer<DebuggerEngine>> result;
|
||||||
m_currentIndex = index;
|
d->m_engineModel.forItemsAtLevel<1>([&result](EngineItem *engineItem) {
|
||||||
endResetModel();
|
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
|
} // namespace Internal
|
||||||
|
@@ -25,47 +25,43 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
|
|
||||||
class DebuggerRunTool;
|
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class SnapshotHandler : public QAbstractTableModel
|
class DebuggerEngine;
|
||||||
|
|
||||||
|
class EngineManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SnapshotHandler();
|
explicit EngineManager();
|
||||||
~SnapshotHandler() override;
|
~EngineManager() final;
|
||||||
|
|
||||||
// Called from SnapshotHandler after a new snapshot has been added
|
static EngineManager *instance();
|
||||||
void removeAll();
|
static QAbstractItemModel *model();
|
||||||
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;
|
|
||||||
|
|
||||||
void createSnapshot(int index);
|
static void registerEngine(DebuggerEngine *engine);
|
||||||
void activateSnapshot(int index);
|
static void unregisterEngine(DebuggerEngine *engine);
|
||||||
void removeSnapshot(int index);
|
static void activateEngine(DebuggerEngine *engine);
|
||||||
|
static void activateDebugMode();
|
||||||
|
|
||||||
private:
|
static QList<QPointer<DebuggerEngine> > engines();
|
||||||
// QAbstractTableModel
|
static QPointer<DebuggerEngine> currentEngine();
|
||||||
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;
|
|
||||||
|
|
||||||
int m_currentIndex = -1;
|
static void selectUiForCurrentEngine();
|
||||||
QList< QPointer<DebuggerRunTool> > m_snapshots;
|
|
||||||
|
static QWidget *engineChooser();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void engineStateChanged(DebuggerEngine *engine);
|
||||||
|
void currentEngineChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -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
|
|
@@ -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
|
|
@@ -121,7 +121,7 @@ bool SourceFilesHandler::setData(const QModelIndex &idx, const QVariant &data, i
|
|||||||
QModelIndex index = idx.sibling(idx.row(), 0);
|
QModelIndex index = idx.sibling(idx.row(), 0);
|
||||||
QString name = index.data().toString();
|
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);
|
QAction *act = menu->addAction(display);
|
||||||
act->setEnabled(on);
|
act->setEnabled(on);
|
||||||
QObject::connect(act, &QAction::triggered, onTriggered);
|
QObject::connect(act, &QAction::triggered, onTriggered);
|
||||||
|
@@ -25,17 +25,17 @@
|
|||||||
|
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
#include "debuggerruncontrol.h"
|
#include <projectexplorer/runconfiguration.h>
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QSocketNotifier>
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
# define DEBUGGER_USE_TERMINAL
|
# define DEBUGGER_USE_TERMINAL
|
||||||
#endif
|
#endif
|
||||||
@@ -168,13 +168,12 @@ void Terminal::onSlaveReaderActivated(int fd)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalRunner::TerminalRunner(DebuggerRunTool *debugger)
|
TerminalRunner::TerminalRunner(RunControl *runControl, const Runnable &stubRunnable)
|
||||||
: RunWorker(debugger->runControl())
|
: RunWorker(runControl)
|
||||||
{
|
{
|
||||||
setDisplayName("TerminalRunner");
|
setDisplayName("TerminalRunner");
|
||||||
|
|
||||||
const DebuggerRunParameters &rp = debugger->runParameters();
|
m_stubRunnable = stubRunnable;
|
||||||
m_stubRunnable = rp.inferior;
|
|
||||||
|
|
||||||
connect(&m_stubProc, &ConsoleProcess::processError,
|
connect(&m_stubProc, &ConsoleProcess::processError,
|
||||||
this, &TerminalRunner::stubError);
|
this, &TerminalRunner::stubError);
|
||||||
|
@@ -71,7 +71,8 @@ private:
|
|||||||
class TerminalRunner : public ProjectExplorer::RunWorker
|
class TerminalRunner : public ProjectExplorer::RunWorker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TerminalRunner(DebuggerRunTool *runControl);
|
TerminalRunner(ProjectExplorer::RunControl *runControl,
|
||||||
|
const ProjectExplorer::Runnable &stubRunnable);
|
||||||
|
|
||||||
qint64 applicationPid() const { return m_applicationPid; }
|
qint64 applicationPid() const { return m_applicationPid; }
|
||||||
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
|
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
|
||||||
|
@@ -367,7 +367,7 @@ void ThreadsHandler::updateThreadBox()
|
|||||||
forItemsAtLevel<1>([&list](ThreadItem *item) {
|
forItemsAtLevel<1>([&list](ThreadItem *item) {
|
||||||
list.append(QString::fromLatin1("#%1 %2").arg(item->threadData.id.raw()).arg(item->threadData.name));
|
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
|
ThreadData ThreadsHandler::thread(ThreadId id) const
|
||||||
|
@@ -1298,7 +1298,7 @@ void WatchModel::timerEvent(QTimerEvent *event)
|
|||||||
}
|
}
|
||||||
ungrabWidget();
|
ungrabWidget();
|
||||||
}
|
}
|
||||||
showMessage(msg, StatusBar);
|
m_engine->showMessage(msg, StatusBar);
|
||||||
} else {
|
} else {
|
||||||
WatchModelBase::timerEvent(event);
|
WatchModelBase::timerEvent(event);
|
||||||
}
|
}
|
||||||
@@ -1951,8 +1951,10 @@ QString WatchModel::nameForFormat(int format)
|
|||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
WatchHandler::WatchHandler(DebuggerEngine *engine)
|
WatchHandler::WatchHandler(DebuggerEngine *engine)
|
||||||
|
: m_engine(engine)
|
||||||
{
|
{
|
||||||
m_model = new WatchModel(this, engine);
|
m_model = new WatchModel(this, engine);
|
||||||
|
loadSessionDataForEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchHandler::~WatchHandler()
|
WatchHandler::~WatchHandler()
|
||||||
@@ -2072,7 +2074,13 @@ void WatchHandler::resetValueCache()
|
|||||||
|
|
||||||
void WatchHandler::resetWatchers()
|
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)
|
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);
|
m_model->m_engine->updateWatchData(item->iname);
|
||||||
}
|
}
|
||||||
updateLocalsWindow();
|
updateLocalsWindow();
|
||||||
Internal::raiseWatchersWindow();
|
m_engine->raiseWatchersWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::updateWatchExpression(WatchItem *item, const QString &newExp)
|
void WatchHandler::updateWatchExpression(WatchItem *item, const QString &newExp)
|
||||||
@@ -2358,7 +2366,7 @@ void WatchHandler::updateLocalsWindow()
|
|||||||
{
|
{
|
||||||
// Force show/hide of return view.
|
// Force show/hide of return view.
|
||||||
bool showReturn = m_model->m_returnRoot->childCount() != 0;
|
bool showReturn = m_model->m_returnRoot->childCount() != 0;
|
||||||
Internal::updateLocalsWindow(showReturn);
|
m_engine->updateLocalsWindow(showReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList WatchHandler::watchedExpressions()
|
QStringList WatchHandler::watchedExpressions()
|
||||||
@@ -2382,6 +2390,11 @@ void WatchHandler::saveSessionData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::loadSessionData()
|
void WatchHandler::loadSessionData()
|
||||||
|
{
|
||||||
|
// Handled by loadSesseionDataForEngine.
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchHandler::loadSessionDataForEngine()
|
||||||
{
|
{
|
||||||
loadFormats();
|
loadFormats();
|
||||||
theWatcherNames.clear();
|
theWatcherNames.clear();
|
||||||
|
@@ -76,8 +76,10 @@ public:
|
|||||||
WatchItem *findItem(const QString &iname) const;
|
WatchItem *findItem(const QString &iname) const;
|
||||||
const WatchItem *findCppLocalVariable(const QString &name) const;
|
const WatchItem *findCppLocalVariable(const QString &name) const;
|
||||||
|
|
||||||
void loadSessionData();
|
void loadSessionDataForEngine();
|
||||||
void saveSessionData();
|
|
||||||
|
static void loadSessionData();
|
||||||
|
static void saveSessionData();
|
||||||
|
|
||||||
bool isExpandedIName(const QString &iname) const;
|
bool isExpandedIName(const QString &iname) const;
|
||||||
QSet<QString> expandedINames() const;
|
QSet<QString> expandedINames() const;
|
||||||
@@ -120,6 +122,7 @@ public:
|
|||||||
void recordTypeInfo(const GdbMi &typeInfo);
|
void recordTypeInfo(const GdbMi &typeInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
DebuggerEngine * const m_engine; // Not owned
|
||||||
WatchModel *m_model; // Owned.
|
WatchModel *m_model; // Owned.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -230,13 +230,13 @@ QmlProfilerTool::QmlProfilerTool()
|
|||||||
QObject::connect(d->m_startAction, &QAction::triggered, this, &QmlProfilerTool::profileStartupProject);
|
QObject::connect(d->m_startAction, &QAction::triggered, this, &QmlProfilerTool::profileStartupProject);
|
||||||
|
|
||||||
Utils::Perspective *perspective = d->m_viewContainer->perspective();
|
Utils::Perspective *perspective = d->m_viewContainer->perspective();
|
||||||
perspective->addToolbarAction(d->m_startAction);
|
perspective->addToolBarAction(d->m_startAction);
|
||||||
perspective->addToolbarAction(d->m_stopAction);
|
perspective->addToolBarAction(d->m_stopAction);
|
||||||
perspective->addToolbarWidget(d->m_recordButton);
|
perspective->addToolBarWidget(d->m_recordButton);
|
||||||
perspective->addToolbarWidget(d->m_clearButton);
|
perspective->addToolBarWidget(d->m_clearButton);
|
||||||
perspective->addToolbarWidget(d->m_searchButton);
|
perspective->addToolBarWidget(d->m_searchButton);
|
||||||
perspective->addToolbarWidget(d->m_displayFeaturesButton);
|
perspective->addToolBarWidget(d->m_displayFeaturesButton);
|
||||||
perspective->addToolbarWidget(d->m_timeLabel);
|
perspective->addToolBarWidget(d->m_timeLabel);
|
||||||
|
|
||||||
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
|
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
|
||||||
this, &QmlProfilerTool::updateRunActions);
|
this, &QmlProfilerTool::updateRunActions);
|
||||||
|
@@ -82,17 +82,17 @@ QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
|
|||||||
m_flameGraphView = new FlameGraphView(m_profilerModelManager);
|
m_flameGraphView = new FlameGraphView(m_profilerModelManager);
|
||||||
prepareEventsView(m_flameGraphView);
|
prepareEventsView(m_flameGraphView);
|
||||||
|
|
||||||
QWidget *anchor = nullptr;
|
QWidget *anchorDock = nullptr;
|
||||||
if (m_traceView->isUsable()) {
|
if (m_traceView->isUsable()) {
|
||||||
anchor = m_traceView;
|
anchorDock = m_traceView;
|
||||||
m_perspective->addWindow(m_traceView, Perspective::SplitVertical, nullptr);
|
m_perspective->addWindow(m_traceView, Perspective::SplitVertical, nullptr);
|
||||||
m_perspective->addWindow(m_flameGraphView, Perspective::AddToTab, anchor);
|
m_perspective->addWindow(m_flameGraphView, Perspective::AddToTab, m_traceView);
|
||||||
} else {
|
} else {
|
||||||
anchor = m_flameGraphView;
|
anchorDock = m_flameGraphView;
|
||||||
m_perspective->addWindow(m_flameGraphView, Perspective::SplitVertical, nullptr);
|
m_perspective->addWindow(m_flameGraphView, Perspective::SplitVertical, nullptr);
|
||||||
}
|
}
|
||||||
m_perspective->addWindow(m_statisticsView, Perspective::AddToTab, anchor);
|
m_perspective->addWindow(m_statisticsView, Perspective::AddToTab, anchorDock);
|
||||||
m_perspective->addWindow(anchor, Perspective::Raise, nullptr);
|
m_perspective->addWindow(anchorDock, Perspective::Raise, nullptr);
|
||||||
|
|
||||||
Debugger::registerPerspective(m_perspective);
|
Debugger::registerPerspective(m_perspective);
|
||||||
}
|
}
|
||||||
@@ -102,6 +102,7 @@ QmlProfilerViewManager::~QmlProfilerViewManager()
|
|||||||
delete m_traceView;
|
delete m_traceView;
|
||||||
delete m_flameGraphView;
|
delete m_flameGraphView;
|
||||||
delete m_statisticsView;
|
delete m_statisticsView;
|
||||||
|
delete m_perspective;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerViewManager::clear()
|
void QmlProfilerViewManager::clear()
|
||||||
|
@@ -420,17 +420,17 @@ CallgrindTool::CallgrindTool()
|
|||||||
updateEventCombo();
|
updateEventCombo();
|
||||||
|
|
||||||
auto perspective = new Perspective(CallgrindPerspectiveId, tr("Callgrind"));
|
auto perspective = new Perspective(CallgrindPerspectiveId, tr("Callgrind"));
|
||||||
perspective->addToolbarAction(m_startAction);
|
perspective->addToolBarAction(m_startAction);
|
||||||
perspective->addToolbarAction(m_stopAction);
|
perspective->addToolBarAction(m_stopAction);
|
||||||
perspective->addToolbarAction(m_loadExternalLogFile);
|
perspective->addToolBarAction(m_loadExternalLogFile);
|
||||||
perspective->addToolbarAction(m_dumpAction);
|
perspective->addToolBarAction(m_dumpAction);
|
||||||
perspective->addToolbarAction(m_resetAction);
|
perspective->addToolBarAction(m_resetAction);
|
||||||
perspective->addToolbarAction(m_pauseAction);
|
perspective->addToolBarAction(m_pauseAction);
|
||||||
perspective->addToolbarAction(m_discardAction);
|
perspective->addToolBarAction(m_discardAction);
|
||||||
perspective->addToolbarAction(m_goBack);
|
perspective->addToolBarAction(m_goBack);
|
||||||
perspective->addToolbarAction(m_goNext);
|
perspective->addToolBarAction(m_goNext);
|
||||||
perspective->addToolbarSeparator();
|
perspective->addToolbarSeparator();
|
||||||
perspective->addToolbarWidget(m_eventCombo);
|
perspective->addToolBarWidget(m_eventCombo);
|
||||||
|
|
||||||
// Cost formatting
|
// Cost formatting
|
||||||
{
|
{
|
||||||
@@ -463,7 +463,7 @@ CallgrindTool::CallgrindTool()
|
|||||||
button->setPopupMode(QToolButton::InstantPopup);
|
button->setPopupMode(QToolButton::InstantPopup);
|
||||||
button->setText(QLatin1String("$"));
|
button->setText(QLatin1String("$"));
|
||||||
button->setToolTip(tr("Cost Format"));
|
button->setToolTip(tr("Cost Format"));
|
||||||
perspective->addToolbarWidget(button);
|
perspective->addToolBarWidget(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings();
|
ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings();
|
||||||
@@ -500,10 +500,10 @@ CallgrindTool::CallgrindTool()
|
|||||||
setCostFormat(settings->costFormat());
|
setCostFormat(settings->costFormat());
|
||||||
enableCycleDetection(settings->detectCycles());
|
enableCycleDetection(settings->detectCycles());
|
||||||
|
|
||||||
perspective->addToolbarAction(m_cycleDetection);
|
perspective->addToolBarAction(m_cycleDetection);
|
||||||
perspective->addToolbarAction(m_shortenTemplates);
|
perspective->addToolBarAction(m_shortenTemplates);
|
||||||
perspective->addToolbarAction(m_filterProjectCosts);
|
perspective->addToolBarAction(m_filterProjectCosts);
|
||||||
perspective->addToolbarWidget(m_searchFilter);
|
perspective->addToolBarWidget(m_searchFilter);
|
||||||
|
|
||||||
perspective->addWindow(m_flatView, Perspective::SplitVertical, nullptr);
|
perspective->addWindow(m_flatView, Perspective::SplitVertical, nullptr);
|
||||||
perspective->addWindow(m_calleesView, Perspective::SplitVertical, nullptr);
|
perspective->addWindow(m_calleesView, Perspective::SplitVertical, nullptr);
|
||||||
|
@@ -683,13 +683,13 @@ MemcheckTool::MemcheckTool()
|
|||||||
ProjectExplorerPlugin::startRunControl(rc);
|
ProjectExplorerPlugin::startRunControl(rc);
|
||||||
});
|
});
|
||||||
|
|
||||||
perspective->addToolbarAction(m_startAction);
|
perspective->addToolBarAction(m_startAction);
|
||||||
//toolbar.addAction(m_startWithGdbAction);
|
//toolbar.addAction(m_startWithGdbAction);
|
||||||
perspective->addToolbarAction(m_stopAction);
|
perspective->addToolBarAction(m_stopAction);
|
||||||
perspective->addToolbarAction(m_loadExternalLogFile);
|
perspective->addToolBarAction(m_loadExternalLogFile);
|
||||||
perspective->addToolbarAction(m_goBack);
|
perspective->addToolBarAction(m_goBack);
|
||||||
perspective->addToolbarAction(m_goNext);
|
perspective->addToolBarAction(m_goNext);
|
||||||
perspective->addToolbarWidget(filterButton);
|
perspective->addToolBarWidget(filterButton);
|
||||||
Debugger::registerPerspective(perspective);
|
Debugger::registerPerspective(perspective);
|
||||||
|
|
||||||
updateFromSettings();
|
updateFromSettings();
|
||||||
|
Reference in New Issue
Block a user