Commit d87d7694 authored by ck's avatar ck
Browse files

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

Reviewed-by: hjk
parent 7c9c99dc
......@@ -37,8 +37,10 @@
#include <QtCore/QTemporaryFile>
#include <QtGui/QApplication>
#include <QtGui/QAction>
#include <QtGui/QClipboard>
#include <QtGui/QFontMetrics>
#include <QtGui/QMenu>
#include <QtGui/QPainter>
#include <QtGui/QScrollBar>
#include <QtGui/QWheelEvent>
......@@ -93,6 +95,7 @@ BinEditor::BinEditor(QWidget *parent)
m_lowNibble = false;
m_cursorVisible = false;
m_caseSensitiveSearch = false;
m_canRequestNewWindow = false;
setFocusPolicy(Qt::WheelFocus);
}
......@@ -178,7 +181,8 @@ bool BinEditor::requestDataAt(int pos, bool synchronous) const
if (!m_lazyRequests.contains(block)) {
m_lazyRequests.insert(block);
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))
return true; // synchronous data source
}
......@@ -1119,12 +1123,16 @@ void BinEditor::zoomOut(int range)
zoomIn(-range);
}
void BinEditor::copy()
void BinEditor::copy(bool raw)
{
const int selStart = selectionStart();
const int selEnd = selectionEnd();
if (selStart < selEnd) {
const QByteArray &data = dataMid(selStart, selEnd - selStart);
if (raw) {
QApplication::clipboard()->setText(data);
return;
}
QString hexString;
const char * const hex = "0123456789abcdef";
for (int i = 0; i < data.size(); ++i) {
......@@ -1217,3 +1225,81 @@ void BinEditor::redo()
if (!m_redoStack.size())
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;
}
......@@ -40,6 +40,8 @@
#include <QtGui/QTextDocument>
#include <QtGui/QTextFormat>
QT_FORWARD_DECLARE_CLASS(QMenu)
namespace Core {
class IEditor;
}
......@@ -69,6 +71,7 @@ public:
Q_INVOKABLE void setLazyData(quint64 startAddr, int range, int blockSize = 4096);
inline int lazyDataBlockSize() const { return m_blockSize; }
Q_INVOKABLE void addLazyData(quint64 block, const QByteArray &data);
Q_INVOKABLE void setNewWindowRequestAllowed();
bool save(const QString &oldFileName, const QString &newFileName);
void zoomIn(int range = 1);
......@@ -116,7 +119,7 @@ public:
public Q_SLOTS:
void setFontSettings(const TextEditor::FontSettings &fs);
void highlightSearchResults(const QByteArray &pattern, QTextDocument::FindFlags findFlags = 0);
void copy();
void copy(bool raw = false);
Q_SIGNALS:
void modificationChanged(bool modified);
......@@ -125,7 +128,8 @@ Q_SIGNALS:
void copyAvailable(bool);
void cursorPositionChanged(int position);
void lazyDataRequested(quint64 block, bool synchronous);
void lazyDataRequested(Core::IEditor *editor, quint64 block, bool synchronous);
void newWindowRequested(quint64 address);
protected:
void scrollContentsBy(int dx, int dy);
......@@ -140,6 +144,7 @@ protected:
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
void timerEvent(QTimerEvent *);
void contextMenuEvent(QContextMenuEvent *event);
private:
bool m_inLazyMode;
......@@ -203,6 +208,9 @@ private:
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 setupJumpToMenuAction(QMenu *menu, QAction *actionHere, QAction *actionNew,
quint64 addr);
struct BinEditorEditCommand {
int position;
uchar character;
......@@ -214,6 +222,7 @@ private:
Core::IEditor *m_ieditor;
QString m_addressString;
int m_addressBytes;
bool m_canRequestNewWindow;
};
} // namespace BINEditor
......
......@@ -174,7 +174,8 @@ public:
m_mimeType(QLatin1String(BINEditor::Constants::C_BINEDITOR_MIMETYPE))
{
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() {}
......@@ -211,7 +212,7 @@ public:
}
private slots:
void provideData(quint64 block) {
void provideData(Core::IEditor *, quint64 block) {
QFile file(m_fileName);
if (file.open(QIODevice::ReadOnly)) {
int blockSize = m_editor->lazyDataBlockSize();
......
......@@ -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)
return;
......@@ -1149,7 +1149,7 @@ void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 l
}
if (received < length)
data.truncate(received);
agent->addLazyData(addr, data);
agent->addLazyData(token, addr, data);
}
void CdbDebugEngine::reloadModules()
......
......@@ -90,7 +90,7 @@ public:
virtual void attemptBreakpointSynchronization();
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 loadSymbols(const QString &moduleName);
......
......@@ -72,35 +72,41 @@ namespace Internal {
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
: QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
init(addr);
createBinEditor(addr);
}
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
: QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
bool ok = true;
init(addr.toULongLong(&ok, 0));
createBinEditor(addr.toULongLong(&ok, 0));
//qDebug() << " ADDRESS: " << addr << addr.toUInt(&ok, 0);
}
MemoryViewAgent::~MemoryViewAgent()
{
if (m_editor)
m_editor->deleteLater();
foreach (QPointer<Core::IEditor> editor, m_editors) {
if (editor)
editor->deleteLater();
}
}
void MemoryViewAgent::init(quint64 addr)
void MemoryViewAgent::createBinEditor(quint64 addr)
{
Core::EditorManager *editorManager = Core::EditorManager::instance();
QString titlePattern = tr("Memory $");
m_editor = editorManager->openEditorWithContents(
Core::IEditor *editor = editorManager->openEditorWithContents(
Core::Constants::K_DEFAULT_BINARY_EDITOR_ID,
&titlePattern);
if (m_editor) {
connect(m_editor->widget(), SIGNAL(lazyDataRequested(quint64,bool)),
this, SLOT(fetchLazyData(quint64,bool)));
editorManager->activateEditor(m_editor);
QMetaObject::invokeMethod(m_editor->widget(), "setLazyData",
if (editor) {
connect(editor->widget(), SIGNAL(lazyDataRequested(Core::IEditor *, quint64,bool)),
this, SLOT(fetchLazyData(Core::IEditor *, quint64,bool)));
connect(editor->widget(), SIGNAL(newWindowRequested(quint64)),
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));
} else {
m_manager->showMessageBox(QMessageBox::Warning,
......@@ -111,18 +117,22 @@ 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
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())
QMetaObject::invokeMethod(m_editor->widget(), "addLazyData",
Core::IEditor *editor = qobject_cast<Core::IEditor *>(editorToken);
if (editor && editor->widget()) {
Core::EditorManager::instance()->activateEditor(editor);
QMetaObject::invokeMethod(editor->widget(), "addLazyData",
Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
}
}
......
......@@ -37,6 +37,7 @@
#include <QtCore/QObject>
#include <QtCore/QDebug>
#include <QtCore/QList>
#include <QtCore/QPointer>
#include <QtGui/QAction>
......@@ -61,15 +62,15 @@ public:
public slots:
// Called from Engine
void addLazyData(quint64 addr, const QByteArray &data);
void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
// Called from Editor
void fetchLazyData(quint64 block, bool sync);
void fetchLazyData(Core::IEditor *, quint64 block, bool sync);
private:
void init(quint64 startaddr);
Q_SLOT void createBinEditor(quint64 startAddr);
QPointer<IDebuggerEngine> m_engine;
QPointer<Core::IEditor> m_editor;
QList<QPointer<Core::IEditor> > m_editors;
QPointer<DebuggerManager> m_manager;
};
......
......@@ -3542,21 +3542,23 @@ void GdbEngine::handleWatchPoint(const GdbResponse &response)
struct MemoryAgentCookie
{
MemoryAgentCookie() : agent(0), address(0) {}
MemoryAgentCookie(MemoryViewAgent *agent_, quint64 address_)
: agent(agent_), address(address_)
MemoryAgentCookie() : agent(0), token(0), address(0) {}
MemoryAgentCookie(MemoryViewAgent *agent_, QObject *token_, quint64 address_)
: agent(agent_), token(token_), address(address_)
{}
QPointer<MemoryViewAgent> agent;
QPointer<QObject> token;
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;
postCommand("-data-read-memory " + QByteArray::number(addr) + " x 1 1 "
+ QByteArray::number(length),
NeedsStop, CB(handleFetchMemory),
QVariant::fromValue(MemoryAgentCookie(agent, addr)));
QVariant::fromValue(MemoryAgentCookie(agent, token, addr)));
}
void GdbEngine::handleFetchMemory(const GdbResponse &response)
......@@ -3581,7 +3583,7 @@ void GdbEngine::handleFetchMemory(const GdbResponse &response)
QTC_ASSERT(ok, return);
ba.append(c);
}
ac.agent->addLazyData(ac.address, ba);
ac.agent->addLazyData(ac.token, ac.address, ba);
}
......
......@@ -428,7 +428,8 @@ private: ////////// View & Data Stuff //////////
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);
virtual void watchPoint(const QPoint &);
......
......@@ -112,7 +112,7 @@ public:
virtual void reloadFullStack() = 0;
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); }
virtual void fetchDisassembler(DisassemblerViewAgent *) {}
virtual void setRegisterValue(int regnr, const QString &value)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment