BinEditor/MemoryView: Follow pointers, potentially in new window.

Reviewed-by: hjk
This commit is contained in:
ck
2010-02-17 17:33:42 +01:00
parent 7c9c99dcf0
commit d87d7694bc
10 changed files with 147 additions and 37 deletions

View File

@@ -37,8 +37,10 @@
#include <QtCore/QTemporaryFile> #include <QtCore/QTemporaryFile>
#include <QtGui/QApplication> #include <QtGui/QApplication>
#include <QtGui/QAction>
#include <QtGui/QClipboard> #include <QtGui/QClipboard>
#include <QtGui/QFontMetrics> #include <QtGui/QFontMetrics>
#include <QtGui/QMenu>
#include <QtGui/QPainter> #include <QtGui/QPainter>
#include <QtGui/QScrollBar> #include <QtGui/QScrollBar>
#include <QtGui/QWheelEvent> #include <QtGui/QWheelEvent>
@@ -93,6 +95,7 @@ BinEditor::BinEditor(QWidget *parent)
m_lowNibble = false; m_lowNibble = false;
m_cursorVisible = false; m_cursorVisible = false;
m_caseSensitiveSearch = false; m_caseSensitiveSearch = false;
m_canRequestNewWindow = false;
setFocusPolicy(Qt::WheelFocus); setFocusPolicy(Qt::WheelFocus);
} }
@@ -178,7 +181,8 @@ bool BinEditor::requestDataAt(int pos, bool synchronous) const
if (!m_lazyRequests.contains(block)) { if (!m_lazyRequests.contains(block)) {
m_lazyRequests.insert(block); m_lazyRequests.insert(block);
emit const_cast<BinEditor*>(this)-> emit const_cast<BinEditor*>(this)->
lazyDataRequested(m_baseAddr / m_blockSize + block, synchronous); lazyDataRequested(editorInterface(), m_baseAddr / m_blockSize + block,
synchronous);
if (!m_lazyRequests.contains(block)) if (!m_lazyRequests.contains(block))
return true; // synchronous data source return true; // synchronous data source
} }
@@ -1119,12 +1123,16 @@ void BinEditor::zoomOut(int range)
zoomIn(-range); zoomIn(-range);
} }
void BinEditor::copy() void BinEditor::copy(bool raw)
{ {
const int selStart = selectionStart(); const int selStart = selectionStart();
const int selEnd = selectionEnd(); const int selEnd = selectionEnd();
if (selStart < selEnd) { if (selStart < selEnd) {
const QByteArray &data = dataMid(selStart, selEnd - selStart); const QByteArray &data = dataMid(selStart, selEnd - selStart);
if (raw) {
QApplication::clipboard()->setText(data);
return;
}
QString hexString; QString hexString;
const char * const hex = "0123456789abcdef"; const char * const hex = "0123456789abcdef";
for (int i = 0; i < data.size(); ++i) { for (int i = 0; i < data.size(); ++i) {
@@ -1217,3 +1225,81 @@ void BinEditor::redo()
if (!m_redoStack.size()) if (!m_redoStack.size())
emit redoAvailable(false); emit redoAvailable(false);
} }
void BinEditor::contextMenuEvent(QContextMenuEvent *event)
{
const int selStart = selectionStart();
const int byteCount = selectionEnd() - selStart;
if (byteCount == 0)
return;
QMenu contextMenu;
QAction copyAsciiAction(tr("Copy Selection as ASCII Characters"), this);
QAction copyHexAction(tr("Copy Selection as Hex Values"), this);
QMenu jumpBeMenu;
QMenu jumpLeMenu;
QAction jumpToBeAddressHere(tr("In This Window"), this);
QAction jumpToBeAddressNewWindow(tr("In New Window"), this);
QAction jumpToLeAddressHere(tr("In This Window"), this);
QAction jumpToLeAddressNewWindow(tr("In New Window"), this);
contextMenu.addAction(&copyAsciiAction);
contextMenu.addAction(&copyHexAction);
contextMenu.addMenu(&jumpBeMenu);
quint64 beAddress = 0;
quint64 leAddress = 0;
if (byteCount <= 8) {
const QByteArray &data = dataMid(selStart, byteCount);
for (int pos = 0; pos < byteCount; ++pos) {
const quint64 val = static_cast<quint64>(data.at(pos)) & 0xff;
beAddress += val << (pos * 8);
leAddress += val << ((byteCount - pos - 1) * 8);
}
setupJumpToMenuAction(&jumpBeMenu, &jumpToBeAddressHere,
&jumpToBeAddressNewWindow, beAddress);
// If the menu entries would be identical, show only one of them.
if (beAddress != leAddress) {
setupJumpToMenuAction(&jumpLeMenu, &jumpToLeAddressHere,
&jumpToLeAddressNewWindow, leAddress);
contextMenu.addMenu(&jumpLeMenu);
}
} else {
jumpBeMenu.setTitle(tr("Jump to Address"));
jumpBeMenu.setEnabled(false);
}
QAction *action = contextMenu.exec(event->globalPos());
if (action == &copyAsciiAction)
copy(true);
else if (action == &copyHexAction)
copy(false);
else if (action == &jumpToBeAddressHere)
setCursorPosition(beAddress - m_baseAddr);
else if (action == &jumpToLeAddressHere)
setCursorPosition(leAddress - m_baseAddr);
else if (action == &jumpToBeAddressNewWindow)
emit newWindowRequested(beAddress);
else if (action == &jumpToLeAddressNewWindow)
emit newWindowRequested(leAddress);
}
void BinEditor::setupJumpToMenuAction(QMenu *menu, QAction *actionHere,
QAction *actionNew, quint64 addr)
{
menu->setTitle(tr("Jump to Address 0x%1").arg(QString::number(addr, 16)));
menu->addAction(actionHere);
if (addr < m_baseAddr || addr >= m_baseAddr + m_size)
actionHere->setEnabled(false);
if (!m_canRequestNewWindow)
actionNew->setEnabled(false);
menu->addAction(actionNew);
if (!actionHere->isEnabled() && !actionNew->isEnabled())
menu->setEnabled(false);
}
void BinEditor::setNewWindowRequestAllowed()
{
m_canRequestNewWindow = true;
}

View File

@@ -40,6 +40,8 @@
#include <QtGui/QTextDocument> #include <QtGui/QTextDocument>
#include <QtGui/QTextFormat> #include <QtGui/QTextFormat>
QT_FORWARD_DECLARE_CLASS(QMenu)
namespace Core { namespace Core {
class IEditor; class IEditor;
} }
@@ -69,6 +71,7 @@ public:
Q_INVOKABLE void setLazyData(quint64 startAddr, int range, int blockSize = 4096); Q_INVOKABLE void setLazyData(quint64 startAddr, int range, int blockSize = 4096);
inline int lazyDataBlockSize() const { return m_blockSize; } inline int lazyDataBlockSize() const { return m_blockSize; }
Q_INVOKABLE void addLazyData(quint64 block, const QByteArray &data); Q_INVOKABLE void addLazyData(quint64 block, const QByteArray &data);
Q_INVOKABLE void setNewWindowRequestAllowed();
bool save(const QString &oldFileName, const QString &newFileName); bool save(const QString &oldFileName, const QString &newFileName);
void zoomIn(int range = 1); void zoomIn(int range = 1);
@@ -116,7 +119,7 @@ public:
public Q_SLOTS: public Q_SLOTS:
void setFontSettings(const TextEditor::FontSettings &fs); void setFontSettings(const TextEditor::FontSettings &fs);
void highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags findFlags = 0); void highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags findFlags = 0);
void copy(); void copy(bool raw = false);
Q_SIGNALS: Q_SIGNALS:
void modificationChanged(bool modified); void modificationChanged(bool modified);
@@ -125,7 +128,8 @@ Q_SIGNALS:
void copyAvailable(bool); void copyAvailable(bool);
void cursorPositionChanged(int position); void cursorPositionChanged(int position);
void lazyDataRequested(quint64 block, bool synchronous); void lazyDataRequested(Core::IEditor *editor, quint64 block, bool synchronous);
void newWindowRequested(quint64 address);
protected: protected:
void scrollContentsBy(int dx, int dy); void scrollContentsBy(int dx, int dy);
@@ -140,6 +144,7 @@ protected:
void focusInEvent(QFocusEvent *); void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *); void focusOutEvent(QFocusEvent *);
void timerEvent(QTimerEvent *); void timerEvent(QTimerEvent *);
void contextMenuEvent(QContextMenuEvent *event);
private: private:
bool m_inLazyMode; bool m_inLazyMode;
@@ -203,6 +208,9 @@ private:
int findPattern(const QByteArray &data, const QByteArray &dataHex, int from, int offset, int *match); int findPattern(const QByteArray &data, const QByteArray &dataHex, int from, int offset, int *match);
void drawItems(QPainter *painter, int x, int y, const QString &itemString); void drawItems(QPainter *painter, int x, int y, const QString &itemString);
void setupJumpToMenuAction(QMenu *menu, QAction *actionHere, QAction *actionNew,
quint64 addr);
struct BinEditorEditCommand { struct BinEditorEditCommand {
int position; int position;
uchar character; uchar character;
@@ -214,6 +222,7 @@ private:
Core::IEditor *m_ieditor; Core::IEditor *m_ieditor;
QString m_addressString; QString m_addressString;
int m_addressBytes; int m_addressBytes;
bool m_canRequestNewWindow;
}; };
} // namespace BINEditor } // namespace BINEditor

View File

@@ -174,7 +174,8 @@ public:
m_mimeType(QLatin1String(BINEditor::Constants::C_BINEDITOR_MIMETYPE)) m_mimeType(QLatin1String(BINEditor::Constants::C_BINEDITOR_MIMETYPE))
{ {
m_editor = parent; m_editor = parent;
connect(m_editor, SIGNAL(lazyDataRequested(quint64, bool)), this, SLOT(provideData(quint64))); connect(m_editor, SIGNAL(lazyDataRequested(Core::IEditor *, quint64, bool)),
this, SLOT(provideData(Core::IEditor *, quint64)));
} }
~BinEditorFile() {} ~BinEditorFile() {}
@@ -211,7 +212,7 @@ public:
} }
private slots: private slots:
void provideData(quint64 block) { void provideData(Core::IEditor *, quint64 block) {
QFile file(m_fileName); QFile file(m_fileName);
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::ReadOnly)) {
int blockSize = m_editor->lazyDataBlockSize(); int blockSize = m_editor->lazyDataBlockSize();

View File

@@ -1135,7 +1135,7 @@ void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent)
} }
} }
void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length) void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, QObject *token, quint64 addr, quint64 length)
{ {
if (!m_d->m_hDebuggeeProcess && !length) if (!m_d->m_hDebuggeeProcess && !length)
return; return;
@@ -1149,7 +1149,7 @@ void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 l
} }
if (received < length) if (received < length)
data.truncate(received); data.truncate(received);
agent->addLazyData(addr, data); agent->addLazyData(token, addr, data);
} }
void CdbDebugEngine::reloadModules() void CdbDebugEngine::reloadModules()

View File

@@ -90,7 +90,7 @@ public:
virtual void attemptBreakpointSynchronization(); virtual void attemptBreakpointSynchronization();
virtual void fetchDisassembler(DisassemblerViewAgent *agent); virtual void fetchDisassembler(DisassemblerViewAgent *agent);
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length); virtual void fetchMemory(MemoryViewAgent *, QObject *, quint64 addr, quint64 length);
virtual void reloadModules(); virtual void reloadModules();
virtual void loadSymbols(const QString &moduleName); virtual void loadSymbols(const QString &moduleName);

View File

@@ -72,35 +72,41 @@ namespace Internal {
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr) MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
: QObject(manager), m_engine(manager->currentEngine()), m_manager(manager) : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{ {
init(addr); createBinEditor(addr);
} }
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr) MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
: QObject(manager), m_engine(manager->currentEngine()), m_manager(manager) : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{ {
bool ok = true; bool ok = true;
init(addr.toULongLong(&ok, 0)); createBinEditor(addr.toULongLong(&ok, 0));
//qDebug() << " ADDRESS: " << addr << addr.toUInt(&ok, 0); //qDebug() << " ADDRESS: " << addr << addr.toUInt(&ok, 0);
} }
MemoryViewAgent::~MemoryViewAgent() MemoryViewAgent::~MemoryViewAgent()
{ {
if (m_editor) foreach (QPointer<Core::IEditor> editor, m_editors) {
m_editor->deleteLater(); if (editor)
editor->deleteLater();
}
} }
void MemoryViewAgent::init(quint64 addr) void MemoryViewAgent::createBinEditor(quint64 addr)
{ {
Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::EditorManager *editorManager = Core::EditorManager::instance();
QString titlePattern = tr("Memory $"); QString titlePattern = tr("Memory $");
m_editor = editorManager->openEditorWithContents( Core::IEditor *editor = editorManager->openEditorWithContents(
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID, Core::Constants::K_DEFAULT_BINARY_EDITOR_ID,
&titlePattern); &titlePattern);
if (m_editor) { if (editor) {
connect(m_editor->widget(), SIGNAL(lazyDataRequested(quint64,bool)), connect(editor->widget(), SIGNAL(lazyDataRequested(Core::IEditor *, quint64,bool)),
this, SLOT(fetchLazyData(quint64,bool))); this, SLOT(fetchLazyData(Core::IEditor *, quint64,bool)));
editorManager->activateEditor(m_editor); connect(editor->widget(), SIGNAL(newWindowRequested(quint64)),
QMetaObject::invokeMethod(m_editor->widget(), "setLazyData", this, SLOT(createBinEditor(quint64)));
m_editors << editor;
editorManager->activateEditor(editor);
QMetaObject::invokeMethod(editor->widget(), "setNewWindowRequestAllowed");
QMetaObject::invokeMethod(editor->widget(), "setLazyData",
Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize)); Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize));
} else { } else {
m_manager->showMessageBox(QMessageBox::Warning, m_manager->showMessageBox(QMessageBox::Warning,
@@ -111,19 +117,23 @@ void MemoryViewAgent::init(quint64 addr)
} }
} }
void MemoryViewAgent::fetchLazyData(quint64 block, bool sync) void MemoryViewAgent::fetchLazyData(Core::IEditor *editor, quint64 block, bool sync)
{ {
Q_UNUSED(sync); // FIXME: needed support for incremental searching Q_UNUSED(sync); // FIXME: needed support for incremental searching
if (m_engine) if (m_engine)
m_engine->fetchMemory(this, BinBlockSize * block, BinBlockSize); m_engine->fetchMemory(this, editor, BinBlockSize * block, BinBlockSize);
} }
void MemoryViewAgent::addLazyData(quint64 addr, const QByteArray &ba) void MemoryViewAgent::addLazyData(QObject *editorToken, quint64 addr,
const QByteArray &ba)
{ {
if (m_editor && m_editor->widget()) Core::IEditor *editor = qobject_cast<Core::IEditor *>(editorToken);
QMetaObject::invokeMethod(m_editor->widget(), "addLazyData", if (editor && editor->widget()) {
Core::EditorManager::instance()->activateEditor(editor);
QMetaObject::invokeMethod(editor->widget(), "addLazyData",
Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba)); Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
} }
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////

View File

@@ -37,6 +37,7 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QList>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtGui/QAction> #include <QtGui/QAction>
@@ -61,15 +62,15 @@ public:
public slots: public slots:
// Called from Engine // Called from Engine
void addLazyData(quint64 addr, const QByteArray &data); void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
// Called from Editor // Called from Editor
void fetchLazyData(quint64 block, bool sync); void fetchLazyData(Core::IEditor *, quint64 block, bool sync);
private: private:
void init(quint64 startaddr); Q_SLOT void createBinEditor(quint64 startAddr);
QPointer<IDebuggerEngine> m_engine; QPointer<IDebuggerEngine> m_engine;
QPointer<Core::IEditor> m_editor; QList<QPointer<Core::IEditor> > m_editors;
QPointer<DebuggerManager> m_manager; QPointer<DebuggerManager> m_manager;
}; };

View File

@@ -3542,21 +3542,23 @@ void GdbEngine::handleWatchPoint(const GdbResponse &response)
struct MemoryAgentCookie struct MemoryAgentCookie
{ {
MemoryAgentCookie() : agent(0), address(0) {} MemoryAgentCookie() : agent(0), token(0), address(0) {}
MemoryAgentCookie(MemoryViewAgent *agent_, quint64 address_) MemoryAgentCookie(MemoryViewAgent *agent_, QObject *token_, quint64 address_)
: agent(agent_), address(address_) : agent(agent_), token(token_), address(address_)
{} {}
QPointer<MemoryViewAgent> agent; QPointer<MemoryViewAgent> agent;
QPointer<QObject> token;
quint64 address; quint64 address;
}; };
void GdbEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length) void GdbEngine::fetchMemory(MemoryViewAgent *agent, QObject *token, quint64 addr,
quint64 length)
{ {
//qDebug() << "GDB MEMORY FETCH" << agent << addr << length; //qDebug() << "GDB MEMORY FETCH" << agent << addr << length;
postCommand("-data-read-memory " + QByteArray::number(addr) + " x 1 1 " postCommand("-data-read-memory " + QByteArray::number(addr) + " x 1 1 "
+ QByteArray::number(length), + QByteArray::number(length),
NeedsStop, CB(handleFetchMemory), NeedsStop, CB(handleFetchMemory),
QVariant::fromValue(MemoryAgentCookie(agent, addr))); QVariant::fromValue(MemoryAgentCookie(agent, token, addr)));
} }
void GdbEngine::handleFetchMemory(const GdbResponse &response) void GdbEngine::handleFetchMemory(const GdbResponse &response)
@@ -3581,7 +3583,7 @@ void GdbEngine::handleFetchMemory(const GdbResponse &response)
QTC_ASSERT(ok, return); QTC_ASSERT(ok, return);
ba.append(c); ba.append(c);
} }
ac.agent->addLazyData(ac.address, ba); ac.agent->addLazyData(ac.token, ac.address, ba);
} }

View File

@@ -428,7 +428,8 @@ private: ////////// View & Data Stuff //////////
virtual void assignValueInDebugger(const QString &expr, const QString &value); virtual void assignValueInDebugger(const QString &expr, const QString &value);
virtual void fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length); virtual void fetchMemory(MemoryViewAgent *agent, QObject *token,
quint64 addr, quint64 length);
void handleFetchMemory(const GdbResponse &response); void handleFetchMemory(const GdbResponse &response);
virtual void watchPoint(const QPoint &); virtual void watchPoint(const QPoint &);

View File

@@ -112,7 +112,7 @@ public:
virtual void reloadFullStack() = 0; virtual void reloadFullStack() = 0;
virtual void watchPoint(const QPoint &) {} virtual void watchPoint(const QPoint &) {}
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length) virtual void fetchMemory(MemoryViewAgent *, QObject *, quint64 addr, quint64 length)
{ Q_UNUSED(addr); Q_UNUSED(length); } { Q_UNUSED(addr); Q_UNUSED(length); }
virtual void fetchDisassembler(DisassemblerViewAgent *) {} virtual void fetchDisassembler(DisassemblerViewAgent *) {}
virtual void setRegisterValue(int regnr, const QString &value) virtual void setRegisterValue(int regnr, const QString &value)