mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
debugger: display iop module list
This commit is contained in:
parent
643c83c2a0
commit
e50fe50daf
@ -173,6 +173,10 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Debugger/DisassemblyView.h
|
||||
Debugger/DisassemblyView.ui
|
||||
Debugger/JsonValueWrapper.h
|
||||
Debugger/ModuleModel.cpp
|
||||
Debugger/ModuleModel.h
|
||||
Debugger/ModuleView.cpp
|
||||
Debugger/ModuleView.h
|
||||
Debugger/RegisterView.cpp
|
||||
Debugger/RegisterView.h
|
||||
Debugger/RegisterView.ui
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
#include "Debugger/DebuggerEvents.h"
|
||||
#include "Debugger/DisassemblyView.h"
|
||||
#include "Debugger/ModuleView.h"
|
||||
#include "Debugger/RegisterView.h"
|
||||
#include "Debugger/StackView.h"
|
||||
#include "Debugger/ThreadView.h"
|
||||
@ -49,6 +50,7 @@ const std::map<std::string, DockTables::DebuggerViewDescription> DockTables::DEB
|
||||
DEBUGGER_VIEW(SavedAddressesView, QT_TRANSLATE_NOOP("DebuggerView", "Saved Addresses"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_VIEW(StackView, QT_TRANSLATE_NOOP("DebuggerView", "Stack"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_VIEW(ThreadView, QT_TRANSLATE_NOOP("DebuggerView", "Threads"), BOTTOM_MIDDLE),
|
||||
DEBUGGER_VIEW(ModuleView, QT_TRANSLATE_NOOP("DebuggerView", "Modules"), BOTTOM_MIDDLE),
|
||||
};
|
||||
|
||||
#undef DEBUGGER_VIEW
|
||||
@ -99,6 +101,7 @@ const std::vector<DockTables::DefaultDockLayout> DockTables::DEFAULT_DOCK_LAYOUT
|
||||
{"MemoryView", DefaultDockGroup::BOTTOM},
|
||||
{"BreakpointView", DefaultDockGroup::BOTTOM},
|
||||
{"ThreadView", DefaultDockGroup::BOTTOM},
|
||||
{"ModuleView", DefaultDockGroup::BOTTOM},
|
||||
{"StackView", DefaultDockGroup::BOTTOM},
|
||||
{"SavedAddressesView", DefaultDockGroup::BOTTOM},
|
||||
{"GlobalVariableTreeView", DefaultDockGroup::BOTTOM},
|
||||
|
||||
134
pcsx2-qt/Debugger/ModuleModel.cpp
Normal file
134
pcsx2-qt/Debugger/ModuleModel.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "ModuleModel.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
ModuleModel::ModuleModel(DebugInterface& cpu, QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_cpu(cpu)
|
||||
{
|
||||
}
|
||||
|
||||
int ModuleModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_cpu.GetModuleList().size();
|
||||
}
|
||||
|
||||
int ModuleModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return ModuleModel::COLUMN_COUNT;
|
||||
}
|
||||
|
||||
QVariant ModuleModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
const std::vector<IopMod> Modules = m_cpu.GetModuleList();
|
||||
|
||||
size_t row = static_cast<size_t>(index.row());
|
||||
if (row >= Modules.size())
|
||||
return QVariant();
|
||||
|
||||
const IopMod* mod = &Modules[row];
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case ModuleModel::ModuleColumns::NAME:
|
||||
return mod->name.c_str();
|
||||
case ModuleModel::ModuleColumns::VERSION:
|
||||
return fmt::format("{}.{}", mod->version >> 8, mod->version & 0xff).c_str();
|
||||
case ModuleModel::ModuleColumns::ENTRY:
|
||||
return QtUtils::FilledQStringFromValue(mod->entry, 16);
|
||||
case ModuleModel::ModuleColumns::GP:
|
||||
return QtUtils::FilledQStringFromValue(mod->gp, 16);
|
||||
case ModuleModel::ModuleColumns::TEXT_SECTION:
|
||||
{
|
||||
return QString("[%1 - %2]").arg(QtUtils::FilledQStringFromValue(mod->text_addr, 16), QtUtils::FilledQStringFromValue(mod->text_addr + mod->text_size - 1, 16));
|
||||
}
|
||||
case ModuleModel::ModuleColumns::DATA_SECTION:
|
||||
{
|
||||
u32 addr = mod->text_addr + mod->text_size;
|
||||
return QString("[%1 - %2]").arg(QtUtils::FilledQStringFromValue(addr, 16), QtUtils::FilledQStringFromValue(addr + mod->data_size - 1, 16));
|
||||
}
|
||||
case ModuleModel::ModuleColumns::BSS_SECTION:
|
||||
{
|
||||
if (mod->bss_size == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
u32 addr = mod->text_addr + mod->text_size + mod->data_size;
|
||||
return QString("[%1 - %2]").arg(QtUtils::FilledQStringFromValue(addr, 16), QtUtils::FilledQStringFromValue(addr + mod->bss_size - 1, 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case ModuleModel::ModuleColumns::NAME:
|
||||
return mod->name.c_str();
|
||||
case ModuleModel::ModuleColumns::VERSION:
|
||||
return mod->version;
|
||||
case ModuleModel::ModuleColumns::ENTRY:
|
||||
return mod->entry;
|
||||
case ModuleModel::ModuleColumns::GP:
|
||||
return mod->gp;
|
||||
case ModuleModel::ModuleColumns::TEXT_SECTION:
|
||||
return mod->text_addr;
|
||||
case ModuleModel::ModuleColumns::DATA_SECTION:
|
||||
return mod->text_addr + mod->text_size;
|
||||
case ModuleModel::ModuleColumns::BSS_SECTION:
|
||||
{
|
||||
if (mod->bss_size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return mod->text_addr + mod->text_size + mod->data_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ModuleModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case ModuleColumns::NAME:
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
return tr("NAME");
|
||||
case ModuleColumns::VERSION:
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
return tr("VERSION");
|
||||
case ModuleColumns::ENTRY:
|
||||
//: Warning: short space limit. Abbreviate if needed. // Entrypoint of the executable
|
||||
return tr("ENTRY");
|
||||
case ModuleColumns::GP:
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
return tr("GP");
|
||||
case ModuleColumns::TEXT_SECTION:
|
||||
//: Warning: short space limit. Abbreviate if needed. // Text section of the executable
|
||||
return tr("TEXT");
|
||||
case ModuleColumns::DATA_SECTION:
|
||||
//: Warning: short space limit. Abbreviate if needed. // Data section of the executable
|
||||
return tr("DATA");
|
||||
case ModuleColumns::BSS_SECTION:
|
||||
//: Warning: short space limit. Abbreviate if needed. // BSS section of the executable
|
||||
return tr("BSS");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ModuleModel::refreshData()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
51
pcsx2-qt/Debugger/ModuleModel.h
Normal file
51
pcsx2-qt/Debugger/ModuleModel.h
Normal file
@ -0,0 +1,51 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QAbstractTableModel>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/BiosDebugData.h"
|
||||
|
||||
class ModuleModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ModuleColumns : int
|
||||
{
|
||||
NAME = 0,
|
||||
VERSION,
|
||||
ENTRY,
|
||||
GP,
|
||||
TEXT_SECTION,
|
||||
DATA_SECTION,
|
||||
BSS_SECTION,
|
||||
COLUMN_COUNT
|
||||
};
|
||||
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[ModuleColumns::COLUMN_COUNT] =
|
||||
{
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
};
|
||||
|
||||
explicit ModuleModel(DebugInterface& cpu, QObject* parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
|
||||
void refreshData();
|
||||
|
||||
private:
|
||||
DebugInterface& m_cpu;
|
||||
};
|
||||
99
pcsx2-qt/Debugger/ModuleView.cpp
Normal file
99
pcsx2-qt/Debugger/ModuleView.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "ModuleView.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QMenu>
|
||||
|
||||
ModuleView::ModuleView(const DebuggerViewParameters& parameters)
|
||||
: DebuggerView(parameters, MONOSPACE_FONT)
|
||||
, m_model(new ModuleModel(cpu()))
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.moduleList->setModel(m_model);
|
||||
|
||||
m_ui.moduleList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.moduleList, &QTableView::customContextMenuRequested, this, &ModuleView::openContextMenu);
|
||||
connect(m_ui.moduleList, &QTableView::doubleClicked, this, &ModuleView::onDoubleClick);
|
||||
|
||||
for (std::size_t i = 0; auto mode : ModuleModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.moduleList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
|
||||
receiveEvent<DebuggerEvents::VMUpdate>([this](const DebuggerEvents::VMUpdate& event) -> bool {
|
||||
m_model->refreshData();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void ModuleView::openContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_ui.moduleList->selectionModel()->hasSelection())
|
||||
return;
|
||||
|
||||
QMenu* menu = new QMenu(m_ui.moduleList);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QAction* copy = menu->addAction(tr("Copy"));
|
||||
connect(copy, &QAction::triggered, [this]() {
|
||||
const QItemSelectionModel* selection_model = m_ui.moduleList->selectionModel();
|
||||
if (!selection_model->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_model->data(selection_model->currentIndex()).toString());
|
||||
});
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
QAction* copy_all_as_csv = menu->addAction(tr("Copy all as CSV"));
|
||||
connect(copy_all_as_csv, &QAction::triggered, [this]() {
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.moduleList->model()));
|
||||
});
|
||||
|
||||
menu->popup(m_ui.moduleList->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void ModuleView::onDoubleClick(const QModelIndex& index)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case ModuleModel::ModuleColumns::ENTRY:
|
||||
{
|
||||
goToInDisassembler(m_model->data(index, Qt::UserRole).toUInt(), true);
|
||||
break;
|
||||
}
|
||||
case ModuleModel::ModuleColumns::GP:
|
||||
{
|
||||
goToInMemoryView(m_model->data(index, Qt::UserRole).toUInt(), true);
|
||||
break;
|
||||
}
|
||||
case ModuleModel::ModuleColumns::TEXT_SECTION:
|
||||
{
|
||||
goToInDisassembler(m_model->data(index, Qt::UserRole).toUInt(), true);
|
||||
break;
|
||||
}
|
||||
case ModuleModel::ModuleColumns::DATA_SECTION:
|
||||
{
|
||||
goToInMemoryView(m_model->data(index, Qt::UserRole).toUInt(), true);
|
||||
break;
|
||||
}
|
||||
case ModuleModel::ModuleColumns::BSS_SECTION:
|
||||
{
|
||||
auto data = m_model->data(index, Qt::UserRole).toUInt();
|
||||
if (data)
|
||||
{
|
||||
goToInMemoryView(data, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
pcsx2-qt/Debugger/ModuleView.h
Normal file
27
pcsx2-qt/Debugger/ModuleView.h
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_ModuleView.h"
|
||||
|
||||
#include "DebuggerView.h"
|
||||
#include "ModuleModel.h"
|
||||
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
|
||||
class ModuleView final : public DebuggerView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModuleView(const DebuggerViewParameters& parameters);
|
||||
|
||||
void openContextMenu(QPoint pos);
|
||||
void onDoubleClick(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
Ui::ModuleView m_ui;
|
||||
|
||||
ModuleModel* m_model;
|
||||
};
|
||||
39
pcsx2-qt/Debugger/ModuleView.ui
Normal file
39
pcsx2-qt/Debugger/ModuleView.ui
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ModuleView</class>
|
||||
<widget class="QWidget" name="ModuleView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Modules</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="moduleList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@ -121,6 +121,8 @@
|
||||
<ClCompile Include="Debugger\StackView.cpp" />
|
||||
<ClCompile Include="Debugger\ThreadModel.cpp" />
|
||||
<ClCompile Include="Debugger\ThreadView.cpp" />
|
||||
<ClCompile Include="Debugger\ModuleModel.cpp" />
|
||||
<ClCompile Include="Debugger\ModuleView.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints\BreakpointDialog.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints\BreakpointModel.cpp" />
|
||||
<ClCompile Include="Debugger\Breakpoints\BreakpointView.cpp" />
|
||||
@ -235,6 +237,8 @@
|
||||
<QtMoc Include="Debugger\RegisterView.h" />
|
||||
<QtMoc Include="Debugger\StackModel.h" />
|
||||
<QtMoc Include="Debugger\StackView.h" />
|
||||
<QtMoc Include="Debugger\ModuleModel.h" />
|
||||
<QtMoc Include="Debugger\ModuleView.h" />
|
||||
<QtMoc Include="Debugger\ThreadModel.h" />
|
||||
<QtMoc Include="Debugger\ThreadView.h" />
|
||||
<ClInclude Include="Debugger\DebuggerSettingsManager.h" />
|
||||
@ -309,6 +313,8 @@
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_RegisterView.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_StackModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_StackView.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_ModuleModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_ModuleView.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_ThreadModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_ThreadView.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\Breakpoints\moc_BreakpointDialog.cpp" />
|
||||
@ -368,6 +374,7 @@
|
||||
<QtUi Include="Debugger\StackView.ui" />
|
||||
<QtUi Include="Debugger\SymbolTree\NewSymbolDialog.ui" />
|
||||
<QtUi Include="Debugger\SymbolTree\SymbolTreeView.ui" />
|
||||
<QtUi Include="Debugger\ModuleView.ui" />
|
||||
<QtUi Include="Debugger\ThreadView.ui" />
|
||||
<QtUi Include="GameList\EmptyGameListWidget.ui" />
|
||||
<QtUi Include="GameList\GameListWidget.ui" />
|
||||
|
||||
@ -79,7 +79,16 @@ std::vector<IopMod> getIOPModules()
|
||||
{
|
||||
IopMod mod;
|
||||
|
||||
mod.name = iopMemReadString(iopMemRead32(maddr + 4));
|
||||
u32 nstr = iopMemRead32(maddr + 4);
|
||||
if (nstr)
|
||||
{
|
||||
mod.name = iopMemReadString(iopMemRead32(maddr + 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
mod.name = "(NULL)";
|
||||
}
|
||||
|
||||
mod.version = iopMemRead16(maddr + 8);
|
||||
mod.entry = iopMemRead32(maddr + 0x10);
|
||||
mod.gp = iopMemRead32(maddr + 0x14);
|
||||
|
||||
@ -734,6 +734,11 @@ std::vector<std::unique_ptr<BiosThread>> R5900DebugInterface::GetThreadList() co
|
||||
return getEEThreads();
|
||||
}
|
||||
|
||||
std::vector<IopMod> R5900DebugInterface::GetModuleList() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
//
|
||||
// R3000DebugInterface
|
||||
//
|
||||
@ -1062,6 +1067,11 @@ std::vector<std::unique_ptr<BiosThread>> R3000DebugInterface::GetThreadList() co
|
||||
return getIOPThreads();
|
||||
}
|
||||
|
||||
std::vector<IopMod> R3000DebugInterface::GetModuleList() const
|
||||
{
|
||||
return getIOPModules();
|
||||
}
|
||||
|
||||
ElfMemoryReader::ElfMemoryReader(const ccc::ElfFile& elf)
|
||||
: m_elf(elf)
|
||||
{
|
||||
|
||||
@ -90,6 +90,7 @@ public:
|
||||
virtual SymbolGuardian& GetSymbolGuardian() const = 0;
|
||||
virtual SymbolImporter* GetSymbolImporter() const = 0;
|
||||
virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
|
||||
virtual std::vector<IopMod> GetModuleList() const = 0;
|
||||
|
||||
bool isAlive();
|
||||
bool isCpuPaused();
|
||||
@ -151,6 +152,7 @@ public:
|
||||
SymbolGuardian& GetSymbolGuardian() const override;
|
||||
SymbolImporter* GetSymbolImporter() const override;
|
||||
std::vector<std::unique_ptr<BiosThread>> GetThreadList() const override;
|
||||
std::vector<IopMod> GetModuleList() const override;
|
||||
|
||||
std::string disasm(u32 address, bool simplify) override;
|
||||
bool isValidAddress(u32 address) override;
|
||||
@ -194,6 +196,7 @@ public:
|
||||
SymbolGuardian& GetSymbolGuardian() const override;
|
||||
SymbolImporter* GetSymbolImporter() const override;
|
||||
std::vector<std::unique_ptr<BiosThread>> GetThreadList() const override;
|
||||
std::vector<IopMod> GetModuleList() const override;
|
||||
|
||||
std::string disasm(u32 address, bool simplify) override;
|
||||
bool isValidAddress(u32 address) override;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user