forked from qt-creator/qt-creator
Debugger: Rework register handling
Use register names as handle, not their index in the view. Store the raw real values, not some stringified version as primary data. Use subentries to break down bigger registers into smaller entities. Also remember the previous value of a register and show it in a tooltip. Change-Id: I8ae3cc8766a7b211bc7cc827c734e5cf6060825c Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com> Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -1193,6 +1193,7 @@ class Dumper(DumperBase):
|
|||||||
for reg in group:
|
for reg in group:
|
||||||
result += '{name="%s"' % reg.GetName()
|
result += '{name="%s"' % reg.GetName()
|
||||||
result += ',value="%s"' % reg.GetValue()
|
result += ',value="%s"' % reg.GetValue()
|
||||||
|
result += ',size="%s"' % reg.GetByteSize()
|
||||||
result += ',type="%s"},' % reg.GetType()
|
result += ',type="%s"},' % reg.GetType()
|
||||||
result += ']'
|
result += ']'
|
||||||
self.report(result)
|
self.report(result)
|
||||||
|
|||||||
@@ -364,6 +364,34 @@ const wchar_t *valueType(ULONG type)
|
|||||||
return L"";
|
return L"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Description of a DEBUG_VALUE type field
|
||||||
|
const int valueSize(ULONG type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case DEBUG_VALUE_INT8:
|
||||||
|
return 1;
|
||||||
|
case DEBUG_VALUE_INT16:
|
||||||
|
return 2;
|
||||||
|
case DEBUG_VALUE_INT32:
|
||||||
|
return 4;
|
||||||
|
case DEBUG_VALUE_INT64:
|
||||||
|
return 8;
|
||||||
|
case DEBUG_VALUE_FLOAT32:
|
||||||
|
return 4;
|
||||||
|
case DEBUG_VALUE_FLOAT64:
|
||||||
|
return 8;
|
||||||
|
case DEBUG_VALUE_FLOAT80:
|
||||||
|
return 10;
|
||||||
|
case DEBUG_VALUE_FLOAT128:
|
||||||
|
return 16;
|
||||||
|
case DEBUG_VALUE_VECTOR64:
|
||||||
|
return 8;
|
||||||
|
case DEBUG_VALUE_VECTOR128:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Format a 128bit vector register by adding digits in reverse order
|
// Format a 128bit vector register by adding digits in reverse order
|
||||||
void formatVectorRegister(std::ostream &str, const unsigned char *array, int size)
|
void formatVectorRegister(std::ostream &str, const unsigned char *array, int size)
|
||||||
{
|
{
|
||||||
@@ -421,6 +449,7 @@ void formatDebugValue(std::ostream &str, const DEBUG_VALUE &dv, CIDebugControl *
|
|||||||
|
|
||||||
Register::Register() : subRegister(false), pseudoRegister(false)
|
Register::Register() : subRegister(false), pseudoRegister(false)
|
||||||
{
|
{
|
||||||
|
size = 0;
|
||||||
value.Type = DEBUG_VALUE_INT32;
|
value.Type = DEBUG_VALUE_INT32;
|
||||||
value.I32 = 0;
|
value.I32 = 0;
|
||||||
}
|
}
|
||||||
@@ -497,6 +526,7 @@ Registers getRegisters(CIDebugRegisters *regs,
|
|||||||
reg.pseudoRegister = true;
|
reg.pseudoRegister = true;
|
||||||
reg.name = buf;
|
reg.name = buf;
|
||||||
reg.description = valueType(type);
|
reg.description = valueType(type);
|
||||||
|
reg.size = valueSize(type);
|
||||||
reg.value = value;
|
reg.value = value;
|
||||||
rc.push_back(reg);
|
rc.push_back(reg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ struct Register
|
|||||||
|
|
||||||
std::wstring name;
|
std::wstring name;
|
||||||
std::wstring description;
|
std::wstring description;
|
||||||
|
int size;
|
||||||
bool subRegister;
|
bool subRegister;
|
||||||
bool pseudoRegister;
|
bool pseudoRegister;
|
||||||
DEBUG_VALUE value;
|
DEBUG_VALUE value;
|
||||||
|
|||||||
@@ -1235,14 +1235,12 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
|
|||||||
continueInferior();
|
continueInferior();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbEngine::setRegisterValue(int regnr, const QString &value)
|
void CdbEngine::setRegisterValue(const QByteArray &name, const QString &value)
|
||||||
{
|
{
|
||||||
const Registers registers = registerHandler()->registers();
|
|
||||||
QTC_ASSERT(regnr < registers.size(), return);
|
|
||||||
// Value is decimal or 0x-hex-prefixed
|
// Value is decimal or 0x-hex-prefixed
|
||||||
QByteArray cmd;
|
QByteArray cmd;
|
||||||
ByteArrayInputStream str(cmd);
|
ByteArrayInputStream str(cmd);
|
||||||
str << "r " << registers.at(regnr).name << '=' << value;
|
str << "r " << name << '=' << value;
|
||||||
postCommand(cmd, 0);
|
postCommand(cmd, 0);
|
||||||
reloadRegisters();
|
reloadRegisters();
|
||||||
}
|
}
|
||||||
@@ -1854,21 +1852,6 @@ void CdbEngine::handlePid(const CdbExtensionCommandPtr &reply)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse CDB gdbmi register syntax.
|
|
||||||
static Register parseRegister(const GdbMi &gdbmiReg)
|
|
||||||
{
|
|
||||||
Register reg;
|
|
||||||
reg.name = gdbmiReg["name"].data();
|
|
||||||
const GdbMi description = gdbmiReg["description"];
|
|
||||||
if (description.type() != GdbMi::Invalid) {
|
|
||||||
reg.name += " (";
|
|
||||||
reg.name += description.data();
|
|
||||||
reg.name += ')';
|
|
||||||
}
|
|
||||||
reg.value = gdbmiReg["value"].data();
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply)
|
void CdbEngine::handleModules(const CdbExtensionCommandPtr &reply)
|
||||||
{
|
{
|
||||||
if (reply->success) {
|
if (reply->success) {
|
||||||
@@ -1906,11 +1889,17 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
|
|||||||
GdbMi value;
|
GdbMi value;
|
||||||
value.fromString(reply->reply);
|
value.fromString(reply->reply);
|
||||||
if (value.type() == GdbMi::List) {
|
if (value.type() == GdbMi::List) {
|
||||||
Registers registers;
|
RegisterHandler *handler = registerHandler();
|
||||||
registers.reserve(value.childCount());
|
foreach (const GdbMi &item, value.children()) {
|
||||||
foreach (const GdbMi &gdbmiReg, value.children())
|
Register reg;
|
||||||
registers.push_back(parseRegister(gdbmiReg));
|
reg.name = item["name"].data();
|
||||||
registerHandler()->setAndMarkRegisters(registers);
|
reg.description = item["description"].data();
|
||||||
|
reg.reportedType = item["type"].data();
|
||||||
|
reg.value = item["value"].data();
|
||||||
|
reg.size = item["size"].data().toInt();
|
||||||
|
handler->updateRegister(reg);
|
||||||
|
}
|
||||||
|
handler->commitUpdates();
|
||||||
} else {
|
} else {
|
||||||
showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
|
showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
|
||||||
qWarning("Parse error in registers response:\n%s", reply->reply.constData());
|
qWarning("Parse error in registers response:\n%s", reply->reply.constData());
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public:
|
|||||||
const WatchUpdateFlags & flags = WatchUpdateFlags());
|
const WatchUpdateFlags & flags = WatchUpdateFlags());
|
||||||
virtual bool hasCapability(unsigned cap) const;
|
virtual bool hasCapability(unsigned cap) const;
|
||||||
virtual void watchPoint(const QPoint &);
|
virtual void watchPoint(const QPoint &);
|
||||||
virtual void setRegisterValue(int regnr, const QString &value);
|
virtual void setRegisterValue(const QByteArray &name, const QString &value);
|
||||||
|
|
||||||
virtual void executeStep();
|
virtual void executeStep();
|
||||||
virtual void executeStepOut();
|
virtual void executeStepOut();
|
||||||
|
|||||||
@@ -477,9 +477,9 @@ void DebuggerEngine::changeMemory(MemoryAgent *, QObject *,
|
|||||||
Q_UNUSED(data);
|
Q_UNUSED(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
|
void DebuggerEngine::setRegisterValue(const QByteArray &name, const QString &value)
|
||||||
{
|
{
|
||||||
Q_UNUSED(regnr);
|
Q_UNUSED(name);
|
||||||
Q_UNUSED(value);
|
Q_UNUSED(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,11 +1746,9 @@ void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description
|
|||||||
Core::AsynchronousMessageBox::information(tr("Exception Triggered"), msg);
|
Core::AsynchronousMessageBox::information(tr("Exception Triggered"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerEngine::openMemoryView(quint64 startAddr, unsigned flags,
|
void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data)
|
||||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
|
||||||
const QString &title, QWidget *parent)
|
|
||||||
{
|
{
|
||||||
d->m_memoryAgent.createBinEditor(startAddr, flags, ml, pos, title, parent);
|
d->m_memoryAgent.createBinEditor(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerEngine::updateMemoryViews()
|
void DebuggerEngine::updateMemoryViews()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class BreakpointParameters;
|
|||||||
class QmlAdapter;
|
class QmlAdapter;
|
||||||
class QmlCppEngine;
|
class QmlCppEngine;
|
||||||
class DebuggerToolTipContext;
|
class DebuggerToolTipContext;
|
||||||
class MemoryMarkup;
|
class MemoryViewSetupData;
|
||||||
|
|
||||||
struct WatchUpdateFlags
|
struct WatchUpdateFlags
|
||||||
{
|
{
|
||||||
@@ -158,10 +158,7 @@ public:
|
|||||||
MemoryView = 0x4 //!< Open a separate view (using the pos-parameter).
|
MemoryView = 0x4 //!< Open a separate view (using the pos-parameter).
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void openMemoryView(quint64 startAddr, unsigned flags,
|
virtual void openMemoryView(const MemoryViewSetupData &data);
|
||||||
const QList<Internal::MemoryMarkup> &ml,
|
|
||||||
const QPoint &pos,
|
|
||||||
const QString &title = QString(), QWidget *parent = 0);
|
|
||||||
virtual void fetchMemory(Internal::MemoryAgent *, QObject *,
|
virtual void fetchMemory(Internal::MemoryAgent *, QObject *,
|
||||||
quint64 addr, quint64 length);
|
quint64 addr, quint64 length);
|
||||||
virtual void changeMemory(Internal::MemoryAgent *, QObject *,
|
virtual void changeMemory(Internal::MemoryAgent *, QObject *,
|
||||||
@@ -185,7 +182,7 @@ public:
|
|||||||
virtual void loadAdditionalQmlStack();
|
virtual void loadAdditionalQmlStack();
|
||||||
virtual void reloadDebuggingHelpers();
|
virtual void reloadDebuggingHelpers();
|
||||||
|
|
||||||
virtual void setRegisterValue(int regnr, const QString &value);
|
virtual void setRegisterValue(const QByteArray &name, const QString &value);
|
||||||
virtual void addOptionPages(QList<Core::IOptionsPage*> *) const;
|
virtual void addOptionPages(QList<Core::IOptionsPage*> *) const;
|
||||||
virtual bool hasCapability(unsigned cap) const = 0;
|
virtual bool hasCapability(unsigned cap) const = 0;
|
||||||
virtual void debugLastCommand() {}
|
virtual void debugLastCommand() {}
|
||||||
|
|||||||
@@ -3356,8 +3356,11 @@ bool isDockVisible(const QString &objectName)
|
|||||||
void openMemoryEditor()
|
void openMemoryEditor()
|
||||||
{
|
{
|
||||||
AddressDialog dialog;
|
AddressDialog dialog;
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
currentEngine()->openMemoryView(dialog.address(), 0, QList<MemoryMarkup>(), QPoint());
|
MemoryViewSetupData data;
|
||||||
|
data.startAddress = dialog.address();
|
||||||
|
currentEngine()->openMemoryView(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setThreads(const QStringList &list, int index)
|
void setThreads(const QStringList &list, int index)
|
||||||
|
|||||||
@@ -78,11 +78,11 @@
|
|||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/savedaction.h>
|
#include <utils/savedaction.h>
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QTemporaryFile>
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
@@ -3585,19 +3585,79 @@ void GdbEngine::reloadRegisters()
|
|||||||
|
|
||||||
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (true) {
|
||||||
if (!m_registerNamesListed) {
|
if (!m_registerNamesListed) {
|
||||||
postCommand("-data-list-register-names", CB(handleRegisterListNames));
|
postCommand("-data-list-register-names", CB(handleRegisterListNames));
|
||||||
m_registerNamesListed = true;
|
m_registerNamesListed = true;
|
||||||
}
|
}
|
||||||
|
// Can cause i386-linux-nat.c:571: internal-error: Got request
|
||||||
|
// for bad register number 41.\nA problem internal to GDB has been detected.
|
||||||
postCommand("-data-list-register-values r",
|
postCommand("-data-list-register-values r",
|
||||||
Discardable, CB(handleRegisterListValues));
|
Discardable, CB(handleRegisterListValues));
|
||||||
|
} else {
|
||||||
|
postCommand("maintenance print cooked-registers", CB(handleMaintPrintRegisters));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::setRegisterValue(int nr, const QString &value)
|
static QByteArray readWord(const QByteArray &ba, int *pos)
|
||||||
{
|
{
|
||||||
Register reg = registerHandler()->registers().at(nr);
|
const int n = ba.size();
|
||||||
postCommand("set $" + reg.name + "=" + value.toLatin1());
|
while (*pos < n && ba.at(*pos) == ' ')
|
||||||
|
++*pos;
|
||||||
|
const int start = *pos;
|
||||||
|
while (*pos < n && ba.at(*pos) != ' ' && ba.at(*pos) != '\n')
|
||||||
|
++*pos;
|
||||||
|
return ba.mid(start, *pos - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleMaintPrintRegisters(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
if (response.resultClass != GdbResultDone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QByteArray &ba = response.consoleStreamOutput;
|
||||||
|
RegisterHandler *handler = registerHandler();
|
||||||
|
//0 1 2 3 4 5 6
|
||||||
|
//0123456789012345678901234567890123456789012345678901234567890
|
||||||
|
// Name Nr Rel Offset Size Type Raw value
|
||||||
|
// rax 0 0 0 8 int64_t 0x0000000000000000
|
||||||
|
// rip 16 16 128 8 *1 0x0000000000400dc9
|
||||||
|
// eflags 17 17 136 4 i386_eflags 0x00000246
|
||||||
|
// cs 18 18 140 4 int32_t 0x00000033
|
||||||
|
// xmm15 55 55 516 16 vec128 0x00000000000000000000000000000000
|
||||||
|
// mxcsr 56 56 532 4 i386_mxcsr 0x00001fa0
|
||||||
|
// ''
|
||||||
|
// st6 30 30 224 10 _i387_ext 0x00000000000000000000
|
||||||
|
// st7 31 31 234 10 _i387_ext 0x00000000000000000000
|
||||||
|
// fctrl 32 32 244 4 int 0x0000037f
|
||||||
|
|
||||||
|
const int n = ba.size();
|
||||||
|
int pos = 0;
|
||||||
|
while (true) {
|
||||||
|
// Skip first line, and until '\n' after each line finished.
|
||||||
|
while (pos < n && ba.at(pos) != '\n')
|
||||||
|
++pos;
|
||||||
|
if (pos >= n)
|
||||||
|
break;
|
||||||
|
++pos; // skip \n
|
||||||
|
Register reg;
|
||||||
|
reg.name = readWord(ba, &pos);
|
||||||
|
if (reg.name == "''" || reg.name == "*1:" || reg.name.isEmpty())
|
||||||
|
continue;
|
||||||
|
readWord(ba, &pos); // Nr
|
||||||
|
readWord(ba, &pos); // Rel
|
||||||
|
readWord(ba, &pos); // Offset
|
||||||
|
reg.size = readWord(ba, &pos).toInt();
|
||||||
|
reg.reportedType = readWord(ba, &pos);
|
||||||
|
reg.value = readWord(ba, &pos);
|
||||||
|
handler->updateRegister(reg);
|
||||||
|
}
|
||||||
|
handler->commitUpdates();
|
||||||
|
}
|
||||||
|
void GdbEngine::setRegisterValue(const QByteArray &name, const QString &value)
|
||||||
|
{
|
||||||
|
postCommand("set $" + name + "=" + value.toLatin1());
|
||||||
reloadRegisters();
|
reloadRegisters();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3608,26 +3668,14 @@ void GdbEngine::handleRegisterListNames(const GdbResponse &response)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Registers registers;
|
|
||||||
int gdbRegisterNumber = 0, internalIndex = 0;
|
|
||||||
|
|
||||||
// This both handles explicitly having space for all the registers and
|
|
||||||
// initializes all indices to 0, giving missing registers a sane default
|
|
||||||
// in the event of something wacky.
|
|
||||||
GdbMi names = response.data["register-names"];
|
GdbMi names = response.data["register-names"];
|
||||||
m_registerNumbers.resize(names.childCount());
|
m_registerNames.clear();
|
||||||
|
int gdbRegisterNumber = 0;
|
||||||
foreach (const GdbMi &item, names.children()) {
|
foreach (const GdbMi &item, names.children()) {
|
||||||
// Since we throw away missing registers to eliminate empty rows
|
if (!item.data().isEmpty())
|
||||||
// we need to maintain a mapping of GDB register numbers to their
|
m_registerNames[gdbRegisterNumber] = item.data();
|
||||||
// respective indices in the register list.
|
++gdbRegisterNumber;
|
||||||
if (!item.data().isEmpty()) {
|
|
||||||
m_registerNumbers[gdbRegisterNumber] = internalIndex++;
|
|
||||||
registers.append(Register(item.data()));
|
|
||||||
}
|
}
|
||||||
gdbRegisterNumber++;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerHandler()->setRegisters(registers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
||||||
@@ -3635,19 +3683,46 @@ void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
|||||||
if (response.resultClass != GdbResultDone)
|
if (response.resultClass != GdbResultDone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Registers registers = registerHandler()->registers();
|
RegisterHandler *handler = registerHandler();
|
||||||
const int registerCount = registers.size();
|
|
||||||
const int gdbRegisterCount = m_registerNumbers.size();
|
|
||||||
|
|
||||||
// 24^done,register-values=[{number="0",value="0xf423f"},...]
|
// 24^done,register-values=[{number="0",value="0xf423f"},...]
|
||||||
const GdbMi values = response.data["register-values"];
|
const GdbMi values = response.data["register-values"];
|
||||||
QTC_ASSERT(registerCount == values.children().size(), return);
|
|
||||||
foreach (const GdbMi &item, values.children()) {
|
foreach (const GdbMi &item, values.children()) {
|
||||||
|
Register reg;
|
||||||
const int number = item["number"].toInt();
|
const int number = item["number"].toInt();
|
||||||
if (number >= 0 && number < gdbRegisterCount)
|
reg.name = m_registerNames[number];
|
||||||
registers[m_registerNumbers[number]].value = item["value"].data();
|
QByteArray data = item["value"].data();
|
||||||
|
if (data.startsWith("0x")) {
|
||||||
|
reg.value = data;
|
||||||
|
} else {
|
||||||
|
// This is what GDB considers machine readable output:
|
||||||
|
// value="{v4_float = {0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||||
|
// v2_double = {0x0000000000000000, 0x0000000000000000},
|
||||||
|
// v16_int8 = {0x00 <repeats 16 times>},
|
||||||
|
// v8_int16 = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
|
||||||
|
// v4_int32 = {0x00000000, 0x00000000, 0x00000000, 0x00000000},
|
||||||
|
// v2_int64 = {0x0000000000000000, 0x0000000000000000},
|
||||||
|
// uint128 = <error reading variable>}"}
|
||||||
|
// Try to make sense of it using the int32 chunks:
|
||||||
|
QByteArray result = "0x";
|
||||||
|
const int pos1 = data.indexOf("_int32");
|
||||||
|
const int pos2 = data.indexOf('{', pos1) + 1;
|
||||||
|
const int pos3 = data.indexOf('}', pos2);
|
||||||
|
QByteArray inner = data.mid(pos2, pos3 - pos2);
|
||||||
|
QList<QByteArray> list = inner.split(',');
|
||||||
|
for (int i = list.size(); --i >= 0; ) {
|
||||||
|
QByteArray chunk = list.at(i);
|
||||||
|
if (chunk.startsWith(' '))
|
||||||
|
chunk.remove(0, 1);
|
||||||
|
if (chunk.startsWith("0x"))
|
||||||
|
chunk.remove(0, 2);
|
||||||
|
QTC_ASSERT(chunk.size() == 8, continue);
|
||||||
|
result.append(chunk);
|
||||||
}
|
}
|
||||||
registerHandler()->setAndMarkRegisters(registers);
|
reg.value = result;
|
||||||
|
}
|
||||||
|
handler->updateRegister(reg);
|
||||||
|
}
|
||||||
|
handler->commitUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -347,10 +347,11 @@ private: ////////// View & Data Stuff //////////
|
|||||||
// Register specific stuff
|
// Register specific stuff
|
||||||
//
|
//
|
||||||
Q_SLOT void reloadRegisters();
|
Q_SLOT void reloadRegisters();
|
||||||
void setRegisterValue(int nr, const QString &value);
|
void setRegisterValue(const QByteArray &name, const QString &value);
|
||||||
void handleRegisterListNames(const GdbResponse &response);
|
void handleRegisterListNames(const GdbResponse &response);
|
||||||
void handleRegisterListValues(const GdbResponse &response);
|
void handleRegisterListValues(const GdbResponse &response);
|
||||||
QVector<int> m_registerNumbers; // Map GDB register numbers to indices
|
void handleMaintPrintRegisters(const GdbResponse &response);
|
||||||
|
QHash<int, QByteArray> m_registerNames; // Map GDB register numbers to indices
|
||||||
|
|
||||||
//
|
//
|
||||||
// Disassembler specific stuff
|
// Disassembler specific stuff
|
||||||
|
|||||||
@@ -1085,16 +1085,15 @@ void LldbEngine::setStackPosition(int index)
|
|||||||
void LldbEngine::refreshRegisters(const GdbMi ®isters)
|
void LldbEngine::refreshRegisters(const GdbMi ®isters)
|
||||||
{
|
{
|
||||||
RegisterHandler *handler = registerHandler();
|
RegisterHandler *handler = registerHandler();
|
||||||
Registers regs;
|
|
||||||
foreach (const GdbMi &item, registers.children()) {
|
foreach (const GdbMi &item, registers.children()) {
|
||||||
Register reg;
|
Register reg;
|
||||||
reg.name = item["name"].data();
|
reg.name = item["name"].data();
|
||||||
reg.value = item["value"].data();
|
reg.value = item["value"].data();
|
||||||
//reg.type = item["type"].data();
|
reg.size = item["size"].data().toInt();
|
||||||
regs.append(reg);
|
reg.reportedType = item["type"].data();
|
||||||
|
handler->updateRegister(reg);
|
||||||
}
|
}
|
||||||
//handler->setRegisters(registers);
|
handler->commitUpdates();
|
||||||
handler->setAndMarkRegisters(regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::refreshThreads(const GdbMi &threads)
|
void LldbEngine::refreshThreads(const GdbMi &threads)
|
||||||
@@ -1250,10 +1249,9 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
|
|||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LldbEngine::setRegisterValue(int regnr, const QString &value)
|
void LldbEngine::setRegisterValue(const QByteArray &name, const QString &value)
|
||||||
{
|
{
|
||||||
Register reg = registerHandler()->registers().at(regnr);
|
runCommand(Command("setRegister").arg("name", name).arg("value", value));
|
||||||
runCommand(Command("setRegister").arg("name", reg.name).arg("value", value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ private:
|
|||||||
bool supportsThreads() const { return true; }
|
bool supportsThreads() const { return true; }
|
||||||
bool isSynchronous() const { return true; }
|
bool isSynchronous() const { return true; }
|
||||||
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
|
void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
|
||||||
void setRegisterValue(int regnr, const QString &value);
|
void setRegisterValue(const QByteArray &name, const QString &value);
|
||||||
|
|
||||||
void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length);
|
void fetchMemory(Internal::MemoryAgent *, QObject *, quint64 addr, quint64 length);
|
||||||
void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data);
|
void changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data);
|
||||||
|
|||||||
@@ -135,15 +135,12 @@ void MemoryAgent::connectBinEditorWidget(QWidget *w)
|
|||||||
connect(w, SIGNAL(addWatchpointRequested(quint64,uint)), SLOT(handleWatchpointRequest(quint64,uint)));
|
connect(w, SIGNAL(addWatchpointRequested(quint64,uint)), SLOT(handleWatchpointRequest(quint64,uint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
bool MemoryAgent::doCreateBinEditor(const MemoryViewSetupData &data)
|
||||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
|
||||||
QString title, QWidget *parent)
|
|
||||||
{
|
{
|
||||||
const bool readOnly = (flags & DebuggerEngine::MemoryReadOnly) != 0;
|
const bool readOnly = (data.flags & DebuggerEngine::MemoryReadOnly) != 0;
|
||||||
if (title.isEmpty())
|
QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title;
|
||||||
title = tr("Memory at 0x%1").arg(addr, 0, 16);
|
|
||||||
// Separate view?
|
// Separate view?
|
||||||
if (flags & DebuggerEngine::MemoryView) {
|
if (data.flags & DebuggerEngine::MemoryView) {
|
||||||
// Ask BIN editor plugin for factory service and have it create a bin editor widget.
|
// Ask BIN editor plugin for factory service and have it create a bin editor widget.
|
||||||
QWidget *binEditor = 0;
|
QWidget *binEditor = 0;
|
||||||
if (QObject *factory = ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("BinEditor::BinEditorWidgetFactory")))
|
if (QObject *factory = ExtensionSystem::PluginManager::getObjectByClassName(QLatin1String("BinEditor::BinEditorWidgetFactory")))
|
||||||
@@ -155,24 +152,22 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
|||||||
MemoryView::setBinEditorNewWindowRequestAllowed(binEditor, true);
|
MemoryView::setBinEditorNewWindowRequestAllowed(binEditor, true);
|
||||||
MemoryView *topLevel = 0;
|
MemoryView *topLevel = 0;
|
||||||
// Memory view tracking register value, providing its own updating mechanism.
|
// Memory view tracking register value, providing its own updating mechanism.
|
||||||
if (flags & DebuggerEngine::MemoryTrackRegister) {
|
if (data.flags & DebuggerEngine::MemoryTrackRegister) {
|
||||||
RegisterMemoryView *rmv = new RegisterMemoryView(binEditor, parent);
|
topLevel = new RegisterMemoryView(binEditor, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent);
|
||||||
rmv->init(m_engine->registerHandler(), int(addr));
|
|
||||||
topLevel = rmv;
|
|
||||||
} else {
|
} else {
|
||||||
// Ordinary memory view
|
// Ordinary memory view
|
||||||
MemoryView::setBinEditorMarkup(binEditor, ml);
|
MemoryView::setBinEditorMarkup(binEditor, data.markup);
|
||||||
MemoryView::setBinEditorRange(binEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
MemoryView::setBinEditorRange(binEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||||
topLevel = new MemoryView(binEditor, parent);
|
topLevel = new MemoryView(binEditor, data.parent);
|
||||||
topLevel->setWindowTitle(title);
|
topLevel->setWindowTitle(title);
|
||||||
}
|
}
|
||||||
m_views << topLevel;
|
m_views << topLevel;
|
||||||
topLevel->move(pos);
|
topLevel->move(data.pos);
|
||||||
topLevel->show();
|
topLevel->show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Editor: Register tracking not supported.
|
// Editor: Register tracking not supported.
|
||||||
QTC_ASSERT(!(flags & DebuggerEngine::MemoryTrackRegister), return false);
|
QTC_ASSERT(!(data.flags & DebuggerEngine::MemoryTrackRegister), return false);
|
||||||
if (!title.endsWith(QLatin1Char('$')))
|
if (!title.endsWith(QLatin1Char('$')))
|
||||||
title.append(QLatin1String(" $"));
|
title.append(QLatin1String(" $"));
|
||||||
IEditor *editor = EditorManager::openEditorWithContents(
|
IEditor *editor = EditorManager::openEditorWithContents(
|
||||||
@@ -185,17 +180,15 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
|||||||
connectBinEditorWidget(editorBinEditor);
|
connectBinEditorWidget(editorBinEditor);
|
||||||
MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly);
|
MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly);
|
||||||
MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true);
|
MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true);
|
||||||
MemoryView::setBinEditorRange(editorBinEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
MemoryView::setBinEditorRange(editorBinEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||||
MemoryView::setBinEditorMarkup(editorBinEditor, ml);
|
MemoryView::setBinEditorMarkup(editorBinEditor, data.markup);
|
||||||
m_editors << editor;
|
m_editors << editor;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryAgent::createBinEditor(quint64 addr, unsigned flags,
|
void MemoryAgent::createBinEditor(const MemoryViewSetupData &data)
|
||||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
|
||||||
const QString &title, QWidget *parent)
|
|
||||||
{
|
{
|
||||||
if (!doCreateBinEditor(addr, flags, ml, pos, title, parent))
|
if (!doCreateBinEditor(data))
|
||||||
Core::AsynchronousMessageBox::warning(
|
Core::AsynchronousMessageBox::warning(
|
||||||
tr("No Memory Viewer Available"),
|
tr("No Memory Viewer Available"),
|
||||||
tr("The memory contents cannot be shown as no viewer plugin "
|
tr("The memory contents cannot be shown as no viewer plugin "
|
||||||
@@ -204,7 +197,9 @@ void MemoryAgent::createBinEditor(quint64 addr, unsigned flags,
|
|||||||
|
|
||||||
void MemoryAgent::createBinEditor(quint64 addr)
|
void MemoryAgent::createBinEditor(quint64 addr)
|
||||||
{
|
{
|
||||||
createBinEditor(addr, 0, QList<MemoryMarkup>(), QPoint(), QString(), 0);
|
MemoryViewSetupData data;
|
||||||
|
data.startAddress = addr;
|
||||||
|
createBinEditor(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryAgent::fetchLazyData(quint64 block)
|
void MemoryAgent::fetchLazyData(quint64 block)
|
||||||
|
|||||||
@@ -34,11 +34,10 @@
|
|||||||
#include "debuggerconstants.h"
|
#include "debuggerconstants.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QPoint>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QPoint)
|
|
||||||
|
|
||||||
namespace Core { class IEditor; }
|
namespace Core { class IEditor; }
|
||||||
|
|
||||||
namespace ProjectExplorer { class Abi; }
|
namespace ProjectExplorer { class Abi; }
|
||||||
@@ -62,6 +61,20 @@ public:
|
|||||||
QString toolTip;
|
QString toolTip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MemoryViewSetupData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemoryViewSetupData() : parent(0), startAddress(0), flags(0) {}
|
||||||
|
|
||||||
|
QWidget *parent;
|
||||||
|
quint64 startAddress;
|
||||||
|
QByteArray registerName;
|
||||||
|
unsigned flags;
|
||||||
|
QList<Internal::MemoryMarkup> markup;
|
||||||
|
QPoint pos;
|
||||||
|
QString title;
|
||||||
|
};
|
||||||
|
|
||||||
class MemoryAgent : public QObject
|
class MemoryAgent : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -80,9 +93,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Called by engine to create a new view.
|
// Called by engine to create a new view.
|
||||||
void createBinEditor(quint64 startAddr, unsigned flags,
|
void createBinEditor(const MemoryViewSetupData &data);
|
||||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
|
||||||
const QString &title, QWidget *parent);
|
|
||||||
void createBinEditor(quint64 startAddr);
|
void createBinEditor(quint64 startAddr);
|
||||||
// Called by engine to create a tooltip.
|
// Called by engine to create a tooltip.
|
||||||
void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
|
void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
|
||||||
@@ -101,9 +112,7 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void connectBinEditorWidget(QWidget *w);
|
void connectBinEditorWidget(QWidget *w);
|
||||||
bool doCreateBinEditor(quint64 startAddr, unsigned flags,
|
bool doCreateBinEditor(const MemoryViewSetupData &data);
|
||||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
|
||||||
QString title, QWidget *parent);
|
|
||||||
|
|
||||||
QList<QPointer<Core::IEditor> > m_editors;
|
QList<QPointer<Core::IEditor> > m_editors;
|
||||||
QList<QPointer<MemoryView> > m_views;
|
QList<QPointer<MemoryView> > m_views;
|
||||||
|
|||||||
@@ -138,24 +138,27 @@ void MemoryView::setMarkup(const QList<MemoryMarkup> &m)
|
|||||||
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
|
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
|
||||||
*/
|
*/
|
||||||
|
|
||||||
RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, QWidget *parent) :
|
RegisterMemoryView::RegisterMemoryView(QWidget *binEditor, quint64 addr,
|
||||||
|
const QByteArray ®Name,
|
||||||
|
RegisterHandler *handler, QWidget *parent) :
|
||||||
MemoryView(binEditor, parent),
|
MemoryView(binEditor, parent),
|
||||||
m_registerIndex(0), m_registerAddress(0)
|
m_registerName(regName), m_registerAddress(addr)
|
||||||
{
|
{
|
||||||
|
connect(handler, &QAbstractItemModel::modelReset, this, &QWidget::close);
|
||||||
|
connect(handler, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged);
|
||||||
|
updateContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMemoryView::slotRegisterSet(const QModelIndex &index)
|
void RegisterMemoryView::onRegisterChanged(const QByteArray &name, quint64 value)
|
||||||
{
|
{
|
||||||
if (m_registerIndex != index.row())
|
if (name == m_registerName)
|
||||||
return;
|
setRegisterAddress(value);
|
||||||
const QVariant newAddressV = index.data(Qt::EditRole);
|
|
||||||
if (newAddressV.type() == QVariant::ULongLong)
|
|
||||||
setRegisterAddress(newAddressV.toULongLong());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RegisterMemoryView::title(const QString ®isterName, quint64 a)
|
QString RegisterMemoryView::title(const QByteArray ®isterName, quint64 a)
|
||||||
{
|
{
|
||||||
return tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(a, 0, 16);
|
return tr("Memory at Register \"%1\" (0x%2)")
|
||||||
|
.arg(QString::fromUtf8(registerName)).arg(a, 0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMemoryView::setRegisterAddress(quint64 v)
|
void RegisterMemoryView::setRegisterAddress(quint64 v)
|
||||||
@@ -171,25 +174,13 @@ void RegisterMemoryView::setRegisterAddress(quint64 v)
|
|||||||
setMarkup(registerMarkup(v, m_registerName));
|
setMarkup(registerMarkup(v, m_registerName));
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<MemoryMarkup> RegisterMemoryView::registerMarkup(quint64 a, const QString &name)
|
QList<MemoryMarkup> RegisterMemoryView::registerMarkup(quint64 a, const QByteArray ®Name)
|
||||||
{
|
{
|
||||||
QList<MemoryMarkup> result;
|
QList<MemoryMarkup> result;
|
||||||
result.push_back(MemoryMarkup(a, 1, QColor(Qt::blue).lighter(),
|
result.push_back(MemoryMarkup(a, 1, QColor(Qt::blue).lighter(),
|
||||||
tr("Register \"%1\"").arg(name)));
|
tr("Register \"%1\"").arg(QString::fromUtf8(regName))));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMemoryView::init(RegisterHandler *h, int registerIndex)
|
|
||||||
{
|
|
||||||
m_registerIndex = registerIndex;
|
|
||||||
m_registerName = QString::fromLatin1(h->registerAt(registerIndex).name);
|
|
||||||
// Known issue: CDB might reset the model by changing the special
|
|
||||||
// registers it reports.
|
|
||||||
connect(h, SIGNAL(modelReset()), this, SLOT(close()));
|
|
||||||
connect(h, SIGNAL(registerSet(QModelIndex)),
|
|
||||||
this, SLOT(slotRegisterSet(QModelIndex)));
|
|
||||||
setRegisterAddress(h->registerAt(m_registerIndex).editValue().toULongLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -69,21 +69,17 @@ class RegisterMemoryView : public MemoryView
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit RegisterMemoryView(QWidget *binEditor, QWidget *parent = 0);
|
explicit RegisterMemoryView(QWidget *binEditor, quint64 addr, const QByteArray ®Name,
|
||||||
|
RegisterHandler *rh, QWidget *parent = 0);
|
||||||
|
|
||||||
void init(RegisterHandler *rh, int index);
|
static QList<MemoryMarkup> registerMarkup(quint64 a, const QByteArray ®Name);
|
||||||
|
static QString title(const QByteArray ®isterName, quint64 a = 0);
|
||||||
static QList<MemoryMarkup> registerMarkup(quint64 a, const QString &name);
|
|
||||||
static QString title(const QString ®isterName, quint64 a = 0);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotRegisterSet(const QModelIndex &index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void onRegisterChanged(const QByteArray &name, quint64 value);
|
||||||
void setRegisterAddress(quint64 v);
|
void setRegisterAddress(quint64 v);
|
||||||
|
|
||||||
int m_registerIndex;
|
QByteArray m_registerName;
|
||||||
QString m_registerName;
|
|
||||||
quint64 m_registerAddress;
|
quint64 m_registerAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -184,9 +184,9 @@ void QmlCppEngine::reloadFullStack()
|
|||||||
m_cppEngine->reloadFullStack();
|
m_cppEngine->reloadFullStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlCppEngine::setRegisterValue(int regnr, const QString &value)
|
void QmlCppEngine::setRegisterValue(const QByteArray &name, const QString &value)
|
||||||
{
|
{
|
||||||
m_cppEngine->setRegisterValue(regnr, value);
|
m_cppEngine->setRegisterValue(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public:
|
|||||||
void reloadSourceFiles();
|
void reloadSourceFiles();
|
||||||
void reloadFullStack();
|
void reloadFullStack();
|
||||||
|
|
||||||
void setRegisterValue(int regnr, const QString &value);
|
void setRegisterValue(const QByteArray &name, const QString &value);
|
||||||
bool hasCapability(unsigned cap) const;
|
bool hasCapability(unsigned cap) const;
|
||||||
|
|
||||||
bool isSynchronous() const;
|
bool isSynchronous() const;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -31,35 +31,73 @@
|
|||||||
#ifndef DEBUGGER_REGISTERHANDLER_H
|
#ifndef DEBUGGER_REGISTERHANDLER_H
|
||||||
#define DEBUGGER_REGISTERHANDLER_H
|
#define DEBUGGER_REGISTERHANDLER_H
|
||||||
|
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
#include <QHash>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
enum RegisterDataRole
|
||||||
|
{
|
||||||
|
RegisterNameRole = Qt::UserRole,
|
||||||
|
RegisterIsBigRole,
|
||||||
|
RegisterChangedRole,
|
||||||
|
RegisterNumberBaseRole,
|
||||||
|
RegisterAsAddressRole
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RegisterKind
|
||||||
|
{
|
||||||
|
UnknownRegister,
|
||||||
|
IntegerRegister,
|
||||||
|
FloatRegister,
|
||||||
|
VectorRegister,
|
||||||
|
FlagRegister,
|
||||||
|
OtherRegister
|
||||||
|
};
|
||||||
|
|
||||||
|
class RegisterValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RegisterValue() { v.u64[1] = v.u64[0] = 0; }
|
||||||
|
void operator=(const QByteArray &ba);
|
||||||
|
bool operator==(const RegisterValue &other);
|
||||||
|
bool operator!=(const RegisterValue &other) { return !operator==(other); }
|
||||||
|
QByteArray toByteArray(int base, RegisterKind kind, int size) const;
|
||||||
|
RegisterValue subValue(int size, int index) const;
|
||||||
|
|
||||||
|
union {
|
||||||
|
quint8 u8[16];
|
||||||
|
quint16 u16[8];
|
||||||
|
quint32 u32[4];
|
||||||
|
quint64 u64[2];
|
||||||
|
float f[4];
|
||||||
|
double d[2];
|
||||||
|
} v;
|
||||||
|
};
|
||||||
|
|
||||||
class Register
|
class Register
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Register() : type(0), changed(true) {}
|
Register() { size = 0; kind = UnknownRegister; }
|
||||||
Register(const QByteArray &name_);
|
void guessMissingData();
|
||||||
|
|
||||||
QVariant editValue() const;
|
|
||||||
QString displayValue(int base, int strlen) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
QByteArray name;
|
QByteArray name;
|
||||||
/* Value should be an integer for which autodetection by passing
|
QByteArray reportedType;
|
||||||
* base=0 to QString::toULongLong() should work (C-language conventions).
|
RegisterValue value;
|
||||||
* Values that cannot be converted (such as 128bit MMX-registers) are
|
RegisterValue previousValue;
|
||||||
* passed through. */
|
QByteArray description;
|
||||||
QByteArray value;
|
int size;
|
||||||
int type;
|
RegisterKind kind;
|
||||||
bool changed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QVector<Register> Registers;
|
class RegisterItem;
|
||||||
|
typedef QMap<quint64, QByteArray> RegisterMap;
|
||||||
|
|
||||||
class RegisterHandler : public QAbstractTableModel
|
class RegisterHandler : public Utils::TreeModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -68,34 +106,17 @@ public:
|
|||||||
|
|
||||||
QAbstractItemModel *model() { return this; }
|
QAbstractItemModel *model() { return this; }
|
||||||
|
|
||||||
bool isEmpty() const; // nothing known so far?
|
void updateRegister(const Register ®);
|
||||||
// Set up register names (gdb)
|
|
||||||
void setRegisters(const Registers ®isters);
|
void setNumberBase(const QByteArray &name, int base);
|
||||||
// Set register values
|
void commitUpdates() { emit layoutChanged(); }
|
||||||
void setAndMarkRegisters(const Registers ®isters);
|
RegisterMap registerMap() const;
|
||||||
Registers registers() const;
|
|
||||||
Register registerAt(int i) const { return m_registers.at(i); }
|
|
||||||
void removeAll();
|
|
||||||
Q_SLOT void setNumberBase(int base);
|
|
||||||
int numberBase() const { return m_base; }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void registerSet(const QModelIndex &r); // Register was set, for memory views
|
void registerChanged(const QByteArray &name, quint64 value); // For memory views
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calculateWidth();
|
QHash<QByteArray, RegisterItem *> m_registerByName;
|
||||||
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;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &idx) const;
|
|
||||||
|
|
||||||
Registers m_registers;
|
|
||||||
int m_base;
|
|
||||||
int m_strlen; // approximate width of a value in chars.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "registerwindow.h"
|
#include "registerwindow.h"
|
||||||
#include "memoryview.h"
|
#include "memoryview.h"
|
||||||
|
#include "memoryagent.h"
|
||||||
#include "debuggeractions.h"
|
#include "debuggeractions.h"
|
||||||
#include "debuggerdialogs.h"
|
#include "debuggerdialogs.h"
|
||||||
#include "debuggercore.h"
|
#include "debuggercore.h"
|
||||||
@@ -42,22 +43,13 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include <QItemDelegate>
|
#include <QItemDelegate>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
static RegisterHandler *currentHandler()
|
|
||||||
{
|
|
||||||
DebuggerEngine *engine = currentEngine();
|
|
||||||
QTC_ASSERT(engine, return 0);
|
|
||||||
return engine->registerHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// RegisterDelegate
|
// RegisterDelegate
|
||||||
@@ -74,10 +66,9 @@ public:
|
|||||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
Register reg = currentHandler()->registerAt(index.row());
|
|
||||||
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
|
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
|
||||||
const int base = currentHandler()->numberBase();
|
const int base = index.data(RegisterNumberBaseRole).toInt();
|
||||||
const bool big = reg.value.size() > 16;
|
const bool big = index.data(RegisterIsBigRole).toBool();
|
||||||
// Big integers are assumed to be hexadecimal.
|
// Big integers are assumed to be hexadecimal.
|
||||||
lineEdit->setBigInt(big);
|
lineEdit->setBigInt(big);
|
||||||
lineEdit->setBase(big ? 16 : base);
|
lineEdit->setBase(big ? 16 : base);
|
||||||
@@ -101,11 +92,11 @@ 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 = currentHandler()->numberBase();
|
const int base = index.data(RegisterNumberBaseRole).toInt();
|
||||||
QString value = lineEdit->text();
|
QString value = lineEdit->text();
|
||||||
if (base == 16 && !value.startsWith(QLatin1String("0x")))
|
if (base == 16 && !value.startsWith(QLatin1String("0x")))
|
||||||
value.insert(0, QLatin1String("0x"));
|
value.insert(0, QLatin1String("0x"));
|
||||||
currentEngine()->setRegisterValue(index.row(), value);
|
currentEngine()->setRegisterValue(index.data(RegisterNameRole).toByteArray(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
|
||||||
@@ -118,27 +109,37 @@ public:
|
|||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (index.column() == 1) {
|
if (index.column() == 1) {
|
||||||
bool paintRed = currentHandler()->registerAt(index.row()).changed;
|
const bool paintRed = index.data(RegisterChangedRole).toBool();
|
||||||
QPen oldPen = painter->pen();
|
QPen oldPen = painter->pen();
|
||||||
|
const QColor lightColor(140, 140, 140);
|
||||||
if (paintRed)
|
if (paintRed)
|
||||||
painter->setPen(QColor(200, 0, 0));
|
painter->setPen(QColor(200, 0, 0));
|
||||||
|
else
|
||||||
|
painter->setPen(lightColor);
|
||||||
// FIXME: performance? this changes only on real font changes.
|
// FIXME: performance? this changes only on real font changes.
|
||||||
QFontMetrics fm(option.font);
|
QFontMetrics fm(option.font);
|
||||||
int charWidth = fm.width(QLatin1Char('x'));
|
int charWidth = qMax(fm.width(QLatin1Char('x')), fm.width(QLatin1Char('0')));
|
||||||
for (int i = '1'; i <= '9'; ++i)
|
|
||||||
charWidth = qMax(charWidth, fm.width(QLatin1Char(i)));
|
|
||||||
for (int i = 'a'; i <= 'f'; ++i)
|
|
||||||
charWidth = qMax(charWidth, fm.width(QLatin1Char(i)));
|
|
||||||
QString str = index.data(Qt::DisplayRole).toString();
|
QString str = index.data(Qt::DisplayRole).toString();
|
||||||
int x = option.rect.x();
|
int x = option.rect.x();
|
||||||
|
bool light = !paintRed;
|
||||||
for (int i = 0; i < str.size(); ++i) {
|
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;
|
QRect r = option.rect;
|
||||||
r.setX(x);
|
r.setX(x);
|
||||||
r.setWidth(charWidth);
|
r.setWidth(charWidth);
|
||||||
x += charWidth;
|
painter->drawText(r, Qt::AlignHCenter, c);
|
||||||
painter->drawText(r, Qt::AlignHCenter, QString(str.at(i)));
|
}
|
||||||
|
x += charWidth;
|
||||||
}
|
}
|
||||||
if (paintRed)
|
|
||||||
painter->setPen(oldPen);
|
painter->setPen(oldPen);
|
||||||
} else {
|
} else {
|
||||||
QItemDelegate::paint(painter, option, index);
|
QItemDelegate::paint(painter, option, index);
|
||||||
@@ -156,6 +157,7 @@ public:
|
|||||||
RegisterTreeView::RegisterTreeView()
|
RegisterTreeView::RegisterTreeView()
|
||||||
{
|
{
|
||||||
setItemDelegate(new RegisterDelegate(this));
|
setItemDelegate(new RegisterDelegate(this));
|
||||||
|
setRootIsDecorated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
@@ -164,7 +166,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
|
|
||||||
DebuggerEngine *engine = currentEngine();
|
DebuggerEngine *engine = currentEngine();
|
||||||
QTC_ASSERT(engine, return);
|
QTC_ASSERT(engine, return);
|
||||||
RegisterHandler *handler = currentHandler();
|
RegisterHandler *handler = engine->registerHandler();
|
||||||
|
|
||||||
const bool actionsEnabled = engine->debuggerActionsEnabled();
|
const bool actionsEnabled = engine->debuggerActionsEnabled();
|
||||||
const DebuggerState state = engine->state();
|
const DebuggerState state = engine->state();
|
||||||
|
|
||||||
@@ -174,13 +177,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
|
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
|
||||||
Register aRegister;
|
|
||||||
const QModelIndex idx = indexAt(ev->pos());
|
const QModelIndex idx = indexAt(ev->pos());
|
||||||
if (idx.isValid())
|
const quint64 address = idx.data(RegisterAsAddressRole).toULongLong();
|
||||||
aRegister = handler->registers().at(idx.row());
|
|
||||||
const QVariant addressV = aRegister.editValue();
|
|
||||||
const quint64 address = addressV.type() == QVariant::ULongLong
|
|
||||||
? addressV.toULongLong() : 0;
|
|
||||||
QAction *actViewMemory = menu.addAction(QString());
|
QAction *actViewMemory = menu.addAction(QString());
|
||||||
QAction *actEditMemory = menu.addAction(QString());
|
QAction *actEditMemory = menu.addAction(QString());
|
||||||
|
|
||||||
@@ -188,12 +186,14 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
QAction *actShowDisassembler = menu.addAction(tr("Open Disassembler..."));
|
QAction *actShowDisassembler = menu.addAction(tr("Open Disassembler..."));
|
||||||
actShowDisassembler->setEnabled(engine->hasCapability(DisassemblerCapability));
|
actShowDisassembler->setEnabled(engine->hasCapability(DisassemblerCapability));
|
||||||
|
|
||||||
|
const QByteArray registerName = idx.data(RegisterNameRole).toByteArray();
|
||||||
|
const QString registerNameStr = QString::fromUtf8(registerName);
|
||||||
if (address) {
|
if (address) {
|
||||||
const bool canShow = actionsEnabled && engine->hasCapability(ShowMemoryCapability);
|
const bool canShow = actionsEnabled && engine->hasCapability(ShowMemoryCapability);
|
||||||
actEditMemory->setText(tr("Open Memory Editor at 0x%1").arg(address, 0, 16));
|
actEditMemory->setText(tr("Open Memory Editor at 0x%1").arg(address, 0, 16));
|
||||||
actEditMemory->setEnabled(canShow);
|
actEditMemory->setEnabled(canShow);
|
||||||
actViewMemory->setText(tr("Open Memory View at Value of Register %1 0x%2")
|
actViewMemory->setText(tr("Open Memory View at Value of Register %1 0x%2")
|
||||||
.arg(QString::fromLatin1(aRegister.name)).arg(address, 0, 16));
|
.arg(registerNameStr).arg(address, 0, 16));
|
||||||
actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1")
|
actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1")
|
||||||
.arg(address, 0, 16));
|
.arg(address, 0, 16));
|
||||||
actShowDisassemblerAt->setEnabled(engine->hasCapability(DisassemblerCapability));
|
actShowDisassemblerAt->setEnabled(engine->hasCapability(DisassemblerCapability));
|
||||||
@@ -207,7 +207,7 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
}
|
}
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
|
||||||
const int base = handler->numberBase();
|
const int base = idx.data(RegisterNumberBaseRole).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(base == 16);
|
||||||
@@ -230,14 +230,20 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
if (act == actReload) {
|
if (act == actReload) {
|
||||||
engine->reloadRegisters();
|
engine->reloadRegisters();
|
||||||
} else if (act == actEditMemory) {
|
} else if (act == actEditMemory) {
|
||||||
const QString registerName = QString::fromLatin1(aRegister.name);
|
MemoryViewSetupData data;
|
||||||
engine->openMemoryView(address, 0,
|
data.startAddress = address;
|
||||||
RegisterMemoryView::registerMarkup(address, registerName),
|
data.registerName = registerName;
|
||||||
QPoint(), RegisterMemoryView::title(registerName), 0);
|
data.markup = RegisterMemoryView::registerMarkup(address, registerName);
|
||||||
|
data.title = RegisterMemoryView::title(registerName);
|
||||||
|
engine->openMemoryView(data);
|
||||||
} else if (act == actViewMemory) {
|
} else if (act == actViewMemory) {
|
||||||
engine->openMemoryView(idx.row(),
|
MemoryViewSetupData data;
|
||||||
DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
|
data.startAddress = address;
|
||||||
QList<MemoryMarkup>(), position, QString(), this);
|
data.flags = DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
|
||||||
|
data.registerName = registerName;
|
||||||
|
data.pos = position;
|
||||||
|
data.parent = this;
|
||||||
|
engine->openMemoryView(data);
|
||||||
} else if (act == actShowDisassembler) {
|
} else if (act == actShowDisassembler) {
|
||||||
AddressDialog dialog;
|
AddressDialog dialog;
|
||||||
if (address)
|
if (address)
|
||||||
@@ -247,13 +253,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(16);
|
handler->setNumberBase(registerName, 16);
|
||||||
else if (act == act10)
|
else if (act == act10)
|
||||||
handler->setNumberBase(10);
|
handler->setNumberBase(registerName, 10);
|
||||||
else if (act == act8)
|
else if (act == act8)
|
||||||
handler->setNumberBase(8);
|
handler->setNumberBase(registerName, 8);
|
||||||
else if (act == act2)
|
else if (act == act2)
|
||||||
handler->setNumberBase(2);
|
handler->setNumberBase(registerName, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterTreeView::reloadRegisters()
|
void RegisterTreeView::reloadRegisters()
|
||||||
|
|||||||
@@ -214,12 +214,13 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
if (act == actCopyContents) {
|
if (act == actCopyContents) {
|
||||||
copyContentsToClipboard();
|
copyContentsToClipboard();
|
||||||
} else if (act == actShowMemory) {
|
} else if (act == actShowMemory) {
|
||||||
const QString title = tr("Memory at Frame #%1 (%2) 0x%3").
|
MemoryViewSetupData data;
|
||||||
|
data.startAddress = address;
|
||||||
|
data.title = tr("Memory at Frame #%1 (%2) 0x%3").
|
||||||
arg(row).arg(frame.function).arg(address, 0, 16);
|
arg(row).arg(frame.function).arg(address, 0, 16);
|
||||||
QList<MemoryMarkup> ml;
|
data.markup.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(),
|
||||||
ml.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(),
|
|
||||||
tr("Frame #%1 (%2)").arg(row).arg(frame.function)));
|
tr("Frame #%1 (%2)").arg(row).arg(frame.function)));
|
||||||
engine->openMemoryView(address, 0, ml, QPoint(), title);
|
engine->openMemoryView(data);
|
||||||
} else if (act == actShowDisassemblerAtAddress) {
|
} else if (act == actShowDisassemblerAtAddress) {
|
||||||
AddressDialog dialog;
|
AddressDialog dialog;
|
||||||
if (address)
|
if (address)
|
||||||
|
|||||||
@@ -178,21 +178,6 @@ static inline uint sizeOf(const QModelIndex &m)
|
|||||||
return m.data(LocalsSizeRole).toUInt();
|
return m.data(LocalsSizeRole).toUInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a map of value->name for register markup.
|
|
||||||
typedef QMap<quint64, QString> RegisterMap;
|
|
||||||
typedef RegisterMap::const_iterator RegisterMapConstIt;
|
|
||||||
|
|
||||||
RegisterMap registerMap(const DebuggerEngine *engine)
|
|
||||||
{
|
|
||||||
RegisterMap result;
|
|
||||||
foreach (const Register ®, engine->registerHandler()->registers()) {
|
|
||||||
const QVariant v = reg.editValue();
|
|
||||||
if (v.type() == QVariant::ULongLong)
|
|
||||||
result.insert(v.toULongLong(), QString::fromLatin1(reg.name));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functionality to indicate the area of a member variable in
|
// Helper functionality to indicate the area of a member variable in
|
||||||
// a vector representing the memory area by a unique color
|
// a vector representing the memory area by a unique color
|
||||||
// number and tooltip. Parts of it will be overwritten when recursing
|
// number and tooltip. Parts of it will be overwritten when recursing
|
||||||
@@ -314,13 +299,12 @@ static MemoryMarkupList
|
|||||||
if (sizeIsEstimate && !childCount)
|
if (sizeIsEstimate && !childCount)
|
||||||
return result; // Fixme: Exact size not known, no point in filling if no children.
|
return result; // Fixme: Exact size not known, no point in filling if no children.
|
||||||
// Punch in registers as 1-byte markers on top.
|
// Punch in registers as 1-byte markers on top.
|
||||||
const RegisterMapConstIt regcEnd = registerMap.constEnd();
|
for (auto it = registerMap.constBegin(), end = registerMap.constEnd(); it != end; ++it) {
|
||||||
for (RegisterMapConstIt it = registerMap.constBegin(); it != regcEnd; ++it) {
|
|
||||||
if (it.key() >= address) {
|
if (it.key() >= address) {
|
||||||
const quint64 offset = it.key() - address;
|
const quint64 offset = it.key() - address;
|
||||||
if (offset < size) {
|
if (offset < size) {
|
||||||
ranges[offset] = ColorNumberToolTip(registerColorNumber,
|
ranges[offset] = ColorNumberToolTip(registerColorNumber,
|
||||||
WatchTreeView::tr("Register <i>%1</i>").arg(it.value()));
|
WatchTreeView::tr("Register <i>%1</i>").arg(QString::fromUtf8(it.value())));
|
||||||
} else {
|
} else {
|
||||||
break; // Sorted.
|
break; // Sorted.
|
||||||
}
|
}
|
||||||
@@ -381,27 +365,27 @@ static void addVariableMemoryView(DebuggerEngine *engine, bool separateView,
|
|||||||
const QPoint &p, QWidget *parent)
|
const QPoint &p, QWidget *parent)
|
||||||
{
|
{
|
||||||
const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base);
|
const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base);
|
||||||
const quint64 address = atPointerAddress ? pointerAddressOf(m) : addressOf(m);
|
MemoryViewSetupData data;
|
||||||
|
data.startAddress = atPointerAddress ? pointerAddressOf(m) : addressOf(m);
|
||||||
|
if (!data.startAddress)
|
||||||
|
return;
|
||||||
// Fixme: Get the size of pointee (see variableMemoryMarkup())?
|
// Fixme: Get the size of pointee (see variableMemoryMarkup())?
|
||||||
const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0);
|
const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0);
|
||||||
const quint64 typeSize = sizeOf(m);
|
const quint64 typeSize = sizeOf(m);
|
||||||
const bool sizeIsEstimate = atPointerAddress || !typeSize;
|
const bool sizeIsEstimate = atPointerAddress || !typeSize;
|
||||||
const quint64 size = sizeIsEstimate ? 1024 : typeSize;
|
const quint64 size = sizeIsEstimate ? 1024 : typeSize;
|
||||||
if (!address)
|
data.markup = variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip,
|
||||||
return;
|
data.startAddress, size,
|
||||||
const QList<MemoryMarkup> markup =
|
engine->registerHandler()->registerMap(),
|
||||||
variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip,
|
|
||||||
address, size,
|
|
||||||
registerMap(engine),
|
|
||||||
sizeIsEstimate, background);
|
sizeIsEstimate, background);
|
||||||
const unsigned flags = separateView
|
data.flags = separateView ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0;
|
||||||
? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0;
|
QString pat = atPointerAddress
|
||||||
const QString title = atPointerAddress
|
|
||||||
? WatchTreeView::tr("Memory at Pointer's Address \"%1\" (0x%2)")
|
? WatchTreeView::tr("Memory at Pointer's Address \"%1\" (0x%2)")
|
||||||
.arg(nameOf(m)).arg(address, 0, 16)
|
: WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)");
|
||||||
: WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)")
|
data.title = pat.arg(nameOf(m)).arg(data.startAddress, 0, 16);
|
||||||
.arg(nameOf(m)).arg(address, 0, 16);
|
data.pos = p;
|
||||||
engine->openMemoryView(address, flags, markup, p, title, parent);
|
data.parent = parent;
|
||||||
|
engine->openMemoryView(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a memory view of the stack layout showing local variables
|
// Add a memory view of the stack layout showing local variables
|
||||||
@@ -444,9 +428,8 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView,
|
|||||||
}
|
}
|
||||||
// Take a look at the register values. Extend the range a bit if suitable
|
// Take a look at the register values. Extend the range a bit if suitable
|
||||||
// to show stack/stack frame pointers.
|
// to show stack/stack frame pointers.
|
||||||
const RegisterMap regMap = registerMap(engine);
|
const RegisterMap regMap = engine->registerHandler()->registerMap();
|
||||||
const RegisterMapConstIt regcEnd = regMap.constEnd();
|
for (auto it = regMap.constBegin(), cend = regMap.constEnd(); it != cend; ++it) {
|
||||||
for (RegisterMapConstIt it = regMap.constBegin(); it != regcEnd; ++it) {
|
|
||||||
const quint64 value = it.key();
|
const quint64 value = it.key();
|
||||||
if (value < start && start - value < 512)
|
if (value < start && start - value < 512)
|
||||||
start = value;
|
start = value;
|
||||||
@@ -454,16 +437,18 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView,
|
|||||||
end = value + 1;
|
end = value + 1;
|
||||||
}
|
}
|
||||||
// Indicate all variables.
|
// Indicate all variables.
|
||||||
|
MemoryViewSetupData data;
|
||||||
const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base);
|
const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base);
|
||||||
const MemoryMarkupList markup =
|
data.startAddress = start;
|
||||||
variableMemoryMarkup(m, localsIndex, QString(),
|
data.markup = variableMemoryMarkup(m, localsIndex, QString(),
|
||||||
QString(), start, end - start,
|
QString(), start, end - start,
|
||||||
regMap, true, background);
|
regMap, true, background);
|
||||||
const unsigned flags = separateView
|
data.flags = separateView
|
||||||
? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0;
|
? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0;
|
||||||
const QString title =
|
data.title = WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16);
|
||||||
WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16);
|
data.pos = p;
|
||||||
engine->openMemoryView(start, flags, markup, p, title, parent);
|
data.parent = parent;
|
||||||
|
engine->openMemoryView(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
@@ -936,8 +921,11 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
AddressDialog dialog;
|
AddressDialog dialog;
|
||||||
if (address)
|
if (address)
|
||||||
dialog.setAddress(address);
|
dialog.setAddress(address);
|
||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
currentEngine()->openMemoryView(dialog.address(), false, MemoryMarkupList(), QPoint());
|
MemoryViewSetupData data;
|
||||||
|
data.startAddress = dialog.address();
|
||||||
|
currentEngine()->openMemoryView(data);
|
||||||
|
}
|
||||||
} else if (act == &actOpenMemoryViewAtObjectAddress) {
|
} else if (act == &actOpenMemoryViewAtObjectAddress) {
|
||||||
addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this);
|
addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this);
|
||||||
} else if (act == &actOpenMemoryViewAtPointerAddress) {
|
} else if (act == &actOpenMemoryViewAtPointerAddress) {
|
||||||
|
|||||||
Reference in New Issue
Block a user