Commit 18815697 authored by hjk's avatar hjk Committed by hjk

debugger: prepare support for partial register display

Change-Id: I74e971cfb41afbdd07f4193c14c3bb7ecd634859
Reviewed-on: http://codereview.qt.nokia.com/3990Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent 5d82ba7d
......@@ -127,6 +127,7 @@ false {
include(../../shared/modeltest/modeltest.pri)
#DEFINES += USE_WATCH_MODEL_TEST=1
#DEFINES += USE_BREAK_MODEL_TEST=1
#DEFINES += USE_REGISTER_MODEL_TEST=1
}
win32 {
include(../../shared/registryaccess/registryaccess.pri)
......
......@@ -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 {
//////////////////////////////////////////////////////////////////
//
// RegisterHandler
// Register
//
//////////////////////////////////////////////////////////////////
namespace Debugger {
namespace Internal {
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
//
//////////////////////////////////////////////////////////////////
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 &idx) const
{
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 &idx) const
{
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;
}
int RegisterHandler::rowCount(const QModelIndex &parent) const
QModelIndex RegisterHandler::index(int row, int col, const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_registers.size();
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());
}
int RegisterHandler::columnCount(const QModelIndex &parent) const
QModelIndex RegisterHandler::parent(const QModelIndex &idx) const
{
return parent.isValid() ? 0 : 2;
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();
QModelIndex topLevel = index.parent();
const int mainRow = topLevel.isValid() ? topLevel.row() : index.row();
if (mainRow >= m_registers.size())
return QVariant();
const Register &reg = m_registers.at(index.row());
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case 0: {
const QString padding = QLatin1String(" ");
return QVariant(padding + reg.name + padding);
const Register &reg = 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 &registers)
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.
}
}
......
......@@ -42,8 +42,8 @@ namespace Internal {
class Register
{
public:
Register() : changed(true) {}
Register(const QByteArray &name_) : name(name_), changed(true) {}
Register() : type(0), changed(true) {}
Register(const QByteArray &name_);
QVariant editValue() const;
QString displayValue(int base, int strlen) const;
......@@ -55,6 +55,7 @@ public:
* Values that cannot be converted (such as 128bit MMX-registers) are
* passed through. */
QString value;
int type;
bool changed;
};
......@@ -85,8 +86,10 @@ signals:
private:
void calculateWidth();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
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;
......
......@@ -93,6 +93,7 @@ public:
lineEdit->setBase(big ? 16 : base);
lineEdit->setSigned(false);
lineEdit->setAlignment(Qt::AlignRight);
lineEdit->setFrame(false);
return lineEdit;
}
......@@ -199,7 +200,8 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
return;
const Register &aRegister = handler->registers().at(idx.row());
const QVariant addressV = aRegister.editValue();
const quint64 address = addressV.type() == QVariant::ULongLong ? addressV.toULongLong() : 0;
const quint64 address = addressV.type() == QVariant::ULongLong
? addressV.toULongLong() : 0;
QAction *actViewMemory = menu.addAction(QString());
QAction *actEditMemory = menu.addAction(QString());
......@@ -212,8 +214,9 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
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::fromAscii(aRegister.name)).arg(address, 0, 16));
actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1").arg(address, 0, 16));
.arg(QString::fromAscii(aRegister.name)).arg(address, 0, 16));
actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1")
.arg(address, 0, 16));
actShowDisassemblerAt->setEnabled(engineCapabilities & DisassemblerCapability);
} else {
actEditMemory->setText(tr("Open Memory Editor"));
......@@ -255,11 +258,13 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
engine->reloadRegisters();
else if (act == actEditMemory) {
const QString registerName = QString::fromAscii(aRegister.name, address);
engine->openMemoryView(address, 0, RegisterMemoryView::registerMarkup(address, registerName),
QPoint(), RegisterMemoryView::title(registerName), 0);
engine->openMemoryView(address, 0,
RegisterMemoryView::registerMarkup(address, registerName),
QPoint(), RegisterMemoryView::title(registerName), 0);
} else if (act == actViewMemory) {
engine->openMemoryView(idx.row(), DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
QList<MemoryMarkup>(), position, QString(), this);
engine->openMemoryView(idx.row(),
DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
QList<MemoryMarkup>(), position, QString(), this);
} else if (act == actShowDisassembler) {
AddressDialog dialog;
if (address)
......@@ -295,7 +300,6 @@ void RegisterWindow::setAlwaysResizeColumnsToContents(bool on)
void RegisterWindow::setModel(QAbstractItemModel *model)
{
QTreeView::setModel(model);
setAlwaysResizeColumnsToContents(true);
if (header()) {
bool adjust = debuggerCore()->boolSetting(AlwaysAdjustRegistersColumnWidths);
setAlwaysResizeColumnsToContents(adjust);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment