forked from qt-creator/qt-creator
debugger: prepare support for partial register display
Change-Id: I74e971cfb41afbdd07f4193c14c3bb7ecd634859 Reviewed-on: http://codereview.qt.nokia.com/3990 Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -33,29 +33,231 @@
|
||||
#include "registerhandler.h"
|
||||
#include "watchdelegatewidgets.h"
|
||||
|
||||
#if USE_REGISTER_MODEL_TEST
|
||||
#include "modeltest.h"
|
||||
#endif
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Register
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
enum RegisterType
|
||||
{
|
||||
RegisterUnknown,
|
||||
//RegisterDummy, // like AH if EAX is present.
|
||||
RegisterI8,
|
||||
RegisterI16,
|
||||
RegisterI32,
|
||||
RegisterI64,
|
||||
RegisterF32,
|
||||
RegisterF64,
|
||||
RegisterF80,
|
||||
RegisterXMM,
|
||||
RegisterMMX,
|
||||
RegisterNeon,
|
||||
RegisterFlags32
|
||||
};
|
||||
|
||||
static struct RegisterNameAndType
|
||||
{
|
||||
const char *name;
|
||||
RegisterType type;
|
||||
} theNameAndType[] = {
|
||||
{ "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 }
|
||||
};
|
||||
|
||||
static RegisterType guessType(const QByteArray &name)
|
||||
{
|
||||
static QHash<QByteArray, RegisterType> 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);
|
||||
}
|
||||
|
||||
static int childCountFromType(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case RegisterUnknown: return 0;
|
||||
case RegisterI8: return 0;
|
||||
case RegisterI16: return 1;
|
||||
case RegisterI32: return 2;
|
||||
case RegisterI64: return 3;
|
||||
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;
|
||||
}
|
||||
QTC_ASSERT(false, /**/);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bitWidthFromType(int type, int subType)
|
||||
{
|
||||
const uint integer[] = { 8, 16, 32, 64 };
|
||||
const uint xmm[] = { 8, 16, 32, 64 };
|
||||
const uint mmx[] = { 8, 16, 32, 64 };
|
||||
const uint neon[] = { 8, 16, 32, 64 };
|
||||
|
||||
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 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;
|
||||
}
|
||||
QTC_ASSERT(false, /**/);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Register::Register(const QByteArray &name_)
|
||||
: name(name_), changed(true)
|
||||
{
|
||||
type = guessType(name);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RegisterHandler
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
RegisterHandler::RegisterHandler()
|
||||
: m_base(-1)
|
||||
{
|
||||
setNumberBase(16);
|
||||
m_base = 16;
|
||||
calculateWidth();
|
||||
#if USE_REGISTER_MODEL_TEST
|
||||
new ModelTest(this, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int RegisterHandler::rowCount(const QModelIndex &parent) const
|
||||
int RegisterHandler::rowCount(const QModelIndex &idx) const
|
||||
{
|
||||
return parent.isValid() ? 0 : m_registers.size();
|
||||
if (idx.column() > 0)
|
||||
return 0;
|
||||
if (!idx.isValid())
|
||||
return m_registers.size(); // Top level.
|
||||
if (idx.internalId() >= 0)
|
||||
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 &parent) const
|
||||
int RegisterHandler::columnCount(const QModelIndex &idx) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 2;
|
||||
if (idx.column() > 0)
|
||||
return 0;
|
||||
if (!idx.isValid())
|
||||
return 2;
|
||||
if (idx.internalId() >= 0)
|
||||
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, -1);
|
||||
if (parent.internalId() >= 0) // 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 (idx.internalId() >= 0)
|
||||
return createIndex(idx.internalId(), 0, -1);
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
// Editor value: Preferably number, else string.
|
||||
@@ -83,27 +285,67 @@ QString Register::displayValue(int base, int strlen) const
|
||||
|
||||
QVariant RegisterHandler::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= m_registers.size())
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
const Register ® = m_registers.at(index.row());
|
||||
QModelIndex topLevel = index.parent();
|
||||
const int mainRow = topLevel.isValid() ? topLevel.row() : index.row();
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case 0: {
|
||||
const QString padding = QLatin1String(" ");
|
||||
return QVariant(padding + reg.name + padding);
|
||||
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 "[Bytes]";
|
||||
case 16: return "[Words]";
|
||||
case 32: return "[DWords]";
|
||||
case 64: return "[QWords]";
|
||||
case -32: return "[Single]";
|
||||
case -64: return "[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 + 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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
@@ -113,8 +355,8 @@ QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation,
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case 0: return tr("Name");
|
||||
case 1: return tr("Value (base %1)").arg(m_base);
|
||||
case 0: return tr("Name");
|
||||
case 1: return tr("Value (Base %1)").arg(m_base);
|
||||
};
|
||||
}
|
||||
return QVariant();
|
||||
@@ -128,7 +370,7 @@ Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const
|
||||
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(m_registers.at(idx.row()).value))
|
||||
&& IntegerWatchLineEdit::isUnsignedHexNumber(m_registers.at(idx.row()).value))
|
||||
return notEditable | Qt::ItemIsEditable;
|
||||
return notEditable;
|
||||
}
|
||||
@@ -173,15 +415,16 @@ void RegisterHandler::setAndMarkRegisters(const Registers ®isters)
|
||||
return;
|
||||
}
|
||||
const int size = m_registers.size();
|
||||
for (int r = 0; r < size; r++) {
|
||||
const QModelIndex regIndex = index(r, 1);
|
||||
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[r].changed || !m_registers.at(r).value.isEmpty();
|
||||
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.
|
||||
emit registerSet(regIndex); // Notify attached memory views.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user