Debugger: Polish register view

Right-align subregister values, drop the 0x prefix for hex values,
add a subitem with ASCII representation and tooltips for subitems.

Change-Id: I6a5764fa5ef8b2bfd916cdd828d949a82304503d
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2015-03-31 14:20:43 +02:00
parent 76a8606c38
commit 29322b6124
3 changed files with 117 additions and 54 deletions

View File

@@ -252,14 +252,29 @@ void Register::guessMissingData()
fixup(this, IntegerRegister, 0); fixup(this, IntegerRegister, 0);
} }
static QString subTypeName(RegisterKind kind, int size) static QString subTypeName(RegisterKind kind, int size, RegisterFormat format)
{ {
if (kind == IntegerRegister) QString name(QLatin1Char('['));
return QString::fromLatin1("[i%1]").arg(size * 8);
if (kind == FloatRegister) switch (kind) {
return QString::fromLatin1("[f%1]").arg(size * 8); case IntegerRegister: name += QLatin1Char('i'); break;
QTC_ASSERT(false, /**/); case FloatRegister: name += QLatin1Char('f'); break;
return QString(); default: break;
}
name += QString::number(size);
switch (format) {
case BinaryFormat: name += QLatin1Char('b'); break;
case OctalFormat: name += QLatin1Char('o'); break;
case DecimalFormat: name += QLatin1Char('d'); break;
case HexadecimalFormat: name += QLatin1Char('x'); break;
case CharacterFormat: name += QLatin1Char('c'); break;
}
name += QLatin1Char(']');
return name;
} }
static uint decodeHexChar(unsigned char c) static uint decodeHexChar(unsigned char c)
@@ -305,15 +320,29 @@ bool RegisterValue::operator==(const RegisterValue &other)
return v.u64[0] == other.v.u64[0] && v.u64[1] == other.v.u64[1]; return v.u64[0] == other.v.u64[0] && v.u64[1] == other.v.u64[1];
} }
static QByteArray format(quint64 v, int base, int size) static QByteArray formatRegister(quint64 v, int size, RegisterFormat format)
{ {
QByteArray result = QByteArray::number(v, base); QByteArray result;
if (base == 16) if (format == HexadecimalFormat) {
result = QByteArray::number(v, 16);
result.prepend(QByteArray(2*size - result.size(), '0')); result.prepend(QByteArray(2*size - result.size(), '0'));
} else if (format == DecimalFormat) {
result = QByteArray::number(v, 10);
result.prepend(QByteArray(2*size - result.size(), ' '));
} else if (format == CharacterFormat) {
if (v >= 32 && v < 127) {
result += '\'';
result += char(v);
result += '\'';
} else {
result += " ";
}
result.prepend(QByteArray(2*size - result.size(), ' '));
}
return result; return result;
} }
QByteArray RegisterValue::toByteArray(int base, RegisterKind kind, int size) const QByteArray RegisterValue::toByteArray(RegisterKind kind, int size, RegisterFormat format) const
{ {
if (!known) if (!known)
return "[inaccessible]"; return "[inaccessible]";
@@ -326,15 +355,12 @@ QByteArray RegisterValue::toByteArray(int base, RegisterKind kind, int size) con
QByteArray result; QByteArray result;
if (size > 8) { if (size > 8) {
result += format(v.u64[1], base, size - 8); result += formatRegister(v.u64[1], size - 8, format);
size = 8; size = 8;
if (base != 16) if (format != HexadecimalFormat)
result += ','; result += ',';
} }
result += format(v.u64[0], base, size); return result + formatRegister(v.u64[0], size, format);
if (base == 16)
result.prepend("0x");
return result;
} }
RegisterValue RegisterValue::subValue(int size, int index) const RegisterValue RegisterValue::subValue(int size, int index) const
@@ -367,8 +393,8 @@ RegisterValue RegisterValue::subValue(int size, int index) const
class RegisterSubItem : public Utils::TreeItem class RegisterSubItem : public Utils::TreeItem
{ {
public: public:
RegisterSubItem(RegisterKind subKind, int subSize, int count) RegisterSubItem(RegisterKind subKind, int subSize, int count, RegisterFormat format)
: m_subKind(subKind), m_subSize(subSize), m_count(count), m_changed(false) : m_subKind(subKind), m_subFormat(format), m_subSize(subSize), m_count(count), m_changed(false)
{} {}
QVariant data(int column, int role) const; QVariant data(int column, int role) const;
@@ -382,6 +408,7 @@ public:
} }
RegisterKind m_subKind; RegisterKind m_subKind;
RegisterFormat m_subFormat;
int m_subSize; int m_subSize;
int m_count; int m_count;
bool m_changed; bool m_changed;
@@ -398,23 +425,27 @@ public:
quint64 addressValue() const; quint64 addressValue() const;
Register m_reg; Register m_reg;
int m_base; RegisterFormat m_format;
bool m_changed; bool m_changed;
}; };
RegisterItem::RegisterItem(const Register &reg) : RegisterItem::RegisterItem(const Register &reg) :
m_reg(reg), m_base(16), m_changed(true) m_reg(reg), m_format(HexadecimalFormat), m_changed(true)
{ {
if (m_reg.kind == UnknownRegister) if (m_reg.kind == UnknownRegister)
m_reg.guessMissingData(); m_reg.guessMissingData();
if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) {
for (int s = m_reg.size / 2; s; s = s / 2) for (int s = m_reg.size / 2; s; s = s / 2) {
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s)); appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, HexadecimalFormat));
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, DecimalFormat));
if (s == 1)
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, CharacterFormat));
}
} }
if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) { if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) {
for (int s = m_reg.size; s >= 4; s = s / 2) for (int s = m_reg.size; s >= 4; s = s / 2)
appendChild(new RegisterSubItem(FloatRegister, s, m_reg.size / s)); appendChild(new RegisterSubItem(FloatRegister, s, m_reg.size / s, DecimalFormat));
} }
} }
@@ -444,12 +475,12 @@ QVariant RegisterItem::data(int column, int role) const
case RegisterChangedRole: case RegisterChangedRole:
return m_changed; return m_changed;
case RegisterNumberBaseRole:
return m_base;
case RegisterAsAddressRole: case RegisterAsAddressRole:
return addressValue(); return addressValue();
case RegisterFormatRole:
return m_format;
case Qt::DisplayRole: case Qt::DisplayRole:
switch (column) { switch (column) {
case RegisterNameColumn: { case RegisterNameColumn: {
@@ -459,17 +490,17 @@ QVariant RegisterItem::data(int column, int role) const
return res; return res;
} }
case RegisterValueColumn: { case RegisterValueColumn: {
return m_reg.value.toByteArray(m_base, m_reg.kind, m_reg.size); return m_reg.value.toByteArray(m_reg.kind, m_reg.size, m_format);
} }
} }
case Qt::ToolTipRole: case Qt::ToolTipRole:
return QString::fromLatin1("Current Value: %1\nPreviousValue: %2") 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.value.toByteArray(m_reg.kind, m_reg.size, m_format)))
.arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_base, m_reg.kind, m_reg.size))); .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_base, m_reg.kind, m_reg.size); return 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();
@@ -486,8 +517,10 @@ QVariant RegisterSubItem::data(int column, int role) const
case RegisterChangedRole: case RegisterChangedRole:
return m_changed; return m_changed;
case RegisterNumberBaseRole: case RegisterFormatRole: {
return 16; RegisterItem *registerItem = static_cast<RegisterItem *>(parent());
return int(registerItem->m_format);
}
case RegisterAsAddressRole: case RegisterAsAddressRole:
return 0; return 0;
@@ -495,20 +528,32 @@ QVariant RegisterSubItem::data(int column, int role) const
case Qt::DisplayRole: case Qt::DisplayRole:
switch (column) { switch (column) {
case RegisterNameColumn: case RegisterNameColumn:
return subTypeName(m_subKind, m_subSize); return subTypeName(m_subKind, m_subSize, m_subFormat);
case RegisterValueColumn: { case RegisterValueColumn: {
QTC_ASSERT(parent(), return QVariant()); QTC_ASSERT(parent(), return QVariant());
RegisterItem *registerItem = static_cast<RegisterItem *>(parent()); RegisterItem *registerItem = static_cast<RegisterItem *>(parent());
RegisterValue value = registerItem->m_reg.value; RegisterValue value = registerItem->m_reg.value;
QByteArray ba; QByteArray ba;
for (int i = 0; i != m_count; ++i) { 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; int tab = 5 * (i + 1) * m_subSize;
ba += QByteArray(tab - ba.size(), ' '); QByteArray b = value.subValue(m_subSize, i).toByteArray(m_subKind, m_subSize, m_subFormat);
ba += QByteArray(tab - ba.size() - b.size(), ' ');
ba += b;
} }
return ba; return ba;
} }
} }
case Qt::ToolTipRole:
if (m_subKind == IntegerRegister) {
if (m_subFormat == CharacterFormat)
return RegisterHandler::tr("Content as ASCII Characters");
else
return RegisterHandler::tr("Content as %1-bit Integer Values").arg(8 * m_subSize);
}
if (m_subKind == FloatRegister)
return RegisterHandler::tr("Contents as %1-bit Floating Point Values").arg(8 * m_subSize);
default: default:
break; break;
} }
@@ -553,11 +598,11 @@ void RegisterHandler::updateRegister(const Register &r)
} }
} }
void RegisterHandler::setNumberBase(const QByteArray &name, int base) void RegisterHandler::setNumberFormat(const QByteArray &name, RegisterFormat format)
{ {
RegisterItem *reg = m_registerByName.value(name, 0); RegisterItem *reg = m_registerByName.value(name, 0);
QTC_ASSERT(reg, return); QTC_ASSERT(reg, return);
reg->m_base = base; reg->m_format = format;
QModelIndex index = indexFromItem(reg); QModelIndex index = indexFromItem(reg);
emit dataChanged(index, index); emit dataChanged(index, index);
} }

View File

@@ -52,7 +52,7 @@ enum RegisterDataRole
RegisterNameRole = Qt::UserRole, RegisterNameRole = Qt::UserRole,
RegisterIsBigRole, RegisterIsBigRole,
RegisterChangedRole, RegisterChangedRole,
RegisterNumberBaseRole, RegisterFormatRole,
RegisterAsAddressRole RegisterAsAddressRole
}; };
@@ -66,6 +66,15 @@ enum RegisterKind
OtherRegister OtherRegister
}; };
enum RegisterFormat
{
CharacterFormat,
HexadecimalFormat,
DecimalFormat,
OctalFormat,
BinaryFormat
};
class RegisterValue class RegisterValue
{ {
public: public:
@@ -73,7 +82,7 @@ public:
void operator=(const QByteArray &ba); 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); }
QByteArray toByteArray(int base, RegisterKind kind, int size) const; QByteArray toByteArray(RegisterKind kind, int size, RegisterFormat format) const;
RegisterValue subValue(int size, int index) const; RegisterValue subValue(int size, int index) const;
union { union {
@@ -116,7 +125,7 @@ public:
void updateRegister(const Register &reg); void updateRegister(const Register &reg);
void setNumberBase(const QByteArray &name, int base); void setNumberFormat(const QByteArray &name, RegisterFormat format);
void commitUpdates() { emit layoutChanged(); } void commitUpdates() { emit layoutChanged(); }
RegisterMap registerMap() const; RegisterMap registerMap() const;

View File

@@ -66,11 +66,20 @@ public:
const QModelIndex &index) const const QModelIndex &index) const
{ {
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent); IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
const int base = index.data(RegisterNumberBaseRole).toInt(); const RegisterFormat format = RegisterFormat(index.data(RegisterFormatRole).toInt());
const bool big = index.data(RegisterIsBigRole).toBool(); const bool big = index.data(RegisterIsBigRole).toBool();
// Big integers are assumed to be hexadecimal. // Big integers are assumed to be hexadecimal.
int base = 16;
if (!big) {
if (format == DecimalFormat)
base = 10;
else if (format == OctalFormat)
base = 8;
else if (format == BinaryFormat)
base = 2;
}
lineEdit->setBigInt(big); lineEdit->setBigInt(big);
lineEdit->setBase(big ? 16 : base); lineEdit->setBase(base);
lineEdit->setSigned(false); lineEdit->setSigned(false);
lineEdit->setAlignment(Qt::AlignRight); lineEdit->setAlignment(Qt::AlignRight);
lineEdit->setFrame(false); lineEdit->setFrame(false);
@@ -91,9 +100,9 @@ public:
return; return;
IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor); IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor);
QTC_ASSERT(lineEdit, return); QTC_ASSERT(lineEdit, return);
const int base = index.data(RegisterNumberBaseRole).toInt(); const RegisterFormat format = RegisterFormat(index.data(RegisterFormatRole).toInt());
QString value = lineEdit->text(); QString value = lineEdit->text();
if (base == 16 && !value.startsWith(QLatin1String("0x"))) if (format == HexadecimalFormat && !value.startsWith(QLatin1String("0x")))
value.insert(0, QLatin1String("0x")); value.insert(0, QLatin1String("0x"));
currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value); currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value);
} }
@@ -206,19 +215,19 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
} }
menu.addSeparator(); menu.addSeparator();
const int base = idx.data(RegisterNumberBaseRole).toInt(); const RegisterFormat format = RegisterFormat(idx.data(RegisterFormatRole).toInt());
QAction *act16 = menu.addAction(tr("Hexadecimal")); QAction *act16 = menu.addAction(tr("Hexadecimal"));
act16->setCheckable(true); act16->setCheckable(true);
act16->setChecked(base == 16); act16->setChecked(format == HexadecimalFormat);
QAction *act10 = menu.addAction(tr("Decimal")); QAction *act10 = menu.addAction(tr("Decimal"));
act10->setCheckable(true); act10->setCheckable(true);
act10->setChecked(base == 10); act10->setChecked(format == DecimalFormat);
QAction *act8 = menu.addAction(tr("Octal")); QAction *act8 = menu.addAction(tr("Octal"));
act8->setCheckable(true); act8->setCheckable(true);
act8->setChecked(base == 8); act8->setChecked(format == OctalFormat);
QAction *act2 = menu.addAction(tr("Binary")); QAction *act2 = menu.addAction(tr("Binary"));
act2->setCheckable(true); act2->setCheckable(true);
act2->setChecked(base == 2); act2->setChecked(format == BinaryFormat);
menu.addSeparator(); menu.addSeparator();
menu.addAction(action(SettingsDialog)); menu.addAction(action(SettingsDialog));
@@ -252,13 +261,13 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
} else if (act == actShowDisassemblerAt) { } else if (act == actShowDisassemblerAt) {
engine->openDisassemblerView(Location(address)); engine->openDisassemblerView(Location(address));
} else if (act == act16) } else if (act == act16)
handler->setNumberBase(registerName, 16); handler->setNumberFormat(registerName, HexadecimalFormat);
else if (act == act10) else if (act == act10)
handler->setNumberBase(registerName, 10); handler->setNumberFormat(registerName, DecimalFormat);
else if (act == act8) else if (act == act8)
handler->setNumberBase(registerName, 8); handler->setNumberFormat(registerName, OctalFormat);
else if (act == act2) else if (act == act2)
handler->setNumberBase(registerName, 2); handler->setNumberFormat(registerName, BinaryFormat);
} }
void RegisterTreeView::reloadRegisters() void RegisterTreeView::reloadRegisters()