Qt/Debugger: Highlight changed bytes in memory view
This commit is contained in:
parent
4cdddf8534
commit
c01e0b8dde
|
@ -95,7 +95,7 @@ void DebuggerWindow::onPauseActionToggled(bool paused)
|
||||||
{
|
{
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
m_registers_model->saveCurrentValues();
|
saveCurrentState();
|
||||||
setUIEnabled(false, true);
|
setUIEnabled(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ void DebuggerWindow::onBreakpointListContextMenuRequested()
|
||||||
void DebuggerWindow::onStepIntoActionTriggered()
|
void DebuggerWindow::onStepIntoActionTriggered()
|
||||||
{
|
{
|
||||||
Assert(System::IsPaused());
|
Assert(System::IsPaused());
|
||||||
m_registers_model->saveCurrentValues();
|
saveCurrentState();
|
||||||
g_emu_thread->singleStepCPU();
|
g_emu_thread->singleStepCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ void DebuggerWindow::onStepOverActionTriggered()
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpause to let it run to the breakpoint
|
// unpause to let it run to the breakpoint
|
||||||
m_registers_model->saveCurrentValues();
|
saveCurrentState();
|
||||||
g_emu_thread->setSystemPaused(false);
|
g_emu_thread->setSystemPaused(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ void DebuggerWindow::onStepOutActionTriggered()
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpause to let it run to the breakpoint
|
// unpause to let it run to the breakpoint
|
||||||
m_registers_model->saveCurrentValues();
|
saveCurrentState();
|
||||||
g_emu_thread->setSystemPaused(false);
|
g_emu_thread->setSystemPaused(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,6 +538,12 @@ void DebuggerWindow::setUIEnabled(bool enabled, bool allow_pause)
|
||||||
m_ui.memoryRegionBIOS->setEnabled(enabled);
|
m_ui.memoryRegionBIOS->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebuggerWindow::saveCurrentState()
|
||||||
|
{
|
||||||
|
m_registers_model->saveCurrentValues();
|
||||||
|
m_ui.memoryView->saveCurrentData();
|
||||||
|
}
|
||||||
|
|
||||||
void DebuggerWindow::setMemoryViewRegion(Bus::MemoryRegion region)
|
void DebuggerWindow::setMemoryViewRegion(Bus::MemoryRegion region)
|
||||||
{
|
{
|
||||||
if (m_active_memory_region == region)
|
if (m_active_memory_region == region)
|
||||||
|
|
|
@ -70,6 +70,7 @@ private:
|
||||||
void disconnectSignals();
|
void disconnectSignals();
|
||||||
void createModels();
|
void createModels();
|
||||||
void setUIEnabled(bool enabled, bool allow_pause);
|
void setUIEnabled(bool enabled, bool allow_pause);
|
||||||
|
void saveCurrentState();
|
||||||
void setMemoryViewRegion(Bus::MemoryRegion region);
|
void setMemoryViewRegion(Bus::MemoryRegion region);
|
||||||
void toggleBreakpoint(VirtualMemoryAddress address);
|
void toggleBreakpoint(VirtualMemoryAddress address);
|
||||||
void clearBreakpoints();
|
void clearBreakpoints();
|
||||||
|
|
|
@ -53,7 +53,10 @@ void MemoryViewWidget::setData(size_t address_offset, void* data_ptr, size_t dat
|
||||||
m_data_editable = data_editable;
|
m_data_editable = data_editable;
|
||||||
m_address_offset = address_offset;
|
m_address_offset = address_offset;
|
||||||
m_selected_address = INVALID_SELECTED_ADDRESS;
|
m_selected_address = INVALID_SELECTED_ADDRESS;
|
||||||
|
m_last_data_start_offset = 0;
|
||||||
|
m_last_data.clear();
|
||||||
adjustContent();
|
adjustContent();
|
||||||
|
saveCurrentData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryViewWidget::setHighlightRange(size_t start, size_t end)
|
void MemoryViewWidget::setHighlightRange(size_t start, size_t end)
|
||||||
|
@ -133,6 +136,7 @@ void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
|
||||||
const char ch = key_text[0].toLatin1();
|
const char ch = key_text[0].toLatin1();
|
||||||
if (m_selection_was_ascii)
|
if (m_selection_was_ascii)
|
||||||
{
|
{
|
||||||
|
expandCurrentDataToInclude(m_selected_address);
|
||||||
std::memcpy(static_cast<unsigned char*>(m_data) + m_selected_address, &ch, sizeof(unsigned char));
|
std::memcpy(static_cast<unsigned char*>(m_data) + m_selected_address, &ch, sizeof(unsigned char));
|
||||||
m_selected_address = std::min(m_selected_address + 1, m_data_size - 1);
|
m_selected_address = std::min(m_selected_address + 1, m_data_size - 1);
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
|
@ -150,6 +154,8 @@ void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
|
||||||
{
|
{
|
||||||
m_editing_nibble++;
|
m_editing_nibble++;
|
||||||
|
|
||||||
|
expandCurrentDataToInclude(m_selected_address);
|
||||||
|
|
||||||
unsigned char* pdata = static_cast<unsigned char*>(m_data) + m_selected_address;
|
unsigned char* pdata = static_cast<unsigned char*>(m_data) + m_selected_address;
|
||||||
*pdata = (*pdata & ~(0xf0 >> (m_editing_nibble * 4))) | (nibble << ((1 - m_editing_nibble) * 4));
|
*pdata = (*pdata & ~(0xf0 >> (m_editing_nibble * 4))) | (nibble << ((1 - m_editing_nibble) * 4));
|
||||||
|
|
||||||
|
@ -185,7 +191,7 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
|
||||||
const QColor highlight_color(100, 100, 0);
|
const QColor highlight_color(100, 100, 0);
|
||||||
const QColor selected_color = viewport()->palette().color(QPalette::Highlight);
|
const QColor selected_color = viewport()->palette().color(QPalette::Highlight);
|
||||||
const QColor text_color = viewport()->palette().color(QPalette::WindowText);
|
const QColor text_color = viewport()->palette().color(QPalette::WindowText);
|
||||||
const QColor edited_color(255, 0, 0);
|
const QColor edited_color(240, 30, 30);
|
||||||
const int offsetX = horizontalScrollBar()->value();
|
const int offsetX = horizontalScrollBar()->value();
|
||||||
|
|
||||||
int y = m_char_height;
|
int y = m_char_height;
|
||||||
|
@ -252,7 +258,18 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
|
||||||
|
|
||||||
if (m_selected_address != offset || m_editing_nibble != 0 || m_selection_was_ascii) [[likely]]
|
if (m_selected_address != offset || m_editing_nibble != 0 || m_selection_was_ascii) [[likely]]
|
||||||
{
|
{
|
||||||
painter.drawText(x, y, QString::asprintf("%02X", value));
|
const QString text = QString::asprintf("%02X", value);
|
||||||
|
const size_t view_offset = offset - m_last_data_start_offset; // may underflow, but unsigned so it's okay
|
||||||
|
if (view_offset < m_last_data.size() && value != m_last_data[view_offset])
|
||||||
|
{
|
||||||
|
painter.setPen(edited_color);
|
||||||
|
painter.drawText(x, y, text);
|
||||||
|
painter.setPen(text_color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter.drawText(x, y, text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -298,9 +315,18 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
|
||||||
else if (offset >= m_highlight_start && offset < m_highlight_end)
|
else if (offset >= m_highlight_start && offset < m_highlight_end)
|
||||||
painter.fillRect(x, y - m_char_height + 4, 2 * m_char_width, m_char_height, highlight_color);
|
painter.fillRect(x, y - m_char_height + 4, 2 * m_char_width, m_char_height, highlight_color);
|
||||||
|
|
||||||
if (!std::isprint(value))
|
const QChar print_char = std::isprint(value) ? static_cast<QChar>(value) : static_cast<QChar>('.');
|
||||||
value = '.';
|
const size_t view_offset = offset - m_last_data_start_offset; // may underflow, but unsigned so it's okay
|
||||||
painter.drawText(x, y, static_cast<QChar>(value));
|
if (view_offset < m_last_data.size() && value != m_last_data[view_offset])
|
||||||
|
{
|
||||||
|
painter.setPen(edited_color);
|
||||||
|
painter.drawText(x, y, print_char);
|
||||||
|
painter.setPen(text_color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter.drawText(x, y, print_char);
|
||||||
|
}
|
||||||
x += 2 * m_char_width;
|
x += 2 * m_char_width;
|
||||||
}
|
}
|
||||||
y += m_char_height;
|
y += m_char_height;
|
||||||
|
@ -354,10 +380,48 @@ void MemoryViewWidget::updateSelectedByte(const QPoint& pos)
|
||||||
{
|
{
|
||||||
m_selected_address = new_selection;
|
m_selected_address = new_selection;
|
||||||
m_selection_was_ascii = new_ascii;
|
m_selection_was_ascii = new_ascii;
|
||||||
|
m_editing_nibble = -1;
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryViewWidget::expandCurrentDataToInclude(size_t offset)
|
||||||
|
{
|
||||||
|
offset = std::min(offset, m_data_size - 1);
|
||||||
|
if (offset < m_last_data_start_offset)
|
||||||
|
{
|
||||||
|
const size_t add_bytes = m_last_data_start_offset - offset;
|
||||||
|
const size_t old_size = m_last_data.size();
|
||||||
|
m_last_data.resize(old_size + add_bytes);
|
||||||
|
std::memmove(&m_last_data[add_bytes], &m_last_data[0], old_size);
|
||||||
|
std::memcpy(&m_last_data[0], static_cast<const u8*>(m_data) + offset, add_bytes);
|
||||||
|
m_last_data_start_offset = offset;
|
||||||
|
}
|
||||||
|
else if (offset >= (m_last_data_start_offset + m_last_data.size()))
|
||||||
|
{
|
||||||
|
const size_t new_size = m_last_data_start_offset + offset + 1;
|
||||||
|
const size_t old_size = m_last_data.size();
|
||||||
|
m_last_data.resize(new_size);
|
||||||
|
std::memcpy(&m_last_data[old_size], static_cast<const u8*>(m_data) + m_last_data_start_offset + old_size,
|
||||||
|
new_size - old_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryViewWidget::saveCurrentData()
|
||||||
|
{
|
||||||
|
if (!m_data)
|
||||||
|
{
|
||||||
|
m_last_data.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t size = m_end_offset - m_start_offset;
|
||||||
|
m_last_data_start_offset = m_start_offset;
|
||||||
|
m_last_data.resize(size);
|
||||||
|
std::memcpy(m_last_data.data(), static_cast<const u8*>(m_data) + m_start_offset, size);
|
||||||
|
viewport()->update();
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryViewWidget::adjustContent()
|
void MemoryViewWidget::adjustContent()
|
||||||
{
|
{
|
||||||
if (!m_data)
|
if (!m_data)
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
#include <QtWidgets/QAbstractScrollArea>
|
#include <QtWidgets/QAbstractScrollArea>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/questions/46375673/how-can-realize-my-own-memory-viewer-by-qt
|
// Based on https://stackoverflow.com/questions/46375673/how-can-realize-my-own-memory-viewer-by-qt
|
||||||
|
|
||||||
|
@ -28,6 +32,9 @@ protected:
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
void keyPressEvent(QKeyEvent* event);
|
void keyPressEvent(QKeyEvent* event);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void saveCurrentData();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void adjustContent();
|
void adjustContent();
|
||||||
|
|
||||||
|
@ -39,6 +46,7 @@ private:
|
||||||
int asciiWidth() const;
|
int asciiWidth() const;
|
||||||
void updateMetrics();
|
void updateMetrics();
|
||||||
void updateSelectedByte(const QPoint& pos);
|
void updateSelectedByte(const QPoint& pos);
|
||||||
|
void expandCurrentDataToInclude(size_t offset);
|
||||||
|
|
||||||
void* m_data;
|
void* m_data;
|
||||||
size_t m_data_size;
|
size_t m_data_size;
|
||||||
|
@ -51,14 +59,17 @@ private:
|
||||||
size_t m_highlight_end = 0;
|
size_t m_highlight_end = 0;
|
||||||
|
|
||||||
size_t m_selected_address = INVALID_SELECTED_ADDRESS;
|
size_t m_selected_address = INVALID_SELECTED_ADDRESS;
|
||||||
int m_editing_nibble = -1;
|
s32 m_editing_nibble = -1;
|
||||||
bool m_selection_was_ascii = false;
|
bool m_selection_was_ascii = false;
|
||||||
bool m_data_editable = false;
|
bool m_data_editable = false;
|
||||||
|
|
||||||
unsigned m_bytes_per_line;
|
u32 m_bytes_per_line;
|
||||||
|
|
||||||
int m_char_width;
|
int m_char_width;
|
||||||
int m_char_height;
|
int m_char_height;
|
||||||
|
|
||||||
int m_rows_visible;
|
int m_rows_visible;
|
||||||
|
|
||||||
|
std::vector<u8> m_last_data;
|
||||||
|
size_t m_last_data_start_offset = 0;
|
||||||
};
|
};
|
Loading…
Reference in New Issue