From 3743211e547ebaa4d6046e018492cf803a4ed018 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 17 Dec 2014 13:14:29 +0100 Subject: [PATCH] Debugger: Rework register handling Use register names as handle, not their index in the view. Store the raw real values, not some stringified version as primary data. Use subentries to break down bigger registers into smaller entities. Also remember the previous value of a register and show it in a tooltip. Change-Id: I8ae3cc8766a7b211bc7cc827c734e5cf6060825c Reviewed-by: Christian Stenger Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 1 + src/libs/qtcreatorcdbext/gdbmihelpers.cpp | 30 + src/libs/qtcreatorcdbext/gdbmihelpers.h | 1 + src/plugins/debugger/cdb/cdbengine.cpp | 37 +- src/plugins/debugger/cdb/cdbengine.h | 2 +- src/plugins/debugger/debuggerengine.cpp | 10 +- src/plugins/debugger/debuggerengine.h | 9 +- src/plugins/debugger/debuggerplugin.cpp | 7 +- src/plugins/debugger/gdb/gdbengine.cpp | 147 +++- src/plugins/debugger/gdb/gdbengine.h | 5 +- src/plugins/debugger/lldb/lldbengine.cpp | 14 +- src/plugins/debugger/lldb/lldbengine.h | 2 +- src/plugins/debugger/memoryagent.cpp | 41 +- src/plugins/debugger/memoryagent.h | 25 +- src/plugins/debugger/memoryview.cpp | 39 +- src/plugins/debugger/memoryview.h | 16 +- src/plugins/debugger/qml/qmlcppengine.cpp | 4 +- src/plugins/debugger/qml/qmlcppengine.h | 2 +- src/plugins/debugger/registerhandler.cpp | 952 +++++++++++----------- src/plugins/debugger/registerhandler.h | 99 ++- src/plugins/debugger/registerwindow.cpp | 98 +-- src/plugins/debugger/stackwindow.cpp | 11 +- src/plugins/debugger/watchwindow.cpp | 74 +- 23 files changed, 881 insertions(+), 745 deletions(-) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 24fada5172e..8b398c7cbb9 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -1193,6 +1193,7 @@ class Dumper(DumperBase): for reg in group: result += '{name="%s"' % reg.GetName() result += ',value="%s"' % reg.GetValue() + result += ',size="%s"' % reg.GetByteSize() result += ',type="%s"},' % reg.GetType() result += ']' self.report(result) diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp index 2b2f043ab21..c6b0fbbeee0 100644 --- a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp +++ b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp @@ -364,6 +364,34 @@ const wchar_t *valueType(ULONG type) return L""; } +// Description of a DEBUG_VALUE type field +const int valueSize(ULONG type) +{ + switch (type) { + case DEBUG_VALUE_INT8: + return 1; + case DEBUG_VALUE_INT16: + return 2; + case DEBUG_VALUE_INT32: + return 4; + case DEBUG_VALUE_INT64: + return 8; + case DEBUG_VALUE_FLOAT32: + return 4; + case DEBUG_VALUE_FLOAT64: + return 8; + case DEBUG_VALUE_FLOAT80: + return 10; + case DEBUG_VALUE_FLOAT128: + return 16; + case DEBUG_VALUE_VECTOR64: + return 8; + case DEBUG_VALUE_VECTOR128: + return 16; + } + return 0; +} + // Format a 128bit vector register by adding digits in reverse order void formatVectorRegister(std::ostream &str, const unsigned char *array, int size) { @@ -421,6 +449,7 @@ void formatDebugValue(std::ostream &str, const DEBUG_VALUE &dv, CIDebugControl * Register::Register() : subRegister(false), pseudoRegister(false) { + size = 0; value.Type = DEBUG_VALUE_INT32; value.I32 = 0; } @@ -497,6 +526,7 @@ Registers getRegisters(CIDebugRegisters *regs, reg.pseudoRegister = true; reg.name = buf; reg.description = valueType(type); + reg.size = valueSize(type); reg.value = value; rc.push_back(reg); } diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.h b/src/libs/qtcreatorcdbext/gdbmihelpers.h index 056991b3c2a..a047defb631 100644 --- a/src/libs/qtcreatorcdbext/gdbmihelpers.h +++ b/src/libs/qtcreatorcdbext/gdbmihelpers.h @@ -129,6 +129,7 @@ struct Register std::wstring name; std::wstring description; + int size; bool subRegister; bool pseudoRegister; DEBUG_VALUE value; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 19f072808c4..9f2474abf08 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1235,14 +1235,12 @@ void CdbEngine::executeRunToFunction(const QString &functionName) continueInferior(); } -void CdbEngine::setRegisterValue(int regnr, const QString &value) +void CdbEngine::setRegisterValue(const QByteArray &name, const QString &value) { - const Registers registers = registerHandler()->registers(); - QTC_ASSERT(regnr < registers.size(), return); // Value is decimal or 0x-hex-prefixed QByteArray cmd; ByteArrayInputStream str(cmd); - str << "r " << registers.at(regnr).name << '=' << value; + str << "r " << name << '=' << value; postCommand(cmd, 0); reloadRegisters(); } @@ -1854,21 +1852,6 @@ void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply) } } -// Parse CDB gdbmi register syntax. -static Register parseRegister(const GdbMi &gdbmiReg) -{ - Register reg; - reg.name = gdbmiReg["name"].data(); - const GdbMi description = gdbmiReg["description"]; - if (description.type() != GdbMi::Invalid) { - reg.name += " ("; - reg.name += description.data(); - reg.name += ')'; - } - reg.value = gdbmiReg["value"].data(); - return reg; -} - void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply) { if (reply->success) { @@ -1906,11 +1889,17 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply) GdbMi value; value.fromString(reply->reply); if (value.type() == GdbMi::List) { - Registers registers; - registers.reserve(value.childCount()); - foreach (const GdbMi &gdbmiReg, value.children()) - registers.push_back(parseRegister(gdbmiReg)); - registerHandler()->setAndMarkRegisters(registers); + RegisterHandler *handler = registerHandler(); + foreach (const GdbMi &item, value.children()) { + Register reg; + reg.name = item["name"].data(); + reg.description = item["description"].data(); + reg.reportedType = item["type"].data(); + reg.value = item["value"].data(); + reg.size = item["size"].data().toInt(); + handler->updateRegister(reg); + } + handler->commitUpdates(); } else { showMessage(QString::fromLatin1("Parse error in registers response."), LogError); qWarning("Parse error in registers response:\n%s", reply->reply.constData()); diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index d259544b75a..b8e6dc38f6b 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -90,7 +90,7 @@ public: const WatchUpdateFlags & flags = WatchUpdateFlags()); virtual bool hasCapability(unsigned cap) const; virtual void watchPoint(const QPoint &); - virtual void setRegisterValue(int regnr, const QString &value); + virtual void setRegisterValue(const QByteArray &name, const QString &value); virtual void executeStep(); virtual void executeStepOut(); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index e89a20a3a8f..78df0bdfa13 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -477,9 +477,9 @@ void DebuggerEngine::changeMemory(MemoryAgent *, QObject *, Q_UNUSED(data); } -void DebuggerEngine::setRegisterValue(int regnr, const QString &value) +void DebuggerEngine::setRegisterValue(const QByteArray &name, const QString &value) { - Q_UNUSED(regnr); + Q_UNUSED(name); Q_UNUSED(value); } @@ -1746,11 +1746,9 @@ void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description Core::AsynchronousMessageBox::information(tr("Exception Triggered"), msg); } -void DebuggerEngine::openMemoryView(quint64 startAddr, unsigned flags, - const QList &ml, const QPoint &pos, - const QString &title, QWidget *parent) +void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data) { - d->m_memoryAgent.createBinEditor(startAddr, flags, ml, pos, title, parent); + d->m_memoryAgent.createBinEditor(data); } void DebuggerEngine::updateMemoryViews() diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 8584a40150b..81197569e68 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -75,7 +75,7 @@ class BreakpointParameters; class QmlAdapter; class QmlCppEngine; class DebuggerToolTipContext; -class MemoryMarkup; +class MemoryViewSetupData; struct WatchUpdateFlags { @@ -158,10 +158,7 @@ public: MemoryView = 0x4 //!< Open a separate view (using the pos-parameter). }; - virtual void openMemoryView(quint64 startAddr, unsigned flags, - const QList &ml, - const QPoint &pos, - const QString &title = QString(), QWidget *parent = 0); + virtual void openMemoryView(const MemoryViewSetupData &data); virtual void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length); virtual void changeMemory(Internal::MemoryAgent *, QObject *, @@ -185,7 +182,7 @@ public: virtual void loadAdditionalQmlStack(); virtual void reloadDebuggingHelpers(); - virtual void setRegisterValue(int regnr, const QString &value); + virtual void setRegisterValue(const QByteArray &name, const QString &value); virtual void addOptionPages(QList *) const; virtual bool hasCapability(unsigned cap) const = 0; virtual void debugLastCommand() {} diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 4c44ac87235..3e7b490bbaf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3356,8 +3356,11 @@ bool isDockVisible(const QString &objectName) void openMemoryEditor() { AddressDialog dialog; - if (dialog.exec() == QDialog::Accepted) - currentEngine()->openMemoryView(dialog.address(), 0, QList(), QPoint()); + if (dialog.exec() == QDialog::Accepted) { + MemoryViewSetupData data; + data.startAddress = dialog.address(); + currentEngine()->openMemoryView(data); + } } void setThreads(const QStringList &list, int index) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 64933c77019..1231a650704 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -78,11 +78,11 @@ #include #include +#include #include -#include - #include #include +#include using namespace Core; using namespace ProjectExplorer; @@ -3585,19 +3585,79 @@ void GdbEngine::reloadRegisters() if (state() != InferiorStopOk && state() != InferiorUnrunnable) return; - if (!m_registerNamesListed) { - postCommand("-data-list-register-names", CB(handleRegisterListNames)); - m_registerNamesListed = true; - } - postCommand("-data-list-register-values r", - Discardable, CB(handleRegisterListValues)); + if (true) { + if (!m_registerNamesListed) { + postCommand("-data-list-register-names", CB(handleRegisterListNames)); + m_registerNamesListed = true; + } + // Can cause i386-linux-nat.c:571: internal-error: Got request + // for bad register number 41.\nA problem internal to GDB has been detected. + postCommand("-data-list-register-values r", + Discardable, CB(handleRegisterListValues)); + } else { + postCommand("maintenance print cooked-registers", CB(handleMaintPrintRegisters)); + } } -void GdbEngine::setRegisterValue(int nr, const QString &value) +static QByteArray readWord(const QByteArray &ba, int *pos) { - Register reg = registerHandler()->registers().at(nr); - postCommand("set $" + reg.name + "=" + value.toLatin1()); + const int n = ba.size(); + while (*pos < n && ba.at(*pos) == ' ') + ++*pos; + const int start = *pos; + while (*pos < n && ba.at(*pos) != ' ' && ba.at(*pos) != '\n') + ++*pos; + return ba.mid(start, *pos - start); +} + +void GdbEngine::handleMaintPrintRegisters(const GdbResponse &response) +{ + if (response.resultClass != GdbResultDone) + return; + + const QByteArray &ba = response.consoleStreamOutput; + RegisterHandler *handler = registerHandler(); + //0 1 2 3 4 5 6 + //0123456789012345678901234567890123456789012345678901234567890 + // Name Nr Rel Offset Size Type Raw value + // rax 0 0 0 8 int64_t 0x0000000000000000 + // rip 16 16 128 8 *1 0x0000000000400dc9 + // eflags 17 17 136 4 i386_eflags 0x00000246 + // cs 18 18 140 4 int32_t 0x00000033 + // xmm15 55 55 516 16 vec128 0x00000000000000000000000000000000 + // mxcsr 56 56 532 4 i386_mxcsr 0x00001fa0 + // '' + // st6 30 30 224 10 _i387_ext 0x00000000000000000000 + // st7 31 31 234 10 _i387_ext 0x00000000000000000000 + // fctrl 32 32 244 4 int 0x0000037f + + const int n = ba.size(); + int pos = 0; + while (true) { + // Skip first line, and until '\n' after each line finished. + while (pos < n && ba.at(pos) != '\n') + ++pos; + if (pos >= n) + break; + ++pos; // skip \n + Register reg; + reg.name = readWord(ba, &pos); + if (reg.name == "''" || reg.name == "*1:" || reg.name.isEmpty()) + continue; + readWord(ba, &pos); // Nr + readWord(ba, &pos); // Rel + readWord(ba, &pos); // Offset + reg.size = readWord(ba, &pos).toInt(); + reg.reportedType = readWord(ba, &pos); + reg.value = readWord(ba, &pos); + handler->updateRegister(reg); + } + handler->commitUpdates(); +} +void GdbEngine::setRegisterValue(const QByteArray &name, const QString &value) +{ + postCommand("set $" + name + "=" + value.toLatin1()); reloadRegisters(); } @@ -3608,26 +3668,14 @@ void GdbEngine::handleRegisterListNames(const GdbResponse &response) return; } - Registers registers; - int gdbRegisterNumber = 0, internalIndex = 0; - - // This both handles explicitly having space for all the registers and - // initializes all indices to 0, giving missing registers a sane default - // in the event of something wacky. GdbMi names = response.data["register-names"]; - m_registerNumbers.resize(names.childCount()); + m_registerNames.clear(); + int gdbRegisterNumber = 0; foreach (const GdbMi &item, names.children()) { - // Since we throw away missing registers to eliminate empty rows - // we need to maintain a mapping of GDB register numbers to their - // respective indices in the register list. - if (!item.data().isEmpty()) { - m_registerNumbers[gdbRegisterNumber] = internalIndex++; - registers.append(Register(item.data())); - } - gdbRegisterNumber++; + if (!item.data().isEmpty()) + m_registerNames[gdbRegisterNumber] = item.data(); + ++gdbRegisterNumber; } - - registerHandler()->setRegisters(registers); } void GdbEngine::handleRegisterListValues(const GdbResponse &response) @@ -3635,19 +3683,46 @@ void GdbEngine::handleRegisterListValues(const GdbResponse &response) if (response.resultClass != GdbResultDone) return; - Registers registers = registerHandler()->registers(); - const int registerCount = registers.size(); - const int gdbRegisterCount = m_registerNumbers.size(); - + RegisterHandler *handler = registerHandler(); // 24^done,register-values=[{number="0",value="0xf423f"},...] const GdbMi values = response.data["register-values"]; - QTC_ASSERT(registerCount == values.children().size(), return); foreach (const GdbMi &item, values.children()) { + Register reg; const int number = item["number"].toInt(); - if (number >= 0 && number < gdbRegisterCount) - registers[m_registerNumbers[number]].value = item["value"].data(); + reg.name = m_registerNames[number]; + QByteArray data = item["value"].data(); + if (data.startsWith("0x")) { + reg.value = data; + } else { + // This is what GDB considers machine readable output: + // value="{v4_float = {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + // v2_double = {0x0000000000000000, 0x0000000000000000}, + // v16_int8 = {0x00 }, + // v8_int16 = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + // v4_int32 = {0x00000000, 0x00000000, 0x00000000, 0x00000000}, + // v2_int64 = {0x0000000000000000, 0x0000000000000000}, + // uint128 = }"} + // Try to make sense of it using the int32 chunks: + QByteArray result = "0x"; + const int pos1 = data.indexOf("_int32"); + const int pos2 = data.indexOf('{', pos1) + 1; + const int pos3 = data.indexOf('}', pos2); + QByteArray inner = data.mid(pos2, pos3 - pos2); + QList list = inner.split(','); + for (int i = list.size(); --i >= 0; ) { + QByteArray chunk = list.at(i); + if (chunk.startsWith(' ')) + chunk.remove(0, 1); + if (chunk.startsWith("0x")) + chunk.remove(0, 2); + QTC_ASSERT(chunk.size() == 8, continue); + result.append(chunk); + } + reg.value = result; + } + handler->updateRegister(reg); } - registerHandler()->setAndMarkRegisters(registers); + handler->commitUpdates(); } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 2072092f216..5b4bd4ff57f 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -347,10 +347,11 @@ private: ////////// View & Data Stuff ////////// // Register specific stuff // Q_SLOT void reloadRegisters(); - void setRegisterValue(int nr, const QString &value); + void setRegisterValue(const QByteArray &name, const QString &value); void handleRegisterListNames(const GdbResponse &response); void handleRegisterListValues(const GdbResponse &response); - QVector m_registerNumbers; // Map GDB register numbers to indices + void handleMaintPrintRegisters(const GdbResponse &response); + QHash m_registerNames; // Map GDB register numbers to indices // // Disassembler specific stuff diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index d669c4e016c..57025b50cf9 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -1085,16 +1085,15 @@ void LldbEngine::setStackPosition(int index) void LldbEngine::refreshRegisters(const GdbMi ®isters) { RegisterHandler *handler = registerHandler(); - Registers regs; foreach (const GdbMi &item, registers.children()) { Register reg; reg.name = item["name"].data(); reg.value = item["value"].data(); - //reg.type = item["type"].data(); - regs.append(reg); + reg.size = item["size"].data().toInt(); + reg.reportedType = item["type"].data(); + handler->updateRegister(reg); } - //handler->setRegisters(registers); - handler->setAndMarkRegisters(regs); + handler->commitUpdates(); } void LldbEngine::refreshThreads(const GdbMi &threads) @@ -1250,10 +1249,9 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken, runCommand(cmd); } -void LldbEngine::setRegisterValue(int regnr, const QString &value) +void LldbEngine::setRegisterValue(const QByteArray &name, const QString &value) { - Register reg = registerHandler()->registers().at(regnr); - runCommand(Command("setRegister").arg("name", reg.name).arg("value", value)); + runCommand(Command("setRegister").arg("name", name).arg("value", value)); } diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index cb4ce7fc7b9..491688c57d7 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -143,7 +143,7 @@ private: bool supportsThreads() const { return true; } bool isSynchronous() const { return true; } void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags); - void setRegisterValue(int regnr, const QString &value); + void setRegisterValue(const QByteArray &name, const QString &value); void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length); void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data); diff --git a/src/plugins/debugger/memoryagent.cpp b/src/plugins/debugger/memoryagent.cpp index 2c800ade315..c9668289330 100644 --- a/src/plugins/debugger/memoryagent.cpp +++ b/src/plugins/debugger/memoryagent.cpp @@ -135,15 +135,12 @@ void MemoryAgent::connectBinEditorWidget(QWidget *w) connect(w, SIGNAL(addWatchpointRequested(quint64,uint)), SLOT(handleWatchpointRequest(quint64,uint))); } -bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, - const QList &ml, const QPoint &pos, - QString title, QWidget *parent) +bool MemoryAgent::doCreateBinEditor(const MemoryViewSetupData &data) { - const bool readOnly = (flags & DebuggerEngine::MemoryReadOnly) != 0; - if (title.isEmpty()) - title = tr("Memory at 0x%1").arg(addr, 0, 16); + const bool readOnly = (data.flags & DebuggerEngine::MemoryReadOnly) != 0; + QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title; // Separate view? - if (flags & DebuggerEngine::MemoryView) { + if (data.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::getObjectByClassName(QLatin1String("BinEditor::BinEditorWidgetFactory"))) @@ -155,24 +152,22 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, 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; + if (data.flags & DebuggerEngine::MemoryTrackRegister) { + topLevel = new RegisterMemoryView(binEditor, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent); } else { // Ordinary memory view - MemoryView::setBinEditorMarkup(binEditor, ml); - MemoryView::setBinEditorRange(binEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); - topLevel = new MemoryView(binEditor, parent); + MemoryView::setBinEditorMarkup(binEditor, data.markup); + MemoryView::setBinEditorRange(binEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); + topLevel = new MemoryView(binEditor, data.parent); topLevel->setWindowTitle(title); } m_views << topLevel; - topLevel->move(pos); + topLevel->move(data.pos); topLevel->show(); return true; } // Editor: Register tracking not supported. - QTC_ASSERT(!(flags & DebuggerEngine::MemoryTrackRegister), return false); + QTC_ASSERT(!(data.flags & DebuggerEngine::MemoryTrackRegister), return false); if (!title.endsWith(QLatin1Char('$'))) title.append(QLatin1String(" $")); IEditor *editor = EditorManager::openEditorWithContents( @@ -185,17 +180,15 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags, connectBinEditorWidget(editorBinEditor); MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly); MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true); - MemoryView::setBinEditorRange(editorBinEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); - MemoryView::setBinEditorMarkup(editorBinEditor, ml); + MemoryView::setBinEditorRange(editorBinEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize); + MemoryView::setBinEditorMarkup(editorBinEditor, data.markup); m_editors << editor; return true; } -void MemoryAgent::createBinEditor(quint64 addr, unsigned flags, - const QList &ml, const QPoint &pos, - const QString &title, QWidget *parent) +void MemoryAgent::createBinEditor(const MemoryViewSetupData &data) { - if (!doCreateBinEditor(addr, flags, ml, pos, title, parent)) + if (!doCreateBinEditor(data)) Core::AsynchronousMessageBox::warning( tr("No Memory Viewer Available"), tr("The memory contents cannot be shown as no viewer plugin " @@ -204,7 +197,9 @@ void MemoryAgent::createBinEditor(quint64 addr, unsigned flags, void MemoryAgent::createBinEditor(quint64 addr) { - createBinEditor(addr, 0, QList(), QPoint(), QString(), 0); + MemoryViewSetupData data; + data.startAddress = addr; + createBinEditor(data); } void MemoryAgent::fetchLazyData(quint64 block) diff --git a/src/plugins/debugger/memoryagent.h b/src/plugins/debugger/memoryagent.h index 77098e9aed0..b5a40b51d9f 100644 --- a/src/plugins/debugger/memoryagent.h +++ b/src/plugins/debugger/memoryagent.h @@ -34,11 +34,10 @@ #include "debuggerconstants.h" #include +#include #include #include -QT_FORWARD_DECLARE_CLASS(QPoint) - namespace Core { class IEditor; } namespace ProjectExplorer { class Abi; } @@ -62,6 +61,20 @@ public: QString toolTip; }; +class MemoryViewSetupData +{ +public: + MemoryViewSetupData() : parent(0), startAddress(0), flags(0) {} + + QWidget *parent; + quint64 startAddress; + QByteArray registerName; + unsigned flags; + QList markup; + QPoint pos; + QString title; +}; + class MemoryAgent : public QObject { Q_OBJECT @@ -80,9 +93,7 @@ public: public slots: // Called by engine to create a new view. - void createBinEditor(quint64 startAddr, unsigned flags, - const QList &ml, const QPoint &pos, - const QString &title, QWidget *parent); + void createBinEditor(const MemoryViewSetupData &data); void createBinEditor(quint64 startAddr); // Called by engine to create a tooltip. void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data); @@ -101,9 +112,7 @@ private slots: private: void connectBinEditorWidget(QWidget *w); - bool doCreateBinEditor(quint64 startAddr, unsigned flags, - const QList &ml, const QPoint &pos, - QString title, QWidget *parent); + bool doCreateBinEditor(const MemoryViewSetupData &data); QList > m_editors; QList > m_views; diff --git a/src/plugins/debugger/memoryview.cpp b/src/plugins/debugger/memoryview.cpp index 0983053bb83..4f1b69cde83 100644 --- a/src/plugins/debugger/memoryview.cpp +++ b/src/plugins/debugger/memoryview.cpp @@ -138,24 +138,27 @@ void MemoryView::setMarkup(const QList &m) \sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine */ -RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, QWidget *parent) : +RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, quint64 addr, + const QByteArray ®Name, + RegisterHandler *handler, QWidget *parent) : MemoryView(binEditor, parent), - m_registerIndex(0), m_registerAddress(0) + m_registerName(regName), m_registerAddress(addr) { + connect(handler, &QAbstractItemModel::modelReset, this, &QWidget::close); + connect(handler, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged); + updateContents(); } -void RegisterMemoryView::slotRegisterSet(const QModelIndex &index) +void RegisterMemoryView::onRegisterChanged(const QByteArray &name, quint64 value) { - if (m_registerIndex != index.row()) - return; - const QVariant newAddressV = index.data(Qt::EditRole); - if (newAddressV.type() == QVariant::ULongLong) - setRegisterAddress(newAddressV.toULongLong()); + if (name == m_registerName) + setRegisterAddress(value); } -QString RegisterMemoryView::title(const QString ®isterName, quint64 a) +QString RegisterMemoryView::title(const QByteArray ®isterName, quint64 a) { - return tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(a, 0, 16); + return tr("Memory at Register \"%1\" (0x%2)") + .arg(QString::fromUtf8(registerName)).arg(a, 0, 16); } void RegisterMemoryView::setRegisterAddress(quint64 v) @@ -171,25 +174,13 @@ void RegisterMemoryView::setRegisterAddress(quint64 v) setMarkup(registerMarkup(v, m_registerName)); } -QList RegisterMemoryView::registerMarkup(quint64 a, const QString &name) +QList RegisterMemoryView::registerMarkup(quint64 a, const QByteArray ®Name) { QList result; result.push_back(MemoryMarkup(a, 1, QColor(Qt::blue).lighter(), - tr("Register \"%1\"").arg(name))); + tr("Register \"%1\"").arg(QString::fromUtf8(regName)))); return result; } -void RegisterMemoryView::init(RegisterHandler *h, int registerIndex) -{ - m_registerIndex = registerIndex; - m_registerName = QString::fromLatin1(h->registerAt(registerIndex).name); - // Known issue: CDB might reset the model by changing the special - // registers it reports. - connect(h, SIGNAL(modelReset()), this, SLOT(close())); - connect(h, SIGNAL(registerSet(QModelIndex)), - this, SLOT(slotRegisterSet(QModelIndex))); - setRegisterAddress(h->registerAt(m_registerIndex).editValue().toULongLong()); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/memoryview.h b/src/plugins/debugger/memoryview.h index 4206d443978..b8e04adf2fe 100644 --- a/src/plugins/debugger/memoryview.h +++ b/src/plugins/debugger/memoryview.h @@ -69,21 +69,17 @@ class RegisterMemoryView : public MemoryView { Q_OBJECT public: - explicit RegisterMemoryView(QWidget *binEditor, QWidget *parent = 0); + explicit RegisterMemoryView(QWidget *binEditor, quint64 addr, const QByteArray ®Name, + RegisterHandler *rh, QWidget *parent = 0); - void init(RegisterHandler *rh, int index); - - static QList registerMarkup(quint64 a, const QString &name); - static QString title(const QString ®isterName, quint64 a = 0); - -private slots: - void slotRegisterSet(const QModelIndex &index); + static QList registerMarkup(quint64 a, const QByteArray ®Name); + static QString title(const QByteArray ®isterName, quint64 a = 0); private: + void onRegisterChanged(const QByteArray &name, quint64 value); void setRegisterAddress(quint64 v); - int m_registerIndex; - QString m_registerName; + QByteArray m_registerName; quint64 m_registerAddress; }; diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 0ccbf07b8f5..9882b7deb20 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -184,9 +184,9 @@ void QmlCppEngine::reloadFullStack() m_cppEngine->reloadFullStack(); } -void QmlCppEngine::setRegisterValue(int regnr, const QString &value) +void QmlCppEngine::setRegisterValue(const QByteArray &name, const QString &value) { - m_cppEngine->setRegisterValue(regnr, value); + m_cppEngine->setRegisterValue(name, value); } diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 4657dd7fe41..050bf87731e 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -68,7 +68,7 @@ public: void reloadSourceFiles(); void reloadFullStack(); - void setRegisterValue(int regnr, const QString &value); + void setRegisterValue(const QByteArray &name, const QString &value); bool hasCapability(unsigned cap) const; bool isSynchronous() const; diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 8432f320592..eba3cfda6df 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -46,266 +46,477 @@ namespace Internal { // ////////////////////////////////////////////////////////////////// -enum RegisterType -{ - RegisterUnknown, - //RegisterDummy, // like AH if EAX is present. - RegisterI8, - RegisterI16, - RegisterI32, - RegisterI64, - RegisterI128, - RegisterF32, - RegisterF64, - RegisterF80, - RegisterXMM, - RegisterMMX, - RegisterNeon, - RegisterFlags32 -}; - static struct RegisterNameAndType { const char *name; - RegisterType type; + RegisterKind kind; + int size; } theNameAndType[] = { // ARM - { "r0", RegisterI32 }, - { "r1", RegisterI32 }, - { "r2", RegisterI32 }, - { "r3", RegisterI32 }, - { "r4", RegisterI32 }, - { "r5", RegisterI32 }, - { "r6", RegisterI32 }, - { "r7", RegisterI32 }, - { "r8", RegisterI32 }, - { "r9", RegisterI32 }, - { "r10", RegisterI32 }, - { "r11", RegisterI32 }, - { "r12", RegisterI32 }, - { "sp", RegisterI32 }, - { "lr", RegisterI32 }, - { "pc", RegisterI32 }, - { "cpsr", RegisterFlags32 }, - { "d0", RegisterI64 }, - { "d1", RegisterI64 }, - { "d2", RegisterI64 }, - { "d3", RegisterI64 }, - { "d4", RegisterI64 }, - { "d5", RegisterI64 }, - { "d6", RegisterI64 }, - { "d7", RegisterI64 }, - { "d8", RegisterI64 }, - { "d9", RegisterI64 }, - { "d10", RegisterI64 }, - { "d11", RegisterI64 }, - { "d12", RegisterI64 }, - { "d13", RegisterI64 }, - { "d14", RegisterI64 }, - { "d15", RegisterI64 }, - { "d16", RegisterI64 }, - { "d17", RegisterI64 }, - { "d18", RegisterI64 }, - { "d19", RegisterI64 }, - { "d20", RegisterI64 }, - { "d21", RegisterI64 }, - { "d22", RegisterI64 }, - { "d23", RegisterI64 }, - { "d24", RegisterI64 }, - { "d25", RegisterI64 }, - { "d26", RegisterI64 }, - { "d27", RegisterI64 }, - { "d28", RegisterI64 }, - { "d29", RegisterI64 }, - { "d30", RegisterI64 }, - { "d31", RegisterI64 }, - { "fpscr", RegisterFlags32 }, - { "s0", RegisterI32 }, - { "s1", RegisterI32 }, - { "s2", RegisterI32 }, - { "s3", RegisterI32 }, - { "s4", RegisterI32 }, - { "s5", RegisterI32 }, - { "s6", RegisterI32 }, - { "s7", RegisterI32 }, - { "s8", RegisterI32 }, - { "s9", RegisterI32 }, - { "s10", RegisterI32 }, - { "s11", RegisterI32 }, - { "s12", RegisterI32 }, - { "s13", RegisterI32 }, - { "s14", RegisterI32 }, - { "s15", RegisterI32 }, - { "s16", RegisterI32 }, - { "s17", RegisterI32 }, - { "s18", RegisterI32 }, - { "s19", RegisterI32 }, - { "s20", RegisterI32 }, - { "s21", RegisterI32 }, - { "s22", RegisterI32 }, - { "s23", RegisterI32 }, - { "s24", RegisterI32 }, - { "s25", RegisterI32 }, - { "s26", RegisterI32 }, - { "s27", RegisterI32 }, - { "s28", RegisterI32 }, - { "s29", RegisterI32 }, - { "s30", RegisterI32 }, - { "s31", RegisterI32 }, - { "q0", RegisterI128 }, - { "q1", RegisterI128 }, - { "q2", RegisterI128 }, - { "q3", RegisterI128 }, - { "q4", RegisterI128 }, - { "q5", RegisterI128 }, - { "q6", RegisterI128 }, - { "q7", RegisterI128 }, - { "q8", RegisterI128 }, - { "q9", RegisterI128 }, - { "q10", RegisterI128 }, - { "q11", RegisterI128 }, - { "q12", RegisterI128 }, - { "q13", RegisterI128 }, - { "q14", RegisterI128 }, - { "q15", RegisterI128 }, + { "r0", IntegerRegister, 4 }, + { "r1", IntegerRegister, 4 }, + { "r2", IntegerRegister, 4 }, + { "r3", IntegerRegister, 4 }, + { "r4", IntegerRegister, 4 }, + { "r5", IntegerRegister, 4 }, + { "r6", IntegerRegister, 4 }, + { "r7", IntegerRegister, 4 }, + { "r8", IntegerRegister, 4 }, + { "r9", IntegerRegister, 4 }, + { "r10", IntegerRegister, 4 }, + { "r11", IntegerRegister, 4 }, + { "r12", IntegerRegister, 4 }, + { "sp", IntegerRegister, 4 }, + { "lr", IntegerRegister, 4 }, + { "pc", IntegerRegister, 4 }, + { "cpsr", FlagRegister, 4 }, + { "d0", IntegerRegister, 8 }, + { "d1", IntegerRegister, 8 }, + { "d2", IntegerRegister, 8 }, + { "d3", IntegerRegister, 8 }, + { "d4", IntegerRegister, 8 }, + { "d5", IntegerRegister, 8 }, + { "d6", IntegerRegister, 8 }, + { "d7", IntegerRegister, 8 }, + { "d8", IntegerRegister, 8 }, + { "d9", IntegerRegister, 8 }, + { "d10", IntegerRegister, 8 }, + { "d11", IntegerRegister, 8 }, + { "d12", IntegerRegister, 8 }, + { "d13", IntegerRegister, 8 }, + { "d14", IntegerRegister, 8 }, + { "d15", IntegerRegister, 8 }, + { "d16", IntegerRegister, 8 }, + { "d17", IntegerRegister, 8 }, + { "d18", IntegerRegister, 8 }, + { "d19", IntegerRegister, 8 }, + { "d20", IntegerRegister, 8 }, + { "d21", IntegerRegister, 8 }, + { "d22", IntegerRegister, 8 }, + { "d23", IntegerRegister, 8 }, + { "d24", IntegerRegister, 8 }, + { "d25", IntegerRegister, 8 }, + { "d26", IntegerRegister, 8 }, + { "d27", IntegerRegister, 8 }, + { "d28", IntegerRegister, 8 }, + { "d29", IntegerRegister, 8 }, + { "d30", IntegerRegister, 8 }, + { "d31", IntegerRegister, 8 }, + { "fpscr", FlagRegister, 4 }, + { "s0", IntegerRegister, 4 }, + { "s1", IntegerRegister, 4 }, + { "s2", IntegerRegister, 4 }, + { "s3", IntegerRegister, 4 }, + { "s4", IntegerRegister, 4 }, + { "s5", IntegerRegister, 4 }, + { "s6", IntegerRegister, 4 }, + { "s7", IntegerRegister, 4 }, + { "s8", IntegerRegister, 4 }, + { "s9", IntegerRegister, 4 }, + { "s10", IntegerRegister, 4 }, + { "s11", IntegerRegister, 4 }, + { "s12", IntegerRegister, 4 }, + { "s13", IntegerRegister, 4 }, + { "s14", IntegerRegister, 4 }, + { "s15", IntegerRegister, 4 }, + { "s16", IntegerRegister, 4 }, + { "s17", IntegerRegister, 4 }, + { "s18", IntegerRegister, 4 }, + { "s19", IntegerRegister, 4 }, + { "s20", IntegerRegister, 4 }, + { "s21", IntegerRegister, 4 }, + { "s22", IntegerRegister, 4 }, + { "s23", IntegerRegister, 4 }, + { "s24", IntegerRegister, 4 }, + { "s25", IntegerRegister, 4 }, + { "s26", IntegerRegister, 4 }, + { "s27", IntegerRegister, 4 }, + { "s28", IntegerRegister, 4 }, + { "s29", IntegerRegister, 4 }, + { "s30", IntegerRegister, 4 }, + { "s31", IntegerRegister, 4 }, + { "q0", IntegerRegister, 16 }, + { "q1", IntegerRegister, 16 }, + { "q2", IntegerRegister, 16 }, + { "q3", IntegerRegister, 16 }, + { "q4", IntegerRegister, 16 }, + { "q5", IntegerRegister, 16 }, + { "q6", IntegerRegister, 16 }, + { "q7", IntegerRegister, 16 }, + { "q8", IntegerRegister, 16 }, + { "q9", IntegerRegister, 16 }, + { "q10", IntegerRegister, 16 }, + { "q11", IntegerRegister, 16 }, + { "q12", IntegerRegister, 16 }, + { "q13", IntegerRegister, 16 }, + { "q14", IntegerRegister, 16 }, + { "q15", IntegerRegister, 16 }, // Intel - { "eax", RegisterI32 }, - { "ecx", RegisterI32 }, - { "edx", RegisterI32 }, - { "ebx", RegisterI32 }, - { "esp", RegisterI32 }, - { "ebp", RegisterI32 }, - { "esi", RegisterI32 }, - { "edi", RegisterI32 }, - { "eip", RegisterI32 }, - { "eflags", RegisterFlags32 }, - { "cs", RegisterI32 }, - { "ss", RegisterI32 }, - { "ds", RegisterI32 }, - { "es", RegisterI32 }, - { "fs", RegisterI32 }, - { "gs", RegisterI32 }, - { "st0", RegisterF80 }, - { "st1", RegisterF80 }, - { "st2", RegisterF80 }, - { "st3", RegisterF80 }, - { "st4", RegisterF80 }, - { "st5", RegisterF80 }, - { "st6", RegisterF80 }, - { "st7", RegisterF80 }, - { "fctrl", RegisterFlags32 }, - { "fstat", RegisterFlags32 }, - { "ftag", RegisterFlags32 }, - { "fiseg", RegisterFlags32 }, - { "fioff", RegisterFlags32 }, - { "foseg", RegisterFlags32 }, - { "fooff", RegisterFlags32 }, - { "fop", RegisterFlags32 }, - { "xmm0", RegisterXMM }, - { "xmm1", RegisterXMM }, - { "xmm2", RegisterXMM }, - { "xmm3", RegisterXMM }, - { "xmm4", RegisterXMM }, - { "xmm5", RegisterXMM }, - { "xmm6", RegisterXMM }, - { "xmm7", RegisterXMM }, - { "mxcsr", RegisterFlags32 }, - { "orig_eax", RegisterI32 }, - { "al", RegisterI8 }, - { "cl", RegisterI8 }, - { "dl", RegisterI8 }, - { "bl", RegisterI8 }, - { "ah", RegisterI8 }, - { "ch", RegisterI8 }, - { "dh", RegisterI8 }, - { "bh", RegisterI8 }, - { "ax", RegisterI16 }, - { "cx", RegisterI16 }, - { "dx", RegisterI16 }, - { "bx", RegisterI16 }, - { "bp", RegisterI16 }, - { "si", RegisterI16 }, - { "di", RegisterI16 }, - { "mm0", RegisterMMX }, - { "mm1", RegisterMMX }, - { "mm2", RegisterMMX }, - { "mm3", RegisterMMX }, - { "mm4", RegisterMMX }, - { "mm5", RegisterMMX }, - { "mm6", RegisterMMX }, - { "mm7", RegisterMMX } + { "eax", IntegerRegister, 4 }, + { "ecx", IntegerRegister, 4 }, + { "edx", IntegerRegister, 4 }, + { "ebx", IntegerRegister, 4 }, + { "esp", IntegerRegister, 4 }, + { "ebp", IntegerRegister, 4 }, + { "esi", IntegerRegister, 4 }, + { "edi", IntegerRegister, 4 }, + { "eip", IntegerRegister, 4 }, + { "rax", IntegerRegister, 8 }, + { "rcx", IntegerRegister, 8 }, + { "rdx", IntegerRegister, 8 }, + { "rbx", IntegerRegister, 8 }, + { "rsp", IntegerRegister, 8 }, + { "rbp", IntegerRegister, 8 }, + { "rsi", IntegerRegister, 8 }, + { "rdi", IntegerRegister, 8 }, + { "rip", IntegerRegister, 8 }, + { "eflags", FlagRegister, 4 }, + { "cs", IntegerRegister, 2 }, + { "ss", IntegerRegister, 2 }, + { "ds", IntegerRegister, 2 }, + { "es", IntegerRegister, 2 }, + { "fs", IntegerRegister, 2 }, + { "gs", IntegerRegister, 2 }, + { "st0", FloatRegister, 10 }, + { "st1", FloatRegister, 10 }, + { "st2", FloatRegister, 10 }, + { "st3", FloatRegister, 10 }, + { "st4", FloatRegister, 10 }, + { "st5", FloatRegister, 10 }, + { "st6", FloatRegister, 10 }, + { "st7", FloatRegister, 10 }, + { "fctrl", FlagRegister, 4 }, + { "fstat", FlagRegister, 4 }, + { "ftag", FlagRegister, 4 }, + { "fiseg", FlagRegister, 4 }, + { "fioff", FlagRegister, 4 }, + { "foseg", FlagRegister, 4 }, + { "fooff", FlagRegister, 4 }, + { "fop", FlagRegister, 4 }, + { "mxcsr", FlagRegister, 4 }, + { "orig_eax", IntegerRegister, 4 }, + { "al", IntegerRegister, 1 }, + { "cl", IntegerRegister, 1 }, + { "dl", IntegerRegister, 1 }, + { "bl", IntegerRegister, 1 }, + { "ah", IntegerRegister, 1 }, + { "ch", IntegerRegister, 1 }, + { "dh", IntegerRegister, 1 }, + { "bh", IntegerRegister, 1 }, + { "ax", IntegerRegister, 2 }, + { "cx", IntegerRegister, 2 }, + { "dx", IntegerRegister, 2 }, + { "bx", IntegerRegister, 2 }, + { "bp", IntegerRegister, 2 }, + { "si", IntegerRegister, 2 }, + { "di", IntegerRegister, 2 } }; -static RegisterType guessType(const QByteArray &name) +////////////////////////////////////////////////////////////////// +// +// RegisterValue +// +////////////////////////////////////////////////////////////////// + +// FIXME: This should not really be needed. Instead the guessing, if any, +// should done by the engines. +static void fixup(Register *reg, RegisterKind kind, int size) { - static QHash theTypes; - if (theTypes.isEmpty()) { - for (int i = 0; i != sizeof(theNameAndType) / sizeof(theNameAndType[0]); ++i) - theTypes[theNameAndType[i].name] = theNameAndType[i].type; - } - return theTypes.value(name, RegisterUnknown); + reg->kind = kind; + if (!reg->size) + reg->size = size; } -static int childCountFromType(int type) +void Register::guessMissingData() { - switch (type) { - case RegisterUnknown: return 0; - case RegisterI8: return 0; - case RegisterI16: return 1; - case RegisterI32: return 2; - case RegisterI64: return 3; - case RegisterI128: return 4; - case RegisterF32: return 0; - case RegisterF64: return 0; - case RegisterF80: return 0; - case RegisterXMM: return 3; - case RegisterMMX: return 3; - case RegisterNeon: return 3; - case RegisterFlags32: return 0; + if (name.startsWith("xmm")) { + fixup(this, VectorRegister, 16); + return; } + + for (int i = 0; i != sizeof(theNameAndType) / sizeof(theNameAndType[0]); ++i) { + if (theNameAndType[i].name == name) { + fixup(this, theNameAndType[i].kind, theNameAndType[i].size); + return; + } + } + + if (reportedType == "int") + fixup(this, IntegerRegister, 4); + else if (reportedType == "float") + fixup(this, IntegerRegister, 8); + else if (reportedType == "_i387_ext") + fixup(this, IntegerRegister, 10); + else if (reportedType == "*1" || reportedType == "long") + fixup(this, IntegerRegister, 0); + else if (reportedType.contains("vec")) + fixup(this, VectorRegister, 0); + else if (reportedType.startsWith("int")) + fixup(this, IntegerRegister, 0); +} + +static QString subTypeName(RegisterKind kind, int size) +{ + if (kind == IntegerRegister) + return QString::fromLatin1("[i%1]").arg(size * 8); + if (kind == FloatRegister) + return QString::fromLatin1("[f%1]").arg(size * 8); QTC_ASSERT(false, /**/); - return 0; + return QString(); } -static int bitWidthFromType(int type, int subType) +static uint decodeHexChar(unsigned char c) { - const uint integer[] = { 8, 16, 32, 64, 128 }; - const uint xmm[] = { 8, 16, 32, 64, 128 }; - const uint mmx[] = { 8, 16, 32, 64, 128 }; - const uint neon[] = { 8, 16, 32, 64, 128 }; + c -= '0'; + if (c < 10) + return c; + c -= 'A' - '0'; + if (c < 6) + return 10 + c; + c -= 'a' - 'A'; + if (c < 6) + return 10 + c; + return uint(-1); +} - switch (type) { - case RegisterUnknown: return 0; - case RegisterI8: return 8; - case RegisterI16: return integer[subType]; - case RegisterI32: return integer[subType]; - case RegisterI64: return integer[subType]; - case RegisterI128: return integer[subType]; - case RegisterF32: return 0; - case RegisterF64: return 0; - case RegisterF80: return 0; - case RegisterXMM: return xmm[subType]; - case RegisterMMX: return mmx[subType]; - case RegisterNeon: return neon[subType]; - case RegisterFlags32: return 0; +void RegisterValue::operator=(const QByteArray &ba) +{ + uint shift = 0; + int j = 0; + v.u64[1] = v.u64[0] = 0; + for (int i = ba.size(); --i >= 0 && j < 16; ++j) { + quint64 d = decodeHexChar(ba.at(i)); + if (d == uint(-1)) + return; + v.u64[0] |= (d << shift); + shift += 4; + } + j = 0; + shift = 0; + for (int i = ba.size() - 16; --i >= 0 && j < 16; ++j) { + quint64 d = decodeHexChar(ba.at(i)); + if (d == uint(-1)) + return; + v.u64[1] |= (d << shift); + shift += 4; } - QTC_ASSERT(false, /**/); - return 0; } -static const uint TopLevelId = UINT_MAX; -static bool isTopLevelItem(const QModelIndex &index) +bool RegisterValue::operator==(const RegisterValue &other) { - return quintptr(index.internalId()) == quintptr(TopLevelId); + return v.u64[0] == other.v.u64[0] && v.u64[1] == other.v.u64[1]; } -Register::Register(const QByteArray &name_) - : name(name_), changed(true) +static QByteArray format(quint64 v, int base, int size) { - type = guessType(name); + QByteArray result = QByteArray::number(v, base); + if (base == 16) + result.prepend(QByteArray(2*size - result.size(), '0')); + return result; } +QByteArray RegisterValue::toByteArray(int base, RegisterKind kind, int size) const +{ + if (kind == FloatRegister) { + if (size == 4) + return QByteArray::number(v.f[0]); + if (size == 8) + return QByteArray::number(v.d[0]); + } + + QByteArray result; + if (size > 8) { + result += format(v.u64[1], base, size - 8); + size = 8; + if (base != 16) + result += ','; + } + result += format(v.u64[0], base, size); + if (base == 16) + result.prepend("0x"); + return result; +} + +RegisterValue RegisterValue::subValue(int size, int index) const +{ + RegisterValue value; + switch (size) { + case 1: + value.v.u8[0] = v.u8[index]; + break; + case 2: + value.v.u16[0] = v.u16[index]; + break; + case 4: + value.v.u32[0] = v.u32[index]; + break; + case 8: + value.v.u64[0] = v.u64[index]; + break; + } + return value; +} + +////////////////////////////////////////////////////////////////// +// +// RegisterSubItem and RegisterItem +// +////////////////////////////////////////////////////////////////// + +class RegisterSubItem : public Utils::TreeItem +{ +public: + RegisterSubItem(RegisterKind subKind, int subSize, int count) + : m_subKind(subKind), m_subSize(subSize), m_count(count), m_changed(false) + {} + + int columnCount() const { return 2; } + QVariant data(int column, int role) const; + + Qt::ItemFlags flags(int column) const + { + //return column == 1 ? Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable + // : Qt::ItemIsSelectable|Qt::ItemIsEnabled; + Q_UNUSED(column); + return Qt::ItemIsSelectable|Qt::ItemIsEnabled; + } + + RegisterKind m_subKind; + int m_subSize; + int m_count; + bool m_changed; +}; + +class RegisterItem : public Utils::TreeItem +{ +public: + explicit RegisterItem(const Register ®); + + int columnCount() const { return 2; } + QVariant data(int column, int role) const; + Qt::ItemFlags flags(int column) const; + + quint64 addressValue() const; + + Register m_reg; + int m_base; + bool m_changed; +}; + +RegisterItem::RegisterItem(const Register ®) : + m_reg(reg), m_base(16), m_changed(true) +{ + if (m_reg.kind == UnknownRegister) + m_reg.guessMissingData(); + + if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { + for (int s = m_reg.size / 2; s; s = s / 2) + appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s)); + } + if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { + for (int s = m_reg.size; s >= 4; s = s / 2) + appendChild(new RegisterSubItem(FloatRegister, s, m_reg.size / s)); + } +} + +Qt::ItemFlags RegisterItem::flags(int column) const +{ + const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled; + // Can edit registers if they are hex numbers and not arrays. + if (column == 1) // && IntegerWatchLineEdit::isUnsignedHexNumber(QLatin1String(m_reg.display))) + return notEditable | Qt::ItemIsEditable; + return notEditable; +} + +quint64 RegisterItem::addressValue() const +{ + return m_reg.value.v.u64[0]; +} + +QVariant RegisterItem::data(int column, int role) const +{ + switch (role) { + case RegisterNameRole: + return m_reg.name; + + case RegisterIsBigRole: + return m_reg.value.v.u64[1] > 0; + + case RegisterChangedRole: + return m_changed; + + case RegisterNumberBaseRole: + return m_base; + + case RegisterAsAddressRole: + return addressValue(); + + case Qt::DisplayRole: + switch (column) { + case 0: { + QByteArray res = m_reg.name; + if (!m_reg.description.isEmpty()) + res += " (" + m_reg.description + ')'; + return res; + } + case 1: { + return m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size); + } + } + + case Qt::ToolTipRole: + return QString::fromLatin1("Current Value: %1\nPreviousValue: %2") + .arg(QString::fromLatin1(m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size))) + .arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_base, m_reg.kind, m_reg.size))); + + case Qt::EditRole: // Edit: Unpadded for editing + return m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size); + + case Qt::TextAlignmentRole: + return column == 1 ? QVariant(Qt::AlignRight) : QVariant(); + + default: + break; + } + return QVariant(); +} + +QVariant RegisterSubItem::data(int column, int role) const +{ + switch (role) { + case RegisterChangedRole: + return m_changed; + + case RegisterNumberBaseRole: + return 16; + + case RegisterAsAddressRole: + return 0; + + case Qt::DisplayRole: + switch (column) { + case 0: + return subTypeName(m_subKind, m_subSize); + case 1: { + QTC_ASSERT(parent(), return QVariant()); + RegisterItem *registerItem = static_cast(parent()); + RegisterValue value = registerItem->m_reg.value; + QByteArray ba; + for (int i = 0; i != m_count; ++i) { + ba += value.subValue(m_subSize, i).toByteArray(16, m_subKind, m_subSize); + int tab = 5 * (i + 1) * m_subSize; + ba += QByteArray(tab - ba.size(), ' '); + } + return ba; + } + } + default: + break; + } + + return QVariant(); +} ////////////////////////////////////////////////////////////////// // @@ -313,251 +524,76 @@ Register::Register(const QByteArray &name_) // ////////////////////////////////////////////////////////////////// +class RegisterRootItem : public Utils::TreeItem +{ +public: + int columnCount() const { return 2; } + QVariant data(int section, int role) const + { + if (role == Qt::DisplayRole) { + switch (section) { + case 0: return RegisterHandler::tr("Name"); + case 1: return RegisterHandler::tr("Value"); + }; + } + return QVariant(); + } +}; + RegisterHandler::RegisterHandler() { setObjectName(QLatin1String("RegisterModel")); - m_base = 16; - calculateWidth(); + setRootItem(new RegisterRootItem); // Needed to get two columns. #if USE_REGISTER_MODEL_TEST new ModelTest(this, 0); #endif } -int RegisterHandler::rowCount(const QModelIndex &idx) const +void RegisterHandler::updateRegister(const Register &r) { - if (idx.column() > 0) - return 0; - if (!idx.isValid()) - return m_registers.size(); // Top level. - if (!isTopLevelItem(idx)) - return 0; // Sub-Items don't have children. - if (idx.row() >= m_registers.size()) - return 0; - return childCountFromType(m_registers[idx.row()].type); -} - -int RegisterHandler::columnCount(const QModelIndex &idx) const -{ - if (idx.column() > 0) - return 0; - if (!idx.isValid()) - return 2; - if (!isTopLevelItem(idx)) - return 0; // Sub-Items don't have children. - return 2; -} - -QModelIndex RegisterHandler::index(int row, int col, const QModelIndex &parent) const -{ - if (row < 0 || col < 0 || col >= 2) - return QModelIndex(); - if (!parent.isValid()) // Top level. - return createIndex(row, col, TopLevelId); - if (!isTopLevelItem(parent)) // Sub-Item has no children. - return QModelIndex(); - if (parent.column() > 0) - return QModelIndex(); - return createIndex(row, col, parent.row()); -} - -QModelIndex RegisterHandler::parent(const QModelIndex &idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - if (!isTopLevelItem(idx)) - return createIndex(idx.internalId(), 0, TopLevelId); - return QModelIndex(); -} - -// Editor value: Preferably number, else string. -QVariant Register::editValue() const -{ - bool ok = true; - // Try to convert to number? - const qulonglong v = value.toULongLong(&ok, 0); // Autodetect format - if (ok) - return QVariant(v); - return QVariant(value); -} - -// Editor value: Preferably padded number, else padded string. -QString Register::displayValue(int base, int strlen) const -{ - const QVariant editV = editValue(); - if (editV.type() == QVariant::ULongLong) - return QString::fromLatin1("%1").arg(editV.toULongLong(), strlen, base); - const QString stringValue = editV.toString(); - if (stringValue.size() < strlen) - return QString(strlen - stringValue.size(), QLatin1Char(' ')) + QLatin1String(value); - return stringValue; -} - -QVariant RegisterHandler::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - QModelIndex topLevel = index.parent(); - const int mainRow = topLevel.isValid() ? topLevel.row() : index.row(); - - if (mainRow >= m_registers.size()) - return QVariant(); - - - const Register ® = m_registers.at(mainRow); - - if (topLevel.isValid()) { - // - // Nested - // - int subType = index.row(); - int bitWidth = bitWidthFromType(reg.type, subType); - - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case 0: { - switch (bitWidth) { - case 8: return QLatin1String("[Bytes]"); - case 16: return QLatin1String("[Words]"); - case 32: return QLatin1String("[DWords]"); - case 64: return QLatin1String("[QWords]"); - case 128: return QLatin1String("[TWords]"); - case -32: return QLatin1String("[Single]"); - case -64: return QLatin1String("[Double]"); - return QVariant(bitWidth); - } - } - } - default: - break; - } - - } else { - // - // Toplevel - // - - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case 0: { - const QString padding = QLatin1String(" "); - return QVariant(padding + QLatin1String(reg.name) + padding); - //return QVariant(reg.name); - } - case 1: // Display: Pad value for alignment - return reg.displayValue(m_base, m_strlen); - } // switch column - case Qt::EditRole: // Edit: Unpadded for editing - return reg.editValue(); - case Qt::TextAlignmentRole: - return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant(); - default: - break; - } - } - return QVariant(); -} - -QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation, - int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) { - case 0: return tr("Name"); - case 1: return tr("Value (Base %1)").arg(m_base); - }; - } - return QVariant(); -} - -Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const -{ - if (!idx.isValid()) - return Qt::ItemFlags(); - - const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled; - // Can edit registers if they are hex numbers and not arrays. - if (idx.column() == 1 - && IntegerWatchLineEdit::isUnsignedHexNumber(QLatin1String(m_registers.at(idx.row()).value))) - return notEditable | Qt::ItemIsEditable; - return notEditable; -} - -void RegisterHandler::removeAll() -{ - beginResetModel(); - m_registers.clear(); - endResetModel(); -} - -bool RegisterHandler::isEmpty() const -{ - return m_registers.isEmpty(); -} - -// Compare register sets by name -static inline bool compareRegisterSet(const Registers &r1, const Registers &r2) -{ - if (r1.size() != r2.size()) - return false; - const int size = r1.size(); - for (int r = 0; r < size; r++) - if (r1.at(r).name != r2.at(r).name) - return false; - return true; -} - -void RegisterHandler::setRegisters(const Registers ®isters) -{ - beginResetModel(); - m_registers = registers; - const int size = m_registers.size(); - for (int r = 0; r < size; r++) - m_registers[r].changed = false; - calculateWidth(); - endResetModel(); -} - -void RegisterHandler::setAndMarkRegisters(const Registers ®isters) -{ - if (!compareRegisterSet(m_registers, registers)) { - setRegisters(registers); + RegisterItem *reg = m_registerByName.value(r.name, 0); + if (!reg) { + reg = new RegisterItem(r); + m_registerByName[r.name] = reg; + rootItem()->appendChild(reg); return; } - const int size = m_registers.size(); - for (int r = 0; r != size; ++r) { - const QModelIndex regIndex = index(r, 1, QModelIndex()); - if (m_registers.at(r).value != registers.at(r).value) { - // Indicate red if values change, keep changed. - m_registers[r].changed = m_registers.at(r).changed - || !m_registers.at(r).value.isEmpty(); - m_registers[r].value = registers.at(r).value; - emit dataChanged(regIndex, regIndex); - } - emit registerSet(regIndex); // Notify attached memory views. + + if (r.size > 0) + reg->m_reg.size = r.size; + if (!r.description.isEmpty()) + reg->m_reg.description = r.description; + if (reg->m_reg.value != r.value) { + // Indicate red if values change, keep changed. + reg->m_changed = true; + reg->m_reg.previousValue = reg->m_reg.value; + reg->m_reg.value = r.value; + emit registerChanged(reg->m_reg.name, reg->addressValue()); // Notify attached memory views. + } else { + reg->m_changed = false; } } -Registers RegisterHandler::registers() const +void RegisterHandler::setNumberBase(const QByteArray &name, int base) { - return m_registers; + RegisterItem *reg = m_registerByName.value(name, 0); + QTC_ASSERT(reg, return); + reg->m_base = base; + QModelIndex index = indexFromItem(reg); + emit dataChanged(index, index); } -void RegisterHandler::calculateWidth() +RegisterMap RegisterHandler::registerMap() const { - m_strlen = (m_base == 2 ? 64 : m_base == 8 ? 32 : m_base == 10 ? 26 : 16); -} - -void RegisterHandler::setNumberBase(int base) -{ - if (m_base != base) { - beginResetModel(); - m_base = base; - calculateWidth(); - endResetModel(); + RegisterMap result; + Utils::TreeItem *root = rootItem(); + for (int i = 0, n = root->rowCount(); i != n; ++i) { + RegisterItem *reg = static_cast(root->child(i)); + quint64 value = reg->addressValue(); + if (value) + result.insert(value, reg->m_reg.name); } + return result; } } // namespace Internal diff --git a/src/plugins/debugger/registerhandler.h b/src/plugins/debugger/registerhandler.h index 2e3a0e4c6db..708ffb9541e 100644 --- a/src/plugins/debugger/registerhandler.h +++ b/src/plugins/debugger/registerhandler.h @@ -31,35 +31,73 @@ #ifndef DEBUGGER_REGISTERHANDLER_H #define DEBUGGER_REGISTERHANDLER_H +#include + #include +#include #include namespace Debugger { namespace Internal { +enum RegisterDataRole +{ + RegisterNameRole = Qt::UserRole, + RegisterIsBigRole, + RegisterChangedRole, + RegisterNumberBaseRole, + RegisterAsAddressRole +}; + +enum RegisterKind +{ + UnknownRegister, + IntegerRegister, + FloatRegister, + VectorRegister, + FlagRegister, + OtherRegister +}; + +class RegisterValue +{ +public: + RegisterValue() { v.u64[1] = v.u64[0] = 0; } + void operator=(const QByteArray &ba); + bool operator==(const RegisterValue &other); + bool operator!=(const RegisterValue &other) { return !operator==(other); } + QByteArray toByteArray(int base, RegisterKind kind, int size) const; + RegisterValue subValue(int size, int index) const; + + union { + quint8 u8[16]; + quint16 u16[8]; + quint32 u32[4]; + quint64 u64[2]; + float f[4]; + double d[2]; + } v; +}; + class Register { public: - Register() : type(0), changed(true) {} - Register(const QByteArray &name_); + Register() { size = 0; kind = UnknownRegister; } + void guessMissingData(); - QVariant editValue() const; - QString displayValue(int base, int strlen) const; - -public: QByteArray name; - /* Value should be an integer for which autodetection by passing - * base=0 to QString::toULongLong() should work (C-language conventions). - * Values that cannot be converted (such as 128bit MMX-registers) are - * passed through. */ - QByteArray value; - int type; - bool changed; + QByteArray reportedType; + RegisterValue value; + RegisterValue previousValue; + QByteArray description; + int size; + RegisterKind kind; }; -typedef QVector Registers; +class RegisterItem; +typedef QMap RegisterMap; -class RegisterHandler : public QAbstractTableModel +class RegisterHandler : public Utils::TreeModel { Q_OBJECT @@ -68,34 +106,17 @@ public: QAbstractItemModel *model() { return this; } - bool isEmpty() const; // nothing known so far? - // Set up register names (gdb) - void setRegisters(const Registers ®isters); - // Set register values - void setAndMarkRegisters(const Registers ®isters); - Registers registers() const; - Register registerAt(int i) const { return m_registers.at(i); } - void removeAll(); - Q_SLOT void setNumberBase(int base); - int numberBase() const { return m_base; } + void updateRegister(const Register ®); + + void setNumberBase(const QByteArray &name, int base); + void commitUpdates() { emit layoutChanged(); } + RegisterMap registerMap() const; signals: - void registerSet(const QModelIndex &r); // Register was set, for memory views + void registerChanged(const QByteArray &name, quint64 value); // For memory views private: - void calculateWidth(); - int rowCount(const QModelIndex &idx = QModelIndex()) const; - int columnCount(const QModelIndex &idx = QModelIndex()) const; - QModelIndex index(int row, int col, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &idx) const; - 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; - - Registers m_registers; - int m_base; - int m_strlen; // approximate width of a value in chars. + QHash m_registerByName; }; } // namespace Internal diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp index eace76960f8..a9c5b9ef471 100644 --- a/src/plugins/debugger/registerwindow.cpp +++ b/src/plugins/debugger/registerwindow.cpp @@ -30,6 +30,7 @@ #include "registerwindow.h" #include "memoryview.h" +#include "memoryagent.h" #include "debuggeractions.h" #include "debuggerdialogs.h" #include "debuggercore.h" @@ -42,22 +43,13 @@ #include #include - #include #include #include - namespace Debugger { namespace Internal { -static RegisterHandler *currentHandler() -{ - DebuggerEngine *engine = currentEngine(); - QTC_ASSERT(engine, return 0); - return engine->registerHandler(); -} - /////////////////////////////////////////////////////////////////////// // // RegisterDelegate @@ -74,10 +66,9 @@ public: QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const { - Register reg = currentHandler()->registerAt(index.row()); IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent); - const int base = currentHandler()->numberBase(); - const bool big = reg.value.size() > 16; + const int base = index.data(RegisterNumberBaseRole).toInt(); + const bool big = index.data(RegisterIsBigRole).toBool(); // Big integers are assumed to be hexadecimal. lineEdit->setBigInt(big); lineEdit->setBase(big ? 16 : base); @@ -101,11 +92,11 @@ public: return; IntegerWatchLineEdit *lineEdit = qobject_cast(editor); QTC_ASSERT(lineEdit, return); - const int base = currentHandler()->numberBase(); + const int base = index.data(RegisterNumberBaseRole).toInt(); QString value = lineEdit->text(); if (base == 16 && !value.startsWith(QLatin1String("0x"))) value.insert(0, QLatin1String("0x")); - currentEngine()->setRegisterValue(index.row(), value); + currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value); } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, @@ -118,28 +109,38 @@ public: const QModelIndex &index) const { if (index.column() == 1) { - bool paintRed = currentHandler()->registerAt(index.row()).changed; + const bool paintRed = index.data(RegisterChangedRole).toBool(); QPen oldPen = painter->pen(); + const QColor lightColor(140, 140, 140); if (paintRed) painter->setPen(QColor(200, 0, 0)); + else + painter->setPen(lightColor); // 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))); + int charWidth = qMax(fm.width(QLatin1Char('x')), fm.width(QLatin1Char('0'))); QString str = index.data(Qt::DisplayRole).toString(); int x = option.rect.x(); + bool light = !paintRed; for (int i = 0; i < str.size(); ++i) { - QRect r = option.rect; - r.setX(x); - r.setWidth(charWidth); + const QChar c = str.at(i); + const int uc = c.unicode(); + if (light && (uc != 'x' && uc != '0')) { + light = false; + painter->setPen(oldPen.color()); + } + if (uc == ' ') { + light = true; + painter->setPen(lightColor); + } else { + QRect r = option.rect; + r.setX(x); + r.setWidth(charWidth); + painter->drawText(r, Qt::AlignHCenter, c); + } x += charWidth; - painter->drawText(r, Qt::AlignHCenter, QString(str.at(i))); } - if (paintRed) - painter->setPen(oldPen); + painter->setPen(oldPen); } else { QItemDelegate::paint(painter, option, index); } @@ -156,6 +157,7 @@ public: RegisterTreeView::RegisterTreeView() { setItemDelegate(new RegisterDelegate(this)); + setRootIsDecorated(true); } void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) @@ -164,7 +166,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) DebuggerEngine *engine = currentEngine(); QTC_ASSERT(engine, return); - RegisterHandler *handler = currentHandler(); + RegisterHandler *handler = engine->registerHandler(); + const bool actionsEnabled = engine->debuggerActionsEnabled(); const DebuggerState state = engine->state(); @@ -174,13 +177,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) menu.addSeparator(); - Register aRegister; const QModelIndex idx = indexAt(ev->pos()); - if (idx.isValid()) - aRegister = handler->registers().at(idx.row()); - const QVariant addressV = aRegister.editValue(); - const quint64 address = addressV.type() == QVariant::ULongLong - ? addressV.toULongLong() : 0; + const quint64 address = idx.data(RegisterAsAddressRole).toULongLong(); QAction *actViewMemory = menu.addAction(QString()); QAction *actEditMemory = menu.addAction(QString()); @@ -188,12 +186,14 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) QAction *actShowDisassembler = menu.addAction(tr("Open Disassembler...")); actShowDisassembler->setEnabled(engine->hasCapability(DisassemblerCapability)); + const QByteArray registerName = idx.data(RegisterNameRole).toByteArray(); + const QString registerNameStr = QString::fromUtf8(registerName); if (address) { const bool canShow = actionsEnabled && engine->hasCapability(ShowMemoryCapability); actEditMemory->setText(tr("Open Memory Editor at 0x%1").arg(address, 0, 16)); actEditMemory->setEnabled(canShow); actViewMemory->setText(tr("Open Memory View at Value of Register %1 0x%2") - .arg(QString::fromLatin1(aRegister.name)).arg(address, 0, 16)); + .arg(registerNameStr).arg(address, 0, 16)); actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1") .arg(address, 0, 16)); actShowDisassemblerAt->setEnabled(engine->hasCapability(DisassemblerCapability)); @@ -207,7 +207,7 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) } menu.addSeparator(); - const int base = handler->numberBase(); + const int base = idx.data(RegisterNumberBaseRole).toInt(); QAction *act16 = menu.addAction(tr("Hexadecimal")); act16->setCheckable(true); act16->setChecked(base == 16); @@ -230,14 +230,20 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) if (act == actReload) { engine->reloadRegisters(); } else if (act == actEditMemory) { - const QString registerName = QString::fromLatin1(aRegister.name); - engine->openMemoryView(address, 0, - RegisterMemoryView::registerMarkup(address, registerName), - QPoint(), RegisterMemoryView::title(registerName), 0); + MemoryViewSetupData data; + data.startAddress = address; + data.registerName = registerName; + data.markup = RegisterMemoryView::registerMarkup(address, registerName); + data.title = RegisterMemoryView::title(registerName); + engine->openMemoryView(data); } else if (act == actViewMemory) { - engine->openMemoryView(idx.row(), - DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView, - QList(), position, QString(), this); + MemoryViewSetupData data; + data.startAddress = address; + data.flags = DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView, + data.registerName = registerName; + data.pos = position; + data.parent = this; + engine->openMemoryView(data); } else if (act == actShowDisassembler) { AddressDialog dialog; if (address) @@ -247,13 +253,13 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev) } else if (act == actShowDisassemblerAt) { engine->openDisassemblerView(Location(address)); } else if (act == act16) - handler->setNumberBase(16); + handler->setNumberBase(registerName, 16); else if (act == act10) - handler->setNumberBase(10); + handler->setNumberBase(registerName, 10); else if (act == act8) - handler->setNumberBase(8); + handler->setNumberBase(registerName, 8); else if (act == act2) - handler->setNumberBase(2); + handler->setNumberBase(registerName, 2); } void RegisterTreeView::reloadRegisters() diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp index c621d84d19d..f2193a91a4c 100644 --- a/src/plugins/debugger/stackwindow.cpp +++ b/src/plugins/debugger/stackwindow.cpp @@ -214,12 +214,13 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev) if (act == actCopyContents) { copyContentsToClipboard(); } else if (act == actShowMemory) { - const QString title = tr("Memory at Frame #%1 (%2) 0x%3"). - arg(row).arg(frame.function).arg(address, 0, 16); - QList ml; - ml.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(), + MemoryViewSetupData data; + data.startAddress = address; + data.title = tr("Memory at Frame #%1 (%2) 0x%3"). + arg(row).arg(frame.function).arg(address, 0, 16); + data.markup.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(), tr("Frame #%1 (%2)").arg(row).arg(frame.function))); - engine->openMemoryView(address, 0, ml, QPoint(), title); + engine->openMemoryView(data); } else if (act == actShowDisassemblerAtAddress) { AddressDialog dialog; if (address) diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 94bc92da7ae..11bc0626979 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -178,21 +178,6 @@ static inline uint sizeOf(const QModelIndex &m) return m.data(LocalsSizeRole).toUInt(); } -// Create a map of value->name for register markup. -typedef QMap RegisterMap; -typedef RegisterMap::const_iterator RegisterMapConstIt; - -RegisterMap registerMap(const DebuggerEngine *engine) -{ - RegisterMap result; - foreach (const Register ®, engine->registerHandler()->registers()) { - const QVariant v = reg.editValue(); - if (v.type() == QVariant::ULongLong) - result.insert(v.toULongLong(), QString::fromLatin1(reg.name)); - } - return result; -} - // Helper functionality to indicate the area of a member variable in // a vector representing the memory area by a unique color // number and tooltip. Parts of it will be overwritten when recursing @@ -314,13 +299,12 @@ static MemoryMarkupList if (sizeIsEstimate && !childCount) return result; // Fixme: Exact size not known, no point in filling if no children. // Punch in registers as 1-byte markers on top. - const RegisterMapConstIt regcEnd = registerMap.constEnd(); - for (RegisterMapConstIt it = registerMap.constBegin(); it != regcEnd; ++it) { + for (auto it = registerMap.constBegin(), end = registerMap.constEnd(); it != end; ++it) { if (it.key() >= address) { const quint64 offset = it.key() - address; if (offset < size) { ranges[offset] = ColorNumberToolTip(registerColorNumber, - WatchTreeView::tr("Register %1").arg(it.value())); + WatchTreeView::tr("Register %1").arg(QString::fromUtf8(it.value()))); } else { break; // Sorted. } @@ -381,27 +365,27 @@ static void addVariableMemoryView(DebuggerEngine *engine, bool separateView, const QPoint &p, QWidget *parent) { const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - const quint64 address = atPointerAddress ? pointerAddressOf(m) : addressOf(m); + MemoryViewSetupData data; + data.startAddress = atPointerAddress ? pointerAddressOf(m) : addressOf(m); + if (!data.startAddress) + return; // Fixme: Get the size of pointee (see variableMemoryMarkup())? const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0); const quint64 typeSize = sizeOf(m); const bool sizeIsEstimate = atPointerAddress || !typeSize; const quint64 size = sizeIsEstimate ? 1024 : typeSize; - if (!address) - return; - const QList markup = - variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip, - address, size, - registerMap(engine), + data.markup = variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip, + data.startAddress, size, + engine->registerHandler()->registerMap(), sizeIsEstimate, background); - const unsigned flags = separateView - ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0; - const QString title = atPointerAddress + data.flags = separateView ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0; + QString pat = atPointerAddress ? WatchTreeView::tr("Memory at Pointer's Address \"%1\" (0x%2)") - .arg(nameOf(m)).arg(address, 0, 16) - : WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)") - .arg(nameOf(m)).arg(address, 0, 16); - engine->openMemoryView(address, flags, markup, p, title, parent); + : WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)"); + data.title = pat.arg(nameOf(m)).arg(data.startAddress, 0, 16); + data.pos = p; + data.parent = parent; + engine->openMemoryView(data); } // Add a memory view of the stack layout showing local variables @@ -444,9 +428,8 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView, } // Take a look at the register values. Extend the range a bit if suitable // to show stack/stack frame pointers. - const RegisterMap regMap = registerMap(engine); - const RegisterMapConstIt regcEnd = regMap.constEnd(); - for (RegisterMapConstIt it = regMap.constBegin(); it != regcEnd; ++it) { + const RegisterMap regMap = engine->registerHandler()->registerMap(); + for (auto it = regMap.constBegin(), cend = regMap.constEnd(); it != cend; ++it) { const quint64 value = it.key(); if (value < start && start - value < 512) start = value; @@ -454,16 +437,18 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView, end = value + 1; } // Indicate all variables. + MemoryViewSetupData data; const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base); - const MemoryMarkupList markup = - variableMemoryMarkup(m, localsIndex, QString(), + data.startAddress = start; + data.markup = variableMemoryMarkup(m, localsIndex, QString(), QString(), start, end - start, regMap, true, background); - const unsigned flags = separateView + data.flags = separateView ? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0; - const QString title = - WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16); - engine->openMemoryView(start, flags, markup, p, title, parent); + data.title = WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16); + data.pos = p; + data.parent = parent; + engine->openMemoryView(data); } ///////////////////////////////////////////////////////////////////// @@ -936,8 +921,11 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) AddressDialog dialog; if (address) dialog.setAddress(address); - if (dialog.exec() == QDialog::Accepted) - currentEngine()->openMemoryView(dialog.address(), false, MemoryMarkupList(), QPoint()); + if (dialog.exec() == QDialog::Accepted) { + MemoryViewSetupData data; + data.startAddress = dialog.address(); + currentEngine()->openMemoryView(data); + } } else if (act == &actOpenMemoryViewAtObjectAddress) { addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this); } else if (act == &actOpenMemoryViewAtPointerAddress) {