2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
|
** Contact: http://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
|
2015-01-14 18:07:15 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms and
|
|
|
|
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
2014-10-01 13:21:18 +02:00
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-10-01 13:21:18 +02:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-10-02 09:12:39 +02:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
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"
|
2010-09-22 17:30:22 +02:00
|
|
|
#include "watchdelegatewidgets.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
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
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2011-08-31 16:45:44 +02:00
|
|
|
static struct RegisterNameAndType
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterKind kind;
|
|
|
|
|
int size;
|
2011-08-31 16:45:44 +02:00
|
|
|
} theNameAndType[] = {
|
2011-09-01 18:56:07 +02:00
|
|
|
// ARM
|
2014-12-17 13:14:29 +01:00
|
|
|
{ "r0", IntegerRegister, 4 },
|
|
|
|
|
{ "r1", IntegerRegister, 4 },
|
|
|
|
|
{ "r2", IntegerRegister, 4 },
|
|
|
|
|
{ "r3", IntegerRegister, 4 },
|
|
|
|
|
{ "r4", IntegerRegister, 4 },
|
|
|
|
|
{ "r5", IntegerRegister, 4 },
|
|
|
|
|
{ "r6", IntegerRegister, 4 },
|
|
|
|
|
{ "r7", IntegerRegister, 4 },
|
|
|
|
|
{ "r8", IntegerRegister, 4 },
|
|
|
|
|
{ "r9", IntegerRegister, 4 },
|
|
|
|
|
{ "r10", IntegerRegister, 4 },
|
|
|
|
|
{ "r11", IntegerRegister, 4 },
|
|
|
|
|
{ "r12", IntegerRegister, 4 },
|
|
|
|
|
{ "sp", IntegerRegister, 4 },
|
|
|
|
|
{ "lr", IntegerRegister, 4 },
|
|
|
|
|
{ "pc", IntegerRegister, 4 },
|
|
|
|
|
{ "cpsr", FlagRegister, 4 },
|
|
|
|
|
{ "d0", IntegerRegister, 8 },
|
|
|
|
|
{ "d1", IntegerRegister, 8 },
|
|
|
|
|
{ "d2", IntegerRegister, 8 },
|
|
|
|
|
{ "d3", IntegerRegister, 8 },
|
|
|
|
|
{ "d4", IntegerRegister, 8 },
|
|
|
|
|
{ "d5", IntegerRegister, 8 },
|
|
|
|
|
{ "d6", IntegerRegister, 8 },
|
|
|
|
|
{ "d7", IntegerRegister, 8 },
|
|
|
|
|
{ "d8", IntegerRegister, 8 },
|
|
|
|
|
{ "d9", IntegerRegister, 8 },
|
|
|
|
|
{ "d10", IntegerRegister, 8 },
|
|
|
|
|
{ "d11", IntegerRegister, 8 },
|
|
|
|
|
{ "d12", IntegerRegister, 8 },
|
|
|
|
|
{ "d13", IntegerRegister, 8 },
|
|
|
|
|
{ "d14", IntegerRegister, 8 },
|
|
|
|
|
{ "d15", IntegerRegister, 8 },
|
|
|
|
|
{ "d16", IntegerRegister, 8 },
|
|
|
|
|
{ "d17", IntegerRegister, 8 },
|
|
|
|
|
{ "d18", IntegerRegister, 8 },
|
|
|
|
|
{ "d19", IntegerRegister, 8 },
|
|
|
|
|
{ "d20", IntegerRegister, 8 },
|
|
|
|
|
{ "d21", IntegerRegister, 8 },
|
|
|
|
|
{ "d22", IntegerRegister, 8 },
|
|
|
|
|
{ "d23", IntegerRegister, 8 },
|
|
|
|
|
{ "d24", IntegerRegister, 8 },
|
|
|
|
|
{ "d25", IntegerRegister, 8 },
|
|
|
|
|
{ "d26", IntegerRegister, 8 },
|
|
|
|
|
{ "d27", IntegerRegister, 8 },
|
|
|
|
|
{ "d28", IntegerRegister, 8 },
|
|
|
|
|
{ "d29", IntegerRegister, 8 },
|
|
|
|
|
{ "d30", IntegerRegister, 8 },
|
|
|
|
|
{ "d31", IntegerRegister, 8 },
|
|
|
|
|
{ "fpscr", FlagRegister, 4 },
|
|
|
|
|
{ "s0", IntegerRegister, 4 },
|
|
|
|
|
{ "s1", IntegerRegister, 4 },
|
|
|
|
|
{ "s2", IntegerRegister, 4 },
|
|
|
|
|
{ "s3", IntegerRegister, 4 },
|
|
|
|
|
{ "s4", IntegerRegister, 4 },
|
|
|
|
|
{ "s5", IntegerRegister, 4 },
|
|
|
|
|
{ "s6", IntegerRegister, 4 },
|
|
|
|
|
{ "s7", IntegerRegister, 4 },
|
|
|
|
|
{ "s8", IntegerRegister, 4 },
|
|
|
|
|
{ "s9", IntegerRegister, 4 },
|
|
|
|
|
{ "s10", IntegerRegister, 4 },
|
|
|
|
|
{ "s11", IntegerRegister, 4 },
|
|
|
|
|
{ "s12", IntegerRegister, 4 },
|
|
|
|
|
{ "s13", IntegerRegister, 4 },
|
|
|
|
|
{ "s14", IntegerRegister, 4 },
|
|
|
|
|
{ "s15", IntegerRegister, 4 },
|
|
|
|
|
{ "s16", IntegerRegister, 4 },
|
|
|
|
|
{ "s17", IntegerRegister, 4 },
|
|
|
|
|
{ "s18", IntegerRegister, 4 },
|
|
|
|
|
{ "s19", IntegerRegister, 4 },
|
|
|
|
|
{ "s20", IntegerRegister, 4 },
|
|
|
|
|
{ "s21", IntegerRegister, 4 },
|
|
|
|
|
{ "s22", IntegerRegister, 4 },
|
|
|
|
|
{ "s23", IntegerRegister, 4 },
|
|
|
|
|
{ "s24", IntegerRegister, 4 },
|
|
|
|
|
{ "s25", IntegerRegister, 4 },
|
|
|
|
|
{ "s26", IntegerRegister, 4 },
|
|
|
|
|
{ "s27", IntegerRegister, 4 },
|
|
|
|
|
{ "s28", IntegerRegister, 4 },
|
|
|
|
|
{ "s29", IntegerRegister, 4 },
|
|
|
|
|
{ "s30", IntegerRegister, 4 },
|
|
|
|
|
{ "s31", IntegerRegister, 4 },
|
|
|
|
|
{ "q0", IntegerRegister, 16 },
|
|
|
|
|
{ "q1", IntegerRegister, 16 },
|
|
|
|
|
{ "q2", IntegerRegister, 16 },
|
|
|
|
|
{ "q3", IntegerRegister, 16 },
|
|
|
|
|
{ "q4", IntegerRegister, 16 },
|
|
|
|
|
{ "q5", IntegerRegister, 16 },
|
|
|
|
|
{ "q6", IntegerRegister, 16 },
|
|
|
|
|
{ "q7", IntegerRegister, 16 },
|
|
|
|
|
{ "q8", IntegerRegister, 16 },
|
|
|
|
|
{ "q9", IntegerRegister, 16 },
|
|
|
|
|
{ "q10", IntegerRegister, 16 },
|
|
|
|
|
{ "q11", IntegerRegister, 16 },
|
|
|
|
|
{ "q12", IntegerRegister, 16 },
|
|
|
|
|
{ "q13", IntegerRegister, 16 },
|
|
|
|
|
{ "q14", IntegerRegister, 16 },
|
|
|
|
|
{ "q15", IntegerRegister, 16 },
|
2011-09-01 18:56:07 +02:00
|
|
|
|
|
|
|
|
// Intel
|
2014-12-17 13:14:29 +01:00
|
|
|
{ "eax", IntegerRegister, 4 },
|
|
|
|
|
{ "ecx", IntegerRegister, 4 },
|
|
|
|
|
{ "edx", IntegerRegister, 4 },
|
|
|
|
|
{ "ebx", IntegerRegister, 4 },
|
|
|
|
|
{ "esp", IntegerRegister, 4 },
|
|
|
|
|
{ "ebp", IntegerRegister, 4 },
|
|
|
|
|
{ "esi", IntegerRegister, 4 },
|
|
|
|
|
{ "edi", IntegerRegister, 4 },
|
|
|
|
|
{ "eip", IntegerRegister, 4 },
|
|
|
|
|
{ "rax", IntegerRegister, 8 },
|
|
|
|
|
{ "rcx", IntegerRegister, 8 },
|
|
|
|
|
{ "rdx", IntegerRegister, 8 },
|
|
|
|
|
{ "rbx", IntegerRegister, 8 },
|
|
|
|
|
{ "rsp", IntegerRegister, 8 },
|
|
|
|
|
{ "rbp", IntegerRegister, 8 },
|
|
|
|
|
{ "rsi", IntegerRegister, 8 },
|
|
|
|
|
{ "rdi", IntegerRegister, 8 },
|
|
|
|
|
{ "rip", IntegerRegister, 8 },
|
|
|
|
|
{ "eflags", FlagRegister, 4 },
|
|
|
|
|
{ "cs", IntegerRegister, 2 },
|
|
|
|
|
{ "ss", IntegerRegister, 2 },
|
|
|
|
|
{ "ds", IntegerRegister, 2 },
|
|
|
|
|
{ "es", IntegerRegister, 2 },
|
|
|
|
|
{ "fs", IntegerRegister, 2 },
|
|
|
|
|
{ "gs", IntegerRegister, 2 },
|
|
|
|
|
{ "st0", FloatRegister, 10 },
|
|
|
|
|
{ "st1", FloatRegister, 10 },
|
|
|
|
|
{ "st2", FloatRegister, 10 },
|
|
|
|
|
{ "st3", FloatRegister, 10 },
|
|
|
|
|
{ "st4", FloatRegister, 10 },
|
|
|
|
|
{ "st5", FloatRegister, 10 },
|
|
|
|
|
{ "st6", FloatRegister, 10 },
|
|
|
|
|
{ "st7", FloatRegister, 10 },
|
|
|
|
|
{ "fctrl", FlagRegister, 4 },
|
|
|
|
|
{ "fstat", FlagRegister, 4 },
|
|
|
|
|
{ "ftag", FlagRegister, 4 },
|
|
|
|
|
{ "fiseg", FlagRegister, 4 },
|
|
|
|
|
{ "fioff", FlagRegister, 4 },
|
|
|
|
|
{ "foseg", FlagRegister, 4 },
|
|
|
|
|
{ "fooff", FlagRegister, 4 },
|
|
|
|
|
{ "fop", FlagRegister, 4 },
|
|
|
|
|
{ "mxcsr", FlagRegister, 4 },
|
|
|
|
|
{ "orig_eax", IntegerRegister, 4 },
|
|
|
|
|
{ "al", IntegerRegister, 1 },
|
|
|
|
|
{ "cl", IntegerRegister, 1 },
|
|
|
|
|
{ "dl", IntegerRegister, 1 },
|
|
|
|
|
{ "bl", IntegerRegister, 1 },
|
|
|
|
|
{ "ah", IntegerRegister, 1 },
|
|
|
|
|
{ "ch", IntegerRegister, 1 },
|
|
|
|
|
{ "dh", IntegerRegister, 1 },
|
|
|
|
|
{ "bh", IntegerRegister, 1 },
|
|
|
|
|
{ "ax", IntegerRegister, 2 },
|
|
|
|
|
{ "cx", IntegerRegister, 2 },
|
|
|
|
|
{ "dx", IntegerRegister, 2 },
|
|
|
|
|
{ "bx", IntegerRegister, 2 },
|
|
|
|
|
{ "bp", IntegerRegister, 2 },
|
|
|
|
|
{ "si", IntegerRegister, 2 },
|
|
|
|
|
{ "di", IntegerRegister, 2 }
|
2011-08-31 16:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// RegisterValue
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// FIXME: This should not really be needed. Instead the guessing, if any,
|
|
|
|
|
// should done by the engines.
|
|
|
|
|
static void fixup(Register *reg, RegisterKind kind, int size)
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
reg->kind = kind;
|
|
|
|
|
if (!reg->size)
|
|
|
|
|
reg->size = size;
|
2011-08-31 16:45:44 +02: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 (name.startsWith("xmm")) {
|
|
|
|
|
fixup(this, VectorRegister, 16);
|
|
|
|
|
return;
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
|
|
|
|
|
for (int i = 0; i != sizeof(theNameAndType) / sizeof(theNameAndType[0]); ++i) {
|
|
|
|
|
if (theNameAndType[i].name == name) {
|
|
|
|
|
fixup(this, theNameAndType[i].kind, theNameAndType[i].size);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reportedType == "int")
|
|
|
|
|
fixup(this, IntegerRegister, 4);
|
|
|
|
|
else if (reportedType == "float")
|
|
|
|
|
fixup(this, IntegerRegister, 8);
|
|
|
|
|
else if (reportedType == "_i387_ext")
|
|
|
|
|
fixup(this, IntegerRegister, 10);
|
|
|
|
|
else if (reportedType == "*1" || reportedType == "long")
|
|
|
|
|
fixup(this, IntegerRegister, 0);
|
|
|
|
|
else if (reportedType.contains("vec"))
|
|
|
|
|
fixup(this, VectorRegister, 0);
|
|
|
|
|
else if (reportedType.startsWith("int"))
|
|
|
|
|
fixup(this, IntegerRegister, 0);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2015-03-31 14:20:43 +02:00
|
|
|
QString name(QLatin1Char('['));
|
|
|
|
|
|
|
|
|
|
switch (kind) {
|
|
|
|
|
case IntegerRegister: name += QLatin1Char('i'); break;
|
|
|
|
|
case FloatRegister: name += QLatin1Char('f'); break;
|
|
|
|
|
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;
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RegisterValue::operator=(const QByteArray &ba)
|
|
|
|
|
{
|
2015-02-26 11:10:25 +01:00
|
|
|
known = !ba.isEmpty();
|
2014-12-17 13:14:29 +01:00
|
|
|
uint shift = 0;
|
|
|
|
|
int j = 0;
|
|
|
|
|
v.u64[1] = v.u64[0] = 0;
|
|
|
|
|
for (int i = ba.size(); --i >= 0 && j < 16; ++j) {
|
|
|
|
|
quint64 d = decodeHexChar(ba.at(i));
|
|
|
|
|
if (d == uint(-1))
|
|
|
|
|
return;
|
|
|
|
|
v.u64[0] |= (d << shift);
|
|
|
|
|
shift += 4;
|
|
|
|
|
}
|
|
|
|
|
j = 0;
|
|
|
|
|
shift = 0;
|
|
|
|
|
for (int i = ba.size() - 16; --i >= 0 && j < 16; ++j) {
|
|
|
|
|
quint64 d = decodeHexChar(ba.at(i));
|
|
|
|
|
if (d == uint(-1))
|
|
|
|
|
return;
|
|
|
|
|
v.u64[1] |= (d << shift);
|
|
|
|
|
shift += 4;
|
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
|
|
|
}
|
|
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
static QByteArray formatRegister(quint64 v, int size, RegisterFormat format)
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2015-03-31 14:20:43 +02:00
|
|
|
QByteArray result;
|
|
|
|
|
if (format == HexadecimalFormat) {
|
|
|
|
|
result = QByteArray::number(v, 16);
|
2014-12-17 13:14:29 +01:00
|
|
|
result.prepend(QByteArray(2*size - result.size(), '0'));
|
2015-03-31 14:20:43 +02:00
|
|
|
} 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(), ' '));
|
|
|
|
|
}
|
2014-12-17 13:14:29 +01:00
|
|
|
return result;
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
QByteArray RegisterValue::toByteArray(RegisterKind kind, int size, RegisterFormat format) const
|
2014-12-17 13:14:29 +01:00
|
|
|
{
|
2015-02-26 11:10:25 +01:00
|
|
|
if (!known)
|
|
|
|
|
return "[inaccessible]";
|
2014-12-17 13:14:29 +01:00
|
|
|
if (kind == FloatRegister) {
|
|
|
|
|
if (size == 4)
|
|
|
|
|
return QByteArray::number(v.f[0]);
|
|
|
|
|
if (size == 8)
|
|
|
|
|
return QByteArray::number(v.d[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray result;
|
|
|
|
|
if (size > 8) {
|
2015-03-31 14:20:43 +02:00
|
|
|
result += formatRegister(v.u64[1], size - 8, format);
|
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-03-31 14:20:43 +02:00
|
|
|
return result + formatRegister(v.u64[0], size, format);
|
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
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
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
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
class RegisterSubItem : public Utils::TreeItem
|
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)
|
2014-12-17 13:14:29 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
QVariant data(int column, int role) const;
|
|
|
|
|
|
|
|
|
|
Qt::ItemFlags flags(int column) const
|
|
|
|
|
{
|
|
|
|
|
//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
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
class RegisterItem : public Utils::TreeItem
|
2011-08-31 16:45:44 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
public:
|
|
|
|
|
explicit RegisterItem(const Register ®);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
QVariant data(int column, int role) const;
|
|
|
|
|
Qt::ItemFlags flags(int column) const;
|
|
|
|
|
|
|
|
|
|
quint64 addressValue() const;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
Register m_reg;
|
2015-03-31 14:20:43 +02:00
|
|
|
RegisterFormat m_format;
|
2014-12-17 13:14:29 +01:00
|
|
|
bool m_changed;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RegisterItem::RegisterItem(const Register ®) :
|
2015-03-31 14:20:43 +02:00
|
|
|
m_reg(reg), m_format(HexadecimalFormat), m_changed(true)
|
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-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));
|
|
|
|
|
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.
|
|
|
|
|
if (column == 1) // && IntegerWatchLineEdit::isUnsignedHexNumber(QLatin1String(m_reg.display)))
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
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 RegisterNameRole:
|
|
|
|
|
return m_reg.name;
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case RegisterIsBigRole:
|
|
|
|
|
return m_reg.value.v.u64[1] > 0;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case RegisterChangedRole:
|
|
|
|
|
return m_changed;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case RegisterAsAddressRole:
|
|
|
|
|
return addressValue();
|
2011-08-31 16:45:44 +02:00
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
case RegisterFormatRole:
|
|
|
|
|
return m_format;
|
|
|
|
|
|
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: {
|
2014-12-17 13:14:29 +01:00
|
|
|
QByteArray res = m_reg.name;
|
|
|
|
|
if (!m_reg.description.isEmpty())
|
|
|
|
|
res += " (" + m_reg.description + ')';
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2015-02-26 11:10:25 +01:00
|
|
|
case RegisterValueColumn: {
|
2015-03-31 14:20:43 +02:00
|
|
|
return m_reg.value.toByteArray(m_reg.kind, m_reg.size, m_format);
|
2011-08-31 16:45:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case Qt::ToolTipRole:
|
|
|
|
|
return QString::fromLatin1("Current Value: %1\nPreviousValue: %2")
|
2015-03-31 14:20:43 +02:00
|
|
|
.arg(QString::fromLatin1(m_reg.value.toByteArray(m_reg.kind, m_reg.size, m_format)))
|
|
|
|
|
.arg(QString::fromLatin1(m_reg.previousValue.toByteArray(m_reg.kind, m_reg.size, m_format)));
|
2011-08-31 16:45:44 +02:00
|
|
|
|
|
|
|
|
case Qt::EditRole: // Edit: Unpadded for editing
|
2015-03-31 14:20:43 +02:00
|
|
|
return m_reg.value.toByteArray(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();
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
case RegisterFormatRole: {
|
|
|
|
|
RegisterItem *registerItem = static_cast<RegisterItem *>(parent());
|
|
|
|
|
return int(registerItem->m_format);
|
|
|
|
|
}
|
2009-08-18 08:34:48 +02:00
|
|
|
|
2014-12-17 13:14:29 +01:00
|
|
|
case RegisterAsAddressRole:
|
|
|
|
|
return 0;
|
2009-08-18 08:34:48 +02: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());
|
|
|
|
|
RegisterItem *registerItem = static_cast<RegisterItem *>(parent());
|
|
|
|
|
RegisterValue value = registerItem->m_reg.value;
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
for (int i = 0; i != m_count; ++i) {
|
|
|
|
|
int tab = 5 * (i + 1) * m_subSize;
|
2015-03-31 14:20:43 +02:00
|
|
|
QByteArray b = value.subValue(m_subSize, i).toByteArray(m_subKind, m_subSize, m_subFormat);
|
|
|
|
|
ba += QByteArray(tab - ba.size() - b.size(), ' ');
|
|
|
|
|
ba += b;
|
2014-12-17 13:14:29 +01:00
|
|
|
}
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
}
|
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");
|
|
|
|
|
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);
|
|
|
|
|
|
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
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
RegisterHandler::RegisterHandler()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
setObjectName(QLatin1String("RegisterModel"));
|
2015-01-16 15:24:53 +01:00
|
|
|
setHeader(QStringList() << 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) {
|
|
|
|
|
reg = new RegisterItem(r);
|
|
|
|
|
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
|
|
|
|
2015-03-31 14:20:43 +02:00
|
|
|
void RegisterHandler::setNumberFormat(const QByteArray &name, RegisterFormat format)
|
2010-09-22 09:41:15 +02:00
|
|
|
{
|
2014-12-17 13:14:29 +01:00
|
|
|
RegisterItem *reg = m_registerByName.value(name, 0);
|
|
|
|
|
QTC_ASSERT(reg, return);
|
2015-03-31 14:20:43 +02:00
|
|
|
reg->m_format = format;
|
2015-04-22 12:37:39 +02:00
|
|
|
QModelIndex index = indexForItem(reg);
|
2014-12-17 13:14:29 +01:00
|
|
|
emit dataChanged(index, index);
|
2010-09-22 09:41:15 +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;
|
|
|
|
|
Utils::TreeItem *root = rootItem();
|
|
|
|
|
for (int i = 0, n = root->rowCount(); i != n; ++i) {
|
|
|
|
|
RegisterItem *reg = static_cast<RegisterItem *>(root->child(i));
|
|
|
|
|
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
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|