Qt: Add access log view to memory view
This commit is contained in:
parent
75dc290853
commit
159b0dc445
@ -262,6 +262,7 @@ if(ENABLE_DEBUGGERS)
|
|||||||
DebuggerConsole.cpp
|
DebuggerConsole.cpp
|
||||||
DebuggerConsoleController.cpp
|
DebuggerConsoleController.cpp
|
||||||
MemoryAccessLogController.cpp
|
MemoryAccessLogController.cpp
|
||||||
|
MemoryAccessLogModel.cpp
|
||||||
MemoryAccessLogView.cpp)
|
MemoryAccessLogView.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -10,8 +10,14 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "VFileDevice.h"
|
#include "VFileDevice.h"
|
||||||
|
|
||||||
|
#include <mgba-util/math.h>
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
int MemoryAccessLogController::Flags::count() const {
|
||||||
|
return popcount32(flags) + popcount32(flagsEx);
|
||||||
|
}
|
||||||
|
|
||||||
MemoryAccessLogController::MemoryAccessLogController(CoreController* controller, QObject* parent)
|
MemoryAccessLogController::MemoryAccessLogController(CoreController* controller, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_controller(controller)
|
, m_controller(controller)
|
||||||
@ -39,6 +45,17 @@ bool MemoryAccessLogController::canExport() const {
|
|||||||
return m_regionMapping.contains("cart0");
|
return m_regionMapping.contains("cart0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryAccessLogController::Flags MemoryAccessLogController::flagsForAddress(uint32_t addresss, int segment) {
|
||||||
|
uint32_t offset = cacheRegion(addresss, segment);
|
||||||
|
if (!m_cachedRegion) {
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
m_cachedRegion->blockEx ? m_cachedRegion->blockEx[offset] : mDebuggerAccessLogFlagsEx{},
|
||||||
|
m_cachedRegion->block ? m_cachedRegion->block[offset] : mDebuggerAccessLogFlags{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryAccessLogController::updateRegion(const QString& internalName, bool checked) {
|
void MemoryAccessLogController::updateRegion(const QString& internalName, bool checked) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
m_watchedRegions += internalName;
|
m_watchedRegions += internalName;
|
||||||
@ -116,3 +133,27 @@ void MemoryAccessLogController::exportFile(const QString& filename) {
|
|||||||
mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0);
|
mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0);
|
||||||
vf->close(vf);
|
vf->close(vf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t MemoryAccessLogController::cacheRegion(uint32_t address, int segment) {
|
||||||
|
if (m_cachedRegion && (address < m_cachedRegion->start || address >= m_cachedRegion->end)) {
|
||||||
|
m_cachedRegion = nullptr;
|
||||||
|
}
|
||||||
|
if (!m_cachedRegion) {
|
||||||
|
m_cachedRegion = mDebuggerAccessLoggerGetRegion(&m_logger, address, segment, nullptr);
|
||||||
|
}
|
||||||
|
if (!m_cachedRegion) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = address - m_cachedRegion->start;
|
||||||
|
if (segment > 0) {
|
||||||
|
uint32_t segmentSize = m_cachedRegion->end - m_cachedRegion->segmentStart;
|
||||||
|
offset %= segmentSize;
|
||||||
|
offset += segmentSize * segment;
|
||||||
|
}
|
||||||
|
if (offset >= m_cachedRegion->size) {
|
||||||
|
m_cachedRegion = nullptr;
|
||||||
|
return cacheRegion(address, segment);
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
|
|
||||||
|
#include <mgba/debugger/debugger.h>
|
||||||
#include <mgba/internal/debugger/access-logger.h>
|
#include <mgba/internal/debugger/access-logger.h>
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
@ -25,6 +26,16 @@ public:
|
|||||||
QString internalName;
|
QString internalName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Flags {
|
||||||
|
mDebuggerAccessLogFlagsEx flagsEx;
|
||||||
|
mDebuggerAccessLogFlags flags;
|
||||||
|
|
||||||
|
int count() const;
|
||||||
|
bool operator==(const Flags& other) const { return flags == other.flags && flagsEx == other.flagsEx; }
|
||||||
|
bool operator!=(const Flags& other) const { return flags != other.flags || flagsEx != other.flagsEx; }
|
||||||
|
operator bool() const { return flags || flagsEx; }
|
||||||
|
};
|
||||||
|
|
||||||
MemoryAccessLogController(CoreController* controller, QObject* parent = nullptr);
|
MemoryAccessLogController(CoreController* controller, QObject* parent = nullptr);
|
||||||
~MemoryAccessLogController();
|
~MemoryAccessLogController();
|
||||||
|
|
||||||
@ -34,6 +45,8 @@ public:
|
|||||||
bool canExport() const;
|
bool canExport() const;
|
||||||
mPlatform platform() const { return m_controller->platform(); }
|
mPlatform platform() const { return m_controller->platform(); }
|
||||||
|
|
||||||
|
Flags flagsForAddress(uint32_t address, int segment = -1);
|
||||||
|
|
||||||
QString file() const { return m_path; }
|
QString file() const { return m_path; }
|
||||||
bool active() const { return m_active; }
|
bool active() const { return m_active; }
|
||||||
|
|
||||||
@ -59,8 +72,10 @@ private:
|
|||||||
QVector<Region> m_regions;
|
QVector<Region> m_regions;
|
||||||
struct mDebuggerAccessLogger m_logger{};
|
struct mDebuggerAccessLogger m_logger{};
|
||||||
bool m_active = false;
|
bool m_active = false;
|
||||||
|
mDebuggerAccessLogRegion* m_cachedRegion = nullptr;
|
||||||
|
|
||||||
mDebuggerAccessLogRegionFlags activeFlags() const;
|
mDebuggerAccessLogRegionFlags activeFlags() const;
|
||||||
|
uint32_t cacheRegion(uint32_t address, int segment);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
283
src/platform/qt/MemoryAccessLogModel.cpp
Normal file
283
src/platform/qt/MemoryAccessLogModel.cpp
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/* Copyright (c) 2013-2025 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "MemoryAccessLogModel.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
using namespace QGBA;
|
||||||
|
|
||||||
|
MemoryAccessLogModel::MemoryAccessLogModel(std::weak_ptr<MemoryAccessLogController> controller, mPlatform platform)
|
||||||
|
: m_controller(controller)
|
||||||
|
, m_platform(platform)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MemoryAccessLogModel::data(const QModelIndex& index, int role) const {
|
||||||
|
if (role != Qt::DisplayRole) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (index.column() != 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
int blockIndex = -1;
|
||||||
|
int flagIndex = -1;
|
||||||
|
QModelIndex parent = index.parent();
|
||||||
|
if (!parent.isValid()) {
|
||||||
|
blockIndex = index.row();
|
||||||
|
} else {
|
||||||
|
blockIndex = parent.row();
|
||||||
|
flagIndex = index.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockIndex < 0 || blockIndex >= m_cachedBlocks.count()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Block& block = m_cachedBlocks[blockIndex];
|
||||||
|
|
||||||
|
if (flagIndex < 0) {
|
||||||
|
return QString("0x%1 – 0x%2")
|
||||||
|
.arg(QString("%0").arg(block.region.first, 8, 16, QChar('0')).toUpper())
|
||||||
|
.arg(QString("%0").arg(block.region.second, 8, 16, QChar('0')).toUpper());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
if (!(block.flags.flags & (1 << i))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flagIndex == 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
return tr("Data read");
|
||||||
|
case 1:
|
||||||
|
return tr("Data written");
|
||||||
|
case 2:
|
||||||
|
return tr("Code executed");
|
||||||
|
case 3:
|
||||||
|
return tr("Code aborted");
|
||||||
|
case 4:
|
||||||
|
return tr("8-bit access");
|
||||||
|
case 5:
|
||||||
|
return tr("16-bit access");
|
||||||
|
case 6:
|
||||||
|
return tr("32-bit access");
|
||||||
|
case 7:
|
||||||
|
return tr("64-bit access");
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--flagIndex;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
if (!(block.flags.flagsEx & (1 << i))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flagIndex == 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
return tr("Accessed by instruction");
|
||||||
|
case 1:
|
||||||
|
return tr("Accessed by DMA");
|
||||||
|
case 2:
|
||||||
|
return tr("Accessed by BIOS");
|
||||||
|
case 3:
|
||||||
|
return tr("Compressed data");
|
||||||
|
case 4:
|
||||||
|
return tr("Accessed by memory copy");
|
||||||
|
case 5:
|
||||||
|
return tr("(Unknown extra bit 5)");
|
||||||
|
case 6:
|
||||||
|
return tr("(Unknown extra bit 6)");
|
||||||
|
case 7:
|
||||||
|
return tr("(Unknown extra bit 7)");
|
||||||
|
case 8:
|
||||||
|
return tr("Invalid instruction");
|
||||||
|
case 9:
|
||||||
|
return tr("Invalid read");
|
||||||
|
case 10:
|
||||||
|
return tr("Invalid write");
|
||||||
|
case 11:
|
||||||
|
return tr("Invalid executable address");
|
||||||
|
case 12:
|
||||||
|
return tr("(Private bit 0)");
|
||||||
|
case 13:
|
||||||
|
return tr("(Private bit 1)");
|
||||||
|
case 14:
|
||||||
|
switch (m_platform) {
|
||||||
|
case mPLATFORM_GBA:
|
||||||
|
return tr("ARM code");
|
||||||
|
default:
|
||||||
|
return tr("(Private bit 2)");
|
||||||
|
}
|
||||||
|
case 15:
|
||||||
|
switch (m_platform) {
|
||||||
|
case mPLATFORM_GBA:
|
||||||
|
return tr("Thumb code");
|
||||||
|
default:
|
||||||
|
return tr("(Private bit 2)");
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--flagIndex;
|
||||||
|
}
|
||||||
|
return tr("(Unknown)");
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex MemoryAccessLogModel::index(int row, int column, const QModelIndex& parent) const {
|
||||||
|
if (column != 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (parent.isValid()) {
|
||||||
|
return createIndex(row, 0, parent.row());
|
||||||
|
}
|
||||||
|
return createIndex(row, 0, std::numeric_limits<quintptr>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex MemoryAccessLogModel::parent(const QModelIndex& index) const {
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
quintptr row = index.internalId();
|
||||||
|
if (row >= std::numeric_limits<uint32_t>::max()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return createIndex(row, 0, std::numeric_limits<quintptr>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
int MemoryAccessLogModel::rowCount(const QModelIndex& parent) const {
|
||||||
|
int blockIndex = -1;
|
||||||
|
if (!parent.isValid()) {
|
||||||
|
return m_cachedBlocks.count();
|
||||||
|
} else if (parent.column() != 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (parent.parent().isValid()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
blockIndex = parent.row();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockIndex < 0 || blockIndex >= m_cachedBlocks.count()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Block& block = m_cachedBlocks[blockIndex];
|
||||||
|
return block.flags.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryAccessLogModel::updateSelection(uint32_t start, uint32_t end) {
|
||||||
|
std::shared_ptr<MemoryAccessLogController> controller = m_controller.lock();
|
||||||
|
if (!controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVector<Block> newBlocks;
|
||||||
|
uint32_t lastStart = start;
|
||||||
|
auto lastFlags = controller->flagsForAddress(m_base + start, m_segment);
|
||||||
|
|
||||||
|
for (uint32_t address = start; address < end; ++address) {
|
||||||
|
auto flags = controller->flagsForAddress(m_base + address, m_segment);
|
||||||
|
if (flags == lastFlags) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lastFlags) {
|
||||||
|
newBlocks.append({ lastFlags, qMakePair(lastStart, address) });
|
||||||
|
}
|
||||||
|
lastFlags = flags;
|
||||||
|
lastStart = address;
|
||||||
|
}
|
||||||
|
if (lastFlags) {
|
||||||
|
newBlocks.append({ lastFlags, qMakePair(lastStart, end) });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cachedBlocks.count() == 0 || newBlocks.count() == 0) {
|
||||||
|
beginResetModel();
|
||||||
|
m_cachedBlocks = newBlocks;
|
||||||
|
endResetModel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<int, int> changed{ -1, -1 };
|
||||||
|
for (int i = 0; i < m_cachedBlocks.count() && i < newBlocks.count(); ++i) {
|
||||||
|
const Block& oldBlock = m_cachedBlocks.at(i);
|
||||||
|
const Block& newBlock = newBlocks.at(i);
|
||||||
|
|
||||||
|
if (oldBlock != newBlock) {
|
||||||
|
changed = qMakePair(i, m_cachedBlocks.count());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cachedBlocks.count() > newBlocks.count()) {
|
||||||
|
beginRemoveRows({}, newBlocks.count(), m_cachedBlocks.count());
|
||||||
|
m_cachedBlocks.resize(newBlocks.count());
|
||||||
|
endRemoveRows();
|
||||||
|
changed.second = newBlocks.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cachedBlocks.count() < newBlocks.count()) {
|
||||||
|
beginInsertRows({}, m_cachedBlocks.count(), newBlocks.count());
|
||||||
|
if (changed.first < 0) {
|
||||||
|
// Only new rows
|
||||||
|
m_cachedBlocks = newBlocks;
|
||||||
|
endInsertRows();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed.first < 0) {
|
||||||
|
// No changed rows, though some might have been removed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_cachedBlocks.count() && i < newBlocks.count(); ++i) {
|
||||||
|
const Block& oldBlock = m_cachedBlocks.at(i);
|
||||||
|
const Block& newBlock = newBlocks.at(i);
|
||||||
|
if (oldBlock.flags != newBlock.flags) {
|
||||||
|
int oldFlags = oldBlock.flags.count();
|
||||||
|
int newFlags = newBlock.flags.count();
|
||||||
|
if (oldFlags > newFlags) {
|
||||||
|
beginRemoveRows(createIndex(i, 0, std::numeric_limits<quintptr>::max()), newFlags, oldFlags);
|
||||||
|
} else if (oldFlags < newFlags) {
|
||||||
|
beginInsertRows(createIndex(i, 0, std::numeric_limits<quintptr>::max()), oldFlags, newFlags);
|
||||||
|
}
|
||||||
|
m_cachedBlocks[i] = newBlock;
|
||||||
|
emit dataChanged(createIndex(0, 0, i), createIndex(std::min(oldFlags, newFlags), 0, i));
|
||||||
|
if (oldFlags > newFlags) {
|
||||||
|
endRemoveRows();
|
||||||
|
} else if (oldFlags < newFlags) {
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit dataChanged(createIndex(changed.first, 0, std::numeric_limits<quintptr>::max()),
|
||||||
|
createIndex(changed.second, 0, std::numeric_limits<quintptr>::max()));
|
||||||
|
|
||||||
|
if (m_cachedBlocks.count() < newBlocks.count()) {
|
||||||
|
m_cachedBlocks = newBlocks;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryAccessLogModel::setSegment(int segment) {
|
||||||
|
if (m_segment == segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beginResetModel();
|
||||||
|
m_segment = segment;
|
||||||
|
m_cachedBlocks.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryAccessLogModel::setRegion(uint32_t base, uint32_t, bool useSegments) {
|
||||||
|
if (m_base == base) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beginResetModel();
|
||||||
|
m_segment = useSegments ? 0 : -1;
|
||||||
|
m_cachedBlocks.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
55
src/platform/qt/MemoryAccessLogModel.h
Normal file
55
src/platform/qt/MemoryAccessLogModel.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Copyright (c) 2013-2025 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "MemoryAccessLogController.h"
|
||||||
|
|
||||||
|
struct mCheatDevice;
|
||||||
|
struct mCheatSet;
|
||||||
|
|
||||||
|
namespace QGBA {
|
||||||
|
|
||||||
|
class MemoryAccessLogModel : public QAbstractItemModel {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MemoryAccessLogModel(std::weak_ptr<MemoryAccessLogController> controller, mPlatform platform);
|
||||||
|
|
||||||
|
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
||||||
|
virtual QModelIndex parent(const QModelIndex& index) const override;
|
||||||
|
|
||||||
|
virtual int columnCount(const QModelIndex& = QModelIndex()) const override { return 1; }
|
||||||
|
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateSelection(uint32_t start, uint32_t end);
|
||||||
|
void setSegment(int segment);
|
||||||
|
void setRegion(uint32_t base, uint32_t segmentSize, bool useSegments);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Block {
|
||||||
|
MemoryAccessLogController::Flags flags;
|
||||||
|
QPair<uint32_t, uint32_t> region;
|
||||||
|
|
||||||
|
bool operator==(const Block& other) const { return flags == other.flags && region == other.region; }
|
||||||
|
bool operator!=(const Block& other) const { return flags != other.flags || region != other.region; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int flagCount(int index) const;
|
||||||
|
|
||||||
|
std::weak_ptr<MemoryAccessLogController> m_controller;
|
||||||
|
mPlatform m_platform;
|
||||||
|
uint32_t m_base = 0;
|
||||||
|
int m_segment = -1;
|
||||||
|
QVector<Block> m_cachedBlocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
#include "MemoryView.h"
|
#include "MemoryView.h"
|
||||||
|
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
|
#include "MemoryAccessLogView.h"
|
||||||
#include "MemoryDump.h"
|
#include "MemoryDump.h"
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
@ -107,6 +108,9 @@ QValidator::State IntValidator::validate(QString& input, int&) const {
|
|||||||
MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* parent)
|
MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_controller(controller)
|
, m_controller(controller)
|
||||||
|
#ifdef ENABLE_DEBUGGERS
|
||||||
|
, m_malModel(controller->memoryAccessLogController(), controller->platform())
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
@ -189,6 +193,22 @@ MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* pare
|
|||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef ENABLE_DEBUGGERS
|
||||||
|
connect(m_ui.hexfield, &MemoryModel::selectionChanged, &m_malModel, &MemoryAccessLogModel::updateSelection);
|
||||||
|
connect(m_ui.segments, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||||
|
&m_malModel, &MemoryAccessLogModel::setSegment);
|
||||||
|
connect(m_ui.accessLoggerButton, &QAbstractButton::clicked, this, [this]() {
|
||||||
|
std::weak_ptr<MemoryAccessLogController> controller = m_controller->memoryAccessLogController();
|
||||||
|
MemoryAccessLogView* view = new MemoryAccessLogView(controller);
|
||||||
|
connect(m_controller.get(), &CoreController::stopping, view, &QWidget::close);
|
||||||
|
view->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
view->show();
|
||||||
|
});
|
||||||
|
m_ui.accessLog->setModel(&m_malModel);
|
||||||
|
#else
|
||||||
|
m_ui.accessLog->hide();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryView::setIndex(int index) {
|
void MemoryView::setIndex(int index) {
|
||||||
@ -206,6 +226,10 @@ void MemoryView::setIndex(int index) {
|
|||||||
m_ui.segmentColon->setVisible(info.maxSegment > 0);
|
m_ui.segmentColon->setVisible(info.maxSegment > 0);
|
||||||
m_ui.segments->setMaximum(info.maxSegment);
|
m_ui.segments->setMaximum(info.maxSegment);
|
||||||
m_ui.hexfield->setRegion(info.start, info.end - info.start, info.shortName);
|
m_ui.hexfield->setRegion(info.start, info.end - info.start, info.shortName);
|
||||||
|
|
||||||
|
#ifdef ENABLE_DEBUGGERS
|
||||||
|
m_malModel.setRegion(info.start, info.segmentStart - info.start, info.maxSegment > 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryView::setSegment(int segment) {
|
void MemoryView::setSegment(int segment) {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
|
|
||||||
#include "MemoryModel.h"
|
#include "MemoryModel.h"
|
||||||
|
#include "MemoryAccessLogModel.h"
|
||||||
|
|
||||||
#include "ui_MemoryView.h"
|
#include "ui_MemoryView.h"
|
||||||
|
|
||||||
@ -54,6 +55,10 @@ private:
|
|||||||
std::shared_ptr<CoreController> m_controller;
|
std::shared_ptr<CoreController> m_controller;
|
||||||
QPair<uint32_t, uint32_t> m_region;
|
QPair<uint32_t, uint32_t> m_region;
|
||||||
QPair<uint32_t, uint32_t> m_selection;
|
QPair<uint32_t, uint32_t> m_selection;
|
||||||
|
|
||||||
|
#ifdef ENABLE_DEBUGGERS
|
||||||
|
MemoryAccessLogModel m_malModel;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,14 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="sidebarLayout" stretch="0,0,0,1,0,1">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="regions"/>
|
<widget class="QComboBox" name="regions"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="addressLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="address">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Address:</string>
|
<string>Address:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -105,9 +105,9 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="alignmentLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="alignmentLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Alignment:</string>
|
<string>Alignment:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -141,7 +141,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="data">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
|
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@ -151,9 +151,9 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_9">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="sintLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Signed:</string>
|
<string>Signed:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -173,7 +173,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="uintLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Unsigned:</string>
|
<string>Unsigned:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -193,7 +193,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_7">
|
<widget class="QLabel" name="stringLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>String:</string>
|
<string>String:</string>
|
||||||
</property>
|
</property>
|
||||||
@ -232,7 +232,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="buttons">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QPushButton" name="copy">
|
<widget class="QPushButton" name="copy">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -276,6 +276,44 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="verticalGroupBox_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Selected address accesses</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="accessLog">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="textElideMode">
|
||||||
|
<enum>Qt::ElideNone</enum>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="accessLoggerButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Logging configuration</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user