forked from qt-creator/qt-creator
Debugger: Use bin editor widget for standalone-memory views.
Remove MemoryViewWidget/RegisterMemoryViewWidget in favour of MemoryView/RegisterMemoryView based on the bin editor widget.
This commit is contained in:
@@ -31,11 +31,11 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "memoryagent.h"
|
||||
#include "memoryview.h"
|
||||
|
||||
#include "debuggerengine.h"
|
||||
#include "debuggerstartparameters.h"
|
||||
#include "debuggercore.h"
|
||||
#include "memoryviewwidget.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
@@ -43,9 +43,12 @@
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <extensionsystem/invoker.h>
|
||||
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -66,6 +69,22 @@ namespace Internal {
|
||||
Objects form this class are created in response to user actions in
|
||||
the Gui for showing raw memory from the inferior. After creation
|
||||
it handles communication between the engine and the bineditor.
|
||||
|
||||
Memory can be shown as
|
||||
\list
|
||||
\o Editor: Create an IEditor using the normal editor factory
|
||||
interface (m_editors)
|
||||
\o View: Separate top-level view consisting of a Bin Editor widget
|
||||
(m_view).
|
||||
\endlist
|
||||
|
||||
Views are updated on the DebuggerEngine::stackFrameCompleted signal.
|
||||
An exception are views of class Debugger::RegisterMemoryView tracking the
|
||||
content pointed to by a register (eg stack pointer, instruction pointer).
|
||||
They are connected to the set/changed signals of
|
||||
the engine's register handler.
|
||||
|
||||
\sa Debugger::MemoryView, Debugger::RegisterMemoryView
|
||||
*/
|
||||
|
||||
namespace { const int DataRange = 1024 * 1024; }
|
||||
@@ -74,37 +93,37 @@ MemoryAgent::MemoryAgent(DebuggerEngine *engine)
|
||||
: QObject(engine), m_engine(engine)
|
||||
{
|
||||
QTC_ASSERT(engine, /**/);
|
||||
connect(engine, SIGNAL(stateChanged(Debugger::DebuggerState)),
|
||||
this, SLOT(engineStateChanged(Debugger::DebuggerState)));
|
||||
connect(engine, SIGNAL(stackFrameCompleted()), this,
|
||||
SLOT(updateContents()));
|
||||
}
|
||||
|
||||
MemoryAgent::~MemoryAgent()
|
||||
{
|
||||
closeEditors();
|
||||
closeViews();
|
||||
}
|
||||
|
||||
void MemoryAgent::closeEditors()
|
||||
{
|
||||
if (m_editors.isEmpty())
|
||||
return;
|
||||
|
||||
QList<IEditor *> editors;
|
||||
foreach (QPointer<IEditor> editor, m_editors)
|
||||
if (editor)
|
||||
editors.append(editor.data());
|
||||
EditorManager::instance()->closeEditors(editors);
|
||||
m_editors.clear();
|
||||
}
|
||||
|
||||
void MemoryAgent::openMemoryView(quint64 address, quint64 length, const QPoint &pos)
|
||||
void MemoryAgent::closeViews()
|
||||
{
|
||||
MemoryViewWidget *w = new MemoryViewWidget(Core::ICore::instance()->mainWindow());
|
||||
w->setUpdateOnInferiorStop(true);
|
||||
w->move(pos);
|
||||
w->requestMemory(address, length);
|
||||
addMemoryView(w);
|
||||
}
|
||||
|
||||
void MemoryAgent::addMemoryView(MemoryViewWidget *w)
|
||||
{
|
||||
w->setAbi(m_engine->startParameters().toolChainAbi);
|
||||
connect(w, SIGNAL(memoryRequested(quint64,quint64)),
|
||||
this, SLOT(updateMemoryView(quint64,quint64)));
|
||||
connect(m_engine, SIGNAL(stateChanged(Debugger::DebuggerState)),
|
||||
w, SLOT(engineStateChanged(Debugger::DebuggerState)));
|
||||
connect(w, SIGNAL(openViewRequested(quint64,quint64,QPoint)),
|
||||
this, SLOT(openMemoryView(quint64,quint64,QPoint)));
|
||||
w->requestMemory();
|
||||
w->show();
|
||||
foreach (const QPointer<MemoryView> &w, m_views)
|
||||
if (w)
|
||||
w->close();
|
||||
m_views.clear();
|
||||
}
|
||||
|
||||
void MemoryAgent::updateMemoryView(quint64 address, quint64 length)
|
||||
@@ -112,104 +131,155 @@ void MemoryAgent::updateMemoryView(quint64 address, quint64 length)
|
||||
m_engine->fetchMemory(this, sender(), address, length);
|
||||
}
|
||||
|
||||
void MemoryAgent::createBinEditor(quint64 addr)
|
||||
void MemoryAgent::connectBinEditorWidget(QWidget *w)
|
||||
{
|
||||
EditorManager *editorManager = EditorManager::instance();
|
||||
QString titlePattern = tr("Memory $");
|
||||
IEditor *editor = editorManager->openEditorWithContents(
|
||||
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID,
|
||||
&titlePattern);
|
||||
if (editor) {
|
||||
editor->setProperty(Constants::OPENED_BY_DEBUGGER, true);
|
||||
editor->setProperty(Constants::OPENED_WITH_MEMORY, true);
|
||||
connect(editor->widget(),
|
||||
SIGNAL(dataRequested(Core::IEditor*,quint64)),
|
||||
SLOT(fetchLazyData(Core::IEditor*,quint64)));
|
||||
connect(editor->widget(),
|
||||
SIGNAL(newWindowRequested(quint64)),
|
||||
SLOT(createBinEditor(quint64)));
|
||||
connect(editor->widget(),
|
||||
SIGNAL(newRangeRequested(Core::IEditor*,quint64)),
|
||||
SLOT(provideNewRange(Core::IEditor*,quint64)));
|
||||
connect(editor->widget(),
|
||||
SIGNAL(startOfFileRequested(Core::IEditor*)),
|
||||
SLOT(handleStartOfFileRequested(Core::IEditor*)));
|
||||
connect(editor->widget(),
|
||||
SIGNAL(endOfFileRequested(Core::IEditor *)),
|
||||
SLOT(handleEndOfFileRequested(Core::IEditor*)));
|
||||
connect(editor->widget(),
|
||||
SIGNAL(dataChanged(Core::IEditor*,quint64,QByteArray)),
|
||||
SLOT(handleDataChanged(Core::IEditor*,quint64,QByteArray)));
|
||||
m_editors << editor;
|
||||
QMetaObject::invokeMethod(editor->widget(), "setNewWindowRequestAllowed");
|
||||
QMetaObject::invokeMethod(editor->widget(), "setSizes",
|
||||
Q_ARG(quint64, addr),
|
||||
Q_ARG(int, DataRange),
|
||||
Q_ARG(int, BinBlockSize));
|
||||
editorManager->activateEditor(editor);
|
||||
} else {
|
||||
showMessageBox(QMessageBox::Warning,
|
||||
tr("No memory viewer available"),
|
||||
tr("The memory contents cannot be shown as no viewer plugin "
|
||||
"for binary data has been loaded."));
|
||||
deleteLater();
|
||||
}
|
||||
connect(w,
|
||||
SIGNAL(dataRequested(Core::IEditor*,quint64)),
|
||||
SLOT(fetchLazyData(Core::IEditor*,quint64)));
|
||||
connect(w,
|
||||
SIGNAL(newWindowRequested(quint64)),
|
||||
SLOT(createBinEditor(quint64)));
|
||||
connect(w,
|
||||
SIGNAL(newRangeRequested(Core::IEditor*,quint64)),
|
||||
SLOT(provideNewRange(Core::IEditor*,quint64)));
|
||||
connect(w,
|
||||
SIGNAL(startOfFileRequested(Core::IEditor*)),
|
||||
SLOT(handleStartOfFileRequested(Core::IEditor*)));
|
||||
connect(w,
|
||||
SIGNAL(endOfFileRequested(Core::IEditor *)),
|
||||
SLOT(handleEndOfFileRequested(Core::IEditor*)));
|
||||
connect(w,
|
||||
SIGNAL(dataChanged(Core::IEditor*,quint64,QByteArray)),
|
||||
SLOT(handleDataChanged(Core::IEditor*,quint64,QByteArray)));
|
||||
}
|
||||
|
||||
void MemoryAgent::fetchLazyData(IEditor *editor, quint64 block)
|
||||
bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
QString title, QWidget *parent)
|
||||
{
|
||||
m_engine->fetchMemory(this, editor, BinBlockSize * block, BinBlockSize);
|
||||
const bool readOnly = (flags & DebuggerEngine::MemoryReadOnly) != 0;
|
||||
if (title.isEmpty())
|
||||
title = tr("Memory at 0x%1").arg(addr, 0, 16);
|
||||
// Separate view?
|
||||
if (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::instance()->getObjectByClassName("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 (flags & DebuggerEngine::MemoryTrackRegister) {
|
||||
RegisterMemoryView *rmv = new RegisterMemoryView(binEditor, parent);
|
||||
rmv->init(m_engine->registerHandler(), int(addr));
|
||||
topLevel = rmv;
|
||||
} else {
|
||||
// Ordinary memory view
|
||||
MemoryView::setBinEditorMarkup(binEditor, ml);
|
||||
MemoryView::setBinEditorRange(binEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
topLevel = new MemoryView(binEditor, parent);
|
||||
topLevel->setWindowTitle(title);
|
||||
}
|
||||
m_views << topLevel;
|
||||
topLevel->move(pos);
|
||||
topLevel->show();
|
||||
return true;
|
||||
}
|
||||
// Editor: Register tracking not supported.
|
||||
QTC_ASSERT(!(flags & DebuggerEngine::MemoryTrackRegister), return false; )
|
||||
EditorManager *editorManager = EditorManager::instance();
|
||||
if (!title.endsWith(QLatin1Char('$')))
|
||||
title.append(QLatin1String(" $"));
|
||||
IEditor *editor = editorManager->openEditorWithContents(
|
||||
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID, &title);
|
||||
if (!editor)
|
||||
return false;
|
||||
editor->setProperty(Constants::OPENED_BY_DEBUGGER, QVariant(true));
|
||||
editor->setProperty(Constants::OPENED_WITH_MEMORY, QVariant(true));
|
||||
QWidget *editorBinEditor = editor->widget();
|
||||
connectBinEditorWidget(editorBinEditor);
|
||||
MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly);
|
||||
MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true);
|
||||
MemoryView::setBinEditorRange(editorBinEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
MemoryView::setBinEditorMarkup(editorBinEditor, ml);
|
||||
m_editors << editor;
|
||||
editorManager->activateEditor(editor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryAgent::createBinEditor(quint64 addr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
const QString &title, QWidget *parent)
|
||||
{
|
||||
if (!doCreateBinEditor(addr, flags, ml, pos, title, parent))
|
||||
showMessageBox(QMessageBox::Warning,
|
||||
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)
|
||||
{
|
||||
createBinEditor(addr, 0, QList<MemoryMarkup>(), QPoint(), QString(), 0);
|
||||
}
|
||||
|
||||
void MemoryAgent::fetchLazyData(IEditor *, quint64 block)
|
||||
{
|
||||
m_engine->fetchMemory(this, sender(), BinBlockSize * block, BinBlockSize);
|
||||
}
|
||||
|
||||
void MemoryAgent::addLazyData(QObject *editorToken, quint64 addr,
|
||||
const QByteArray &ba)
|
||||
{
|
||||
|
||||
if (IEditor *editor = qobject_cast<IEditor *>(editorToken)) {
|
||||
if (QWidget *editorWidget = editor->widget()) {
|
||||
QMetaObject::invokeMethod(editorWidget , "addData",
|
||||
Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (MemoryViewWidget *mvw = qobject_cast<MemoryViewWidget*>(editorToken))
|
||||
mvw->setData(ba);
|
||||
QWidget *w = qobject_cast<QWidget *>(editorToken);
|
||||
QTC_ASSERT(w, return ;)
|
||||
MemoryView::binEditorAddData(w, addr, ba);
|
||||
}
|
||||
|
||||
void MemoryAgent::provideNewRange(IEditor *editor, quint64 address)
|
||||
void MemoryAgent::provideNewRange(IEditor *, quint64 address)
|
||||
{
|
||||
QMetaObject::invokeMethod(editor->widget(), "setSizes",
|
||||
Q_ARG(quint64, address),
|
||||
Q_ARG(int, DataRange),
|
||||
Q_ARG(int, BinBlockSize));
|
||||
QWidget *w = qobject_cast<QWidget *>(sender());
|
||||
QTC_ASSERT(w, return ;)
|
||||
MemoryView::setBinEditorRange(w, address, DataRange, BinBlockSize);
|
||||
}
|
||||
|
||||
// Since we are not dealing with files, we take these signals to mean
|
||||
// "move to start/end of range". This seems to make more sense than
|
||||
// jumping to the start or end of the address space, respectively.
|
||||
void MemoryAgent::handleStartOfFileRequested(IEditor *editor)
|
||||
void MemoryAgent::handleStartOfFileRequested(IEditor *)
|
||||
{
|
||||
QMetaObject::invokeMethod(editor->widget(),
|
||||
"setCursorPosition", Q_ARG(int, 0));
|
||||
QWidget *w = qobject_cast<QWidget *>(sender());
|
||||
QTC_ASSERT(w, return ;)
|
||||
MemoryView::binEditorSetCursorPosition(w, 0);
|
||||
}
|
||||
|
||||
void MemoryAgent::handleEndOfFileRequested(IEditor *editor)
|
||||
void MemoryAgent::handleEndOfFileRequested(IEditor *)
|
||||
{
|
||||
QMetaObject::invokeMethod(editor->widget(),
|
||||
"setCursorPosition", Q_ARG(int, DataRange - 1));
|
||||
QWidget *w = qobject_cast<QWidget *>(sender());
|
||||
QTC_ASSERT(w, return ;)
|
||||
MemoryView::binEditorSetCursorPosition(w, DataRange - 1);
|
||||
}
|
||||
|
||||
void MemoryAgent::handleDataChanged(IEditor *editor,
|
||||
void MemoryAgent::handleDataChanged(IEditor *,
|
||||
quint64 addr, const QByteArray &data)
|
||||
{
|
||||
m_engine->changeMemory(this, editor, addr, data);
|
||||
m_engine->changeMemory(this, sender(), addr, data);
|
||||
}
|
||||
|
||||
void MemoryAgent::updateContents()
|
||||
{
|
||||
foreach (QPointer<IEditor> editor, m_editors)
|
||||
if (editor)
|
||||
QMetaObject::invokeMethod(editor->widget(), "updateContents");
|
||||
foreach (const QPointer<Core::IEditor> &e, m_editors)
|
||||
if (e)
|
||||
MemoryView::binEditorUpdateContents(e->widget());
|
||||
// Update all views except register views, which trigger on
|
||||
// register value set/changed.
|
||||
foreach (const QPointer<MemoryView> &w, m_views)
|
||||
if (w && !qobject_cast<RegisterMemoryView *>(w.data()))
|
||||
w->updateContents();
|
||||
}
|
||||
|
||||
bool MemoryAgent::hasVisibleEditor() const
|
||||
@@ -221,6 +291,22 @@ bool MemoryAgent::hasVisibleEditor() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void MemoryAgent::engineStateChanged(Debugger::DebuggerState s)
|
||||
{
|
||||
switch (s) {
|
||||
case DebuggerFinished:
|
||||
closeViews();
|
||||
foreach (const QPointer<IEditor> &editor, m_editors)
|
||||
if (editor) { // Prevent triggering updates, etc.
|
||||
MemoryView::setBinEditorReadOnly(editor->widget(), true);
|
||||
editor->widget()->disconnect(this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryAgent::isBigEndian(const ProjectExplorer::Abi &a)
|
||||
{
|
||||
switch (a.architecture()) {
|
||||
@@ -260,3 +346,4 @@ quint64 MemoryAgent::readInferiorPointerValue(const unsigned char *data, const P
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user