mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-24 12:22:34 -06:00
MemoryWidget: Add symbols and Notes.
Add option to hide them. Add box to search. Add ability to edit data symbols and notes in MemoryViewWidget.
This commit is contained in:
@ -29,8 +29,10 @@
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/AddressSpace.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinQt/Debugger/EditSymbolDialog.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/Resources.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
@ -196,7 +198,7 @@ private:
|
||||
};
|
||||
|
||||
MemoryViewWidget::MemoryViewWidget(Core::System& system, QWidget* parent)
|
||||
: QWidget(parent), m_system(system)
|
||||
: QWidget(parent), m_system(system), m_ppc_symbol_db(m_system.GetPPCSymbolDB())
|
||||
{
|
||||
auto* layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
@ -220,6 +222,8 @@ MemoryViewWidget::MemoryViewWidget(Core::System& system, QWidget* parent)
|
||||
this->setLayout(layout);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont);
|
||||
connect(Host::GetInstance(), &Host::PPCSymbolsChanged, this,
|
||||
[this] { UpdateDispatcher(UpdateType::Symbols); });
|
||||
connect(Host::GetInstance(), &Host::PPCBreakpointsChanged, this,
|
||||
&MemoryViewWidget::UpdateBreakpointTags);
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
|
||||
@ -347,6 +351,9 @@ void MemoryViewWidget::UpdateDispatcher(UpdateType type)
|
||||
if (Core::GetState(m_system) == Core::State::Paused)
|
||||
GetValues();
|
||||
UpdateColumns();
|
||||
[[fallthrough]];
|
||||
case UpdateType::Symbols:
|
||||
UpdateSymbols();
|
||||
break;
|
||||
case UpdateType::Auto:
|
||||
// Values were captured on CPU thread while doing a callback.
|
||||
@ -371,7 +378,7 @@ void MemoryViewWidget::CreateTable()
|
||||
// Span is the number of unique memory values covered in one row.
|
||||
const int data_span = m_bytes_per_row / GetTypeSize(m_type);
|
||||
m_data_columns = m_dual_view ? data_span * 2 : data_span;
|
||||
const int total_columns = MISC_COLUMNS + m_data_columns;
|
||||
const int total_columns = MISC_COLUMNS + m_data_columns + (m_show_symbols ? 1 : 0);
|
||||
|
||||
const int rows =
|
||||
std::round((m_table->height() / static_cast<float>(m_table->rowHeight(0))) - 0.25);
|
||||
@ -440,6 +447,15 @@ void MemoryViewWidget::CreateTable()
|
||||
|
||||
m_table->setItem(i, c + MISC_COLUMNS, item.clone());
|
||||
}
|
||||
|
||||
if (!m_show_symbols)
|
||||
continue;
|
||||
|
||||
// Symbols
|
||||
auto* description_item = new QTableWidgetItem(QStringLiteral("-"));
|
||||
description_item->setFlags(Qt::ItemIsEnabled);
|
||||
|
||||
m_table->setItem(i, m_table->columnCount() - 1, description_item);
|
||||
}
|
||||
|
||||
// Update column width
|
||||
@ -500,6 +516,9 @@ void MemoryViewWidget::Update()
|
||||
item->setBackground(Qt::transparent);
|
||||
item->setData(USER_ROLE_VALID_ADDRESS, false);
|
||||
}
|
||||
|
||||
if (m_show_symbols)
|
||||
m_table->item(i, m_table->columnCount() - 1)->setData(USER_ROLE_CELL_ADDRESS, row_address);
|
||||
}
|
||||
|
||||
UpdateBreakpointTags();
|
||||
@ -576,6 +595,34 @@ void MemoryViewWidget::UpdateColumns()
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryViewWidget::UpdateSymbols()
|
||||
{
|
||||
if (!m_show_symbols)
|
||||
return;
|
||||
|
||||
// Update symbols
|
||||
for (int i = 0; i < m_table->rowCount(); i++)
|
||||
{
|
||||
auto* item = m_table->item(i, m_table->columnCount() - 1);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
const u32 address = item->data(USER_ROLE_CELL_ADDRESS).toUInt();
|
||||
const Common::Note* note = m_ppc_symbol_db.GetNoteFromAddr(address);
|
||||
|
||||
std::string desc;
|
||||
if (note == nullptr)
|
||||
desc = m_ppc_symbol_db.GetDescription(address);
|
||||
else
|
||||
desc = note->name;
|
||||
|
||||
item->setText(QString::fromStdString(" " + desc));
|
||||
}
|
||||
|
||||
if (m_show_symbols)
|
||||
m_table->resizeColumnToContents(m_table->columnCount() - 1);
|
||||
}
|
||||
|
||||
// Always runs on CPU thread from a callback.
|
||||
void MemoryViewWidget::UpdateOnFrameEnd()
|
||||
{
|
||||
@ -1059,6 +1106,78 @@ void MemoryViewWidget::OnCopyHex(u32 addr)
|
||||
QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2));
|
||||
}
|
||||
|
||||
void MemoryViewWidget::ShowSymbols(bool enable)
|
||||
{
|
||||
m_show_symbols = enable;
|
||||
UpdateDispatcher(UpdateType::Full);
|
||||
}
|
||||
|
||||
void MemoryViewWidget::OnEditSymbol(EditSymbolType type, u32 addr)
|
||||
{
|
||||
// Add Note and Add Region use these values.
|
||||
std::string name = "";
|
||||
std::string object_name = "";
|
||||
u32 size = GetTypeSize(m_type);
|
||||
u32 address = addr;
|
||||
EditSymbolDialog::Type dialog_type = EditSymbolDialog::Type::Note;
|
||||
|
||||
// Add and edit region are tied to the same context menu action.
|
||||
if (type == EditSymbolType::EditRegion)
|
||||
{
|
||||
// If symbol doesn't exist, it's safe to add a new region.
|
||||
const Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
dialog_type = EditSymbolDialog::Type::Symbol;
|
||||
|
||||
if (symbol != nullptr)
|
||||
{
|
||||
// Leave the more specialized function editing to code widget.
|
||||
if (symbol->type != Common::Symbol::Type::Data)
|
||||
return;
|
||||
|
||||
// Edit data region.
|
||||
name = symbol->name;
|
||||
object_name = symbol->object_name;
|
||||
size = symbol->size;
|
||||
address = symbol->address;
|
||||
}
|
||||
}
|
||||
else if (type == EditSymbolType::EditNote)
|
||||
{
|
||||
const Common::Note* note = m_ppc_symbol_db.GetNoteFromAddr(addr);
|
||||
if (note == nullptr)
|
||||
return;
|
||||
|
||||
name = note->name;
|
||||
size = note->size;
|
||||
address = note->address;
|
||||
}
|
||||
|
||||
EditSymbolDialog dialog(this, address, &size, &name, dialog_type);
|
||||
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
if (dialog.DeleteRequested())
|
||||
{
|
||||
if (type == EditSymbolType::EditRegion)
|
||||
m_ppc_symbol_db.DeleteFunction(address);
|
||||
else
|
||||
m_ppc_symbol_db.DeleteNote(address);
|
||||
}
|
||||
else if (type == EditSymbolType::EditRegion)
|
||||
{
|
||||
m_ppc_symbol_db.AddKnownSymbol(Core::CPUThreadGuard{m_system}, address, size, name, object_name,
|
||||
Common::Symbol::Type::Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ppc_symbol_db.AddKnownNote(address, size, name);
|
||||
m_ppc_symbol_db.DetermineNoteLayers();
|
||||
}
|
||||
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MemoryViewWidget::OnContextMenu(const QPoint& pos)
|
||||
{
|
||||
auto* item_selected = m_table->itemAt(pos);
|
||||
@ -1089,6 +1208,21 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos)
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
auto* note_add_action = menu->addAction(
|
||||
tr("Add Note"), this, [this, addr] { OnEditSymbol(EditSymbolType::AddNote, addr); });
|
||||
auto* note_edit_action = menu->addAction(
|
||||
tr("Edit Note"), this, [this, addr] { OnEditSymbol(EditSymbolType::EditNote, addr); });
|
||||
menu->addAction(tr("Add or edit region label"), this,
|
||||
[this, addr] { OnEditSymbol(EditSymbolType::EditRegion, addr); });
|
||||
|
||||
auto* note = m_ppc_symbol_db.GetNoteFromAddr(addr);
|
||||
note_edit_action->setEnabled(note != nullptr);
|
||||
// A note cannot be added ontop of the starting address of another note.
|
||||
if (note != nullptr && note->address == addr)
|
||||
note_add_action->setEnabled(false);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
menu->addAction(tr("Show in code"), this, [this, addr] { emit ShowCode(addr); });
|
||||
|
||||
menu->addSeparator();
|
||||
|
Reference in New Issue
Block a user