mirror of https://github.com/PCSX2/pcsx2.git
Debugger Stack frames: (Refactor) Use model based widgets
This commit is contained in:
parent
c00caa886e
commit
b6125e97e9
|
@ -138,6 +138,8 @@ target_sources(pcsx2-qt PRIVATE
|
|||
Debugger/Models/BreakpointModel.h
|
||||
Debugger/Models/ThreadModel.cpp
|
||||
Debugger/Models/ThreadModel.h
|
||||
Debugger/Models/StackModel.cpp
|
||||
Debugger/Models/StackModel.h
|
||||
Tools/InputRecording/NewInputRecordingDlg.cpp
|
||||
Tools/InputRecording/NewInputRecordingDlg.h
|
||||
Tools/InputRecording/NewInputRecordingDlg.ui
|
||||
|
|
|
@ -43,6 +43,7 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
|||
: m_cpu(cpu)
|
||||
, m_bpModel(cpu)
|
||||
, m_threadModel(cpu)
|
||||
, m_stackModel(cpu)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
|
@ -70,8 +71,11 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
|||
m_ui.threadList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
m_ui.threadList->setModel(&m_threadModel);
|
||||
|
||||
connect(m_ui.stackframeList, &QTableWidget::customContextMenuRequested, this, &CpuWidget::onStackListContextMenu);
|
||||
connect(m_ui.stackframeList, &QTableWidget::cellDoubleClicked, this, &CpuWidget::onStackListDoubleClick);
|
||||
connect(m_ui.stackList, &QTableView::customContextMenuRequested, this, &CpuWidget::onStackListContextMenu);
|
||||
connect(m_ui.stackList, &QTableView::doubleClicked, this, &CpuWidget::onStackListDoubleClick);
|
||||
|
||||
m_ui.stackList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
m_ui.stackList->setModel(&m_stackModel);
|
||||
|
||||
connect(m_ui.tabWidgetRegFunc, &QTabWidget::currentChanged, [this](int i) {if(i == 1){updateFunctionList(true);} });
|
||||
connect(m_ui.listFunctions, &QListWidget::customContextMenuRequested, this, &CpuWidget::onFuncListContextMenu);
|
||||
|
@ -471,72 +475,46 @@ void CpuWidget::onFuncListDoubleClick(QListWidgetItem* item)
|
|||
|
||||
void CpuWidget::updateStackFrames()
|
||||
{
|
||||
m_ui.stackframeList->setRowCount(0);
|
||||
|
||||
m_stacklistObjects = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
|
||||
m_activeThread.data.entry_init, m_activeThread.data.stack);
|
||||
|
||||
for (size_t i = 0; i < m_stacklistObjects.size(); i++)
|
||||
{
|
||||
m_ui.stackframeList->insertRow(i);
|
||||
|
||||
const auto& stackFrame = m_stacklistObjects.at(i);
|
||||
|
||||
QTableWidgetItem* entryItem = new QTableWidgetItem();
|
||||
entryItem->setText(FilledQStringFromValue(stackFrame.entry, 16));
|
||||
entryItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 0, entryItem);
|
||||
|
||||
QTableWidgetItem* entryName = new QTableWidgetItem();
|
||||
entryName->setText(m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str());
|
||||
entryName->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 1, entryName);
|
||||
|
||||
QTableWidgetItem* entryPC = new QTableWidgetItem();
|
||||
entryPC->setText(FilledQStringFromValue(stackFrame.pc, 16));
|
||||
entryPC->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 2, entryPC);
|
||||
|
||||
QTableWidgetItem* entryOpcode = new QTableWidgetItem();
|
||||
entryOpcode->setText(m_ui.disassemblyWidget->GetLineDisasm(stackFrame.pc));
|
||||
entryOpcode->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 3, entryOpcode);
|
||||
|
||||
QTableWidgetItem* entrySP = new QTableWidgetItem();
|
||||
entrySP->setText(FilledQStringFromValue(stackFrame.sp, 16));
|
||||
entrySP->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 4, entrySP);
|
||||
|
||||
QTableWidgetItem* entryStackSize = new QTableWidgetItem();
|
||||
entryStackSize->setText(QString::number(stackFrame.stackSize));
|
||||
entryStackSize->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
|
||||
m_ui.stackframeList->setItem(i, 5, entryStackSize);
|
||||
}
|
||||
m_stackModel.refreshData();
|
||||
}
|
||||
|
||||
void CpuWidget::onStackListContextMenu(QPoint pos)
|
||||
{
|
||||
if (!m_stacklistContextMenu)
|
||||
{
|
||||
m_stacklistContextMenu = new QMenu(m_ui.stackframeList);
|
||||
if (!m_ui.stackList->selectionModel()->hasSelection())
|
||||
return;
|
||||
|
||||
QAction* copyAction = new QAction(tr("Copy"), m_ui.stackframeList);
|
||||
connect(copyAction, &QAction::triggered, [this] {
|
||||
const auto& items = m_ui.stackframeList->selectedItems();
|
||||
if (!items.size())
|
||||
return;
|
||||
QApplication::clipboard()->setText(items.first()->text());
|
||||
});
|
||||
m_stacklistContextMenu->addAction(copyAction);
|
||||
}
|
||||
QMenu* contextMenu = new QMenu(tr("Stack List Context Menu"), m_ui.stackList);
|
||||
|
||||
m_stacklistContextMenu->exec(m_ui.stackframeList->mapToGlobal(pos));
|
||||
QAction* actionCopy = new QAction(tr("Copy"), m_ui.stackList);
|
||||
connect(actionCopy, &QAction::triggered, [this]() {
|
||||
const auto* selModel = m_ui.stackList->selectionModel();
|
||||
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
QGuiApplication::clipboard()->setText(m_ui.stackList->model()->data(selModel->currentIndex()).toString());
|
||||
});
|
||||
contextMenu->addAction(actionCopy);
|
||||
|
||||
contextMenu->popup(m_ui.stackList->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void CpuWidget::onStackListDoubleClick(int row, int column)
|
||||
void CpuWidget::onStackListDoubleClick(const QModelIndex& index)
|
||||
{
|
||||
const auto& entry = m_stacklistObjects.at(row);
|
||||
m_ui.disassemblyWidget->gotoAddress(entry.pc);
|
||||
switch (index.column())
|
||||
{
|
||||
case StackModel::StackModel::ENTRY:
|
||||
case StackModel::StackModel::ENTRY_LABEL:
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::ENTRY), Qt::UserRole).toUInt());
|
||||
break;
|
||||
case StackModel::StackModel::SP:
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.stackList->model()->data(index, Qt::UserRole).toUInt());
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
break;
|
||||
default: // Default to PC
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::PC), Qt::UserRole).toUInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/StackModel.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
|
@ -65,7 +66,7 @@ public slots:
|
|||
|
||||
void updateStackFrames();
|
||||
void onStackListContextMenu(QPoint pos);
|
||||
void onStackListDoubleClick(int row, int column);
|
||||
void onStackListDoubleClick(const QModelIndex& index);
|
||||
|
||||
void updateFunctionList(bool whenEmpty = false);
|
||||
void onFuncListContextMenu(QPoint pos);
|
||||
|
@ -102,9 +103,9 @@ private:
|
|||
|
||||
BreakpointModel m_bpModel;
|
||||
ThreadModel m_threadModel;
|
||||
StackModel m_stackModel;
|
||||
|
||||
std::vector<EEThread> m_threadlistObjects;
|
||||
EEThread m_activeThread;
|
||||
std::vector<StackFrame> m_stacklistObjects;
|
||||
|
||||
bool m_demangleFunctions = true;
|
||||
|
|
|
@ -457,7 +457,7 @@
|
|||
</widget>
|
||||
<widget class="QWidget" name="tab_callstack">
|
||||
<attribute name="title">
|
||||
<string>Call Stack</string>
|
||||
<string>Active Call Stack</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="spacing">
|
||||
|
@ -476,7 +476,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="stackframeList">
|
||||
<widget class="QTableView" name="stackList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
|
@ -495,48 +495,6 @@
|
|||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Entry</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>PC</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Opcode</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>SP</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Frame Size</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "StackModel.h"
|
||||
#include "DebugTools/MipsStackWalk.h"
|
||||
#include "DebugTools/BiosDebugData.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
StackModel::StackModel(DebugInterface& cpu, QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_cpu(cpu)
|
||||
{
|
||||
}
|
||||
|
||||
int StackModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_stackFrames.size();
|
||||
}
|
||||
|
||||
int StackModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return StackModel::COLUMN_COUNT;
|
||||
}
|
||||
|
||||
QVariant StackModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const auto& stackFrame = m_stackFrames.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case StackModel::ENTRY:
|
||||
return QtUtils::FilledQStringFromValue(stackFrame.entry, 16);
|
||||
case StackModel::ENTRY_LABEL:
|
||||
return m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str();
|
||||
case StackModel::PC:
|
||||
return QtUtils::FilledQStringFromValue(stackFrame.pc, 16);
|
||||
case StackModel::PC_OPCODE:
|
||||
return m_cpu.disasm(stackFrame.pc, true).c_str();
|
||||
case StackModel::SP:
|
||||
return QtUtils::FilledQStringFromValue(stackFrame.sp, 16);
|
||||
case StackModel::SIZE:
|
||||
return QString::number(stackFrame.stackSize);
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
{
|
||||
const auto& stackFrame = m_stackFrames.at(index.row());
|
||||
switch (index.column())
|
||||
{
|
||||
case StackModel::ENTRY:
|
||||
return stackFrame.entry;
|
||||
case StackModel::ENTRY_LABEL:
|
||||
return m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str();
|
||||
case StackModel::PC:
|
||||
return stackFrame.pc;
|
||||
case StackModel::PC_OPCODE:
|
||||
return m_cpu.disasm(stackFrame.pc, true).c_str();
|
||||
case StackModel::SP:
|
||||
return stackFrame.sp;
|
||||
case StackModel::SIZE:
|
||||
return stackFrame.stackSize;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant StackModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case StackColumns::ENTRY:
|
||||
return tr("ENTRY");
|
||||
case StackColumns::ENTRY_LABEL:
|
||||
return tr("LABEL");
|
||||
case StackColumns::PC:
|
||||
return tr("PC");
|
||||
case StackColumns::PC_OPCODE:
|
||||
return tr("INSTRUCTION");
|
||||
case StackColumns::SP:
|
||||
return tr("STACK POINTER");
|
||||
case StackColumns::SIZE:
|
||||
return tr("SIZE");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void StackModel::refreshData()
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_IOP)
|
||||
return;
|
||||
|
||||
// Hopefully in the near future we can get a stack frame for
|
||||
// each thread
|
||||
beginResetModel();
|
||||
for (const auto& thread : getEEThreads())
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
{
|
||||
m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
|
||||
thread.data.entry_init, thread.data.stack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QAbstractTableModel>
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/MipsStackWalk.h"
|
||||
|
||||
class StackModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum StackColumns : int
|
||||
{
|
||||
ENTRY = 0,
|
||||
ENTRY_LABEL,
|
||||
PC,
|
||||
PC_OPCODE,
|
||||
SP,
|
||||
SIZE,
|
||||
COLUMN_COUNT
|
||||
};
|
||||
|
||||
explicit StackModel(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;
|
||||
std::vector<MipsStackWalk::StackFrame> m_stackFrames;
|
||||
};
|
|
@ -28,10 +28,7 @@ ThreadModel::ThreadModel(DebugInterface& cpu, QObject* parent)
|
|||
int ThreadModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_EE)
|
||||
{
|
||||
Console.Warning("%d", getEEThreads().size());
|
||||
return getEEThreads().size();
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -139,4 +136,4 @@ void ThreadModel::refreshData()
|
|||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,4 +63,4 @@ private:
|
|||
{WAIT_SEMA, tr("SEMAPHORE")}};
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
<ClCompile Include="Debugger\BreakpointDialog.cpp" />
|
||||
<ClCompile Include="Debugger\Models\BreakpointModel.cpp" />
|
||||
<ClCompile Include="Debugger\Models\ThreadModel.cpp" />
|
||||
<ClCompile Include="Debugger\Models\StackModel.cpp" />
|
||||
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
|
||||
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
|
||||
|
@ -232,6 +233,7 @@
|
|||
<QtMoc Include="Debugger\BreakpointDialog.h" />
|
||||
<QtMoc Include="Debugger\Models\BreakpointModel.h" />
|
||||
<QtMoc Include="Debugger\Models\ThreadModel.h" />
|
||||
<QtMoc Include="Debugger\Models\StackModel.h" />
|
||||
<QtMoc Include="Settings\ControllerBindingWidgets.h" />
|
||||
<QtMoc Include="Settings\ControllerGlobalSettingsWidget.h" />
|
||||
<ClInclude Include="Settings\MemoryCardConvertWorker.h" />
|
||||
|
@ -284,6 +286,7 @@
|
|||
<ClCompile Include="$(IntDir)Debugger\moc_BreakpointDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\Models\moc_BreakpointModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\Models\moc_ThreadModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\Models\moc_StackModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
|
||||
|
|
|
@ -283,6 +283,9 @@
|
|||
<ClCompile Include="Debugger\Models\ThreadModel.cpp">
|
||||
<Filter>Debugger\Models</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\Models\StackModel.cpp">
|
||||
<Filter>Debugger\Models</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_CpuWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
|
@ -307,6 +310,9 @@
|
|||
<ClCompile Include="$(IntDir)Debugger\Models\moc_ThreadModel.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\Models\moc_StackModel.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
|
@ -450,6 +456,9 @@
|
|||
<QtMoc Include="Debugger\Models\ThreadModel.h">
|
||||
<Filter>Debugger\Models</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\Models\StackModel.h">
|
||||
<Filter>Debugger\Models</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
|
|
Loading…
Reference in New Issue