diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 6987065c2aede290d474bc88d83e114deee0bdd4..c08acacf05dcfc8de699d2cc15e9d79508860c21 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -1278,6 +1278,19 @@ class Dumper(DumperBase): result += ']' self.report(result) + def setRegister(self, args): + self.reportToken(args) + name = args["name"] + value = args["value"] + result = lldb.SBCommandReturnObject() + self.debugger.GetCommandInterpreter().HandleCommand( + "register write %s %s" % (name, value), result) + success = result.Succeeded() + if success: + self.report('output="%s"' % result.GetOutput()) + else: + self.report('error="%s"' % result.GetError()) + def report(self, stuff): with self.outputLock: sys.stdout.write("@\n" + stuff + "@\n") diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index a18de4de12b3aacf0d391421e8d8762dc656cd26..4c7dc4e9c55ca482b12d76d33534af3b92634697 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1672,7 +1672,7 @@ void CdbEngine::handleRegistersExt(const DebuggerResponse &response) reg.name = item["name"].data(); reg.description = item["description"].data(); reg.reportedType = item["type"].data(); - reg.value = item["value"].data(); + reg.value.fromByteArray(item["value"].data(), HexadecimalFormat); reg.size = item["size"].data().toInt(); handler->updateRegister(reg); } diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index e19c526c7a036002681654683551e950d36cf2ab..2279e8c996d610670898d13ceb21768d778d6032 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -195,7 +195,7 @@ public: m_remoteSetupState(RemoteSetupNone), m_inferiorPid(0), m_modulesHandler(engine), - m_registerHandler(), + m_registerHandler(engine), m_sourceFilesHandler(), m_stackHandler(), m_threadsHandler(), diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 435cb85098a9164e34cc70fbcf7cbb2ec6001519..855fd85f287dda753914f21b428cd638caf4abfc 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3632,14 +3632,18 @@ void GdbEngine::handleMaintPrintRegisters(const DebuggerResponse &response) readWord(ba, &pos); // Offset reg.size = readWord(ba, &pos).toInt(); reg.reportedType = readWord(ba, &pos); - reg.value = readWord(ba, &pos); + reg.value.fromByteArray(readWord(ba, &pos), HexadecimalFormat); handler->updateRegister(reg); } handler->commitUpdates(); } + void GdbEngine::setRegisterValue(const QByteArray &name, const QString &value) { - postCommand("set $" + name + "=" + value.toLatin1()); + QByteArray fullName = name; + if (name.startsWith("xmm")) + fullName += ".uint128"; + postCommand("set $" + fullName + "=" + value.toLatin1()); reloadRegisters(); } @@ -3705,7 +3709,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) Register reg = m_registers[number]; QByteArray data = item["value"].data(); if (data.startsWith("0x")) { - reg.value = data; + reg.value.fromByteArray(data, HexadecimalFormat); } else if (data == "") { // Nothing. See QTCREATORBUG-14029. } else { @@ -3718,7 +3722,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) // v2_int64 = {0x0000000000000000, 0x0000000000000000}, // uint128 = }"} // Try to make sense of it using the int32 chunks: - QByteArray result = "0x"; + QByteArray result; const int pos1 = data.indexOf("_int32"); const int pos2 = data.indexOf('{', pos1) + 1; const int pos3 = data.indexOf('}', pos2); @@ -3733,7 +3737,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) QTC_ASSERT(chunk.size() == 8, continue); result.append(chunk); } - reg.value = result; + reg.value.fromByteArray(result, HexadecimalFormat); } handler->updateRegister(reg); } diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 6d135df89ca69783fddc294d8993ae619cd409c0..9173a77cc1c0aac787cb750ab17dfaa1c296ce65 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -1033,9 +1033,11 @@ void LldbEngine::refreshRegisters(const GdbMi ®isters) foreach (const GdbMi &item, registers.children()) { Register reg; reg.name = item["name"].data(); - reg.value = item["value"].data(); + reg.value.fromByteArray(item["value"].data(), HexadecimalFormat); reg.size = item["size"].data().toInt(); reg.reportedType = item["type"].data(); + if (reg.reportedType.startsWith("unsigned")) + reg.kind = IntegerRegister; handler->updateRegister(reg); } handler->commitUpdates(); diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index ca2dd95706c65824f89ec6a76a3c6858a2b9bce3..16279988f7096be5e95de9d613bfd7337c0b87c0 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -29,6 +29,8 @@ ****************************************************************************/ #include "registerhandler.h" + +#include "debuggerengine.h" #include "watchdelegatewidgets.h" #include @@ -100,27 +102,37 @@ static uint decodeHexChar(unsigned char c) return uint(-1); } -void RegisterValue::operator=(const QByteArray &ba) +void RegisterValue::fromByteArray(const QByteArray &ba, RegisterFormat format) { known = !ba.isEmpty(); - 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; + + const int n = ba.size(); + int pos = 0; + if (ba.startsWith("0x")) + pos += 2; + + bool negative = pos < n && ba.at(pos) == '-'; + if (negative) + ++pos; + + while (pos < n) { + uint c = ba.at(pos); + if (format != CharacterFormat) { + c = decodeHexChar(c); + if (c == uint(-1)) + break; + } + shiftOneDigit(c, format); + ++pos; } - 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; + + if (negative) { + v.u64[1] = ~v.u64[1]; + v.u64[0] = ~v.u64[0]; + ++v.u64[0]; + if (v.u64[0] == 0) + ++v.u64[1]; } } @@ -205,18 +217,102 @@ RegisterValue RegisterValue::subValue(int size, int index) const return value; } +void RegisterValue::setSubValue(int size, int index, RegisterValue subValue) +{ + switch (size) { + case 1: + v.u8[index] = subValue.v.u8[0]; + break; + case 2: + v.u16[index] = subValue.v.u16[0]; + break; + case 4: + v.u32[index] = subValue.v.u32[0]; + break; + case 8: + v.u64[index] = subValue.v.u64[0]; + break; + } +} + +static inline void shiftBitsLeft(RegisterValue *val, int amount) +{ + val->v.u64[1] <<= amount; + val->v.u64[1] |= val->v.u64[0] >> (64 - amount); + val->v.u64[0] <<= amount; +} + +void RegisterValue::shiftOneDigit(uint digit, RegisterFormat format) +{ + switch (format) { + case HexadecimalFormat: + shiftBitsLeft(this, 4); + v.u64[0] |= digit; + break; + case OctalFormat: + shiftBitsLeft(this, 3); + v.u64[0] |= digit; + break; + case BinaryFormat: + shiftBitsLeft(this, 1); + v.u64[0] |= digit; + break; + case DecimalFormat: + case SignedDecimalFormat: { + shiftBitsLeft(this, 1); + quint64 tmp0 = v.u64[0]; + quint64 tmp1 = v.u64[1]; + shiftBitsLeft(this, 2); + v.u64[1] += tmp1; + v.u64[0] += tmp0; + if (v.u64[0] < tmp0) + ++v.u64[1]; + v.u64[0] += digit; + if (v.u64[0] < digit) + ++v.u64[1]; + break; + } + case CharacterFormat: + shiftBitsLeft(this, 8); + v.u64[0] |= digit; + } +} + ////////////////////////////////////////////////////////////////// // // RegisterSubItem and RegisterItem // ////////////////////////////////////////////////////////////////// +class RegisterSubItem; + +class RegisterEditItem : public Utils::TreeItem +{ +public: + RegisterEditItem(int pos, RegisterKind subKind, int subSize, RegisterFormat format) + : m_index(pos), m_subKind(subKind), m_subSize(subSize), m_subFormat(format) + {} + + QVariant data(int column, int role) const override; + bool setData(int column, const QVariant &value, int role) override; + Qt::ItemFlags flags(int column) const override; + + int m_index; + RegisterKind m_subKind; + int m_subSize; + RegisterFormat m_subFormat; +}; + + class RegisterSubItem : public Utils::TreeItem { public: RegisterSubItem(RegisterKind subKind, int subSize, int count, RegisterFormat format) : m_subKind(subKind), m_subFormat(format), m_subSize(subSize), m_count(count), m_changed(false) - {} + { + for (int i = 0; i != count; ++i) + appendChild(new RegisterEditItem(i, subKind, subSize, format)); + } QVariant data(int column, int role) const; @@ -240,10 +336,12 @@ class RegisterItem : public Utils::TreeItem public: explicit RegisterItem(const Register ®); - QVariant data(int column, int role) const; - Qt::ItemFlags flags(int column) const; + QVariant data(int column, int role) const override; + bool setData(int column, const QVariant &value, int role) override; + Qt::ItemFlags flags(int column) const override; quint64 addressValue() const; + void triggerChange(); Register m_reg; RegisterFormat m_format; @@ -289,6 +387,13 @@ quint64 RegisterItem::addressValue() const return m_reg.value.v.u64[0]; } +void RegisterItem::triggerChange() +{ + QByteArray ba = "0x" + m_reg.value.toByteArray(m_reg.kind, m_reg.size, HexadecimalFormat); + DebuggerEngine *engine = static_cast(model())->engine(); + engine->setRegisterValue(m_reg.name, QString::fromLatin1(ba)); +} + QVariant RegisterItem::data(int column, int role) const { switch (role) { @@ -326,7 +431,7 @@ QVariant RegisterItem::data(int column, int role) const .arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_reg.kind, m_reg.size, m_format))); case Qt::EditRole: // Edit: Unpadded for editing - return m_reg.value.toByteArray(m_reg.kind, m_reg.size, m_format); + return QString::fromLatin1(m_reg.value.toByteArray(m_reg.kind, m_reg.size, m_format)); case Qt::TextAlignmentRole: return column == RegisterValueColumn ? QVariant(Qt::AlignRight) : QVariant(); @@ -337,6 +442,16 @@ QVariant RegisterItem::data(int column, int role) const return QVariant(); } +bool RegisterItem::setData(int column, const QVariant &value, int role) +{ + if (column == RegisterValueColumn && role == Qt::EditRole) { + m_reg.value.fromByteArray(value.toString().toLatin1(), m_format); + triggerChange(); + return true; + } + return false; +} + QVariant RegisterSubItem::data(int column, int role) const { switch (role) { @@ -401,10 +516,11 @@ QVariant RegisterSubItem::data(int column, int role) const // ////////////////////////////////////////////////////////////////// -RegisterHandler::RegisterHandler() +RegisterHandler::RegisterHandler(DebuggerEngine *engine) + : m_engine(engine) { setObjectName(QLatin1String("RegisterModel")); - setHeader(QStringList() << tr("Name") << tr("Value")); + setHeader({tr("Name"), tr("Value")}); } void RegisterHandler::updateRegister(const Register &r) @@ -454,5 +570,58 @@ RegisterMap RegisterHandler::registerMap() const return result; } +QVariant RegisterEditItem::data(int column, int role) const +{ + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + switch (column) { + case RegisterNameColumn: { + return QString::fromLatin1("[%1]").arg(m_index); + } + case RegisterValueColumn: { + RegisterItem *registerItem = static_cast(parent()->parent()); + RegisterValue value = registerItem->m_reg.value; + return value.subValue(m_subSize, m_index).toByteArray(m_subKind, m_subSize, m_subFormat); + } + } + case Qt::ToolTipRole: { + RegisterItem *registerItem = static_cast(parent()->parent()); + return RegisterHandler::tr("Edit bits %1...%2 of register %3") + .arg(m_index * 8).arg(m_index * 8 + 8) + .arg(QString::fromLatin1(registerItem->m_reg.name)); + } + default: + break; + } + return QVariant(); +} + +bool RegisterEditItem::setData(int column, const QVariant &value, int role) +{ + if (column == RegisterValueColumn && role == Qt::EditRole) { + QTC_ASSERT(parent(), return false); + QTC_ASSERT(parent()->parent(), return false); + RegisterItem *registerItem = static_cast(parent()->parent()); + Register ® = registerItem->m_reg; + RegisterValue vv; + vv.fromByteArray(value.toString().toLatin1(), m_subFormat); + reg.value.setSubValue(m_subSize, m_index, vv); + registerItem->triggerChange(); + return true; + } + return false; +} + +Qt::ItemFlags RegisterEditItem::flags(int column) const +{ + QTC_ASSERT(parent(), return Qt::ItemFlags()); + RegisterSubItem *registerSubItem = static_cast(parent()); + Qt::ItemFlags f = registerSubItem->flags(column); + if (column == RegisterValueColumn) + f |= Qt::ItemIsEditable; + return f; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/registerhandler.h b/src/plugins/debugger/registerhandler.h index 3afe40bd4cafb95a571f4b02a0b6c51a5c86e026..fae27ae2a02d6d58da5436b988008e4e2f8e48d4 100644 --- a/src/plugins/debugger/registerhandler.h +++ b/src/plugins/debugger/registerhandler.h @@ -40,6 +40,8 @@ namespace Debugger { namespace Internal { +class DebuggerEngine; + enum RegisterColumns { RegisterNameColumn, @@ -80,11 +82,16 @@ class RegisterValue { public: RegisterValue() { known = false; 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); } + + void fromByteArray(const QByteArray &ba, RegisterFormat format); QByteArray toByteArray(RegisterKind kind, int size, RegisterFormat format) const; + RegisterValue subValue(int size, int index) const; + void setSubValue(int size, int index, RegisterValue subValue); + + void shiftOneDigit(uint digit, RegisterFormat format); union { quint8 u8[16]; @@ -120,9 +127,10 @@ class RegisterHandler : public Utils::TreeModel Q_OBJECT public: - RegisterHandler(); + explicit RegisterHandler(DebuggerEngine *engine); QAbstractItemModel *model() { return this; } + DebuggerEngine *engine() const { return m_engine; } void updateRegister(const Register ®); @@ -135,6 +143,7 @@ signals: private: QHash m_registerByName; + DebuggerEngine * const m_engine; }; } // namespace Internal diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp index 1cdc690f5e42d9b5870e0c4aa167c9de5729ef12..254007ca59b62eddc0660c05d5c712ff0e2a4c4e 100644 --- a/src/plugins/debugger/registerwindow.cpp +++ b/src/plugins/debugger/registerwindow.cpp @@ -63,58 +63,42 @@ public: {} QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, - const QModelIndex &index) const + const QModelIndex &index) const override { - IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent); - const RegisterFormat format = RegisterFormat(index.data(RegisterFormatRole).toInt()); - const bool big = index.data(RegisterIsBigRole).toBool(); - // Big integers are assumed to be hexadecimal. - int base = 16; - if (!big) { - if (format == DecimalFormat || format == SignedDecimalFormat) - base = 10; - else if (format == OctalFormat) - base = 8; - else if (format == BinaryFormat) - base = 2; + if (index.column() == RegisterValueColumn) { + auto lineEdit = new QLineEdit(parent); + lineEdit->setAlignment(Qt::AlignLeft); + lineEdit->setFrame(false); + return lineEdit; } - lineEdit->setBigInt(big); - lineEdit->setBase(base); - lineEdit->setSigned(false); - lineEdit->setAlignment(Qt::AlignRight); - lineEdit->setFrame(false); - return lineEdit; + return 0; } - void setEditorData(QWidget *editor, const QModelIndex &index) const + void setEditorData(QWidget *editor, const QModelIndex &index) const override { - IntegerWatchLineEdit *lineEdit = qobject_cast(editor); + auto lineEdit = qobject_cast(editor); QTC_ASSERT(lineEdit, return); - lineEdit->setModelData(index.data(Qt::EditRole)); + lineEdit->setText(index.data(Qt::EditRole).toString()); } - void setModelData(QWidget *editor, QAbstractItemModel *, - const QModelIndex &index) const + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const override { - if (index.column() != 1) - return; - IntegerWatchLineEdit *lineEdit = qobject_cast(editor); - QTC_ASSERT(lineEdit, return); - const RegisterFormat format = RegisterFormat(index.data(RegisterFormatRole).toInt()); - QString value = lineEdit->text(); - if (format == HexadecimalFormat && !value.startsWith(QLatin1String("0x"))) - value.insert(0, QLatin1String("0x")); - currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value); + if (index.column() == RegisterValueColumn) { + auto lineEdit = qobject_cast(editor); + QTC_ASSERT(lineEdit, return); + model->setData(index, lineEdit->text(), Qt::EditRole); + } } void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, - const QModelIndex &) const + const QModelIndex &) const override { editor->setGeometry(option.rect); } void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const + const QModelIndex &index) const override { if (index.column() == RegisterValueColumn) { const bool paintRed = index.data(RegisterChangedRole).toBool();