Commit afa6bb9d authored by hjk's avatar hjk

Debugger: Make (sub-)registers editable

Change-Id: Ibca2808513b6784b65d5c7223717a8b1d930c381
Reviewed-by: default avatarChristian Stenger <christian.stenger@theqtcompany.com>
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
parent 03be835b
...@@ -1278,6 +1278,19 @@ class Dumper(DumperBase): ...@@ -1278,6 +1278,19 @@ class Dumper(DumperBase):
result += ']' result += ']'
self.report(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): def report(self, stuff):
with self.outputLock: with self.outputLock:
sys.stdout.write("@\n" + stuff + "@\n") sys.stdout.write("@\n" + stuff + "@\n")
......
...@@ -1672,7 +1672,7 @@ void CdbEngine::handleRegistersExt(const DebuggerResponse &response) ...@@ -1672,7 +1672,7 @@ void CdbEngine::handleRegistersExt(const DebuggerResponse &response)
reg.name = item["name"].data(); reg.name = item["name"].data();
reg.description = item["description"].data(); reg.description = item["description"].data();
reg.reportedType = item["type"].data(); reg.reportedType = item["type"].data();
reg.value = item["value"].data(); reg.value.fromByteArray(item["value"].data(), HexadecimalFormat);
reg.size = item["size"].data().toInt(); reg.size = item["size"].data().toInt();
handler->updateRegister(reg); handler->updateRegister(reg);
} }
......
...@@ -195,7 +195,7 @@ public: ...@@ -195,7 +195,7 @@ public:
m_remoteSetupState(RemoteSetupNone), m_remoteSetupState(RemoteSetupNone),
m_inferiorPid(0), m_inferiorPid(0),
m_modulesHandler(engine), m_modulesHandler(engine),
m_registerHandler(), m_registerHandler(engine),
m_sourceFilesHandler(), m_sourceFilesHandler(),
m_stackHandler(), m_stackHandler(),
m_threadsHandler(), m_threadsHandler(),
......
...@@ -3632,14 +3632,18 @@ void GdbEngine::handleMaintPrintRegisters(const DebuggerResponse &response) ...@@ -3632,14 +3632,18 @@ void GdbEngine::handleMaintPrintRegisters(const DebuggerResponse &response)
readWord(ba, &pos); // Offset readWord(ba, &pos); // Offset
reg.size = readWord(ba, &pos).toInt(); reg.size = readWord(ba, &pos).toInt();
reg.reportedType = readWord(ba, &pos); reg.reportedType = readWord(ba, &pos);
reg.value = readWord(ba, &pos); reg.value.fromByteArray(readWord(ba, &pos), HexadecimalFormat);
handler->updateRegister(reg); handler->updateRegister(reg);
} }
handler->commitUpdates(); handler->commitUpdates();
} }
void GdbEngine::setRegisterValue(const QByteArray &name, const QString &value) 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(); reloadRegisters();
} }
...@@ -3705,7 +3709,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) ...@@ -3705,7 +3709,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
Register reg = m_registers[number]; Register reg = m_registers[number];
QByteArray data = item["value"].data(); QByteArray data = item["value"].data();
if (data.startsWith("0x")) { if (data.startsWith("0x")) {
reg.value = data; reg.value.fromByteArray(data, HexadecimalFormat);
} else if (data == "<error reading variable>") { } else if (data == "<error reading variable>") {
// Nothing. See QTCREATORBUG-14029. // Nothing. See QTCREATORBUG-14029.
} else { } else {
...@@ -3718,7 +3722,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) ...@@ -3718,7 +3722,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
// v2_int64 = {0x0000000000000000, 0x0000000000000000}, // v2_int64 = {0x0000000000000000, 0x0000000000000000},
// uint128 = <error reading variable>}"} // uint128 = <error reading variable>}"}
// Try to make sense of it using the int32 chunks: // Try to make sense of it using the int32 chunks:
QByteArray result = "0x"; QByteArray result;
const int pos1 = data.indexOf("_int32"); const int pos1 = data.indexOf("_int32");
const int pos2 = data.indexOf('{', pos1) + 1; const int pos2 = data.indexOf('{', pos1) + 1;
const int pos3 = data.indexOf('}', pos2); const int pos3 = data.indexOf('}', pos2);
...@@ -3733,7 +3737,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response) ...@@ -3733,7 +3737,7 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
QTC_ASSERT(chunk.size() == 8, continue); QTC_ASSERT(chunk.size() == 8, continue);
result.append(chunk); result.append(chunk);
} }
reg.value = result; reg.value.fromByteArray(result, HexadecimalFormat);
} }
handler->updateRegister(reg); handler->updateRegister(reg);
} }
......
...@@ -1033,9 +1033,11 @@ void LldbEngine::refreshRegisters(const GdbMi &registers) ...@@ -1033,9 +1033,11 @@ void LldbEngine::refreshRegisters(const GdbMi &registers)
foreach (const GdbMi &item, registers.children()) { foreach (const GdbMi &item, registers.children()) {
Register reg; Register reg;
reg.name = item["name"].data(); reg.name = item["name"].data();
reg.value = item["value"].data(); reg.value.fromByteArray(item["value"].data(), HexadecimalFormat);
reg.size = item["size"].data().toInt(); reg.size = item["size"].data().toInt();
reg.reportedType = item["type"].data(); reg.reportedType = item["type"].data();
if (reg.reportedType.startsWith("unsigned"))
reg.kind = IntegerRegister;
handler->updateRegister(reg); handler->updateRegister(reg);
} }
handler->commitUpdates(); handler->commitUpdates();
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
****************************************************************************/ ****************************************************************************/
#include "registerhandler.h" #include "registerhandler.h"
#include "debuggerengine.h"
#include "watchdelegatewidgets.h" #include "watchdelegatewidgets.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
...@@ -100,27 +102,37 @@ static uint decodeHexChar(unsigned char c) ...@@ -100,27 +102,37 @@ static uint decodeHexChar(unsigned char c)
return uint(-1); return uint(-1);
} }
void RegisterValue::operator=(const QByteArray &ba) void RegisterValue::fromByteArray(const QByteArray &ba, RegisterFormat format)
{ {
known = !ba.isEmpty(); known = !ba.isEmpty();
uint shift = 0;
int j = 0;
v.u64[1] = v.u64[0] = 0; v.u64[1] = v.u64[0] = 0;
for (int i = ba.size(); --i >= 0 && j < 16; ++j) {
quint64 d = decodeHexChar(ba.at(i)); const int n = ba.size();
if (d == uint(-1)) int pos = 0;
return; if (ba.startsWith("0x"))
v.u64[0] |= (d << shift); pos += 2;
shift += 4;
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; if (negative) {
for (int i = ba.size() - 16; --i >= 0 && j < 16; ++j) { v.u64[1] = ~v.u64[1];
quint64 d = decodeHexChar(ba.at(i)); v.u64[0] = ~v.u64[0];
if (d == uint(-1)) ++v.u64[0];
return; if (v.u64[0] == 0)
v.u64[1] |= (d << shift); ++v.u64[1];
shift += 4;
} }
} }
...@@ -205,18 +217,102 @@ RegisterValue RegisterValue::subValue(int size, int index) const ...@@ -205,18 +217,102 @@ RegisterValue RegisterValue::subValue(int size, int index) const
return value; 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 // 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 class RegisterSubItem : public Utils::TreeItem
{ {
public: public:
RegisterSubItem(RegisterKind subKind, int subSize, int count, RegisterFormat format) RegisterSubItem(RegisterKind subKind, int subSize, int count, RegisterFormat format)
: m_subKind(subKind), m_subFormat(format), m_subSize(subSize), m_count(count), m_changed(false) : 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; QVariant data(int column, int role) const;
...@@ -240,10 +336,12 @@ class RegisterItem : public Utils::TreeItem ...@@ -240,10 +336,12 @@ class RegisterItem : public Utils::TreeItem
public: public:
explicit RegisterItem(const Register &reg); explicit RegisterItem(const Register &reg);
QVariant data(int column, int role) const; QVariant data(int column, int role) const override;
Qt::ItemFlags flags(int column) const; bool setData(int column, const QVariant &value, int role) override;
Qt::ItemFlags flags(int column) const override;
quint64 addressValue() const; quint64 addressValue() const;
void triggerChange();
Register m_reg; Register m_reg;
RegisterFormat m_format; RegisterFormat m_format;
...@@ -289,6 +387,13 @@ quint64 RegisterItem::addressValue() const ...@@ -289,6 +387,13 @@ quint64 RegisterItem::addressValue() const
return m_reg.value.v.u64[0]; 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<RegisterHandler *>(model())->engine();
engine->setRegisterValue(m_reg.name, QString::fromLatin1(ba));
}
QVariant RegisterItem::data(int column, int role) const QVariant RegisterItem::data(int column, int role) const
{ {
switch (role) { switch (role) {
...@@ -326,7 +431,7 @@ QVariant RegisterItem::data(int column, int role) const ...@@ -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))); .arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_reg.kind, m_reg.size, m_format)));
case Qt::EditRole: // Edit: Unpadded for editing 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: case Qt::TextAlignmentRole:
return column == RegisterValueColumn ? QVariant(Qt::AlignRight) : QVariant(); return column == RegisterValueColumn ? QVariant(Qt::AlignRight) : QVariant();
...@@ -337,6 +442,16 @@ QVariant RegisterItem::data(int column, int role) const ...@@ -337,6 +442,16 @@ QVariant RegisterItem::data(int column, int role) const
return QVariant(); 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 QVariant RegisterSubItem::data(int column, int role) const
{ {
switch (role) { switch (role) {
...@@ -401,10 +516,11 @@ QVariant RegisterSubItem::data(int column, int role) const ...@@ -401,10 +516,11 @@ QVariant RegisterSubItem::data(int column, int role) const
// //
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
RegisterHandler::RegisterHandler() RegisterHandler::RegisterHandler(DebuggerEngine *engine)
: m_engine(engine)
{ {
setObjectName(QLatin1String("RegisterModel")); setObjectName(QLatin1String("RegisterModel"));
setHeader(QStringList() << tr("Name") << tr("Value")); setHeader({tr("Name"), tr("Value")});
} }
void RegisterHandler::updateRegister(const Register &r) void RegisterHandler::updateRegister(const Register &r)
...@@ -454,5 +570,58 @@ RegisterMap RegisterHandler::registerMap() const ...@@ -454,5 +570,58 @@ RegisterMap RegisterHandler::registerMap() const
return result; 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<RegisterItem *>(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<RegisterItem *>(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<RegisterItem *>(parent()->parent());
Register &reg = 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<RegisterSubItem *>(parent());
Qt::ItemFlags f = registerSubItem->flags(column);
if (column == RegisterValueColumn)
f |= Qt::ItemIsEditable;
return f;
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerEngine;
enum RegisterColumns enum RegisterColumns
{ {
RegisterNameColumn, RegisterNameColumn,
...@@ -80,11 +82,16 @@ class RegisterValue ...@@ -80,11 +82,16 @@ class RegisterValue
{ {
public: public:
RegisterValue() { known = false; v.u64[1] = v.u64[0] = 0; } 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);
bool operator!=(const RegisterValue &other) { return !operator==(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; QByteArray toByteArray(RegisterKind kind, int size, RegisterFormat format) const;
RegisterValue subValue(int size, int index) const; RegisterValue subValue(int size, int index) const;
void setSubValue(int size, int index, RegisterValue subValue);
void shiftOneDigit(uint digit, RegisterFormat format);
union { union {
quint8 u8[16]; quint8 u8[16];
...@@ -120,9 +127,10 @@ class RegisterHandler : public Utils::TreeModel ...@@ -120,9 +127,10 @@ class RegisterHandler : public Utils::TreeModel
Q_OBJECT Q_OBJECT
public: public:
RegisterHandler(); explicit RegisterHandler(DebuggerEngine *engine);
QAbstractItemModel *model() { return this; } QAbstractItemModel *model() { return this; }
DebuggerEngine *engine() const { return m_engine; }
void updateRegister(const Register &reg); void updateRegister(const Register &reg);
...@@ -135,6 +143,7 @@ signals: ...@@ -135,6 +143,7 @@ signals:
private: private:
QHash<QByteArray, RegisterItem *> m_registerByName; QHash<QByteArray, RegisterItem *> m_registerByName;
DebuggerEngine * const m_engine;
}; };
} // namespace Internal } // namespace Internal
......
...@@ -63,58 +63,42 @@ public: ...@@ -63,58 +63,42 @@ public:
{} {}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
const QModelIndex &index) const const QModelIndex &index) const override
{ {
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent); if (index.column() == RegisterValueColumn) {
const RegisterFormat format = RegisterFormat(index.data(RegisterFormatRole).toInt()); auto lineEdit = new QLineEdit(parent);
const bool big = index.data(RegisterIsBigRole).toBool(); lineEdit->setAlignment(Qt::AlignLeft);
// Big integers are assumed to be hexadecimal. lineEdit->setFrame(false);
int base = 16; return lineEdit;
if (!big) {
if (format == DecimalFormat || format == SignedDecimalFormat)
base = 10;
else if (format == OctalFormat)
base = 8;
else if (format == BinaryFormat)
base = 2;
} }
lineEdit->setBigInt(big); return 0;