2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "registerhandler.h"
|
2015-08-25 13:48:55 +02:00
|
|
|
|
|
|
|
|
#include "debuggerengine.h"
|
2010-09-22 17:30:22 +02:00
|
|
|
#include "watchdelegatewidgets.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-07-18 12:36:31 +02:00
|
|
|
#include "memoryagent.h"
|
|
|
|
|
#include "debuggeractions.h"
|
|
|
|
|
#include "debuggerdialogs.h"
|
|
|
|
|
#include "debuggercore.h"
|
|
|
|
|
#include "debuggerengine.h"
|
|
|
|
|
|
|
|
|
|
#include <utils/basetreeview.h>
|
2011-08-31 16:45:44 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2016-07-18 12:36:31 +02:00
|
|
|
#include <utils/savedaction.h>
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QItemDelegate>
|
|
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QPainter>
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2016-06-24 08:38:42 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2016-07-18 12:36:31 +02:00
|
|
|
enum RegisterColumns
|
|
|
|
|
{
|
|
|
|
|
RegisterNameColumn,
|
|
|
|
|
RegisterValueColumn,
|
|
|
|
|
RegisterColumnCount
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum RegisterDataRole
|
|
|
|
|
{
|
|
|
|
|
RegisterChangedRole = Qt::UserRole
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// RegisterDelegate
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class RegisterDelegate : public QItemDelegate
|
|
|
|
|
{
|
|
|
|
|
public:
|
2018-07-23 22:28:49 +02:00
|
|
|
RegisterDelegate() = default;
|
2016-07-18 12:36:31 +02:00
|
|
|
|
|
|
|
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
|
|
|
|
const QModelIndex &index) const override
|
|
|
|
|
{
|
|
|
|
|
if (index.column() == RegisterValueColumn) {
|
|
|
|
|
auto lineEdit = new QLineEdit(parent);
|
|
|
|
|
lineEdit->setAlignment(Qt::AlignLeft);
|
|
|
|
|
lineEdit->setFrame(false);
|
|
|
|
|
return lineEdit;
|
|
|
|
|
}
|
2018-07-23 22:28:49 +02:00
|
|
|
return nullptr;
|
2016-07-18 12:36:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setEditorData(QWidget *editor, const QModelIndex &index) const override
|
|
|
|
|
{
|
|
|
|
|
auto lineEdit = qobject_cast<QLineEdit *>(editor);
|
|
|
|
|
QTC_ASSERT(lineEdit, return);
|
|
|
|
|
lineEdit->setText(index.data(Qt::EditRole).toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
|
|
|
|
const QModelIndex &index) const override
|
|
|
|
|
{
|
|
|
|
|
if (index.column() == RegisterValueColumn) {
|
|
|
|
|
auto lineEdit = qobject_cast<QLineEdit *>(editor);
|
|
|
|
|
QTC_ASSERT(lineEdit, return);
|
|
|
|
|
model->setData(index, lineEdit->text(), Qt::EditRole);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
|
|
|
|
const QModelIndex &) const override
|
|
|
|
|
{
|
|
|
|
|
editor->setGeometry(option.rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|
|
|
|
const QModelIndex &index) const override
|
|
|
|
|
{
|
|
|
|
|
if (index.column() == RegisterValueColumn) {
|
|
|
|
|
const bool paintRed = index.data(RegisterChangedRole).toBool();
|
|
|
|
|
QPen oldPen = painter->pen();
|
|
|
|
|
const QColor lightColor(140, 140, 140);
|
|
|
|
|
if (paintRed)
|
|
|
|
|
painter->setPen(QColor(200, 0, 0));
|
|
|
|
|
else
|
|
|
|
|
painter->setPen(lightColor);
|
|
|
|
|
// FIXME: performance? this changes only on real font changes.
|
|
|
|
|
QFontMetrics fm(option.font);
|
2018-10-07 22:38:47 +03:00
|
|
|
int charWidth = qMax(fm.width('x'), fm.width('0'));
|
2016-07-18 12:36:31 +02:00
|
|
|
QString str = index.data(Qt::DisplayRole).toString();
|
|
|
|
|
int x = option.rect.x();
|
|
|
|
|
bool light = !paintRed;
|
|
|
|
|
for (int i = 0; i < str.size(); ++i) {
|
|
|
|
|
const QChar c = str.at(i);
|
|
|
|
|
const int uc = c.unicode();
|
|
|
|
|
if (light && (uc != 'x' && uc != '0')) {
|
|
|
|
|
light = false;
|
|
|
|
|
painter->setPen(oldPen.color());
|
|
|
|
|
}
|
|
|
|
|
if (uc == ' ') {
|
|
|
|
|
light = true;
|
|
|
|
|
painter->setPen(lightColor);
|
|
|
|
|
} else {
|
|
|
|
|
QRect r = option.rect;
|
|
|
|
|
r.setX(x);
|
|
|
|
|
r.setWidth(charWidth);
|
|
|
|
|
painter->drawText(r, Qt::AlignHCenter, c);
|
|
|
|
|
}
|
|
|
|
|
x += charWidth;
|
|
|
|
|
}
|
|
|
|
|
painter->setPen(oldPen);
|
|
|
|
|
} else {
|
|
|
|
|
QItemDelegate::paint(painter, option, index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2011-08-31 16:45:44 +02:00
|
|
|
// Register
|
2008-12-02 12:01:29 +01:00
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
void Register::guessMissingData()
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
if (reportedType == "int")
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = IntegerRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
else if (reportedType == "float")
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = FloatRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
else if (reportedType == "_i387_ext")
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = FloatRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
else if (reportedType == "*1" || reportedType == "long")
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = IntegerRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
else if (reportedType.contains("vec"))
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = VectorRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
else if (reportedType.startsWith("int"))
|
2015-07-21 12:52:18 +02:00
|
|
|
kind = IntegerRegister;
|
|
|
|
|
else if (name.startsWith("xmm") || name.startsWith("ymm"))
|
|
|
|
|
kind = VectorRegister;
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
static QString subTypeName(RegisterKind kind, int size, RegisterFormat format)
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
2018-10-07 22:38:47 +03:00
|
|
|
QString name('[');
|
2015-03-31 14:20:43 +02:00
|
|
|
|
|
|
|
|
switch (kind) {
|
2018-10-07 22:38:47 +03:00
|
|
|
case IntegerRegister: name += 'i'; break;
|
|
|
|
|
case FloatRegister: name += 'f'; break;
|
2015-03-31 14:20:43 +02:00
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name += QString::number(size);
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
2018-10-07 22:38:47 +03:00
|
|
|
case BinaryFormat: name += 'b'; break;
|
|
|
|
|
case OctalFormat: name += 'o'; break;
|
|
|
|
|
case DecimalFormat: name += 'u'; break;
|
|
|
|
|
case SignedDecimalFormat: name += 's'; break;
|
|
|
|
|
case HexadecimalFormat: name += 'x'; break;
|
|
|
|
|
case CharacterFormat: name += 'c'; break;
|
2015-03-31 14:20:43 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-07 22:38:47 +03:00
|
|
|
name += ']';
|
2015-03-31 14:20:43 +02:00
|
|
|
|
|
|
|
|
return name;
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
static uint decodeHexChar(unsigned char c)
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
c -= '0';
|
|
|
|
|
if (c < 10)
|
|
|
|
|
return c;
|
|
|
|
|
c -= 'A' - '0';
|
|
|
|
|
if (c < 6)
|
|
|
|
|
return 10 + c;
|
|
|
|
|
c -= 'a' - 'A';
|
|
|
|
|
if (c < 6)
|
|
|
|
|
return 10 + c;
|
|
|
|
|
return uint(-1);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
void RegisterValue::fromString(const QString &str, RegisterFormat format)
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
known = !str.isEmpty();
|
2014-12-17 13:14:29 +01:00
|
|
|
v.u64[1] = v.u64[0] = 0;
|
2015-08-25 13:48:55 +02:00
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
const int n = str.size();
|
2015-08-25 13:48:55 +02:00
|
|
|
int pos = 0;
|
2016-06-07 17:04:53 +02:00
|
|
|
if (str.startsWith("0x"))
|
2015-08-25 13:48:55 +02:00
|
|
|
pos += 2;
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
bool negative = pos < n && str.at(pos) == '-';
|
2015-08-25 13:48:55 +02:00
|
|
|
if (negative)
|
|
|
|
|
++pos;
|
|
|
|
|
|
|
|
|
|
while (pos < n) {
|
2016-06-07 17:04:53 +02:00
|
|
|
uint c = str.at(pos).unicode();
|
2015-08-25 13:48:55 +02:00
|
|
|
if (format != CharacterFormat) {
|
|
|
|
|
c = decodeHexChar(c);
|
|
|
|
|
if (c == uint(-1))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
shiftOneDigit(c, format);
|
|
|
|
|
++pos;
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
2015-08-25 13:48:55 +02:00
|
|
|
|
|
|
|
|
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];
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
bool RegisterValue::operator==(const RegisterValue &other)
|
2012-09-24 15:48:17 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
return v.u64[0] == other.v.u64[0] && v.u64[1] == other.v.u64[1];
|
2012-09-24 15:48:17 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
static QString formatRegister(quint64 v, int size, RegisterFormat format, bool forEdit)
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString result;
|
2015-03-31 14:20:43 +02:00
|
|
|
if (format == HexadecimalFormat) {
|
2016-06-07 17:04:53 +02:00
|
|
|
result = QString::number(v, 16);
|
|
|
|
|
result.prepend(QString(2*size - result.size(), '0'));
|
2015-03-31 14:20:43 +02:00
|
|
|
} else if (format == DecimalFormat) {
|
2016-06-07 17:04:53 +02:00
|
|
|
result = QString::number(v, 10);
|
|
|
|
|
result.prepend(QString(2*size - result.size(), ' '));
|
2015-07-21 10:26:39 +02:00
|
|
|
} else if (format == SignedDecimalFormat) {
|
|
|
|
|
qint64 sv;
|
|
|
|
|
if (size >= 8)
|
|
|
|
|
sv = qint64(v);
|
|
|
|
|
else if (size >= 4)
|
|
|
|
|
sv = qint32(v);
|
|
|
|
|
else if (size >= 2)
|
|
|
|
|
sv = qint16(v);
|
|
|
|
|
else
|
|
|
|
|
sv = qint8(v);
|
2016-06-07 17:04:53 +02:00
|
|
|
result = QString::number(sv, 10);
|
|
|
|
|
result.prepend(QString(2*size - result.size(), ' '));
|
2015-03-31 14:20:43 +02:00
|
|
|
} else if (format == CharacterFormat) {
|
2015-08-28 13:35:50 +02:00
|
|
|
bool spacesOnly = true;
|
2015-03-31 14:20:43 +02:00
|
|
|
if (v >= 32 && v < 127) {
|
2015-08-28 13:35:50 +02:00
|
|
|
spacesOnly = false;
|
|
|
|
|
if (!forEdit)
|
|
|
|
|
result += '\'';
|
2015-03-31 14:20:43 +02:00
|
|
|
result += char(v);
|
2015-08-28 13:35:50 +02:00
|
|
|
if (!forEdit)
|
|
|
|
|
result += '\'';
|
2015-03-31 14:20:43 +02:00
|
|
|
} else {
|
|
|
|
|
result += " ";
|
|
|
|
|
}
|
2015-08-28 13:35:50 +02:00
|
|
|
if (spacesOnly && forEdit)
|
|
|
|
|
result.clear();
|
|
|
|
|
else
|
2016-06-07 17:04:53 +02:00
|
|
|
result.prepend(QString(2*size - result.size(), ' '));
|
2015-03-31 14:20:43 +02:00
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
return result;
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
QString RegisterValue::toString(RegisterKind kind, int size, RegisterFormat format, bool forEdit) const
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
2015-02-26 11:10:25 +01:00
|
|
|
if (!known)
|
2016-06-07 17:04:53 +02:00
|
|
|
return QLatin1String("[inaccessible]");
|
2014-12-17 13:14:29 +01:00
|
|
|
if (kind == FloatRegister) {
|
|
|
|
|
if (size == 4)
|
2016-06-07 17:04:53 +02:00
|
|
|
return QString::number(v.f[0]);
|
2014-12-17 13:14:29 +01:00
|
|
|
if (size == 8)
|
2016-06-07 17:04:53 +02:00
|
|
|
return QString::number(v.d[0]);
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-07 17:04:53 +02:00
|
|
|
QString result;
|
2014-12-17 13:14:29 +01:00
|
|
|
if (size > 8) {
|
2015-08-28 13:35:50 +02:00
|
|
|
result += formatRegister(v.u64[1], size - 8, format, forEdit);
|
2014-12-17 13:14:29 +01:00
|
|
|
size = 8;
|
2015-03-31 14:20:43 +02:00
|
|
|
if (format != HexadecimalFormat)
|
2014-12-17 13:14:29 +01:00
|
|
|
result += ',';
|
|
|
|
|
}
|
2015-08-28 13:35:50 +02:00
|
|
|
return result + formatRegister(v.u64[0], size, format, forEdit);
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RegisterValue RegisterValue::subValue(int size, int index) const
|
|
|
|
|
{
|
|
|
|
|
RegisterValue value;
|
2015-03-25 12:54:00 +01:00
|
|
|
value.known = known;
|
2014-12-17 13:14:29 +01:00
|
|
|
switch (size) {
|
|
|
|
|
case 1:
|
|
|
|
|
value.v.u8[0] = v.u8[index];
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
value.v.u16[0] = v.u16[index];
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
value.v.u32[0] = v.u32[index];
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
value.v.u64[0] = v.u64[index];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2014-12-17 13:14:29 +01:00
|
|
|
// RegisterSubItem and RegisterItem
|
2011-08-31 16:45:44 +02:00
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
2010-11-05 13:35:31 +01:00
|
|
|
|
2016-06-24 08:38:42 +02:00
|
|
|
class RegisterEditItem : public TypedTreeItem<TreeItem, RegisterSubItem>
|
2015-08-25 13:48:55 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2016-06-24 08:38:42 +02:00
|
|
|
class RegisterSubItem : public TypedTreeItem<RegisterEditItem, RegisterItem>
|
2009-08-13 16:16:19 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
public:
|
2015-03-31 14:20:43 +02:00
|
|
|
RegisterSubItem(RegisterKind subKind, int subSize, int count, RegisterFormat format)
|
|
|
|
|
: m_subKind(subKind), m_subFormat(format), m_subSize(subSize), m_count(count), m_changed(false)
|
2015-08-25 13:48:55 +02:00
|
|
|
{
|
|
|
|
|
for (int i = 0; i != count; ++i)
|
|
|
|
|
appendChild(new RegisterEditItem(i, subKind, subSize, format));
|
|
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
|
2018-07-23 22:28:49 +02:00
|
|
|
QVariant data(int column, int role) const override;
|
2014-12-17 13:14:29 +01:00
|
|
|
|
2018-07-23 22:28:49 +02:00
|
|
|
Qt::ItemFlags flags(int column) const override
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
|
|
|
|
//return column == 1 ? Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable
|
|
|
|
|
// : Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
|
|
|
|
Q_UNUSED(column);
|
|
|
|
|
return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
|
|
|
|
}
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterKind m_subKind;
|
2015-03-31 14:20:43 +02:00
|
|
|
RegisterFormat m_subFormat;
|
2014-12-17 13:14:29 +01:00
|
|
|
int m_subSize;
|
|
|
|
|
int m_count;
|
|
|
|
|
bool m_changed;
|
|
|
|
|
};
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2016-06-24 08:38:42 +02:00
|
|
|
class RegisterItem : public TypedTreeItem<RegisterSubItem>
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
public:
|
2016-07-18 12:36:31 +02:00
|
|
|
RegisterItem(DebuggerEngine *engine, const Register ®);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
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;
|
2014-12-17 13:14:29 +01:00
|
|
|
|
|
|
|
|
quint64 addressValue() const;
|
2015-08-25 13:48:55 +02:00
|
|
|
void triggerChange();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-07-18 12:36:31 +02:00
|
|
|
DebuggerEngine *m_engine;
|
2014-12-17 13:14:29 +01:00
|
|
|
Register m_reg;
|
2016-07-18 12:36:31 +02:00
|
|
|
RegisterFormat m_format = HexadecimalFormat;
|
|
|
|
|
bool m_changed = true;
|
2014-12-17 13:14:29 +01:00
|
|
|
};
|
|
|
|
|
|
2016-07-18 12:36:31 +02:00
|
|
|
RegisterItem::RegisterItem(DebuggerEngine *engine, const Register ®)
|
2018-07-12 00:49:23 +02:00
|
|
|
: m_engine(engine), m_reg(reg)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
if (m_reg.kind == UnknownRegister)
|
|
|
|
|
m_reg.guessMissingData();
|
|
|
|
|
|
|
|
|
|
if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) {
|
2015-07-21 10:26:39 +02:00
|
|
|
if (m_reg.size <= 8) {
|
|
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, m_reg.size, 1, SignedDecimalFormat));
|
|
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, m_reg.size, 1, DecimalFormat));
|
|
|
|
|
}
|
2015-03-31 14:20:43 +02:00
|
|
|
for (int s = m_reg.size / 2; s; s = s / 2) {
|
|
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, HexadecimalFormat));
|
2015-07-21 10:26:39 +02:00
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, SignedDecimalFormat));
|
2015-03-31 14:20:43 +02:00
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, DecimalFormat));
|
|
|
|
|
if (s == 1)
|
|
|
|
|
appendChild(new RegisterSubItem(IntegerRegister, s, m_reg.size / s, CharacterFormat));
|
|
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
if (m_reg.kind == IntegerRegister || m_reg.kind == VectorRegister) {
|
|
|
|
|
for (int s = m_reg.size; s >= 4; s = s / 2)
|
2015-03-31 14:20:43 +02:00
|
|
|
appendChild(new RegisterSubItem(FloatRegister, s, m_reg.size / s, DecimalFormat));
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
Qt::ItemFlags RegisterItem::flags(int column) const
|
2010-09-22 09:41:15 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled;
|
|
|
|
|
// Can edit registers if they are hex numbers and not arrays.
|
2018-10-07 22:38:47 +03:00
|
|
|
if (column == 1) // && IntegerWatchLineEdit::isUnsignedHexNumber(m_reg.display))
|
2014-12-17 13:14:29 +01:00
|
|
|
return notEditable | Qt::ItemIsEditable;
|
|
|
|
|
return notEditable;
|
2010-09-22 17:30:22 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
quint64 RegisterItem::addressValue() const
|
2010-09-22 17:30:22 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
return m_reg.value.v.u64[0];
|
2010-09-22 09:41:15 +02:00
|
|
|
}
|
|
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
void RegisterItem::triggerChange()
|
|
|
|
|
{
|
2016-06-07 17:04:53 +02:00
|
|
|
QString value = "0x" + m_reg.value.toString(m_reg.kind, m_reg.size, HexadecimalFormat);
|
2016-07-18 12:36:31 +02:00
|
|
|
m_engine->setRegisterValue(m_reg.name, value);
|
2015-08-25 13:48:55 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
QVariant RegisterItem::data(int column, int role) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
switch (role) {
|
|
|
|
|
case RegisterChangedRole:
|
|
|
|
|
return m_changed;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
case Qt::DisplayRole:
|
2014-12-17 13:14:29 +01:00
|
|
|
switch (column) {
|
2015-02-26 11:10:25 +01:00
|
|
|
case RegisterNameColumn: {
|
2016-06-07 17:04:53 +02:00
|
|
|
QString res = m_reg.name;
|
2014-12-17 13:14:29 +01:00
|
|
|
if (!m_reg.description.isEmpty())
|
|
|
|
|
res += " (" + m_reg.description + ')';
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2015-02-26 11:10:25 +01:00
|
|
|
case RegisterValueColumn: {
|
2016-06-07 17:04:53 +02:00
|
|
|
return m_reg.value.toString(m_reg.kind, m_reg.size, m_format);
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-06-02 16:12:39 +03:00
|
|
|
break;
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case Qt::ToolTipRole:
|
2016-06-07 17:04:53 +02:00
|
|
|
return QString("Current Value: %1\nPreviousValue: %2")
|
|
|
|
|
.arg(m_reg.value.toString(m_reg.kind, m_reg.size, m_format))
|
|
|
|
|
.arg(m_reg.previousValue.toString(m_reg.kind, m_reg.size, m_format));
|
2011-08-31 16:45:44 +02:00
|
|
|
|
|
|
|
|
case Qt::EditRole: // Edit: Unpadded for editing
|
2016-06-07 17:04:53 +02:00
|
|
|
return m_reg.value.toString(m_reg.kind, m_reg.size, m_format);
|
2014-12-17 13:14:29 +01:00
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
case Qt::TextAlignmentRole:
|
2015-02-26 11:10:25 +01:00
|
|
|
return column == RegisterValueColumn ? QVariant(Qt::AlignRight) : QVariant();
|
2014-12-17 13:14:29 +01:00
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
bool RegisterItem::setData(int column, const QVariant &value, int role)
|
|
|
|
|
{
|
|
|
|
|
if (column == RegisterValueColumn && role == Qt::EditRole) {
|
2016-06-07 17:04:53 +02:00
|
|
|
m_reg.value.fromString(value.toString(), m_format);
|
2015-08-25 13:48:55 +02:00
|
|
|
triggerChange();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
QVariant RegisterSubItem::data(int column, int role) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
switch (role) {
|
|
|
|
|
case RegisterChangedRole:
|
|
|
|
|
return m_changed;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case Qt::DisplayRole:
|
|
|
|
|
switch (column) {
|
2015-02-26 11:10:25 +01:00
|
|
|
case RegisterNameColumn:
|
2015-03-31 14:20:43 +02:00
|
|
|
return subTypeName(m_subKind, m_subSize, m_subFormat);
|
2015-02-26 11:10:25 +01:00
|
|
|
case RegisterValueColumn: {
|
2014-12-17 13:14:29 +01:00
|
|
|
QTC_ASSERT(parent(), return QVariant());
|
2016-06-24 08:38:42 +02:00
|
|
|
RegisterValue value = parent()->m_reg.value;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString ba;
|
2014-12-17 13:14:29 +01:00
|
|
|
for (int i = 0; i != m_count; ++i) {
|
|
|
|
|
int tab = 5 * (i + 1) * m_subSize;
|
2016-06-07 17:04:53 +02:00
|
|
|
QString b = value.subValue(m_subSize, i).toString(m_subKind, m_subSize, m_subFormat);
|
|
|
|
|
ba += QString(tab - ba.size() - b.size(), ' ');
|
2015-03-31 14:20:43 +02:00
|
|
|
ba += b;
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-02 16:12:39 +03:00
|
|
|
break;
|
2015-03-31 14:20:43 +02:00
|
|
|
|
|
|
|
|
case Qt::ToolTipRole:
|
|
|
|
|
if (m_subKind == IntegerRegister) {
|
|
|
|
|
if (m_subFormat == CharacterFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as ASCII Characters");
|
2015-07-21 10:26:39 +02:00
|
|
|
if (m_subFormat == SignedDecimalFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as %1-bit Signed Decimal Values").arg(8 * m_subSize);
|
|
|
|
|
if (m_subFormat == DecimalFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as %1-bit Unsigned Decimal Values").arg(8 * m_subSize);
|
|
|
|
|
if (m_subFormat == HexadecimalFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as %1-bit Hexadecimal Values").arg(8 * m_subSize);
|
|
|
|
|
if (m_subFormat == OctalFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as %1-bit Octal Values").arg(8 * m_subSize);
|
|
|
|
|
if (m_subFormat == BinaryFormat)
|
|
|
|
|
return RegisterHandler::tr("Content as %1-bit Binary Values").arg(8 * m_subSize);
|
2015-03-31 14:20:43 +02:00
|
|
|
}
|
|
|
|
|
if (m_subKind == FloatRegister)
|
2016-01-20 15:50:07 +01:00
|
|
|
return RegisterHandler::tr("Content as %1-bit Floating Point Values").arg(8 * m_subSize);
|
2015-03-31 14:20:43 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
return QVariant();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// RegisterHandler
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
RegisterHandler::RegisterHandler(DebuggerEngine *engine)
|
|
|
|
|
: m_engine(engine)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-07-18 12:36:31 +02:00
|
|
|
setObjectName("RegisterModel");
|
2015-08-25 13:48:55 +02:00
|
|
|
setHeader({tr("Name"), tr("Value")});
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
void RegisterHandler::updateRegister(const Register &r)
|
2010-09-01 13:56:51 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterItem *reg = m_registerByName.value(r.name, 0);
|
|
|
|
|
if (!reg) {
|
2016-07-18 12:36:31 +02:00
|
|
|
reg = new RegisterItem(m_engine, r);
|
2014-12-17 13:14:29 +01:00
|
|
|
m_registerByName[r.name] = reg;
|
|
|
|
|
rootItem()->appendChild(reg);
|
2011-04-06 14:07:09 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-09-01 13:56:51 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
if (r.size > 0)
|
|
|
|
|
reg->m_reg.size = r.size;
|
|
|
|
|
if (!r.description.isEmpty())
|
|
|
|
|
reg->m_reg.description = r.description;
|
|
|
|
|
if (reg->m_reg.value != r.value) {
|
|
|
|
|
// Indicate red if values change, keep changed.
|
|
|
|
|
reg->m_changed = true;
|
|
|
|
|
reg->m_reg.previousValue = reg->m_reg.value;
|
|
|
|
|
reg->m_reg.value = r.value;
|
|
|
|
|
emit registerChanged(reg->m_reg.name, reg->addressValue()); // Notify attached memory views.
|
|
|
|
|
} else {
|
|
|
|
|
reg->m_changed = false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2009-08-13 16:16:19 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterMap RegisterHandler::registerMap() const
|
2009-08-13 16:16:19 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterMap result;
|
2016-06-27 13:56:16 +02:00
|
|
|
for (int i = 0, n = rootItem()->childCount(); i != n; ++i) {
|
|
|
|
|
RegisterItem *reg = rootItem()->childAt(i);
|
2014-12-17 13:14:29 +01:00
|
|
|
quint64 value = reg->addressValue();
|
|
|
|
|
if (value)
|
|
|
|
|
result.insert(value, reg->m_reg.name);
|
2010-09-22 09:41:15 +02:00
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
return result;
|
2009-08-13 16:16:19 +02:00
|
|
|
}
|
2010-11-05 13:35:31 +01:00
|
|
|
|
2016-07-18 12:36:31 +02:00
|
|
|
QVariant RegisterHandler::data(const QModelIndex &idx, int role) const
|
|
|
|
|
{
|
|
|
|
|
if (role == BaseTreeView::ItemDelegateRole)
|
|
|
|
|
return QVariant::fromValue(static_cast<QAbstractItemDelegate *>(new RegisterDelegate));
|
|
|
|
|
|
|
|
|
|
return RegisterModel::data(idx, role);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RegisterHandler::setData(const QModelIndex &idx, const QVariant &data, int role)
|
|
|
|
|
{
|
|
|
|
|
if (role == BaseTreeView::ItemViewEventRole) {
|
|
|
|
|
ItemViewEvent ev = data.value<ItemViewEvent>();
|
|
|
|
|
if (ev.type() == QEvent::ContextMenu)
|
|
|
|
|
return contextMenuEvent(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RegisterModel::setData(idx, data, role);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev)
|
|
|
|
|
{
|
|
|
|
|
const DebuggerState state = m_engine->state();
|
Debugger: Make most views per-engine instead of singletons
This is a step towards properly supporting multiple debugger
sessions side-by-side.
The combined C++-and-QML engine has been removed, instead a
combined setup creates now two individual engines, under a single
DebuggerRunTool but mostly independent with no combined state
machine. This requires a few more clicks in some cases, but
makes it easier to direct e.g. interrupt requests to the
interesting engine.
Care has been taken to not change the UX of the single debugger
session use case if possible. The fat debug button operates
as-before in that case, i.e. switches to Interrupt if the
single active runconfiguration runs in the debugger etc.
Most views are made per-engine, running an engine creates
a new Perspective, which is destroyed when the run control dies.
The snapshot view remains global and becomes primary source
of information on a "current engine" that receives all menu
and otherwise global input.
There is a new global "Breakpoint Preset" view containing
all "static" breakpoint data. When an engine starts up it
"claims" breakpoint it believes it can handle, but operates
on a copy of the static data. The markers of the static
version are suppressed as long as an engine controls a
breakpoint (that inclusive all resolved locations), but are
re-instatet once the engine quits.
The old Breakpoint class that already contained this split
per-instance was split into a new Breakpoint and a
GlobalBreakpoint class, with a per-engine model for Breakpoints,
and a singleton model containing GlobalBreakpoints.
There is a new CppDebuggerEngine intermediate level serving as
base for C++ (or, rather, "compiled") binary debugging, i.e.
{Gdb,Lldb,Cdb}Engine, taking over bits of the current DebuggerEngine
base that are not applicable to non-binary debuggers.
Change-Id: I9994f4c188379b4aee0c4f379edd4759fbb0bd43
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2018-07-31 12:30:48 +02:00
|
|
|
const bool actionsEnabled = m_engine->debuggerActionsEnabled();
|
2016-07-18 12:36:31 +02:00
|
|
|
|
2016-06-24 09:36:42 +02:00
|
|
|
RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.index());
|
|
|
|
|
RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.index());
|
2016-07-18 12:36:31 +02:00
|
|
|
|
|
|
|
|
const quint64 address = registerItem ? registerItem->addressValue() : 0;
|
|
|
|
|
const QString registerName = registerItem ? registerItem->m_reg.name : QString();
|
|
|
|
|
|
|
|
|
|
auto menu = new QMenu;
|
|
|
|
|
|
|
|
|
|
addAction(menu, tr("Reload Register Listing"),
|
|
|
|
|
m_engine->hasCapability(RegisterCapability)
|
|
|
|
|
&& (state == InferiorStopOk || state == InferiorUnrunnable),
|
|
|
|
|
[this] { m_engine->reloadRegisters(); });
|
|
|
|
|
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
|
|
|
|
addAction(menu, tr("Open Memory View at Value of Register %1 0x%2")
|
|
|
|
|
.arg(registerName).arg(address, 0, 16),
|
|
|
|
|
tr("Open Memory View at Value of Register"),
|
|
|
|
|
address,
|
|
|
|
|
[this, registerName, address] {
|
|
|
|
|
MemoryViewSetupData data;
|
|
|
|
|
data.startAddress = address;
|
|
|
|
|
data.registerName = registerName;
|
2016-08-03 22:19:34 +02:00
|
|
|
data.trackRegisters = true;
|
|
|
|
|
data.separateView = true;
|
2016-07-18 12:36:31 +02:00
|
|
|
m_engine->openMemoryView(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16),
|
|
|
|
|
tr("Open Memory Editor"),
|
|
|
|
|
address && actionsEnabled && m_engine->hasCapability(ShowMemoryCapability),
|
|
|
|
|
[this, registerName, address] {
|
|
|
|
|
MemoryViewSetupData data;
|
|
|
|
|
data.startAddress = address;
|
|
|
|
|
data.registerName = registerName;
|
2016-07-14 10:00:15 +02:00
|
|
|
data.markup = registerViewMarkup(address, registerName);
|
|
|
|
|
data.title = registerViewTitle(registerName);
|
2016-07-18 12:36:31 +02:00
|
|
|
m_engine->openMemoryView(data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16),
|
|
|
|
|
tr("Open Disassembler"),
|
|
|
|
|
address && m_engine->hasCapability(DisassemblerCapability),
|
|
|
|
|
[this, address] { m_engine->openDisassemblerView(Location(address)); });
|
|
|
|
|
|
|
|
|
|
addAction(menu, tr("Open Disassembler..."),
|
|
|
|
|
m_engine->hasCapability(DisassemblerCapability),
|
|
|
|
|
[this, address] {
|
|
|
|
|
AddressDialog dialog;
|
|
|
|
|
if (address)
|
|
|
|
|
dialog.setAddress(address);
|
|
|
|
|
if (dialog.exec() == QDialog::Accepted)
|
|
|
|
|
m_engine->openDisassemblerView(Location(dialog.address()));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
|
|
|
|
const RegisterFormat currentFormat = registerItem
|
|
|
|
|
? registerItem->m_format
|
|
|
|
|
: registerSubItem
|
|
|
|
|
? registerSubItem->parent()->m_format
|
|
|
|
|
: HexadecimalFormat;
|
|
|
|
|
|
2017-09-07 17:05:47 +02:00
|
|
|
auto addFormatAction =
|
|
|
|
|
[menu, currentFormat, registerItem](const QString &display, RegisterFormat format) {
|
|
|
|
|
addCheckableAction(menu, display, registerItem, currentFormat == format,
|
|
|
|
|
[registerItem, format] {
|
2016-07-18 12:36:31 +02:00
|
|
|
registerItem->m_format = format;
|
|
|
|
|
registerItem->update();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
addFormatAction(tr("Hexadecimal"), HexadecimalFormat);
|
2016-11-03 18:13:30 +01:00
|
|
|
addFormatAction(tr("Decimal"), DecimalFormat);
|
2016-07-18 12:36:31 +02:00
|
|
|
addFormatAction(tr("Octal"), OctalFormat);
|
|
|
|
|
addFormatAction(tr("Binary"), BinaryFormat);
|
|
|
|
|
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
menu->addAction(action(SettingsDialog));
|
|
|
|
|
menu->popup(ev.globalPos());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-25 13:48:55 +02:00
|
|
|
QVariant RegisterEditItem::data(int column, int role) const
|
|
|
|
|
{
|
|
|
|
|
switch (role) {
|
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
|
case Qt::EditRole:
|
|
|
|
|
switch (column) {
|
|
|
|
|
case RegisterNameColumn: {
|
2016-06-07 17:04:53 +02:00
|
|
|
return QString("[%1]").arg(m_index);
|
2015-08-25 13:48:55 +02:00
|
|
|
}
|
|
|
|
|
case RegisterValueColumn: {
|
2016-06-24 08:38:42 +02:00
|
|
|
RegisterValue value = parent()->parent()->m_reg.value;
|
2015-08-28 13:35:50 +02:00
|
|
|
return value.subValue(m_subSize, m_index)
|
2016-06-07 17:04:53 +02:00
|
|
|
.toString(m_subKind, m_subSize, m_subFormat, role == Qt::EditRole);
|
2015-08-25 13:48:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-06-02 16:12:39 +03:00
|
|
|
break;
|
2015-08-25 13:48:55 +02:00
|
|
|
case Qt::ToolTipRole: {
|
2016-06-24 08:38:42 +02:00
|
|
|
RegisterItem *registerItem = parent()->parent();
|
2015-08-25 13:48:55 +02:00
|
|
|
return RegisterHandler::tr("Edit bits %1...%2 of register %3")
|
2016-06-07 17:04:53 +02:00
|
|
|
.arg(m_index * 8).arg(m_index * 8 + 7).arg(registerItem->m_reg.name);
|
2015-08-25 13:48:55 +02:00
|
|
|
}
|
|
|
|
|
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);
|
2016-06-24 08:38:42 +02:00
|
|
|
RegisterItem *registerItem = parent()->parent();
|
2015-08-25 13:48:55 +02:00
|
|
|
Register ® = registerItem->m_reg;
|
|
|
|
|
RegisterValue vv;
|
2016-06-07 17:04:53 +02:00
|
|
|
vv.fromString(value.toString(), m_subFormat);
|
2015-08-25 13:48:55 +02:00
|
|
|
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());
|
2016-06-24 08:38:42 +02:00
|
|
|
Qt::ItemFlags f = parent()->flags(column);
|
2015-08-25 13:48:55 +02:00
|
|
|
if (column == RegisterValueColumn)
|
|
|
|
|
f |= Qt::ItemIsEditable;
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-05 13:35:31 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|