diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 6b86696c0a58cf86cbc2bd540dcd739bf9d7250c..e0a84f9648fe7e4eed899e1cbb8fde6860ff895a 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -227,7 +227,6 @@ DebuggerSettings *DebuggerSettings::instance() item->setText(tr("Synchronize breakpoints")); instance->insertItem(SynchronizeBreakpoints, item); - // // Settings // diff --git a/src/plugins/debugger/debuggeragents.cpp b/src/plugins/debugger/debuggeragents.cpp index c7b0e4befee8f356ec6d359cd7e86e42be4f94e3..d00bc5cf398ab98ac83131cf346dee39b765238d 100644 --- a/src/plugins/debugger/debuggeragents.cpp +++ b/src/plugins/debugger/debuggeragents.cpp @@ -75,6 +75,7 @@ MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr) { bool ok = true; init(addr.toUInt(&ok, 0)); + //qDebug() << " ADDRESS: " << addr << addr.toUInt(&ok, 0); } MemoryViewAgent::~MemoryViewAgent() diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 2c6f6b78b7c92292008981dde5bc3b92a310de89..f8cd042b50106feada599b6d282595507e9d8169 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -88,7 +88,6 @@ // of the engine. using namespace Debugger::Internal; -IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *); IDebuggerEngine *createWinEngine(DebuggerManager *, bool /* cmdLineEnabled */, QList<Core::IOptionsPage*> *) #ifdef CDB_ENABLED ; @@ -102,6 +101,8 @@ IDebuggerEngine *createTcfEngine(DebuggerManager *parent, QList<Core::IOptionsPa namespace Debugger { namespace Internal { +IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *); + QDebug operator<<(QDebug str, const DebuggerStartParameters &p) { QDebug nospace = str.nospace(); @@ -1430,6 +1431,12 @@ void DebuggerManager::reloadFullStack() m_engine->reloadFullStack(); } +void DebuggerManager::setRegisterValue(int nr, const QString &value) +{ + if (m_engine) + m_engine->setRegisterValue(nr, value); +} + bool DebuggerManager::isReverseDebugging() const { return m_reverseDirectionAction->isChecked(); @@ -1448,7 +1455,6 @@ void DebuggerManager::setSessionValue(const QString &name, const QVariant &value emit setSessionValueRequested(name, value); } - ////////////////////////////////////////////////////////////////////// // // Testing diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index ab5f1e06104153e180c9de849cdeac34e0801935..de2a192abd1a3258cb481c36571a05a029c6cf8e 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -319,6 +319,7 @@ public slots: void executeDebuggerCommand(const QString &command); void watchPoint(); + void setRegisterValue(int nr, const QString &value); void showStatusMessage(const QString &msg, int timeout = -1); // -1 forever diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 55aa3125a6f568d4a6ec844a101c8ec09c36cdd6..0e8dcf448b17fd3d333af3f1b2651dcc0a2b8858 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -78,12 +78,10 @@ #endif #include <ctype.h> -using namespace Debugger; -using namespace Debugger::Internal; +namespace Debugger { +namespace Internal { using namespace Debugger::Constants; -Q_DECLARE_METATYPE(Debugger::Internal::GdbMi); - //#define DEBUG_PENDING 1 //#define DEBUG_SUBITEM 1 @@ -1721,13 +1719,6 @@ void GdbEngine::handleAttach(const GdbResultRecord &, const QVariant &) if (supportsThreads()) postCommand(_("-thread-list-ids"), WatchUpdate, CB(handleStackListThreads), 0); - // - // Disassembler - // - // XXX we have no data here ... - //m_address = data.findChild("frame").findChild("addr").data(); - //qq->reloadDisassembler(); - // // Registers // @@ -2583,6 +2574,20 @@ void GdbEngine::reloadRegisters() Discardable, CB(handleRegisterListValues)); } +void GdbEngine::setRegisterValue(int nr, const QString &value) +{ + Register reg = qq->registerHandler()->registers().at(nr); + //qDebug() << "NOT IMPLEMENTED: CHANGE REGISTER " << nr << reg.name << ":" + // << value; + postCommand(_("-var-delete \"R@\"")); + postCommand(_("-var-create \"R@\" * $%1").arg(reg.name)); + postCommand(_("-var-assign \"R@\" %1").arg(value)); + postCommand(_("-var-delete \"R@\"")); + //postCommand(_("-data-list-register-values d"), + // Discardable, CB(handleRegisterListValues)); + reloadRegisters(); +} + void GdbEngine::handleRegisterListNames(const GdbResultRecord &record, const QVariant &) { if (record.resultClass != GdbResultDone) @@ -3926,16 +3931,23 @@ void GdbEngine::handleWatchPoint(const GdbResultRecord &record, const QVariant & } } -static QVariant agentCookie(void *agent) + +struct MemoryAgentCookie { - return QVariant(quint64(quintptr(agent))); -} + MemoryAgentCookie() : agent(0), address(0) {} + MemoryAgentCookie(MemoryViewAgent *agent_, quint64 address_) + : agent(agent_), address(address_) + {} + MemoryViewAgent *agent; + quint64 address; +}; void GdbEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length) { - //qDebug() << "GDB MEMORY FETCH" << addr << length; + //qDebug() << "GDB MEMORY FETCH" << agent << addr << length; postCommand(_("-data-read-memory %1 x 1 1 %2").arg(addr).arg(length), - NeedsStop, CB(handleFetchMemory), agentCookie(agent)); + NeedsStop, CB(handleFetchMemory), + QVariant::fromValue(MemoryAgentCookie(agent, addr))); } void GdbEngine::handleFetchMemory(const GdbResultRecord &record, @@ -3945,27 +3957,34 @@ void GdbEngine::handleFetchMemory(const GdbResultRecord &record, // next-row="0x08910c98",prev-row="0x08910c78",next-page="0x08910c98", // prev-page="0x08910c78",memory=[{addr="0x08910c88", // data=["1","0","0","0","5","0","0","0","0","0","0","0","0","0","0","0"]}] - bool ok = true; - MemoryViewAgent *agent = (MemoryViewAgent *)cookie.toULongLong(&ok); - QTC_ASSERT(ok, return); - QTC_ASSERT(agent, return); + MemoryAgentCookie ac = cookie.value<MemoryAgentCookie>(); + QTC_ASSERT(ac.agent, return); QByteArray ba; GdbMi memory = record.data.findChild("memory"); QTC_ASSERT(memory.children().size() <= 1, return); + if (memory.children().isEmpty()) + return; GdbMi memory0 = memory.children().at(0); // we asked for only one 'row' - quint64 addr = memory0.findChild("addr").data().toULongLong(&ok, 0); - QTC_ASSERT(ok, return); GdbMi data = memory0.findChild("data"); foreach (const GdbMi &child, data.children()) { + bool ok = true; unsigned char c = child.data().toUInt(&ok, 0); QTC_ASSERT(ok, return); ba.append(c); } - //qDebug() << "GDB READ MEMORY" << agent << addr << data.data() << ba.size(); - agent->addLazyData(addr, ba); + ac.agent->addLazyData(ac.address, ba); } +struct DisassemblerAgentCookie +{ + DisassemblerAgentCookie() : agent(0) {} + DisassemblerAgentCookie(DisassemblerViewAgent *agent_) + : agent(agent_) + {} + DisassemblerViewAgent *agent; +}; + void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent, const StackFrame &frame) { @@ -3975,7 +3994,8 @@ void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent, // Disassemble full function: QString cmd = _("-data-disassemble -f %1 -l %2 -n -1 -- 1"); postCommand(cmd.arg(frame.file).arg(frame.line), - Discardable, CB(handleFetchDisassemblerByLine), agentCookie(agent)); + Discardable, CB(handleFetchDisassemblerByLine), + QVariant::fromValue(DisassemblerAgentCookie(agent))); } } @@ -3991,10 +4011,12 @@ void GdbEngine::fetchDisassemblerByAddress(DisassemblerViewAgent *agent, // | [ -f filename -l linenum [ -n lines ] ] -- mode if (useMixedMode) postCommand(_("-data-disassemble -s %1 -e %2 -- 1").arg(start).arg(end), - Discardable, CB(handleFetchDisassemblerByAddress1), agentCookie(agent)); + Discardable, CB(handleFetchDisassemblerByAddress1), + QVariant::fromValue(DisassemblerAgentCookie(agent))); else postCommand(_("-data-disassemble -s %1 -e %2 -- 0").arg(start).arg(end), - Discardable, CB(handleFetchDisassemblerByAddress0), agentCookie(agent)); + Discardable, CB(handleFetchDisassemblerByAddress0), + QVariant::fromValue(DisassemblerAgentCookie(agent))); } static QByteArray parseLine(const GdbMi &line) @@ -4060,37 +4082,35 @@ static QString parseDisassembler(const GdbMi &lines) void GdbEngine::handleFetchDisassemblerByLine(const GdbResultRecord &record, const QVariant &cookie) { - bool ok = true; - DisassemblerViewAgent *agent = (DisassemblerViewAgent *)cookie.toULongLong(&ok); - QTC_ASSERT(agent, return); + DisassemblerAgentCookie ac = cookie.value<DisassemblerAgentCookie>(); + QTC_ASSERT(ac.agent, return); if (record.resultClass == GdbResultDone) { GdbMi lines = record.data.findChild("asm_insns"); if (lines.children().isEmpty()) - fetchDisassemblerByAddress(agent, true); + fetchDisassemblerByAddress(ac.agent, true); else - agent->setContents(parseDisassembler(lines)); + ac.agent->setContents(parseDisassembler(lines)); } else if (record.resultClass == GdbResultError) { //536^error,msg="mi_cmd_disassemble: Invalid line number" QByteArray msg = record.data.findChild("msg").data(); if (msg == "mi_cmd_disassemble: Invalid line number") - fetchDisassemblerByAddress(agent, true); + fetchDisassemblerByAddress(ac.agent, true); } } void GdbEngine::handleFetchDisassemblerByAddress1(const GdbResultRecord &record, const QVariant &cookie) { - bool ok = true; - DisassemblerViewAgent *agent = (DisassemblerViewAgent *)cookie.toULongLong(&ok); - QTC_ASSERT(agent, return); + DisassemblerAgentCookie ac = cookie.value<DisassemblerAgentCookie>(); + QTC_ASSERT(ac.agent, return); if (record.resultClass == GdbResultDone) { GdbMi lines = record.data.findChild("asm_insns"); if (lines.children().isEmpty()) - fetchDisassemblerByAddress(agent, false); + fetchDisassemblerByAddress(ac.agent, false); else - agent->setContents(parseDisassembler(lines)); + ac.agent->setContents(parseDisassembler(lines)); } } @@ -4107,9 +4127,16 @@ void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResultRecord &record, } } - IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *opts) { opts->push_back(new GdbOptionsPage); return new GdbEngine(parent); } + +} // namespace Internal +} // namespace Debugger + +Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgentCookie); +Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgentCookie); +Q_DECLARE_METATYPE(Debugger::Internal::GdbMi); + diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 820c507bba25125bfeab8022149dea1d5b1450e0..e9a2b41a92f84d5748a4df4b83a28c675a258fe9 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -299,6 +299,7 @@ private: // Register specific stuff // Q_SLOT void reloadRegisters(); + void setRegisterValue(int nr, const QString &value); void handleRegisterListNames(const GdbResultRecord &record, const QVariant &); void handleRegisterListValues(const GdbResultRecord &record, const QVariant &); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index abfacb97463667a9ded822ce5f914608f113b048..89ff30293195d52270afbb7a3e891f5777719720 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -98,8 +98,9 @@ public: virtual void watchPoint(const QPoint &) {} virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length) { Q_UNUSED(addr); Q_UNUSED(length); } - virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame & /* frame */) - { } + virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame &) {} + virtual void setRegisterValue(int regnr, const QString &value) + { Q_UNUSED(regnr); Q_UNUSED(value); } }; } // namespace Internal diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 2cc7772c880f212164421aa1a68d2e8780a2b7f6..6419bbf2b8acb292ef8a1b1df51c2e9de4eba8d3 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -50,8 +50,9 @@ using namespace Debugger::Constants; ////////////////////////////////////////////////////////////////// RegisterHandler::RegisterHandler(QObject *parent) - : QAbstractTableModel(parent), m_base(16) + : QAbstractTableModel(parent) { + setNumberBase(16); } int RegisterHandler::rowCount(const QModelIndex &parent) const @@ -68,7 +69,7 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const { static const QVariant red = QColor(200, 0, 0); - if (role == Qt::UserRole) + if (role == RegisterNumberBaseRole) return m_base; if (!index.isValid() || index.row() >= m_registers.size()) @@ -76,7 +77,7 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const const Register ® = m_registers.at(index.row()); - if (role == Qt::UserRole + 1) { + if (role == RegisterAddressRole) { // return some address associated with the register bool ok = true; qulonglong value = reg.value.toULongLong(&ok, 0); @@ -90,7 +91,8 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const case 1: { bool ok = true; qulonglong value = reg.value.toULongLong(&ok, 0); - return ok ? padding + QString::number(value, m_base) + padding : reg.value; + QString res = ok ? QString::number(value, m_base) : reg.value; + return QString(m_strlen - res.size(), QLatin1Char(' ')) + res; } } } @@ -116,6 +118,26 @@ QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation, return QVariant(); } +Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const +{ + using namespace Qt; + + if (!idx.isValid()) + return ItemFlags(); + + static const ItemFlags notEditable = + ItemIsSelectable + | ItemIsDragEnabled + | ItemIsDropEnabled + | ItemIsEnabled; + + static const ItemFlags editable = notEditable | ItemIsEditable; + + if (idx.column() == 1) + return editable; // locals and watcher values are editable + return notEditable; +} + void RegisterHandler::removeAll() { m_registers.clear(); @@ -141,5 +163,6 @@ QList<Register> RegisterHandler::registers() const void RegisterHandler::setNumberBase(int base) { m_base = base; + m_strlen = (base == 2 ? 64 : base == 8 ? 32 : base == 10 ? 26 : 16); emit reset(); } diff --git a/src/plugins/debugger/registerhandler.h b/src/plugins/debugger/registerhandler.h index f16723884078cb3685282405262fa158b86817eb..c2766dd64665fa25511f7f0c64c3ceb9488d2807 100644 --- a/src/plugins/debugger/registerhandler.h +++ b/src/plugins/debugger/registerhandler.h @@ -35,6 +35,12 @@ namespace Debugger { namespace Internal { +enum RegisterRole +{ + RegisterNumberBaseRole = Qt::UserRole, // Currently used number base + RegisterAddressRole // Start value for opening memory view +}; + class Register { public: @@ -68,9 +74,11 @@ private: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + Qt::ItemFlags flags(const QModelIndex &idx) const; QList<Register> m_registers; int m_base; + int m_strlen; // approximate width of an value in chars }; } // namespace Internal diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp index 2a8fd34437389d6cdb51daa7c8755acdc8112526..baf9ff0802cf36a0c0a97435829e2cb0dc1962ac 100644 --- a/src/plugins/debugger/registerwindow.cpp +++ b/src/plugins/debugger/registerwindow.cpp @@ -28,11 +28,14 @@ **************************************************************************/ #include "registerwindow.h" +#include "registerhandler.h" #include "debuggeractions.h" #include "debuggeragents.h" #include "debuggerconstants.h" +#include <utils/qtcassert.h> + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFileInfo> @@ -40,13 +43,99 @@ #include <QtGui/QAction> #include <QtGui/QHeaderView> +#include <QtGui/QItemDelegate> +#include <QtGui/QLineEdit> #include <QtGui/QMenu> +#include <QtGui/QPainter> #include <QtGui/QResizeEvent> #include <QtGui/QToolButton> -using namespace Debugger::Internal; -using namespace Debugger::Constants; +namespace Debugger { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// RegisterDelegate +// +/////////////////////////////////////////////////////////////////////// + +class RegisterDelegate : public QItemDelegate +{ +public: + RegisterDelegate(DebuggerManager *manager, QObject *parent) + : QItemDelegate(parent), m_manager(manager) + {} + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &) const + { + QLineEdit *lineEdit = new QLineEdit(parent); + lineEdit->setAlignment(Qt::AlignRight); + return lineEdit; + } + + void setEditorData(QWidget *editor, const QModelIndex &index) const + { + QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor); + QTC_ASSERT(lineEdit, return); + lineEdit->setText(index.model()->data(index, Qt::DisplayRole).toString()); + } + + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const + { + Q_UNUSED(model); + //qDebug() << "SET MODEL DATA"; + QLineEdit *lineEdit = qobject_cast<QLineEdit*>(editor); + QTC_ASSERT(lineEdit, return); + QString value = lineEdit->text(); + //model->setData(index, value, Qt::EditRole); + if (index.column() == 1) + m_manager->setRegisterValue(index.row(), value); + } + + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, + const QModelIndex &) const + { + editor->setGeometry(option.rect); + } + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const + { + if (index.column() == 1) { + // FIXME: performance? this changes only on real font changes. + QFontMetrics fm(option.font); + int charWidth = fm.width(QLatin1Char('x')); + for (int i = '1'; i <= '9'; ++i) + charWidth = qMax(charWidth, fm.width(QLatin1Char(i))); + for (int i = 'a'; i <= 'f'; ++i) + charWidth = qMax(charWidth, fm.width(QLatin1Char(i))); + QString str = index.model()->data(index, Qt::DisplayRole).toString(); + int x = option.rect.x(); + for (int i = 0; i < str.size(); ++i) { + QRect r = option.rect; + r.setX(x); + r.setWidth(charWidth); + x += charWidth; + painter->drawText(r, Qt::AlignHCenter, QString(str.at(i))); + } + } else { + QItemDelegate::paint(painter, option, index); + } + } + +private: + DebuggerManager *m_manager; +}; + + +/////////////////////////////////////////////////////////////////////// +// +// RegisterWindow +// +/////////////////////////////////////////////////////////////////////// RegisterWindow::RegisterWindow(DebuggerManager *manager) : m_manager(manager), m_alwaysResizeColumnsToContents(true), @@ -57,6 +146,7 @@ RegisterWindow::RegisterWindow(DebuggerManager *manager) setSortingEnabled(true); setAlternatingRowColors(act->isChecked()); setRootIsDecorated(false); + setItemDelegate(new RegisterDelegate(m_manager, this)); connect(act, SIGNAL(toggled(bool)), this, SLOT(setAlternatingRowColorsHelper(bool))); @@ -84,7 +174,7 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addSeparator(); QModelIndex idx = indexAt(ev->pos()); - QString address = model()->data(idx, Qt::UserRole + 1).toString(); + QString address = model()->data(idx, RegisterAddressRole).toString(); QAction *actShowMemory = menu.addAction(QString()); if (address.isEmpty()) { actShowMemory->setText(tr("Open memory editor")); @@ -94,7 +184,7 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) } menu.addSeparator(); - int base = model()->data(QModelIndex(), Qt::UserRole).toInt(); + int base = model()->data(QModelIndex(), RegisterNumberBaseRole).toInt(); QAction *act16 = menu.addAction(tr("Hexadecimal")); act16->setCheckable(true); act16->setChecked(base == 16); @@ -112,7 +202,7 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); - + if (act == actAdjust) resizeColumnsToContents(); else if (act == actAlwaysAdjust) @@ -162,4 +252,6 @@ void RegisterWindow::setModel(QAbstractItemModel *model) QTreeView::setModel(model); setAlwaysResizeColumnsToContents(true); } - + +} // namespace Internal +} // namespace Debugger