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:
|
||||
result += '{name="%s"' % reg.GetName()
|
||||
result += ',value="%s"' % reg.GetValue()
|
||||
result += ',size="%s"' % reg.GetByteSize()
|
||||
result += ',type="%s"},' % reg.GetType()
|
||||
result += ']'
|
||||
self.report(result)
|
||||
|
||||
@@ -364,6 +364,34 @@ const wchar_t *valueType(ULONG type)
|
||||
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
|
||||
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)
|
||||
{
|
||||
size = 0;
|
||||
value.Type = DEBUG_VALUE_INT32;
|
||||
value.I32 = 0;
|
||||
}
|
||||
@@ -497,6 +526,7 @@ Registers getRegisters(CIDebugRegisters *regs,
|
||||
reg.pseudoRegister = true;
|
||||
reg.name = buf;
|
||||
reg.description = valueType(type);
|
||||
reg.size = valueSize(type);
|
||||
reg.value = value;
|
||||
rc.push_back(reg);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ struct Register
|
||||
|
||||
std::wstring name;
|
||||
std::wstring description;
|
||||
int size;
|
||||
bool subRegister;
|
||||
bool pseudoRegister;
|
||||
DEBUG_VALUE value;
|
||||
|
||||
@@ -1235,14 +1235,12 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
|
||||
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
|
||||
QByteArray cmd;
|
||||
ByteArrayInputStream str(cmd);
|
||||
str << "r " << registers.at(regnr).name << '=' << value;
|
||||
str << "r " << name << '=' << value;
|
||||
postCommand(cmd, 0);
|
||||
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)
|
||||
{
|
||||
if (reply->success) {
|
||||
@@ -1906,11 +1889,17 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
|
||||
GdbMi value;
|
||||
value.fromString(reply->reply);
|
||||
if (value.type() == GdbMi::List) {
|
||||
Registers registers;
|
||||
registers.reserve(value.childCount());
|
||||
foreach (const GdbMi &gdbmiReg, value.children())
|
||||
registers.push_back(parseRegister(gdbmiReg));
|
||||
registerHandler()->setAndMarkRegisters(registers);
|
||||
RegisterHandler *handler = registerHandler();
|
||||
foreach (const GdbMi &item, value.children()) {
|
||||
Register reg;
|
||||
reg.name = item["name"].data();
|
||||
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 {
|
||||
showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
|
||||
qWarning("Parse error in registers response:\n%s", reply->reply.constData());
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
const WatchUpdateFlags & flags = WatchUpdateFlags());
|
||||
virtual bool hasCapability(unsigned cap) const;
|
||||
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 executeStepOut();
|
||||
|
||||
@@ -477,9 +477,9 @@ void DebuggerEngine::changeMemory(MemoryAgent *, QObject *,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1746,11 +1746,9 @@ void DebuggerEngine::showStoppedByExceptionMessageBox(const QString &description
|
||||
Core::AsynchronousMessageBox::information(tr("Exception Triggered"), msg);
|
||||
}
|
||||
|
||||
void DebuggerEngine::openMemoryView(quint64 startAddr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
const QString &title, QWidget *parent)
|
||||
void DebuggerEngine::openMemoryView(const MemoryViewSetupData &data)
|
||||
{
|
||||
d->m_memoryAgent.createBinEditor(startAddr, flags, ml, pos, title, parent);
|
||||
d->m_memoryAgent.createBinEditor(data);
|
||||
}
|
||||
|
||||
void DebuggerEngine::updateMemoryViews()
|
||||
|
||||
@@ -75,7 +75,7 @@ class BreakpointParameters;
|
||||
class QmlAdapter;
|
||||
class QmlCppEngine;
|
||||
class DebuggerToolTipContext;
|
||||
class MemoryMarkup;
|
||||
class MemoryViewSetupData;
|
||||
|
||||
struct WatchUpdateFlags
|
||||
{
|
||||
@@ -158,10 +158,7 @@ public:
|
||||
MemoryView = 0x4 //!< Open a separate view (using the pos-parameter).
|
||||
};
|
||||
|
||||
virtual void openMemoryView(quint64 startAddr, unsigned flags,
|
||||
const QList<Internal::MemoryMarkup> &ml,
|
||||
const QPoint &pos,
|
||||
const QString &title = QString(), QWidget *parent = 0);
|
||||
virtual void openMemoryView(const MemoryViewSetupData &data);
|
||||
virtual void fetchMemory(Internal::MemoryAgent *, QObject *,
|
||||
quint64 addr, quint64 length);
|
||||
virtual void changeMemory(Internal::MemoryAgent *, QObject *,
|
||||
@@ -185,7 +182,7 @@ public:
|
||||
virtual void loadAdditionalQmlStack();
|
||||
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 bool hasCapability(unsigned cap) const = 0;
|
||||
virtual void debugLastCommand() {}
|
||||
|
||||
@@ -3356,8 +3356,11 @@ bool isDockVisible(const QString &objectName)
|
||||
void openMemoryEditor()
|
||||
{
|
||||
AddressDialog dialog;
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
currentEngine()->openMemoryView(dialog.address(), 0, QList<MemoryMarkup>(), QPoint());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
MemoryViewSetupData data;
|
||||
data.startAddress = dialog.address();
|
||||
currentEngine()->openMemoryView(data);
|
||||
}
|
||||
}
|
||||
|
||||
void setThreads(const QStringList &list, int index)
|
||||
|
||||
@@ -78,11 +78,11 @@
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QDirIterator>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
@@ -3585,19 +3585,79 @@ void GdbEngine::reloadRegisters()
|
||||
|
||||
if (state() != InferiorStopOk && state() != InferiorUnrunnable)
|
||||
return;
|
||||
|
||||
if (true) {
|
||||
if (!m_registerNamesListed) {
|
||||
postCommand("-data-list-register-names", CB(handleRegisterListNames));
|
||||
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",
|
||||
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);
|
||||
postCommand("set $" + reg.name + "=" + value.toLatin1());
|
||||
const int n = ba.size();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -3608,26 +3668,14 @@ void GdbEngine::handleRegisterListNames(const GdbResponse &response)
|
||||
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"];
|
||||
m_registerNumbers.resize(names.childCount());
|
||||
m_registerNames.clear();
|
||||
int gdbRegisterNumber = 0;
|
||||
foreach (const GdbMi &item, names.children()) {
|
||||
// Since we throw away missing registers to eliminate empty rows
|
||||
// we need to maintain a mapping of GDB register numbers to their
|
||||
// respective indices in the register list.
|
||||
if (!item.data().isEmpty()) {
|
||||
m_registerNumbers[gdbRegisterNumber] = internalIndex++;
|
||||
registers.append(Register(item.data()));
|
||||
if (!item.data().isEmpty())
|
||||
m_registerNames[gdbRegisterNumber] = item.data();
|
||||
++gdbRegisterNumber;
|
||||
}
|
||||
gdbRegisterNumber++;
|
||||
}
|
||||
|
||||
registerHandler()->setRegisters(registers);
|
||||
}
|
||||
|
||||
void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
||||
@@ -3635,19 +3683,46 @@ void GdbEngine::handleRegisterListValues(const GdbResponse &response)
|
||||
if (response.resultClass != GdbResultDone)
|
||||
return;
|
||||
|
||||
Registers registers = registerHandler()->registers();
|
||||
const int registerCount = registers.size();
|
||||
const int gdbRegisterCount = m_registerNumbers.size();
|
||||
|
||||
RegisterHandler *handler = registerHandler();
|
||||
// 24^done,register-values=[{number="0",value="0xf423f"},...]
|
||||
const GdbMi values = response.data["register-values"];
|
||||
QTC_ASSERT(registerCount == values.children().size(), return);
|
||||
foreach (const GdbMi &item, values.children()) {
|
||||
Register reg;
|
||||
const int number = item["number"].toInt();
|
||||
if (number >= 0 && number < gdbRegisterCount)
|
||||
registers[m_registerNumbers[number]].value = item["value"].data();
|
||||
reg.name = m_registerNames[number];
|
||||
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
|
||||
//
|
||||
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 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
|
||||
|
||||
@@ -1085,16 +1085,15 @@ void LldbEngine::setStackPosition(int index)
|
||||
void LldbEngine::refreshRegisters(const GdbMi ®isters)
|
||||
{
|
||||
RegisterHandler *handler = registerHandler();
|
||||
Registers regs;
|
||||
foreach (const GdbMi &item, registers.children()) {
|
||||
Register reg;
|
||||
reg.name = item["name"].data();
|
||||
reg.value = item["value"].data();
|
||||
//reg.type = item["type"].data();
|
||||
regs.append(reg);
|
||||
reg.size = item["size"].data().toInt();
|
||||
reg.reportedType = item["type"].data();
|
||||
handler->updateRegister(reg);
|
||||
}
|
||||
//handler->setRegisters(registers);
|
||||
handler->setAndMarkRegisters(regs);
|
||||
handler->commitUpdates();
|
||||
}
|
||||
|
||||
void LldbEngine::refreshThreads(const GdbMi &threads)
|
||||
@@ -1250,10 +1249,9 @@ void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
|
||||
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", reg.name).arg("value", value));
|
||||
runCommand(Command("setRegister").arg("name", name).arg("value", value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
bool supportsThreads() const { return true; }
|
||||
bool isSynchronous() const { return true; }
|
||||
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 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)));
|
||||
}
|
||||
|
||||
bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
QString title, QWidget *parent)
|
||||
bool MemoryAgent::doCreateBinEditor(const MemoryViewSetupData &data)
|
||||
{
|
||||
const bool readOnly = (flags & DebuggerEngine::MemoryReadOnly) != 0;
|
||||
if (title.isEmpty())
|
||||
title = tr("Memory at 0x%1").arg(addr, 0, 16);
|
||||
const bool readOnly = (data.flags & DebuggerEngine::MemoryReadOnly) != 0;
|
||||
QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title;
|
||||
// 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.
|
||||
QWidget *binEditor = 0;
|
||||
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 *topLevel = 0;
|
||||
// Memory view tracking register value, providing its own updating mechanism.
|
||||
if (flags & DebuggerEngine::MemoryTrackRegister) {
|
||||
RegisterMemoryView *rmv = new RegisterMemoryView(binEditor, parent);
|
||||
rmv->init(m_engine->registerHandler(), int(addr));
|
||||
topLevel = rmv;
|
||||
if (data.flags & DebuggerEngine::MemoryTrackRegister) {
|
||||
topLevel = new RegisterMemoryView(binEditor, data.startAddress, data.registerName, m_engine->registerHandler(), data.parent);
|
||||
} else {
|
||||
// Ordinary memory view
|
||||
MemoryView::setBinEditorMarkup(binEditor, ml);
|
||||
MemoryView::setBinEditorRange(binEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
topLevel = new MemoryView(binEditor, parent);
|
||||
MemoryView::setBinEditorMarkup(binEditor, data.markup);
|
||||
MemoryView::setBinEditorRange(binEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
topLevel = new MemoryView(binEditor, data.parent);
|
||||
topLevel->setWindowTitle(title);
|
||||
}
|
||||
m_views << topLevel;
|
||||
topLevel->move(pos);
|
||||
topLevel->move(data.pos);
|
||||
topLevel->show();
|
||||
return true;
|
||||
}
|
||||
// Editor: Register tracking not supported.
|
||||
QTC_ASSERT(!(flags & DebuggerEngine::MemoryTrackRegister), return false);
|
||||
QTC_ASSERT(!(data.flags & DebuggerEngine::MemoryTrackRegister), return false);
|
||||
if (!title.endsWith(QLatin1Char('$')))
|
||||
title.append(QLatin1String(" $"));
|
||||
IEditor *editor = EditorManager::openEditorWithContents(
|
||||
@@ -185,17 +180,15 @@ bool MemoryAgent::doCreateBinEditor(quint64 addr, unsigned flags,
|
||||
connectBinEditorWidget(editorBinEditor);
|
||||
MemoryView::setBinEditorReadOnly(editorBinEditor, readOnly);
|
||||
MemoryView::setBinEditorNewWindowRequestAllowed(editorBinEditor, true);
|
||||
MemoryView::setBinEditorRange(editorBinEditor, addr, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
MemoryView::setBinEditorMarkup(editorBinEditor, ml);
|
||||
MemoryView::setBinEditorRange(editorBinEditor, data.startAddress, MemoryAgent::DataRange, MemoryAgent::BinBlockSize);
|
||||
MemoryView::setBinEditorMarkup(editorBinEditor, data.markup);
|
||||
m_editors << editor;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryAgent::createBinEditor(quint64 addr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
const QString &title, QWidget *parent)
|
||||
void MemoryAgent::createBinEditor(const MemoryViewSetupData &data)
|
||||
{
|
||||
if (!doCreateBinEditor(addr, flags, ml, pos, title, parent))
|
||||
if (!doCreateBinEditor(data))
|
||||
Core::AsynchronousMessageBox::warning(
|
||||
tr("No Memory Viewer Available"),
|
||||
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)
|
||||
{
|
||||
createBinEditor(addr, 0, QList<MemoryMarkup>(), QPoint(), QString(), 0);
|
||||
MemoryViewSetupData data;
|
||||
data.startAddress = addr;
|
||||
createBinEditor(data);
|
||||
}
|
||||
|
||||
void MemoryAgent::fetchLazyData(quint64 block)
|
||||
|
||||
@@ -34,11 +34,10 @@
|
||||
#include "debuggerconstants.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QPointer>
|
||||
#include <QColor>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPoint)
|
||||
|
||||
namespace Core { class IEditor; }
|
||||
|
||||
namespace ProjectExplorer { class Abi; }
|
||||
@@ -62,6 +61,20 @@ public:
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -80,9 +93,7 @@ public:
|
||||
|
||||
public slots:
|
||||
// Called by engine to create a new view.
|
||||
void createBinEditor(quint64 startAddr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
const QString &title, QWidget *parent);
|
||||
void createBinEditor(const MemoryViewSetupData &data);
|
||||
void createBinEditor(quint64 startAddr);
|
||||
// Called by engine to create a tooltip.
|
||||
void addLazyData(QObject *editorToken, quint64 addr, const QByteArray &data);
|
||||
@@ -101,9 +112,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void connectBinEditorWidget(QWidget *w);
|
||||
bool doCreateBinEditor(quint64 startAddr, unsigned flags,
|
||||
const QList<MemoryMarkup> &ml, const QPoint &pos,
|
||||
QString title, QWidget *parent);
|
||||
bool doCreateBinEditor(const MemoryViewSetupData &data);
|
||||
|
||||
QList<QPointer<Core::IEditor> > m_editors;
|
||||
QList<QPointer<MemoryView> > m_views;
|
||||
|
||||
@@ -138,24 +138,27 @@ void MemoryView::setMarkup(const QList<MemoryMarkup> &m)
|
||||
\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),
|
||||
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())
|
||||
return;
|
||||
const QVariant newAddressV = index.data(Qt::EditRole);
|
||||
if (newAddressV.type() == QVariant::ULongLong)
|
||||
setRegisterAddress(newAddressV.toULongLong());
|
||||
if (name == m_registerName)
|
||||
setRegisterAddress(value);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -171,25 +174,13 @@ void RegisterMemoryView::setRegisterAddress(quint64 v)
|
||||
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;
|
||||
result.push_back(MemoryMarkup(a, 1, QColor(Qt::blue).lighter(),
|
||||
tr("Register \"%1\"").arg(name)));
|
||||
tr("Register \"%1\"").arg(QString::fromUtf8(regName))));
|
||||
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 Debugger
|
||||
|
||||
@@ -69,21 +69,17 @@ class RegisterMemoryView : public MemoryView
|
||||
{
|
||||
Q_OBJECT
|
||||
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 QString &name);
|
||||
static QString title(const QString ®isterName, quint64 a = 0);
|
||||
|
||||
private slots:
|
||||
void slotRegisterSet(const QModelIndex &index);
|
||||
static QList<MemoryMarkup> registerMarkup(quint64 a, const QByteArray ®Name);
|
||||
static QString title(const QByteArray ®isterName, quint64 a = 0);
|
||||
|
||||
private:
|
||||
void onRegisterChanged(const QByteArray &name, quint64 value);
|
||||
void setRegisterAddress(quint64 v);
|
||||
|
||||
int m_registerIndex;
|
||||
QString m_registerName;
|
||||
QByteArray m_registerName;
|
||||
quint64 m_registerAddress;
|
||||
};
|
||||
|
||||
|
||||
@@ -184,9 +184,9 @@ void QmlCppEngine::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 reloadFullStack();
|
||||
|
||||
void setRegisterValue(int regnr, const QString &value);
|
||||
void setRegisterValue(const QByteArray &name, const QString &value);
|
||||
bool hasCapability(unsigned cap) const;
|
||||
|
||||
bool isSynchronous() const;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,35 +31,73 @@
|
||||
#ifndef DEBUGGER_REGISTERHANDLER_H
|
||||
#define DEBUGGER_REGISTERHANDLER_H
|
||||
|
||||
#include <utils/treemodel.h>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QHash>
|
||||
#include <QVector>
|
||||
|
||||
namespace Debugger {
|
||||
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
|
||||
{
|
||||
public:
|
||||
Register() : type(0), changed(true) {}
|
||||
Register(const QByteArray &name_);
|
||||
Register() { size = 0; kind = UnknownRegister; }
|
||||
void guessMissingData();
|
||||
|
||||
QVariant editValue() const;
|
||||
QString displayValue(int base, int strlen) const;
|
||||
|
||||
public:
|
||||
QByteArray name;
|
||||
/* Value should be an integer for which autodetection by passing
|
||||
* base=0 to QString::toULongLong() should work (C-language conventions).
|
||||
* Values that cannot be converted (such as 128bit MMX-registers) are
|
||||
* passed through. */
|
||||
QByteArray value;
|
||||
int type;
|
||||
bool changed;
|
||||
QByteArray reportedType;
|
||||
RegisterValue value;
|
||||
RegisterValue previousValue;
|
||||
QByteArray description;
|
||||
int size;
|
||||
RegisterKind kind;
|
||||
};
|
||||
|
||||
typedef QVector<Register> Registers;
|
||||
class RegisterItem;
|
||||
typedef QMap<quint64, QByteArray> RegisterMap;
|
||||
|
||||
class RegisterHandler : public QAbstractTableModel
|
||||
class RegisterHandler : public Utils::TreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -68,34 +106,17 @@ public:
|
||||
|
||||
QAbstractItemModel *model() { return this; }
|
||||
|
||||
bool isEmpty() const; // nothing known so far?
|
||||
// Set up register names (gdb)
|
||||
void setRegisters(const Registers ®isters);
|
||||
// Set register values
|
||||
void setAndMarkRegisters(const Registers ®isters);
|
||||
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; }
|
||||
void updateRegister(const Register ®);
|
||||
|
||||
void setNumberBase(const QByteArray &name, int base);
|
||||
void commitUpdates() { emit layoutChanged(); }
|
||||
RegisterMap registerMap() const;
|
||||
|
||||
signals:
|
||||
void registerSet(const QModelIndex &r); // Register was set, for memory views
|
||||
void registerChanged(const QByteArray &name, quint64 value); // For memory views
|
||||
|
||||
private:
|
||||
void calculateWidth();
|
||||
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.
|
||||
QHash<QByteArray, RegisterItem *> m_registerByName;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "registerwindow.h"
|
||||
#include "memoryview.h"
|
||||
#include "memoryagent.h"
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggerdialogs.h"
|
||||
#include "debuggercore.h"
|
||||
@@ -42,22 +43,13 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
static RegisterHandler *currentHandler()
|
||||
{
|
||||
DebuggerEngine *engine = currentEngine();
|
||||
QTC_ASSERT(engine, return 0);
|
||||
return engine->registerHandler();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RegisterDelegate
|
||||
@@ -74,10 +66,9 @@ public:
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Register reg = currentHandler()->registerAt(index.row());
|
||||
IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
|
||||
const int base = currentHandler()->numberBase();
|
||||
const bool big = reg.value.size() > 16;
|
||||
const int base = index.data(RegisterNumberBaseRole).toInt();
|
||||
const bool big = index.data(RegisterIsBigRole).toBool();
|
||||
// Big integers are assumed to be hexadecimal.
|
||||
lineEdit->setBigInt(big);
|
||||
lineEdit->setBase(big ? 16 : base);
|
||||
@@ -101,11 +92,11 @@ public:
|
||||
return;
|
||||
IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor);
|
||||
QTC_ASSERT(lineEdit, return);
|
||||
const int base = currentHandler()->numberBase();
|
||||
const int base = index.data(RegisterNumberBaseRole).toInt();
|
||||
QString value = lineEdit->text();
|
||||
if (base == 16 && !value.startsWith(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,
|
||||
@@ -118,27 +109,37 @@ public:
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == 1) {
|
||||
bool paintRed = currentHandler()->registerAt(index.row()).changed;
|
||||
const bool paintRed = index.data(RegisterChangedRole).toBool();
|
||||
QPen oldPen = painter->pen();
|
||||
const QColor lightColor(140, 140, 140);
|
||||
if (paintRed)
|
||||
painter->setPen(QColor(200, 0, 0));
|
||||
else
|
||||
painter->setPen(lightColor);
|
||||
// FIXME: performance? this changes only on real font changes.
|
||||
QFontMetrics fm(option.font);
|
||||
int charWidth = fm.width(QLatin1Char('x'));
|
||||
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)));
|
||||
int charWidth = qMax(fm.width(QLatin1Char('x')), fm.width(QLatin1Char('0')));
|
||||
QString str = index.data(Qt::DisplayRole).toString();
|
||||
int x = option.rect.x();
|
||||
bool light = !paintRed;
|
||||
for (int i = 0; i < str.size(); ++i) {
|
||||
const QChar c = str.at(i);
|
||||
const int uc = c.unicode();
|
||||
if (light && (uc != 'x' && uc != '0')) {
|
||||
light = false;
|
||||
painter->setPen(oldPen.color());
|
||||
}
|
||||
if (uc == ' ') {
|
||||
light = true;
|
||||
painter->setPen(lightColor);
|
||||
} else {
|
||||
QRect r = option.rect;
|
||||
r.setX(x);
|
||||
r.setWidth(charWidth);
|
||||
x += charWidth;
|
||||
painter->drawText(r, Qt::AlignHCenter, QString(str.at(i)));
|
||||
painter->drawText(r, Qt::AlignHCenter, c);
|
||||
}
|
||||
x += charWidth;
|
||||
}
|
||||
if (paintRed)
|
||||
painter->setPen(oldPen);
|
||||
} else {
|
||||
QItemDelegate::paint(painter, option, index);
|
||||
@@ -156,6 +157,7 @@ public:
|
||||
RegisterTreeView::RegisterTreeView()
|
||||
{
|
||||
setItemDelegate(new RegisterDelegate(this));
|
||||
setRootIsDecorated(true);
|
||||
}
|
||||
|
||||
void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
@@ -164,7 +166,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
|
||||
DebuggerEngine *engine = currentEngine();
|
||||
QTC_ASSERT(engine, return);
|
||||
RegisterHandler *handler = currentHandler();
|
||||
RegisterHandler *handler = engine->registerHandler();
|
||||
|
||||
const bool actionsEnabled = engine->debuggerActionsEnabled();
|
||||
const DebuggerState state = engine->state();
|
||||
|
||||
@@ -174,13 +177,8 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
Register aRegister;
|
||||
const QModelIndex idx = indexAt(ev->pos());
|
||||
if (idx.isValid())
|
||||
aRegister = handler->registers().at(idx.row());
|
||||
const QVariant addressV = aRegister.editValue();
|
||||
const quint64 address = addressV.type() == QVariant::ULongLong
|
||||
? addressV.toULongLong() : 0;
|
||||
const quint64 address = idx.data(RegisterAsAddressRole).toULongLong();
|
||||
QAction *actViewMemory = menu.addAction(QString());
|
||||
QAction *actEditMemory = menu.addAction(QString());
|
||||
|
||||
@@ -188,12 +186,14 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
QAction *actShowDisassembler = menu.addAction(tr("Open Disassembler..."));
|
||||
actShowDisassembler->setEnabled(engine->hasCapability(DisassemblerCapability));
|
||||
|
||||
const QByteArray registerName = idx.data(RegisterNameRole).toByteArray();
|
||||
const QString registerNameStr = QString::fromUtf8(registerName);
|
||||
if (address) {
|
||||
const bool canShow = actionsEnabled && engine->hasCapability(ShowMemoryCapability);
|
||||
actEditMemory->setText(tr("Open Memory Editor at 0x%1").arg(address, 0, 16));
|
||||
actEditMemory->setEnabled(canShow);
|
||||
actViewMemory->setText(tr("Open Memory View at Value of Register %1 0x%2")
|
||||
.arg(QString::fromLatin1(aRegister.name)).arg(address, 0, 16));
|
||||
.arg(registerNameStr).arg(address, 0, 16));
|
||||
actShowDisassemblerAt->setText(tr("Open Disassembler at 0x%1")
|
||||
.arg(address, 0, 16));
|
||||
actShowDisassemblerAt->setEnabled(engine->hasCapability(DisassemblerCapability));
|
||||
@@ -207,7 +207,7 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
}
|
||||
menu.addSeparator();
|
||||
|
||||
const int base = handler->numberBase();
|
||||
const int base = idx.data(RegisterNumberBaseRole).toInt();
|
||||
QAction *act16 = menu.addAction(tr("Hexadecimal"));
|
||||
act16->setCheckable(true);
|
||||
act16->setChecked(base == 16);
|
||||
@@ -230,14 +230,20 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
if (act == actReload) {
|
||||
engine->reloadRegisters();
|
||||
} else if (act == actEditMemory) {
|
||||
const QString registerName = QString::fromLatin1(aRegister.name);
|
||||
engine->openMemoryView(address, 0,
|
||||
RegisterMemoryView::registerMarkup(address, registerName),
|
||||
QPoint(), RegisterMemoryView::title(registerName), 0);
|
||||
MemoryViewSetupData data;
|
||||
data.startAddress = address;
|
||||
data.registerName = registerName;
|
||||
data.markup = RegisterMemoryView::registerMarkup(address, registerName);
|
||||
data.title = RegisterMemoryView::title(registerName);
|
||||
engine->openMemoryView(data);
|
||||
} else if (act == actViewMemory) {
|
||||
engine->openMemoryView(idx.row(),
|
||||
DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
|
||||
QList<MemoryMarkup>(), position, QString(), this);
|
||||
MemoryViewSetupData data;
|
||||
data.startAddress = address;
|
||||
data.flags = DebuggerEngine::MemoryTrackRegister|DebuggerEngine::MemoryView,
|
||||
data.registerName = registerName;
|
||||
data.pos = position;
|
||||
data.parent = this;
|
||||
engine->openMemoryView(data);
|
||||
} else if (act == actShowDisassembler) {
|
||||
AddressDialog dialog;
|
||||
if (address)
|
||||
@@ -247,13 +253,13 @@ void RegisterTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
} else if (act == actShowDisassemblerAt) {
|
||||
engine->openDisassemblerView(Location(address));
|
||||
} else if (act == act16)
|
||||
handler->setNumberBase(16);
|
||||
handler->setNumberBase(registerName, 16);
|
||||
else if (act == act10)
|
||||
handler->setNumberBase(10);
|
||||
handler->setNumberBase(registerName, 10);
|
||||
else if (act == act8)
|
||||
handler->setNumberBase(8);
|
||||
handler->setNumberBase(registerName, 8);
|
||||
else if (act == act2)
|
||||
handler->setNumberBase(2);
|
||||
handler->setNumberBase(registerName, 2);
|
||||
}
|
||||
|
||||
void RegisterTreeView::reloadRegisters()
|
||||
|
||||
@@ -214,12 +214,13 @@ void StackTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
if (act == actCopyContents) {
|
||||
copyContentsToClipboard();
|
||||
} 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);
|
||||
QList<MemoryMarkup> ml;
|
||||
ml.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(),
|
||||
data.markup.push_back(MemoryMarkup(address, 1, QColor(Qt::blue).lighter(),
|
||||
tr("Frame #%1 (%2)").arg(row).arg(frame.function)));
|
||||
engine->openMemoryView(address, 0, ml, QPoint(), title);
|
||||
engine->openMemoryView(data);
|
||||
} else if (act == actShowDisassemblerAtAddress) {
|
||||
AddressDialog dialog;
|
||||
if (address)
|
||||
|
||||
@@ -178,21 +178,6 @@ static inline uint sizeOf(const QModelIndex &m)
|
||||
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
|
||||
// a vector representing the memory area by a unique color
|
||||
// number and tooltip. Parts of it will be overwritten when recursing
|
||||
@@ -314,13 +299,12 @@ static MemoryMarkupList
|
||||
if (sizeIsEstimate && !childCount)
|
||||
return result; // Fixme: Exact size not known, no point in filling if no children.
|
||||
// Punch in registers as 1-byte markers on top.
|
||||
const RegisterMapConstIt regcEnd = registerMap.constEnd();
|
||||
for (RegisterMapConstIt it = registerMap.constBegin(); it != regcEnd; ++it) {
|
||||
for (auto it = registerMap.constBegin(), end = registerMap.constEnd(); it != end; ++it) {
|
||||
if (it.key() >= address) {
|
||||
const quint64 offset = it.key() - address;
|
||||
if (offset < size) {
|
||||
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 {
|
||||
break; // Sorted.
|
||||
}
|
||||
@@ -381,27 +365,27 @@ static void addVariableMemoryView(DebuggerEngine *engine, bool separateView,
|
||||
const QPoint &p, QWidget *parent)
|
||||
{
|
||||
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())?
|
||||
const QString rootToolTip = variableToolTip(nameOf(m), typeOf(m), 0);
|
||||
const quint64 typeSize = sizeOf(m);
|
||||
const bool sizeIsEstimate = atPointerAddress || !typeSize;
|
||||
const quint64 size = sizeIsEstimate ? 1024 : typeSize;
|
||||
if (!address)
|
||||
return;
|
||||
const QList<MemoryMarkup> markup =
|
||||
variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip,
|
||||
address, size,
|
||||
registerMap(engine),
|
||||
data.markup = variableMemoryMarkup(m.model(), m, nameOf(m), rootToolTip,
|
||||
data.startAddress, size,
|
||||
engine->registerHandler()->registerMap(),
|
||||
sizeIsEstimate, background);
|
||||
const unsigned flags = separateView
|
||||
? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0;
|
||||
const QString title = atPointerAddress
|
||||
data.flags = separateView ? DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly : 0;
|
||||
QString pat = atPointerAddress
|
||||
? 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)")
|
||||
.arg(nameOf(m)).arg(address, 0, 16);
|
||||
engine->openMemoryView(address, flags, markup, p, title, parent);
|
||||
: WatchTreeView::tr("Memory at Object's Address \"%1\" (0x%2)");
|
||||
data.title = pat.arg(nameOf(m)).arg(data.startAddress, 0, 16);
|
||||
data.pos = p;
|
||||
data.parent = parent;
|
||||
engine->openMemoryView(data);
|
||||
}
|
||||
|
||||
// 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
|
||||
// to show stack/stack frame pointers.
|
||||
const RegisterMap regMap = registerMap(engine);
|
||||
const RegisterMapConstIt regcEnd = regMap.constEnd();
|
||||
for (RegisterMapConstIt it = regMap.constBegin(); it != regcEnd; ++it) {
|
||||
const RegisterMap regMap = engine->registerHandler()->registerMap();
|
||||
for (auto it = regMap.constBegin(), cend = regMap.constEnd(); it != cend; ++it) {
|
||||
const quint64 value = it.key();
|
||||
if (value < start && start - value < 512)
|
||||
start = value;
|
||||
@@ -454,16 +437,18 @@ static void addStackLayoutMemoryView(DebuggerEngine *engine, bool separateView,
|
||||
end = value + 1;
|
||||
}
|
||||
// Indicate all variables.
|
||||
MemoryViewSetupData data;
|
||||
const QColor background = parent->palette().color(QPalette::Normal, QPalette::Base);
|
||||
const MemoryMarkupList markup =
|
||||
variableMemoryMarkup(m, localsIndex, QString(),
|
||||
data.startAddress = start;
|
||||
data.markup = variableMemoryMarkup(m, localsIndex, QString(),
|
||||
QString(), start, end - start,
|
||||
regMap, true, background);
|
||||
const unsigned flags = separateView
|
||||
data.flags = separateView
|
||||
? (DebuggerEngine::MemoryView|DebuggerEngine::MemoryReadOnly) : 0;
|
||||
const QString title =
|
||||
WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16);
|
||||
engine->openMemoryView(start, flags, markup, p, title, parent);
|
||||
data.title = WatchTreeView::tr("Memory Layout of Local Variables at 0x%1").arg(start, 0, 16);
|
||||
data.pos = p;
|
||||
data.parent = parent;
|
||||
engine->openMemoryView(data);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@@ -936,8 +921,11 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||
AddressDialog dialog;
|
||||
if (address)
|
||||
dialog.setAddress(address);
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
currentEngine()->openMemoryView(dialog.address(), false, MemoryMarkupList(), QPoint());
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
MemoryViewSetupData data;
|
||||
data.startAddress = dialog.address();
|
||||
currentEngine()->openMemoryView(data);
|
||||
}
|
||||
} else if (act == &actOpenMemoryViewAtObjectAddress) {
|
||||
addVariableMemoryView(currentEngine(), true, mi0, false, ev->globalPos(), this);
|
||||
} else if (act == &actOpenMemoryViewAtPointerAddress) {
|
||||
|
||||
Reference in New Issue
Block a user