Debugger/BinEditor: Standardize interface

Change-Id: I4acf6bc7648e57c564e86023176ae3905a293a99
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2016-07-14 10:00:15 +02:00
committed by hjk
parent 66142d94d2
commit 6e925910b4
26 changed files with 600 additions and 661 deletions

View File

@@ -3,6 +3,7 @@ include(../../qtcreatorplugin.pri)
DEFINES += BINEDITOR_LIBRARY DEFINES += BINEDITOR_LIBRARY
HEADERS += bineditorplugin.h \ HEADERS += bineditorplugin.h \
bineditorservice.h \
bineditorwidget.h \ bineditorwidget.h \
bineditorconstants.h \ bineditorconstants.h \
bineditor_global.h \ bineditor_global.h \

View File

@@ -11,12 +11,11 @@ QtcPlugin {
Depends { name: "TextEditor" } Depends { name: "TextEditor" }
files: [ files: [
"bineditorwidget.cpp",
"bineditorwidget.h",
"bineditorconstants.h",
"bineditor_global.h", "bineditor_global.h",
"bineditorplugin.cpp", "bineditorconstants.h",
"bineditorplugin.h", "bineditorwidget.cpp", "bineditorwidget.h",
"bineditorplugin.cpp", "bineditorplugin.h",
"bineditorservice.h",
"markup.cpp", "markup.cpp",
"markup.h", "markup.h",
] ]

View File

@@ -26,6 +26,7 @@
#include "bineditorplugin.h" #include "bineditorplugin.h"
#include "bineditorwidget.h" #include "bineditorwidget.h"
#include "bineditorconstants.h" #include "bineditorconstants.h"
#include "bineditorservice.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -59,30 +60,6 @@ using namespace Utils;
using namespace Core; using namespace Core;
namespace BinEditor { namespace BinEditor {
///////////////////////////////// BinEditorWidgetFactory //////////////////////////////////
/*!
\class BinEditor::BinEditorWidgetFactory
\brief The BinEditorWidgetFactory class offers a service registered with
PluginManager to create bin editor widgets for plugins
without direct linkage.
\sa ExtensionSystem::PluginManager::getObjectByClassName, ExtensionSystem::invoke
*/
class BinEditorWidgetFactory : public QObject
{
Q_OBJECT
public:
BinEditorWidgetFactory() {}
Q_INVOKABLE QWidget *createWidget(QWidget *parent)
{
return new BinEditorWidget(parent);
}
};
namespace Internal { namespace Internal {
class BinEditorFind : public IFindSupport class BinEditorFind : public IFindSupport
@@ -230,12 +207,10 @@ public:
setId(Core::Constants::K_DEFAULT_BINARY_EDITOR_ID); setId(Core::Constants::K_DEFAULT_BINARY_EDITOR_ID);
setMimeType(QLatin1String(BinEditor::Constants::C_BINEDITOR_MIMETYPE)); setMimeType(QLatin1String(BinEditor::Constants::C_BINEDITOR_MIMETYPE));
m_widget = parent; m_widget = parent;
connect(m_widget, &BinEditorWidget::dataRequested, EditorService *es = m_widget->editorService();
this, &BinEditorDocument::provideData); es->setFetchDataHandler([this](quint64 address) { provideData(address); });
connect(m_widget, &BinEditorWidget::newRangeRequested, es->setNewRangeRequestHandler([this](quint64 offset) { provideNewRange(offset); });
this, &BinEditorDocument::provideNewRange); es->setDataChangedHandler([this](quint64, const QByteArray &) { contentsChanged(); });
connect(m_widget, &BinEditorWidget::dataChanged,
this, &IDocument::contentsChanged);
} }
QByteArray contents() const override QByteArray contents() const override
@@ -316,7 +291,7 @@ public:
return OpenResult::ReadError; return OpenResult::ReadError;
} }
void provideData(quint64 block) void provideData(quint64 address)
{ {
const FileName fn = filePath(); const FileName fn = filePath();
if (fn.isEmpty()) if (fn.isEmpty())
@@ -324,13 +299,13 @@ public:
QFile file(fn.toString()); QFile file(fn.toString());
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::ReadOnly)) {
int blockSize = m_widget->dataBlockSize(); int blockSize = m_widget->dataBlockSize();
file.seek(block * blockSize); file.seek(address);
QByteArray data = file.read(blockSize); QByteArray data = file.read(blockSize);
file.close(); file.close();
const int dataSize = data.size(); const int dataSize = data.size();
if (dataSize != blockSize) if (dataSize != blockSize)
data += QByteArray(blockSize - dataSize, 0); data += QByteArray(blockSize - dataSize, 0);
m_widget->addData(block, data); m_widget->addData(address, data);
} else { } else {
QMessageBox::critical(ICore::mainWindow(), tr("File Error"), QMessageBox::critical(ICore::mainWindow(), tr("File Error"),
tr("Cannot open %1: %2").arg( tr("Cannot open %1: %2").arg(
@@ -470,12 +445,30 @@ IEditor *BinEditorFactory::createEditor()
return editor; return editor;
} }
///////////////////////////////// BinEditor Services //////////////////////////////////
EditorService *FactoryServiceImpl::createEditorService(const QString &title0, bool wantsEditor)
{
BinEditorWidget *widget = nullptr;
if (wantsEditor) {
QString title = title0;
IEditor *editor = EditorManager::openEditorWithContents(
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID, &title);
if (!editor)
return 0;
widget = qobject_cast<BinEditorWidget *>(editor->widget());
widget->setEditor(editor);
} else {
widget = new BinEditorWidget;
widget->setWindowTitle(title0);
}
return widget->editorService();
}
///////////////////////////////// BinEditorPlugin ////////////////////////////////// ///////////////////////////////// BinEditorPlugin //////////////////////////////////
BinEditorPlugin::BinEditorPlugin() BinEditorPlugin::BinEditorPlugin()
{ {
m_undoAction = m_redoAction = m_copyAction = m_selectAllAction = 0;
} }
BinEditorPlugin::~BinEditorPlugin() BinEditorPlugin::~BinEditorPlugin()
@@ -522,8 +515,8 @@ bool BinEditorPlugin::initialize(const QStringList &arguments, QString *errorMes
connect(Core::EditorManager::instance(), &EditorManager::currentEditorChanged, connect(Core::EditorManager::instance(), &EditorManager::currentEditorChanged,
this, &BinEditorPlugin::updateCurrentEditor); this, &BinEditorPlugin::updateCurrentEditor);
addAutoReleasedObject(new FactoryServiceImpl);
addAutoReleasedObject(new BinEditorFactory(this)); addAutoReleasedObject(new BinEditorFactory(this));
addAutoReleasedObject(new BinEditorWidgetFactory);
return true; return true;
} }

View File

@@ -25,6 +25,8 @@
#pragma once #pragma once
#include "bineditorservice.h"
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include <coreplugin/editormanager/ieditorfactory.h> #include <coreplugin/editormanager/ieditorfactory.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
@@ -34,9 +36,9 @@
#include <QAction> #include <QAction>
namespace BinEditor { namespace BinEditor {
class BinEditorWidget;
namespace Internal { namespace Internal {
class BinEditorWidget;
class BinEditorFactory; class BinEditorFactory;
class BinEditorPlugin : public ExtensionSystem::IPlugin class BinEditorPlugin : public ExtensionSystem::IPlugin
@@ -65,10 +67,10 @@ private:
Core::Context m_context; Core::Context m_context;
QAction *registerNewAction(Core::Id id, const QString &title = QString()); QAction *registerNewAction(Core::Id id, const QString &title = QString());
QAction *m_undoAction; QAction *m_undoAction = nullptr;
QAction *m_redoAction; QAction *m_redoAction = nullptr;
QAction *m_copyAction; QAction *m_copyAction = nullptr;
QAction *m_selectAllAction; QAction *m_selectAllAction = nullptr;
QPointer<BinEditorWidget> m_currentEditor; QPointer<BinEditorWidget> m_currentEditor;
}; };
@@ -86,5 +88,14 @@ private:
BinEditorPlugin *m_owner; BinEditorPlugin *m_owner;
}; };
class FactoryServiceImpl : public QObject, public FactoryService
{
Q_OBJECT
Q_INTERFACES(BinEditor::FactoryService)
public:
EditorService *createEditorService(const QString &title0, bool wantsEditor) override;
};
} // namespace Internal } // namespace Internal
} // namespace BinEditor } // namespace BinEditor

View File

@@ -0,0 +1,85 @@
/****************************************************************************
**
** 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 "bineditor_global.h"
#include <QColor>
#include <QObject>
#include <QString>
#include <functional>
namespace Core { class IEditor; }
namespace BinEditor {
class EditorService
{
public:
virtual ~EditorService() {}
virtual QWidget *widget() = 0;
virtual Core::IEditor *editor() = 0;
// "Slots"
virtual void setSizes(quint64 address, qint64 range, int blockSize) = 0;
virtual void setReadOnly(bool on) = 0;
virtual void setFinished() = 0;
virtual void setNewWindowRequestAllowed(bool on) = 0;
virtual void setCursorPosition(qint64 pos) = 0;
virtual void updateContents() = 0;
virtual void addData(quint64 address, const QByteArray &data) = 0;
virtual void clearMarkup() = 0;
virtual void addMarkup(quint64 address, quint64 len, const QColor &color, const QString &toolTip) = 0;
virtual void commitMarkup() = 0;
// "Signals"
virtual void setFetchDataHandler(const std::function<void(quint64 block)> &) = 0;
virtual void setNewWindowRequestHandler(const std::function<void(quint64 address)> &) = 0;
virtual void setNewRangeRequestHandler(const std::function<void(quint64 address)> &) = 0;
virtual void setDataChangedHandler(const std::function<void(quint64 address, const QByteArray &)> &) = 0;
virtual void setWatchPointRequestHandler(const std::function<void(quint64 address, uint size)> &) = 0;
virtual void setAboutToBeDestroyedHandler(const std::function<void()> &) = 0;
};
class FactoryService
{
public:
virtual ~FactoryService() {}
// Create a BinEditor widget. Embed into a Core::IEditor iff wantsEditor == true.
virtual EditorService *createEditorService(const QString &title, bool wantsEditor) = 0;
};
} // namespace BinEditor
#define BinEditor_FactoryService_iid "org.qt-project.Qt.Creator.BinEditor.EditorService"
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(BinEditor::FactoryService, BinEditor_FactoryService_iid)
QT_END_NAMESPACE

View File

@@ -24,11 +24,17 @@
****************************************************************************/ ****************************************************************************/
#include "bineditorwidget.h" #include "bineditorwidget.h"
#include "bineditorservice.h"
#include "markup.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <texteditor/fontsettings.h> #include <texteditor/fontsettings.h>
#include <texteditor/texteditorconstants.h> #include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -51,6 +57,8 @@
#include <QToolTip> #include <QToolTip>
#include <QWheelEvent> #include <QWheelEvent>
using namespace Core;
static QByteArray calculateHexPattern(const QByteArray &pattern) static QByteArray calculateHexPattern(const QByteArray &pattern)
{ {
QByteArray result; QByteArray result;
@@ -69,9 +77,65 @@ static QByteArray calculateHexPattern(const QByteArray &pattern)
} }
namespace BinEditor { namespace BinEditor {
namespace Internal {
class BinEditorWidgetPrivate : public EditorService
{
public:
BinEditorWidgetPrivate(BinEditorWidget *widget) : q(widget) {}
~BinEditorWidgetPrivate() override { if (m_aboutToBeDestroyedHandler) m_aboutToBeDestroyedHandler(); }
QWidget *widget() override { return q; }
IEditor *editor() override { return q->editor(); }
void setReadOnly(bool on) override { q->setReadOnly(on); }
void setNewWindowRequestAllowed(bool on) override { q->setNewWindowRequestAllowed(on); }
void setFinished() override
{
q->setReadOnly(true);
m_fetchDataHandler = {};
m_newWindowRequestHandler = {};
m_newRangeRequestHandler = {};
m_dataChangedHandler = {};
m_watchPointRequestHandler = {};
}
void setSizes(quint64 address, qint64 range, int blockSize) override { q->setSizes(address, range, blockSize); }
void setCursorPosition(qint64 pos) override { q->setCursorPosition(pos); }
void updateContents() override { q->updateContents(); }
void addData(quint64 address, const QByteArray &data) override { q->addData(address, data); }
void clearMarkup() override { m_markup.clear(); }
void addMarkup(quint64 a, quint64 l, const QColor &c, const QString &t) override { m_markup.append(Markup(a, l, c, t)); }
void commitMarkup() override { q->setMarkup(m_markup); }
void setFetchDataHandler(const std::function<void(quint64)> &cb) override { m_fetchDataHandler = cb; }
void setNewWindowRequestHandler(const std::function<void(quint64)> &cb) { m_newWindowRequestHandler = cb; }
void setNewRangeRequestHandler(const std::function<void(quint64)> &cb) { m_newRangeRequestHandler = cb; }
void setDataChangedHandler(const std::function<void(quint64, const QByteArray &)> &cb) { m_dataChangedHandler = cb; }
void setWatchPointRequestHandler(const std::function<void(quint64, uint)> &cb) { m_watchPointRequestHandler = cb; }
void setAboutToBeDestroyedHandler(const std::function<void()> & cb) { m_aboutToBeDestroyedHandler = cb; }
void fetchData(quint64 address) { if (m_fetchDataHandler) m_fetchDataHandler(address); }
void requestNewWindow(quint64 address) { if (m_newWindowRequestHandler) m_newWindowRequestHandler(address); }
void requestWatchPoint(quint64 address, int size) { if (m_watchPointRequestHandler) m_watchPointRequestHandler(address, size); }
void requestNewRange(quint64 address) { if (m_newRangeRequestHandler) m_newRangeRequestHandler(address); }
void announceChangedData(quint64 address, const QByteArray &ba) { if (m_dataChangedHandler) m_dataChangedHandler(address, ba); }
private:
BinEditorWidget *q;
std::function<void(quint64)> m_fetchDataHandler;
std::function<void(quint64)> m_newWindowRequestHandler;
std::function<void(quint64)> m_newRangeRequestHandler;
std::function<void(quint64, const QByteArray &)> m_dataChangedHandler;
std::function<void(quint64, uint)> m_watchPointRequestHandler;
std::function<void()> m_aboutToBeDestroyedHandler;
QList<Markup> m_markup;
};
BinEditorWidget::BinEditorWidget(QWidget *parent) BinEditorWidget::BinEditorWidget(QWidget *parent)
: QAbstractScrollArea(parent) : QAbstractScrollArea(parent), d(new BinEditorWidgetPrivate(this))
{ {
m_bytesPerLine = 16; m_bytesPerLine = 16;
m_ieditor = 0; m_ieditor = 0;
@@ -102,6 +166,12 @@ BinEditorWidget::BinEditorWidget(QWidget *parent)
BinEditorWidget::~BinEditorWidget() BinEditorWidget::~BinEditorWidget()
{ {
delete d;
}
EditorService *BinEditorWidget::editorService() const
{
return d;
} }
void BinEditorWidget::init() void BinEditorWidget::init()
@@ -153,10 +223,9 @@ void BinEditorWidget::init()
} }
void BinEditorWidget::addData(quint64 block, const QByteArray &data) void BinEditorWidget::addData(quint64 addr, const QByteArray &data)
{ {
QTC_ASSERT(data.size() == m_blockSize, return); QTC_ASSERT(data.size() == m_blockSize, return);
const quint64 addr = block * m_blockSize;
if (addr >= m_baseAddr && addr <= m_baseAddr + m_size - 1) { if (addr >= m_baseAddr && addr <= m_baseAddr + m_size - 1) {
if (m_data.size() * m_blockSize >= 64 * 1024 * 1024) if (m_data.size() * m_blockSize >= 64 * 1024 * 1024)
m_data.clear(); m_data.clear();
@@ -176,13 +245,11 @@ bool BinEditorWidget::requestDataAt(qint64 pos) const
it = m_data.find(block); it = m_data.find(block);
if (it != m_data.end()) if (it != m_data.end())
return true; return true;
if (!m_requests.contains(block)) { if (m_requests.contains(block))
m_requests.insert(block);
emit const_cast<BinEditorWidget*>(this)->
dataRequested(m_baseAddr / m_blockSize + block);
return true;
}
return false; return false;
m_requests.insert(block);
d->fetchData((m_baseAddr / m_blockSize + block) * m_blockSize);
return true;
} }
bool BinEditorWidget::requestOldDataAt(qint64 pos) const bool BinEditorWidget::requestOldDataAt(qint64 pos) const
@@ -215,7 +282,7 @@ void BinEditorWidget::changeDataAt(qint64 pos, char c)
} }
} }
emit dataChanged(m_baseAddr + pos, QByteArray(1, c)); d->announceChangedData(m_baseAddr + pos, QByteArray(1, c));
} }
QByteArray BinEditorWidget::dataMid(qint64 from, int length, bool old) const QByteArray BinEditorWidget::dataMid(qint64 from, int length, bool old) const
@@ -429,9 +496,9 @@ void BinEditorWidget::scrollContentsBy(int dx, int dy)
const QScrollBar * const scrollBar = verticalScrollBar(); const QScrollBar * const scrollBar = verticalScrollBar();
const int scrollPos = scrollBar->value(); const int scrollPos = scrollBar->value();
if (dy <= 0 && scrollPos == scrollBar->maximum()) if (dy <= 0 && scrollPos == scrollBar->maximum())
emit newRangeRequested(baseAddress() + m_size); d->requestNewRange(baseAddress() + m_size);
else if (dy >= 0 && scrollPos == scrollBar->minimum()) else if (dy >= 0 && scrollPos == scrollBar->minimum())
emit newRangeRequested(baseAddress()); d->requestNewRange(baseAddress());
} }
void BinEditorWidget::changeEvent(QEvent *e) void BinEditorWidget::changeEvent(QEvent *e)
@@ -1044,7 +1111,7 @@ bool BinEditorWidget::event(QEvent *e)
const QScrollBar * const scrollBar = verticalScrollBar(); const QScrollBar * const scrollBar = verticalScrollBar();
const int maximum = scrollBar->maximum(); const int maximum = scrollBar->maximum();
if (maximum && scrollBar->value() >= maximum - 1) { if (maximum && scrollBar->value() >= maximum - 1) {
emit newRangeRequested(baseAddress() + m_size); d->requestNewRange(baseAddress() + m_size);
return true; return true;
} }
break; break;
@@ -1531,11 +1598,11 @@ void BinEditorWidget::contextMenuEvent(QContextMenuEvent *event)
else if (action == jumpToLeAddressHereAction) else if (action == jumpToLeAddressHereAction)
jumpToAddress(leAddress); jumpToAddress(leAddress);
else if (action == jumpToBeAddressNewWindowAction) else if (action == jumpToBeAddressNewWindowAction)
emit newWindowRequested(beAddress); d->requestNewWindow(beAddress);
else if (action == jumpToLeAddressNewWindowAction) else if (action == jumpToLeAddressNewWindowAction)
emit newWindowRequested(leAddress); d->requestNewWindow(leAddress);
else if (action == addWatchpointAction) else if (action == addWatchpointAction)
emit addWatchpointRequested(m_baseAddr + selStart, byteCount); d->requestWatchPoint(m_baseAddr + selStart, byteCount);
delete contextMenu; delete contextMenu;
} }
@@ -1557,7 +1624,7 @@ void BinEditorWidget::jumpToAddress(quint64 address)
if (address >= m_baseAddr && address < m_baseAddr + m_size) if (address >= m_baseAddr && address < m_baseAddr + m_size)
setCursorPosition(address - m_baseAddr); setCursorPosition(address - m_baseAddr);
else else
emit newRangeRequested(address); d->requestNewRange(address);
} }
void BinEditorWidget::setNewWindowRequestAllowed(bool c) void BinEditorWidget::setNewWindowRequestAllowed(bool c)
@@ -1614,4 +1681,5 @@ void BinEditorWidget::setMarkup(const QList<Markup> &markup)
viewport()->update(); viewport()->update();
} }
} // namespace Internal
} // namespace BinEditor } // namespace BinEditor

View File

@@ -27,6 +27,7 @@
#include "bineditor_global.h" #include "bineditor_global.h"
#include "markup.h" #include "markup.h"
#include "bineditorservice.h"
#include <QBasicTimer> #include <QBasicTimer>
#include <QMap> #include <QMap>
@@ -46,8 +47,11 @@ namespace Core { class IEditor; }
namespace TextEditor { class FontSettings; } namespace TextEditor { class FontSettings; }
namespace BinEditor { namespace BinEditor {
namespace Internal {
class BINEDITOR_EXPORT BinEditorWidget : public QAbstractScrollArea class BinEditorWidgetPrivate;
class BinEditorWidget : public QAbstractScrollArea
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool modified READ isModified WRITE setModified DESIGNABLE false) Q_PROPERTY(bool modified READ isModified WRITE setModified DESIGNABLE false)
@@ -59,17 +63,19 @@ public:
BinEditorWidget(QWidget *parent = 0); BinEditorWidget(QWidget *parent = 0);
~BinEditorWidget(); ~BinEditorWidget();
EditorService *editorService() const;
quint64 baseAddress() const { return m_baseAddr; } quint64 baseAddress() const { return m_baseAddr; }
Q_INVOKABLE void setSizes(quint64 startAddr, qint64 range, int blockSize = 4096); void setSizes(quint64 startAddr, qint64 range, int blockSize = 4096);
int dataBlockSize() const { return m_blockSize; } int dataBlockSize() const { return m_blockSize; }
QByteArray contents() const { return dataMid(0, m_size); } QByteArray contents() const { return dataMid(0, m_size); }
Q_INVOKABLE void addData(quint64 block, const QByteArray &data); void addData(quint64 addr, const QByteArray &data);
bool newWindowRequestAllowed() const { return m_canRequestNewWindow; } bool newWindowRequestAllowed() const { return m_canRequestNewWindow; }
Q_INVOKABLE void updateContents(); void updateContents();
bool save(QString *errorString, const QString &oldFileName, const QString &newFileName); bool save(QString *errorString, const QString &oldFileName, const QString &newFileName);
void zoomIn(int range = 1); void zoomIn(int range = 1);
@@ -81,7 +87,7 @@ public:
}; };
qint64 cursorPosition() const; qint64 cursorPosition() const;
Q_INVOKABLE void setCursorPosition(qint64 pos, MoveMode moveMode = MoveAnchor); void setCursorPosition(qint64 pos, MoveMode moveMode = MoveAnchor);
void jumpToAddress(quint64 address); void jumpToAddress(quint64 address);
void setModified(bool); void setModified(bool);
@@ -123,19 +129,13 @@ public:
void setMarkup(const QList<Markup> &markup); void setMarkup(const QList<Markup> &markup);
void setNewWindowRequestAllowed(bool c); void setNewWindowRequestAllowed(bool c);
Q_SIGNALS: signals:
void modificationChanged(bool modified); void modificationChanged(bool modified);
void undoAvailable(bool); void undoAvailable(bool);
void redoAvailable(bool); void redoAvailable(bool);
void cursorPositionChanged(int position); void cursorPositionChanged(int position);
void dataRequested(quint64 block); private:
void newWindowRequested(quint64 address);
void newRangeRequested(quint64 address);
void addWatchpointRequested(quint64 address, uint size);
void dataChanged(quint64 address, const QByteArray &data);
protected:
void scrollContentsBy(int dx, int dy); void scrollContentsBy(int dx, int dy);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *); void resizeEvent(QResizeEvent *);
@@ -150,7 +150,9 @@ protected:
void timerEvent(QTimerEvent *); void timerEvent(QTimerEvent *);
void contextMenuEvent(QContextMenuEvent *event); void contextMenuEvent(QContextMenuEvent *event);
private: friend class BinEditorWidgetPrivate;
BinEditorWidgetPrivate *d;
typedef QMap<qint64, QByteArray> BlockMap; typedef QMap<qint64, QByteArray> BlockMap;
BlockMap m_data; BlockMap m_data;
BlockMap m_oldData; BlockMap m_oldData;
@@ -242,4 +244,5 @@ private:
QList<Markup> m_markup; QList<Markup> m_markup;
}; };
} // namespace Internal
} // namespace BinEditor } // namespace BinEditor

View File

@@ -151,13 +151,11 @@ static const char localsPrefixC[] = "local.";
struct MemoryViewCookie struct MemoryViewCookie
{ {
explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0, explicit MemoryViewCookie(MemoryAgent *a = 0, quint64 addr = 0, quint64 l = 0)
quint64 addr = 0, quint64 l = 0) : : agent(a), address(addr), length(l)
agent(a), editorToken(e), address(addr), length(l)
{} {}
MemoryAgent *agent; MemoryAgent *agent;
QObject *editorToken;
quint64 address; quint64 address;
quint64 length; quint64 length;
}; };
@@ -1499,11 +1497,11 @@ void CdbEngine::handleResolveSymbolHelper(const QList<quint64> &addresses, Disas
} }
} }
void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length) void CdbEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
{ {
if (debug) if (debug)
qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr); qDebug("CdbEngine::fetchMemory %llu bytes from 0x%llx", length, addr);
const MemoryViewCookie cookie(agent, editor, addr, length); const MemoryViewCookie cookie(agent, addr, length);
if (m_accessible) if (m_accessible)
postFetchMemory(cookie); postFetchMemory(cookie);
else else
@@ -1521,7 +1519,7 @@ void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie)
if (response.resultClass == ResultDone && cookie.agent) { if (response.resultClass == ResultDone && cookie.agent) {
const QByteArray data = QByteArray::fromHex(response.data.data().toUtf8()); const QByteArray data = QByteArray::fromHex(response.data.data().toUtf8());
if (unsigned(data.size()) == cookie.length) if (unsigned(data.size()) == cookie.length)
cookie.agent->addLazyData(cookie.editorToken, cookie.address, data); cookie.agent->addData(cookie.address, data);
} else { } else {
showMessage(response.data["msg"].data(), LogWarning); showMessage(response.data["msg"].data(), LogWarning);
} }
@@ -1529,7 +1527,7 @@ void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie)
runCommand(cmd); runCommand(cmd);
} }
void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data) void CdbEngine::changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data)
{ {
QTC_ASSERT(!data.isEmpty(), return); QTC_ASSERT(!data.isEmpty(), return);
if (!m_accessible) { if (!m_accessible) {

View File

@@ -99,9 +99,8 @@ public:
void attemptBreakpointSynchronization() override; void attemptBreakpointSynchronization() override;
void fetchDisassembler(DisassemblerAgent *agent) override; void fetchDisassembler(DisassemblerAgent *agent) override;
void fetchMemory(MemoryAgent *, QObject *, quint64 addr, quint64 length) override; void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, void changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data) override;
const QByteArray &data) override;
void reloadModules() override; void reloadModules() override;
void loadSymbols(const QString &moduleName) override; void loadSymbols(const QString &moduleName) override;

View File

@@ -59,7 +59,6 @@ HEADERS += \
watchdelegatewidgets.h \ watchdelegatewidgets.h \
debuggertooltipmanager.h \ debuggertooltipmanager.h \
debuggersourcepathmappingwidget.h \ debuggersourcepathmappingwidget.h \
memoryview.h \
localsandexpressionswindow.h \ localsandexpressionswindow.h \
imageviewer.h \ imageviewer.h \
simplifytype.h \ simplifytype.h \
@@ -109,7 +108,6 @@ SOURCES += \
watchdelegatewidgets.cpp \ watchdelegatewidgets.cpp \
debuggertooltipmanager.cpp \ debuggertooltipmanager.cpp \
debuggersourcepathmappingwidget.cpp \ debuggersourcepathmappingwidget.cpp \
memoryview.cpp \
localsandexpressionswindow.cpp \ localsandexpressionswindow.cpp \
imageviewer.cpp \ imageviewer.cpp \
simplifytype.cpp \ simplifytype.cpp \

View File

@@ -35,7 +35,8 @@ Project {
cpp.enableExceptions: true cpp.enableExceptions: true
pluginRecommends: [ pluginRecommends: [
"CppEditor" "CppEditor",
"BinEditor"
] ]
Group { Group {
@@ -73,7 +74,6 @@ Project {
"localsandexpressionswindow.cpp", "localsandexpressionswindow.h", "localsandexpressionswindow.cpp", "localsandexpressionswindow.h",
"logwindow.cpp", "logwindow.h", "logwindow.cpp", "logwindow.h",
"memoryagent.cpp", "memoryagent.h", "memoryagent.cpp", "memoryagent.h",
"memoryview.cpp", "memoryview.h",
"moduleshandler.cpp", "moduleshandler.h", "moduleshandler.cpp", "moduleshandler.h",
"outputcollector.cpp", "outputcollector.h", "outputcollector.cpp", "outputcollector.h",
"procinterrupt.cpp", "procinterrupt.h", "procinterrupt.cpp", "procinterrupt.h",

View File

@@ -15,7 +15,8 @@ QTC_PLUGIN_DEPENDS += \
qtsupport \ qtsupport \
texteditor texteditor
QTC_PLUGIN_RECOMMENDS += \ QTC_PLUGIN_RECOMMENDS += \
cppeditor cppeditor \
bineditor
QTC_TEST_DEPENDS += \ QTC_TEST_DEPENDS += \
qmakeprojectmanager qmakeprojectmanager

View File

@@ -152,6 +152,59 @@ void LocationMark::dragToLine(int line)
} }
} }
//////////////////////////////////////////////////////////////////////
//
// MemoryAgentSet
//
//////////////////////////////////////////////////////////////////////
class MemoryAgentSet
{
public:
~MemoryAgentSet()
{
qDeleteAll(m_agents);
m_agents.clear();
}
// Called by engine to create a new view.
void createBinEditor(const MemoryViewSetupData &data, DebuggerEngine *engine)
{
auto agent = new MemoryAgent(data, engine);
if (agent->isUsable()) {
m_agents.append(agent);
} else {
delete agent;
AsynchronousMessageBox::warning(
DebuggerEngine::tr("No Memory Viewer Available"),
DebuggerEngine::tr("The memory contents cannot be shown as no viewer plugin "
"for binary data has been loaded."));
}
}
// On stack frame completed and on request.
void updateContents()
{
foreach (MemoryAgent *agent, m_agents) {
if (agent)
agent->updateContents();
}
}
void handleDebuggerFinished()
{
foreach (MemoryAgent *agent, m_agents) {
if (agent)
agent->setFinished(); // Prevent triggering updates, etc.
}
}
private:
QList<MemoryAgent *> m_agents;
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// //
// DebuggerEnginePrivate // DebuggerEnginePrivate
@@ -182,7 +235,7 @@ public:
m_threadsHandler(engine), m_threadsHandler(engine),
m_watchHandler(engine), m_watchHandler(engine),
m_disassemblerAgent(engine), m_disassemblerAgent(engine),
m_memoryAgent(engine) m_isStateDebugging(false)
{ {
connect(&m_locationTimer, &QTimer::timeout, connect(&m_locationTimer, &QTimer::timeout,
this, &DebuggerEnginePrivate::resetLocation); this, &DebuggerEnginePrivate::resetLocation);
@@ -320,7 +373,7 @@ public:
QFutureInterface<void> m_progress; QFutureInterface<void> m_progress;
DisassemblerAgent m_disassemblerAgent; DisassemblerAgent m_disassemblerAgent;
MemoryAgent m_memoryAgent; MemoryAgentSet m_memoryAgents;
QScopedPointer<LocationMark> m_locationMark; QScopedPointer<LocationMark> m_locationMark;
QTimer m_locationTimer; QTimer m_locationTimer;
@@ -480,15 +533,13 @@ QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
return sourceFilesHandler()->model(); return sourceFilesHandler()->model();
} }
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *, void DebuggerEngine::fetchMemory(MemoryAgent *, quint64 addr, quint64 length)
quint64 addr, quint64 length)
{ {
Q_UNUSED(addr); Q_UNUSED(addr);
Q_UNUSED(length); Q_UNUSED(length);
} }
void DebuggerEngine::changeMemory(MemoryAgent *, QObject *, void DebuggerEngine::changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data)
quint64 addr, const QByteArray &data)
{ {
Q_UNUSED(addr); Q_UNUSED(addr);
Q_UNUSED(data); Q_UNUSED(data);
@@ -618,8 +669,6 @@ void DebuggerEngine::gotoLocation(const Location &loc)
if (loc.needsMarker()) if (loc.needsMarker())
d->m_locationMark.reset(new LocationMark(this, file, line)); d->m_locationMark.reset(new LocationMark(this, file, line));
//qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
} }
// Called from RunControl. // Called from RunControl.
@@ -1270,7 +1319,7 @@ void DebuggerEngine::setState(DebuggerState state, bool forced)
foreach (Breakpoint bp, breakHandler()->engineBreakpoints(this)) foreach (Breakpoint bp, breakHandler()->engineBreakpoints(this))
bp.notifyBreakpointReleased(); bp.notifyBreakpointReleased();
DebuggerToolTipManager::deregisterEngine(this); DebuggerToolTipManager::deregisterEngine(this);
d->m_memoryAgent.handleDebuggerFinished(); d->m_memoryAgents.handleDebuggerFinished();
prepareForRestart(); prepareForRestart();
} }
@@ -1798,12 +1847,12 @@ void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description
void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data) void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data)
{ {
d->m_memoryAgent.createBinEditor(data); d->m_memoryAgents.createBinEditor(data, this);
} }
void DebuggerEngine::updateMemoryViews() void DebuggerEngine::updateMemoryViews()
{ {
d->m_memoryAgent.updateContents(); d->m_memoryAgents.updateContents();
} }
void DebuggerEngine::openDisassemblerView(const Location &location) void DebuggerEngine::openDisassemblerView(const Location &location)
@@ -2005,7 +2054,7 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
const bool partial = all["partial"].toInt(); const bool partial = all["partial"].toInt();
if (!partial) if (!partial)
emit stackFrameCompleted(); updateMemoryViews();
} }
bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) const bool DebuggerEngine::canHandleToolTip(const DebuggerToolTipContext &context) const

View File

@@ -217,10 +217,8 @@ public:
virtual void runCommand(const DebuggerCommand &cmd); virtual void runCommand(const DebuggerCommand &cmd);
virtual void openMemoryView(const MemoryViewSetupData &data); virtual void openMemoryView(const MemoryViewSetupData &data);
virtual void fetchMemory(Internal::MemoryAgent *, QObject *, virtual void fetchMemory(MemoryAgent *, quint64 addr, quint64 length);
quint64 addr, quint64 length); virtual void changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data);
virtual void changeMemory(Internal::MemoryAgent *, QObject *,
quint64 addr, const QByteArray &data);
virtual void updateMemoryViews(); virtual void updateMemoryViews();
virtual void openDisassemblerView(const Internal::Location &location); virtual void openDisassemblerView(const Internal::Location &location);
virtual void fetchDisassembler(Internal::DisassemblerAgent *); virtual void fetchDisassembler(Internal::DisassemblerAgent *);
@@ -328,8 +326,6 @@ public:
signals: signals:
void stateChanged(Debugger::DebuggerState state); void stateChanged(Debugger::DebuggerState state);
// A new stack frame is on display including locals.
void stackFrameCompleted();
/* /*
* For "external" clients of a debugger run control that needs to do * For "external" clients of a debugger run control that needs to do
* further setup before the debugger is started (e.g. RemoteLinux). * further setup before the debugger is started (e.g. RemoteLinux).

View File

@@ -3710,39 +3710,34 @@ void GdbEngine::handleWatchPoint(const DebuggerResponse &response)
class MemoryAgentCookie class MemoryAgentCookie
{ {
public: public:
MemoryAgentCookie() MemoryAgentCookie() {}
: accumulator(0), pendingRequests(0), agent(0), token(0), base(0), offset(0), length(0)
{}
public: QByteArray *accumulator = nullptr; // Shared between split request. Last one cleans up.
QByteArray *accumulator; // Shared between split request. Last one cleans up. uint *pendingRequests = nullptr; // Shared between split request. Last one cleans up.
uint *pendingRequests; // Shared between split request. Last one cleans up.
QPointer<MemoryAgent> agent; QPointer<MemoryAgent> agent;
QPointer<QObject> token; quint64 base = 0; // base address.
quint64 base; // base address. uint offset = 0; // offset to base, and in accumulator
uint offset; // offset to base, and in accumulator uint length = 0; //
uint length; //
}; };
void GdbEngine::changeMemory(MemoryAgent *, QObject *, void GdbEngine::changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data)
quint64 addr, const QByteArray &data)
{ {
Q_UNUSED(agent)
DebuggerCommand cmd("-data-write-memory 0x" + QString::number(addr, 16) + " d 1", NeedsStop); DebuggerCommand cmd("-data-write-memory 0x" + QString::number(addr, 16) + " d 1", NeedsStop);
foreach (unsigned char c, data) foreach (unsigned char c, data)
cmd.function += ' ' + QString::number(uint(c)); cmd.function += ' ' + QString::number(uint(c));
cmd.callback = CB(handleVarAssign);
runCommand(cmd); runCommand(cmd);
} }
void GdbEngine::fetchMemory(MemoryAgent *agent, QObject *token, quint64 addr, void GdbEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
quint64 length)
{ {
MemoryAgentCookie ac; MemoryAgentCookie ac;
ac.accumulator = new QByteArray(length, char()); ac.accumulator = new QByteArray(length, char());
ac.pendingRequests = new uint(1); ac.pendingRequests = new uint(1);
ac.agent = agent; ac.agent = agent;
ac.token = token;
ac.base = addr; ac.base = addr;
ac.length = length; ac.length = length;
fetchMemoryHelper(ac); fetchMemoryHelper(ac);
@@ -3800,7 +3795,7 @@ void GdbEngine::handleFetchMemory(const DebuggerResponse &response, MemoryAgentC
} }
if (*ac.pendingRequests <= 0) { if (*ac.pendingRequests <= 0) {
ac.agent->addLazyData(ac.token, ac.base, *ac.accumulator); ac.agent->addData(ac.base, *ac.accumulator);
delete ac.pendingRequests; delete ac.pendingRequests;
delete ac.accumulator; delete ac.accumulator;
} }

View File

@@ -370,12 +370,10 @@ protected:
virtual void assignValueInDebugger(WatchItem *item, virtual void assignValueInDebugger(WatchItem *item,
const QString &expr, const QVariant &value) override; const QString &expr, const QVariant &value) override;
virtual void fetchMemory(MemoryAgent *agent, QObject *token, void fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length) override;
quint64 addr, quint64 length) override;
void fetchMemoryHelper(const MemoryAgentCookie &cookie); void fetchMemoryHelper(const MemoryAgentCookie &cookie);
void handleChangeMemory(const DebuggerResponse &response); void handleChangeMemory(const DebuggerResponse &response);
virtual void changeMemory(MemoryAgent *agent, QObject *token, void changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data) override;
quint64 addr, const QByteArray &data) override;
void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac); void handleFetchMemory(const DebuggerResponse &response, MemoryAgentCookie ac);
virtual void watchPoint(const QPoint &) override; virtual void watchPoint(const QPoint &) override;

View File

@@ -1054,45 +1054,26 @@ void LldbEngine::fetchFullBacktrace()
runCommand(cmd); runCommand(cmd);
} }
void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken, void LldbEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
quint64 addr, quint64 length)
{ {
int id = m_memoryAgents.value(agent, -1);
if (id == -1) {
id = ++m_lastAgentId;
m_memoryAgents.insert(agent, id);
}
m_memoryAgentTokens.insert(id, editorToken);
DebuggerCommand cmd("fetchMemory"); DebuggerCommand cmd("fetchMemory");
cmd.arg("address", addr); cmd.arg("address", addr);
cmd.arg("length", length); cmd.arg("length", length);
cmd.callback = [this, id](const DebuggerResponse &response) { cmd.callback = [this, agent](const DebuggerResponse &response) {
qulonglong addr = response.data["address"].toAddress(); qulonglong addr = response.data["address"].toAddress();
QPointer<MemoryAgent> agent = m_memoryAgents.key(id);
if (!agent.isNull()) {
QPointer<QObject> token = m_memoryAgentTokens.value(id);
QTC_ASSERT(!token.isNull(), return);
QByteArray ba = QByteArray::fromHex(response.data["contents"].data().toUtf8()); QByteArray ba = QByteArray::fromHex(response.data["contents"].data().toUtf8());
agent->addLazyData(token.data(), addr, ba); agent->addData(addr, ba);
}
}; };
runCommand(cmd); runCommand(cmd);
} }
void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken, void LldbEngine::changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data)
quint64 addr, const QByteArray &data)
{ {
int id = m_memoryAgents.value(agent, -1); Q_UNUSED(agent)
if (id == -1) {
id = ++m_lastAgentId;
m_memoryAgents.insert(agent, id);
m_memoryAgentTokens.insert(id, editorToken);
}
DebuggerCommand cmd("writeMemory"); DebuggerCommand cmd("writeMemory");
cmd.arg("address", addr); cmd.arg("address", addr);
cmd.arg("data", QString::fromUtf8(data.toHex())); cmd.arg("data", QString::fromUtf8(data.toHex()));
cmd.callback = [this, id](const DebuggerResponse &response) { Q_UNUSED(response); }; cmd.callback = [this](const DebuggerResponse &response) { Q_UNUSED(response); };
runCommand(cmd); runCommand(cmd);
} }

View File

@@ -118,8 +118,8 @@ private:
bool isSynchronous() const override { return true; } bool isSynchronous() const override { return true; }
void setRegisterValue(const QString &name, const QString &value) override; void setRegisterValue(const QString &name, const QString &value) override;
void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length) override; void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data) override; void changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data) override;
QString errorMessage(QProcess::ProcessError error) const; QString errorMessage(QProcess::ProcessError error) const;
bool hasCapability(unsigned cap) const override; bool hasCapability(unsigned cap) const override;
@@ -156,8 +156,6 @@ private:
int m_lastAgentId; int m_lastAgentId;
int m_continueAtNextSpontaneousStop; int m_continueAtNextSpontaneousStop;
QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents; QMap<QPointer<DisassemblerAgent>, int> m_disassemblerAgents;
QMap<QPointer<MemoryAgent>, int> m_memoryAgents;
QHash<int, QPointer<QObject> > m_memoryAgentTokens;
QHash<int, DebuggerCommand> m_commandForToken; QHash<int, DebuggerCommand> m_commandForToken;

View File

@@ -24,13 +24,15 @@
****************************************************************************/ ****************************************************************************/
#include "memoryagent.h" #include "memoryagent.h"
#include "memoryview.h"
#include "breakhandler.h" #include "breakhandler.h"
#include "debuggerengine.h" #include "debuggerengine.h"
#include "debuggerstartparameters.h" #include "debuggerstartparameters.h"
#include "debuggercore.h" #include "debuggercore.h"
#include "debuggerinternalconstants.h" #include "debuggerinternalconstants.h"
#include "registerhandler.h"
#include <bineditor/bineditorservice.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
@@ -42,13 +44,131 @@
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <extensionsystem/invoker.h> #include <extensionsystem/invoker.h>
#include <QVBoxLayout>
#include <cstring> #include <cstring>
using namespace Core; using namespace Core;
using namespace ProjectExplorer;
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
enum { BinBlockSize = 1024 };
enum { DataRange = 1024 * 1024 };
/*!
\class Debugger::Internal::MemoryView
\brief The MemoryView class is a base class for memory view tool windows.
This class is a small tool-window that stays on top and displays a chunk
of memory based on the widget provided by the BinEditor plugin.
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
*/
class MemoryView : public QWidget
{
public:
explicit MemoryView(MemoryAgent *agent, QWidget *parent)
: QWidget(parent, Qt::Tool), m_agent(agent)
{
setAttribute(Qt::WA_DeleteOnClose);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(agent->service()->widget());
layout->setContentsMargins(0, 0, 0, 0);
setMinimumWidth(400);
resize(800, 200);
}
void updateContents()
{
if (m_agent)
m_agent->updateContents();
}
protected:
void setAddress(quint64 a)
{
if (m_agent)
m_agent->setAddress(a);
}
void setMarkup(const QList<MemoryMarkup> &m)
{
if (m_agent)
m_agent->setMarkup(m);
}
private:
QPointer<MemoryAgent> m_agent;
};
/*!
\class Debugger::Internal::RegisterMemoryView
\brief The RegisterMemoryView class provides a memory view that shows the
memory around the contents of a register (such as stack pointer,
program counter), tracking changes of the register value.
Connects to Debugger::Internal::RegisterHandler to listen for changes
of the register value.
\note Some registers might switch to 0 (for example, 'rsi','rbp'
while stepping out of a function with parameters).
This must be handled gracefully.
\sa Debugger::Internal::RegisterHandler, Debugger::Internal::RegisterWindow
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
*/
class RegisterMemoryView : public MemoryView
{
public:
RegisterMemoryView(MemoryAgent *agent, quint64 addr, const QString &regName,
RegisterHandler *rh, QWidget *parent)
: MemoryView(agent, parent), m_registerName(regName), m_registerAddress(addr)
{
connect(rh, &QAbstractItemModel::modelReset, this, &QWidget::close);
connect(rh, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged);
updateContents();
}
private:
void onRegisterChanged(const QString &name, quint64 value)
{
if (name == m_registerName)
setRegisterAddress(value);
}
void setRegisterAddress(quint64 v)
{
if (v == m_registerAddress) {
updateContents();
return;
}
m_registerAddress = v;
setAddress(v);
setWindowTitle(registerViewTitle(m_registerName, v));
if (v)
setMarkup(registerViewMarkup(v, m_registerName));
}
QString m_registerName;
quint64 m_registerAddress;
};
QString registerViewTitle(const QString &registerName, quint64 addr)
{
return MemoryAgent::tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(addr, 0, 16);
}
QList<MemoryMarkup> registerViewMarkup(quint64 a, const QString &regName)
{
return { MemoryMarkup(a, 1, QColor(Qt::blue).lighter(),
MemoryAgent::tr("Register \"%1\"").arg(regName)) };
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// MemoryAgent // MemoryAgent
@@ -80,219 +200,137 @@ namespace Internal {
\sa Debugger::MemoryView, Debugger::RegisterMemoryView \sa Debugger::MemoryView, Debugger::RegisterMemoryView
*/ */
MemoryAgent::MemoryAgent(DebuggerEngine *engine) BinEditor::FactoryService *binEditorFactory()
: QObject(engine), m_engine(engine)
{ {
QTC_CHECK(engine); static auto theBinEditorFactory = ExtensionSystem::PluginManager::getObject<BinEditor::FactoryService>();
connect(engine, &DebuggerEngine::stackFrameCompleted, return theBinEditorFactory;
this, &MemoryAgent::updateContents); }
bool MemoryAgent::hasBinEditor()
{
return binEditorFactory() != nullptr;
}
MemoryAgent::MemoryAgent(const MemoryViewSetupData &data, DebuggerEngine *engine)
: m_engine(engine), m_flags(data.flags)
{
auto factory = binEditorFactory();
if (!factory)
return;
const bool readOnly = (m_flags & DebuggerEngine::MemoryReadOnly) != 0;
QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title;
if (!(m_flags & DebuggerEngine::MemoryView) && !title.endsWith('$'))
title.append(" $");
if (m_flags & DebuggerEngine::MemoryView) {
// Ask BIN editor plugin for factory service and have it create a bin editor widget.
m_service = factory->createEditorService(title, false);
} else {
// Editor: Register tracking not supported.
m_service = factory->createEditorService(title, true);
}
if (!m_service)
return;
m_service->setNewRangeRequestHandler([this](quint64 address) {
m_service->setSizes(address, DataRange, BinBlockSize);
});
m_service->setFetchDataHandler([this](quint64 address) {
m_engine->fetchMemory(this, address, BinBlockSize);
});
m_service->setNewWindowRequestHandler([this](quint64 address) {
MemoryViewSetupData data;
data.startAddress = address;
auto agent = new MemoryAgent(data, m_engine);
if (!agent->isUsable())
delete agent;
});
m_service->setDataChangedHandler([this](quint64 address, const QByteArray &data) {
m_engine->changeMemory(this, address, data);
});
m_service->setWatchPointRequestHandler([this](quint64 address, uint size) {
m_engine->breakHandler()->setWatchpointAtAddress(address, size);
});
m_service->setAboutToBeDestroyedHandler([this] { m_service = nullptr; });
// Separate view?
if (m_flags & DebuggerEngine::MemoryView) {
// Memory view tracking register value, providing its own updating mechanism.
if (m_flags & DebuggerEngine::MemoryTrackRegister) {
auto view = new RegisterMemoryView(this, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent);
view->show();
} else {
// Ordinary memory view
auto view = new MemoryView(this, data.parent);
view->setWindowTitle(title);
view->show();
}
} else {
m_service->editor()->document()->setTemporary(true);
m_service->editor()->document()->setProperty(Constants::OPENED_BY_DEBUGGER, QVariant(true));
}
m_service->setReadOnly(readOnly);
m_service->setNewWindowRequestAllowed(true);
m_service->setSizes(data.startAddress, DataRange, BinBlockSize);
setMarkup(data.markup);
} }
MemoryAgent::~MemoryAgent() MemoryAgent::~MemoryAgent()
{ {
closeEditors(); if (m_service) {
closeViews(); if (m_service->editor())
} EditorManager::closeDocument(m_service->editor()->document());
if (m_service->widget())
void MemoryAgent::closeEditors() m_service->widget()->close();
{
if (m_editors.isEmpty())
return;
QSet<IDocument *> documents;
foreach (QPointer<IEditor> editor, m_editors)
if (editor)
documents.insert(editor->document());
EditorManager::closeDocuments(documents.toList());
m_editors.clear();
}
void MemoryAgent::closeViews()
{
foreach (const QPointer<MemoryView> &w, m_views)
if (w)
w->close();
m_views.clear();
}
void MemoryAgent::updateMemoryView(quint64 address, quint64 length)
{
m_engine->fetchMemory(this, sender(), address, length);
}
void MemoryAgent::connectBinEditorWidget(QWidget *w)
{
connect(w, SIGNAL(dataRequested(quint64)), SLOT(fetchLazyData(quint64)));
connect(w, SIGNAL(newWindowRequested(quint64)), SLOT(createBinEditor(quint64)));
connect(w, SIGNAL(newRangeRequested(quint64)), SLOT(provideNewRange(quint64)));
connect(w, SIGNAL(dataChanged(quint64,QByteArray)), SLOT(handleDataChanged(quint64,QByteArray)));
connect(w, SIGNAL(dataChanged(quint64,QByteArray)), SLOT(handleDataChanged(quint64,QByteArray)));
connect(w, SIGNAL(addWatchpointRequested(quint64,uint)), SLOT(handleWatchpointRequest(quint64,uint)));
}
bool MemoryAgent::doCreateBinEditor(const MemoryViewSetupData &data)
{
const bool readOnly = (data.flags & DebuggerEngine::MemoryReadOnly) != 0;
QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title;
// Separate view?
if (data.flags & DebuggerEngine::MemoryView) {
// Ask BIN editor plugin for factory service and have it create a bin editor widget.
QWidget *binEditor = 0;
if (QObject *factory = ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("BinEditor::BinEditorWidgetFactory")))
binEditor = ExtensionSystem::invoke<QWidget *>(factory, "createWidget", (QWidget *)0);
if (!binEditor)
return false;
connectBinEditorWidget(binEditor);
MemoryView::setBinEditorReadOnly(binEditor, readOnly);
MemoryView::setBinEditorNewWindowRequestAllowed(binEditor, true);
MemoryView *topLevel = 0;
// Memory view tracking register value, providing its own updating mechanism.
if (data.flags & DebuggerEngine::MemoryTrackRegister) {
topLevel = new RegisterMemoryView(binEditor, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent);
} else {
// Ordinary memory view
MemoryView::setBinEditorMarkup(binEditor, data.markup);
MemoryView::setBinEditorRange(binEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
topLevel = new MemoryView(binEditor, data.parent);
topLevel->setWindowTitle(title);
} }
m_views << topLevel;
topLevel->show();
return true;
}
// Editor: Register tracking not supported.
QTC_ASSERT(!(data.flags & DebuggerEngine::MemoryTrackRegister), return false);
if (!title.endsWith(QLatin1Char('$')))
title.append(QLatin1String(" $"));
IEditor *editor = EditorManager::openEditorWithContents(
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID, &title);
if (!editor)
return false;
editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, QVariant(true));
editor->document()->setTemporary(true);
QWidget *editorBinEditor = editor->widget();
connectBinEditorWidget(editorBinEditor);
MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly);
MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true);
MemoryView::setBinEditorRange(editorBinEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
MemoryView::setBinEditorMarkup(editorBinEditor, data.markup);
m_editors << editor;
return true;
} }
void MemoryAgent::createBinEditor(const MemoryViewSetupData &data) void MemoryAgent::setAddress(quint64 address)
{ {
if (!doCreateBinEditor(data)) QTC_ASSERT(m_service, return);
AsynchronousMessageBox::warning( m_service->setSizes(address, DataRange, BinBlockSize);
tr("No Memory Viewer Available"),
tr("The memory contents cannot be shown as no viewer plugin "
"for binary data has been loaded."));
} }
void MemoryAgent::createBinEditor(quint64 addr) void MemoryAgent::setMarkup(const QList<MemoryMarkup> &markup)
{ {
MemoryViewSetupData data; QTC_ASSERT(m_service, return);
data.startAddress = addr; m_service->clearMarkup();
createBinEditor(data); for (const MemoryMarkup &m : markup)
} m_service->addMarkup(m.address, m.length, m.color, m.toolTip);
m_service->commitMarkup();
void MemoryAgent::fetchLazyData(quint64 block)
{
m_engine->fetchMemory(this, sender(), BinBlockSize * block, BinBlockSize);
}
void MemoryAgent::addLazyData(QObject *editorToken, quint64 addr,
const QByteArray &ba)
{
QWidget *w = qobject_cast<QWidget *>(editorToken);
QTC_ASSERT(w, return);
MemoryView::binEditorAddData(w, addr, ba);
}
void MemoryAgent::provideNewRange(quint64 address)
{
QWidget *w = qobject_cast<QWidget *>(sender());
QTC_ASSERT(w, return);
MemoryView::setBinEditorRange(w, address, DataRange, BinBlockSize);
}
void MemoryAgent::handleDataChanged(quint64 addr, const QByteArray &data)
{
m_engine->changeMemory(this, sender(), addr, data);
}
void MemoryAgent::handleWatchpointRequest(quint64 address, uint size)
{
m_engine->breakHandler()->setWatchpointAtAddress(address, size);
} }
void MemoryAgent::updateContents() void MemoryAgent::updateContents()
{ {
foreach (const QPointer<IEditor> &e, m_editors)
if (e)
MemoryView::binEditorUpdateContents(e->widget());
// Update all views except register views, which trigger on // Update all views except register views, which trigger on
// register value set/changed. // register value set/changed.
foreach (const QPointer<MemoryView> &w, m_views) if (!(m_flags & DebuggerEngine::MemoryTrackRegister) && m_service)
if (w && !qobject_cast<RegisterMemoryView *>(w.data())) m_service->updateContents();
w->updateContents();
} }
bool MemoryAgent::hasVisibleEditor() const void MemoryAgent::addData(quint64 address, const QByteArray &a)
{ {
QList<IEditor *> visible = EditorManager::visibleEditors(); QTC_ASSERT(m_service, return);
foreach (QPointer<IEditor> editor, m_editors) m_service->addData(address, a);
if (visible.contains(editor.data()))
return true;
return false;
} }
void MemoryAgent::handleDebuggerFinished() void MemoryAgent::setFinished()
{ {
foreach (const QPointer<IEditor> &editor, m_editors) { if (m_service)
if (editor) { // Prevent triggering updates, etc. m_service->setFinished();
MemoryView::setBinEditorReadOnly(editor->widget(), true);
editor->widget()->disconnect(this);
}
}
} }
bool MemoryAgent::isBigEndian(const ProjectExplorer::Abi &a) bool MemoryAgent::isUsable()
{ {
switch (a.architecture()) { return m_service != nullptr;
case ProjectExplorer::Abi::UnknownArchitecture:
case ProjectExplorer::Abi::X86Architecture:
case ProjectExplorer::Abi::ItaniumArchitecture: // Configureable
case ProjectExplorer::Abi::ArmArchitecture: // Configureable
case ProjectExplorer::Abi::ShArchitecture: // Configureable
break;
case ProjectExplorer::Abi::MipsArchitecture: // Configureable
case ProjectExplorer::Abi::PowerPCArchitecture: // Configureable
return true;
}
return false;
}
// Read a POD variable from a memory location. Swap bytes if endianness differs
template <class POD> POD readPod(const unsigned char *data, bool swapByteOrder)
{
POD pod = 0;
if (swapByteOrder) {
unsigned char *target = reinterpret_cast<unsigned char *>(&pod) + sizeof(POD) - 1;
for (size_t i = 0; i < sizeof(POD); i++)
*target-- = data[i];
} else {
std::memcpy(&pod, data, sizeof(POD));
}
return pod;
}
// Read memory from debuggee
quint64 MemoryAgent::readInferiorPointerValue(const unsigned char *data, const ProjectExplorer::Abi &a)
{
const bool swapByteOrder = isBigEndian(a) != isBigEndian(ProjectExplorer::Abi::hostAbi());
return a.wordWidth() == 32 ? readPod<quint32>(data, swapByteOrder) :
readPod<quint64>(data, swapByteOrder);
} }
} // namespace Internal } // namespace Internal

View File

@@ -32,25 +32,23 @@
#include <QPointer> #include <QPointer>
#include <QColor> #include <QColor>
namespace Core { class IEditor; } namespace BinEditor { class EditorService; }
namespace ProjectExplorer { class Abi; }
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerEngine; class DebuggerEngine;
class MemoryView;
class MemoryMarkup class MemoryMarkup
{ {
public: public:
MemoryMarkup(quint64 a = 0, quint64 l = 0, QColor c = Qt::yellow, MemoryMarkup() {}
const QString &tt = QString()) : MemoryMarkup(quint64 address, quint64 length, QColor c, const QString &tt)
address(a), length(l), color(c), toolTip(tt) {} : address(address), length(length), color(c), toolTip(tt)
{}
quint64 address; quint64 address = 0;
quint64 length; quint64 length = 0;
QColor color; QColor color;
QString toolTip; QString toolTip;
}; };
@@ -58,13 +56,13 @@ public:
class MemoryViewSetupData class MemoryViewSetupData
{ {
public: public:
MemoryViewSetupData() : parent(0), startAddress(0), flags(0) {} MemoryViewSetupData() {}
QWidget *parent; QWidget *parent = nullptr;
quint64 startAddress; quint64 startAddress = 0;
QString registerName; QString registerName;
unsigned flags; unsigned flags = 0;
QList<Internal::MemoryMarkup> markup; QList<MemoryMarkup> markup;
QPoint pos; QPoint pos;
QString title; QString title;
}; };
@@ -74,44 +72,30 @@ class MemoryAgent : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit MemoryAgent(DebuggerEngine *engine); MemoryAgent(const MemoryViewSetupData &data, DebuggerEngine *engine);
~MemoryAgent(); ~MemoryAgent();
enum { BinBlockSize = 1024 }; void setAddress(quint64 address);
enum { DataRange = 1024 * 1024 }; void setMarkup(const QList<MemoryMarkup> &ml);
bool hasVisibleEditor() const;
static bool isBigEndian(const ProjectExplorer::Abi &a);
static quint64 readInferiorPointerValue(const unsigned char *data, const ProjectExplorer::Abi &a);
public slots:
// Called by engine to create a new view.
void createBinEditor(const MemoryViewSetupData &data);
void createBinEditor(quint64 startAddr);
// Called by engine to create a tooltip.
void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
// On stack frame completed and on request.
void updateContents(); void updateContents();
void closeEditors(); void addData(quint64 address, const QByteArray &data);
void closeViews(); void setFinished();
void handleDebuggerFinished(); bool isUsable();
private slots: BinEditor::EditorService *service() { return m_service; }
void fetchLazyData(quint64 block);
void provideNewRange(quint64 address); static bool hasBinEditor();
void handleDataChanged(quint64 address, const QByteArray &data);
void handleWatchpointRequest(quint64 address, uint size);
void updateMemoryView(quint64 address, quint64 length);
private: private:
void connectBinEditorWidget(QWidget *w); // The backend, provided by the BinEditor plugin, if loaded.
bool doCreateBinEditor(const MemoryViewSetupData &data); BinEditor::EditorService *m_service = nullptr;
QList<QPointer<Core::IEditor> > m_editors; DebuggerEngine *m_engine = nullptr;
QList<QPointer<MemoryView> > m_views; int m_flags = 0;
QPointer<DebuggerEngine> m_engine;
}; };
QList<MemoryMarkup> registerViewMarkup(quint64 address, const QString &regName);
QString registerViewTitle(const QString &registerName, quint64 address = 0);
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -1,178 +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 "memoryview.h"
#include "registerhandler.h"
#include "memoryagent.h"
#include <bineditor/markup.h>
#include <QVBoxLayout>
#include <QDebug>
namespace Debugger {
namespace Internal {
/*!
\class Debugger::Internal::MemoryView
\brief The MemoryView class is a base class for memory view tool windows.
This class is a small tool-window that stays on top and displays a chunk of memory
based on the widget provided by the Bin editor plugin.
Provides static functionality for handling a Bin Editor Widget
(soft dependency) via QMetaObject invocation.
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
*/
MemoryView::MemoryView(QWidget *binEditor, QWidget *parent) :
QWidget(parent, Qt::Tool), m_binEditor(binEditor)
{
setAttribute(Qt::WA_DeleteOnClose);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(binEditor);
layout->setContentsMargins(0, 0, 0, 0);
setMinimumWidth(400);
resize(800, 200);
}
void MemoryView::setBinEditorRange(QWidget *w, quint64 address, qint64 range, int blockSize)
{
QMetaObject::invokeMethod(w, "setSizes",
Q_ARG(quint64, address), Q_ARG(qint64, range), Q_ARG(int, blockSize));
}
void MemoryView::setBinEditorReadOnly(QWidget *w, bool readOnly)
{
w->setProperty("readOnly", QVariant(readOnly));
}
void MemoryView::setBinEditorNewWindowRequestAllowed(QWidget *w, bool a)
{
w->setProperty("newWindowRequestAllowed", QVariant(a));
}
void MemoryView::setBinEditorMarkup(QWidget *w, const QList<MemoryMarkup> &ml)
{
// Convert into bin editor markup and set.
QList<BinEditor::Markup> bml;
foreach (const MemoryMarkup &m, ml)
bml.push_back(BinEditor::Markup(m.address, m.length, m.color, m.toolTip));
w->setProperty("markup", qVariantFromValue(bml));
}
void MemoryView::binEditorUpdateContents(QWidget *w)
{
QMetaObject::invokeMethod(w, "updateContents");
}
void MemoryView::binEditorSetCursorPosition(QWidget *w, qint64 pos)
{
QMetaObject::invokeMethod(w, "setCursorPosition", Q_ARG(qint64, pos));
}
void MemoryView::binEditorAddData(QWidget *w, quint64 addr, const QByteArray &ba)
{
QMetaObject::invokeMethod(w, "addData",
Q_ARG(quint64, addr / MemoryAgent::BinBlockSize),
Q_ARG(QByteArray, ba));
}
void MemoryView::setAddress(quint64 a)
{
setBinEditorRange(m_binEditor, a, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
}
void MemoryView::updateContents()
{
binEditorUpdateContents(m_binEditor);
}
void MemoryView::setMarkup(const QList<MemoryMarkup> &m)
{
MemoryView::setBinEditorMarkup(m_binEditor, m);
}
/*!
\class Debugger::Internal::RegisterMemoryView
\brief The RegisterMemoryView class provides a memory view that shows the
memory around the contents of a register
(such as stack pointer, program counter),
tracking changes of the register value.
Connects to Debugger::Internal::RegisterHandler to listen for changes
of the register value.
\note Some registers might switch to 0 (for example, 'rsi','rbp'
while stepping out of a function with parameters).
This must be handled gracefully.
\sa Debugger::Internal::RegisterHandler, Debugger::Internal::RegisterWindow
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
*/
RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, quint64 addr,
const QString &regName,
RegisterHandler *handler, QWidget *parent) :
MemoryView(binEditor, parent),
m_registerName(regName), m_registerAddress(addr)
{
connect(handler, &QAbstractItemModel::modelReset, this, &QWidget::close);
connect(handler, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged);
updateContents();
}
void RegisterMemoryView::onRegisterChanged(const QString &name, quint64 value)
{
if (name == m_registerName)
setRegisterAddress(value);
}
QString RegisterMemoryView::title(const QString &registerName, quint64 a)
{
return tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(a, 0, 16);
}
void RegisterMemoryView::setRegisterAddress(quint64 v)
{
if (v == m_registerAddress) {
updateContents();
return;
}
m_registerAddress = v;
setAddress(v);
setWindowTitle(title(m_registerName, v));
if (v)
setMarkup(registerMarkup(v, m_registerName));
}
QList<MemoryMarkup> RegisterMemoryView::registerMarkup(quint64 a, const QString &regName)
{
return { MemoryMarkup(a, 1, QColor(Qt::blue).lighter(), tr("Register \"%1\"").arg(regName)) };
}
} // namespace Internal
} // namespace Debugger

View File

@@ -1,81 +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 <QWidget>
QT_FORWARD_DECLARE_CLASS(QModelIndex)
namespace Debugger {
namespace Internal {
class MemoryMarkup;
class RegisterHandler;
class MemoryView : public QWidget
{
Q_OBJECT
public:
explicit MemoryView(QWidget *binEditor, QWidget *parent = 0);
static void setBinEditorRange(QWidget *w, quint64 address, qint64 range, int blockSize);
static void setBinEditorReadOnly(QWidget *w, bool readOnly);
static void setBinEditorNewWindowRequestAllowed(QWidget *w, bool a);
static void setBinEditorMarkup(QWidget *w, const QList<MemoryMarkup> &ml);
static void binEditorSetCursorPosition(QWidget *w, qint64 pos);
static void binEditorUpdateContents(QWidget *w);
static void binEditorAddData(QWidget *w, quint64 addr, const QByteArray &a);
public slots:
void updateContents();
protected:
void setAddress(quint64 a);
void setMarkup(const QList<MemoryMarkup> &m);
private:
QWidget *m_binEditor;
};
class RegisterMemoryView : public MemoryView
{
Q_OBJECT
public:
explicit RegisterMemoryView(QWidget *binEditor, quint64 addr, const QString &regName,
RegisterHandler *rh, QWidget *parent = 0);
static QList<MemoryMarkup> registerMarkup(quint64 a, const QString &regName);
static QString title(const QString &registerName, quint64 a = 0);
private:
void onRegisterChanged(const QString &name, quint64 value);
void setRegisterAddress(quint64 v);
QString m_registerName;
quint64 m_registerAddress;
};
} // namespace Internal
} // namespace Debugger

View File

@@ -129,10 +129,14 @@ void QmlCppEngine::watchPoint(const QPoint &point)
m_cppEngine->watchPoint(point); m_cppEngine->watchPoint(point);
} }
void QmlCppEngine::fetchMemory(MemoryAgent *ma, QObject *obj, void QmlCppEngine::fetchMemory(MemoryAgent *agent, quint64 addr, quint64 length)
quint64 addr, quint64 length)
{ {
m_cppEngine->fetchMemory(ma, obj, addr, length); m_cppEngine->fetchMemory(agent, addr, length);
}
void QmlCppEngine::changeMemory(MemoryAgent *agent, quint64 addr, const QByteArray &data)
{
m_cppEngine->changeMemory(agent, addr, data);
} }
void QmlCppEngine::fetchDisassembler(DisassemblerAgent *da) void QmlCppEngine::fetchDisassembler(DisassemblerAgent *da)

View File

@@ -47,7 +47,8 @@ public:
void selectWatchData(const QString &iname) override; void selectWatchData(const QString &iname) override;
void watchPoint(const QPoint &) override; void watchPoint(const QPoint &) override;
void fetchMemory(MemoryAgent *, QObject *, quint64 addr, quint64 length) override; void fetchMemory(MemoryAgent *, quint64 addr, quint64 length) override;
void changeMemory(MemoryAgent *, quint64 addr, const QByteArray &data) override;
void fetchDisassembler(DisassemblerAgent *) override; void fetchDisassembler(DisassemblerAgent *) override;
void activateFrame(int index) override; void activateFrame(int index) override;

View File

@@ -28,7 +28,6 @@
#include "debuggerengine.h" #include "debuggerengine.h"
#include "watchdelegatewidgets.h" #include "watchdelegatewidgets.h"
#include "memoryview.h"
#include "memoryagent.h" #include "memoryagent.h"
#include "debuggeractions.h" #include "debuggeractions.h"
#include "debuggerdialogs.h" #include "debuggerdialogs.h"
@@ -712,8 +711,8 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
MemoryViewSetupData data; MemoryViewSetupData data;
data.startAddress = address; data.startAddress = address;
data.registerName = registerName; data.registerName = registerName;
data.markup = RegisterMemoryView::registerMarkup(address, registerName); data.markup = registerViewMarkup(address, registerName);
data.title = RegisterMemoryView::title(registerName); data.title = registerViewTitle(registerName);
m_engine->openMemoryView(data); m_engine->openMemoryView(data);
}); });

View File

@@ -35,7 +35,6 @@
#include "debuggertooltipmanager.h" #include "debuggertooltipmanager.h"
#include "imageviewer.h" #include "imageviewer.h"
#include "memoryagent.h" #include "memoryagent.h"
#include "memoryview.h"
#include "registerhandler.h" #include "registerhandler.h"
#include "simplifytype.h" #include "simplifytype.h"
#include "watchdelegatewidgets.h" #include "watchdelegatewidgets.h"