diff --git a/src/plugins/bineditor/bineditor.cpp b/src/plugins/bineditor/bineditor.cpp index cc82aac138a54198213a33aa3e8d18254b0d148b..4046ab6a076641b75f3fbc36cf63d5112b5893ba 100644 --- a/src/plugins/bineditor/bineditor.cpp +++ b/src/plugins/bineditor/bineditor.cpp @@ -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(©AsciiAction); + contextMenu.addAction(©HexAction); + 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 == ©AsciiAction) + copy(true); + else if (action == ©HexAction) + 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; +} diff --git a/src/plugins/bineditor/bineditor.h b/src/plugins/bineditor/bineditor.h index bc62df085f37c05d5869aa681998774dd1fe136c..105ce4c42a24c3db86a26e229dc804a77f8cba5c 100644 --- a/src/plugins/bineditor/bineditor.h +++ b/src/plugins/bineditor/bineditor.h @@ -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 diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 4faeccf10aa6b9503fc166abf8fbeb8fe6ea880a..fe7f3f489a92b7d31c0b7f17586f6f0deaa127de 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -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(); diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 2231a5c259c0845d399400920c2cd4bdd3e84441..5869de1660e0da67a57915bab540954b370ec613 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -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() diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 9265ce757f2ae205915e3880bf9cd5402d1c3898..d6f6bebb0198ffd8f17996c66c5a4d3a8379b5c6 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -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); diff --git a/src/plugins/debugger/debuggeragents.cpp b/src/plugins/debugger/debuggeragents.cpp index 7874c204dd347b0734629b033f838325ebce2817..49559ea2a084ea5df01df15c06225688f652e60f 100644 --- a/src/plugins/debugger/debuggeragents.cpp +++ b/src/plugins/debugger/debuggeragents.cpp @@ -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)); + } } diff --git a/src/plugins/debugger/debuggeragents.h b/src/plugins/debugger/debuggeragents.h index 63d3e7ba238f29083efcca36f6e21bdcbf5c5dd3..d34f4702203536cc0bd33cfde153d6c319167e1d 100644 --- a/src/plugins/debugger/debuggeragents.h +++ b/src/plugins/debugger/debuggeragents.h @@ -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; }; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 14f8b65a058c448c0ea4c1b3432fc8858fe34c7b..a169b9df4a08320d6f448224d90810e27959ad37 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -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); } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 479a6d64b3e25b3ef9aefb8b54c39bb8a06c00a0..46234eeff7acb2c11daf9d09d6a34a0b28cc3944 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -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 &); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 6409ae5cb9569f2c7feec39fabe0be93fd768d3e..7756c6ee37f28a09609ab2637acce13eabf26f6f 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -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)