CodeDiffDialog: Add saving/loading function finder results.
This commit is contained in:
parent
ec69ed2173
commit
0826586f96
|
@ -4,9 +4,11 @@
|
||||||
#include "DolphinQt/Debugger/CodeDiffDialog.h"
|
#include "DolphinQt/Debugger/CodeDiffDialog.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
@ -16,7 +18,11 @@
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/IOFile.h"
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Debugger/PPCDebugInterface.h"
|
#include "Core/Debugger/PPCDebugInterface.h"
|
||||||
#include "Core/HW/CPU.h"
|
#include "Core/HW/CPU.h"
|
||||||
|
@ -55,12 +61,15 @@ void CodeDiffDialog::reject()
|
||||||
|
|
||||||
void CodeDiffDialog::CreateWidgets()
|
void CodeDiffDialog::CreateWidgets()
|
||||||
{
|
{
|
||||||
|
bool running = Core::GetState() != Core::State::Uninitialized;
|
||||||
|
|
||||||
auto* btns_layout = new QGridLayout;
|
auto* btns_layout = new QGridLayout;
|
||||||
m_exclude_btn = new QPushButton(tr("Code did not get executed"));
|
m_exclude_btn = new QPushButton(tr("Code did not get executed"));
|
||||||
m_include_btn = new QPushButton(tr("Code has been executed"));
|
m_include_btn = new QPushButton(tr("Code has been executed"));
|
||||||
m_record_btn = new QPushButton(tr("Start Recording"));
|
m_record_btn = new QPushButton(tr("Start Recording"));
|
||||||
m_record_btn->setCheckable(true);
|
m_record_btn->setCheckable(true);
|
||||||
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
||||||
|
m_record_btn->setEnabled(running);
|
||||||
m_exclude_btn->setEnabled(false);
|
m_exclude_btn->setEnabled(false);
|
||||||
m_include_btn->setEnabled(false);
|
m_include_btn->setEnabled(false);
|
||||||
|
|
||||||
|
@ -89,19 +98,30 @@ void CodeDiffDialog::CreateWidgets()
|
||||||
m_matching_results_table->setColumnWidth(3, 210);
|
m_matching_results_table->setColumnWidth(3, 210);
|
||||||
m_matching_results_table->setColumnWidth(4, 65);
|
m_matching_results_table->setColumnWidth(4, 65);
|
||||||
m_matching_results_table->setCornerButtonEnabled(false);
|
m_matching_results_table->setCornerButtonEnabled(false);
|
||||||
|
m_autosave_check = new QCheckBox(tr("Auto Save"));
|
||||||
|
m_save_btn = new QPushButton(tr("Save"));
|
||||||
|
m_save_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
m_save_btn->setEnabled(running);
|
||||||
|
m_load_btn = new QPushButton(tr("Load"));
|
||||||
|
m_load_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
m_load_btn->setEnabled(running);
|
||||||
m_reset_btn = new QPushButton(tr("Reset All"));
|
m_reset_btn = new QPushButton(tr("Reset All"));
|
||||||
m_reset_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
m_reset_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
m_help_btn = new QPushButton(tr("Help"));
|
m_help_btn = new QPushButton(tr("Help"));
|
||||||
m_help_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
m_help_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
auto* help_reset_layout = new QHBoxLayout;
|
auto* bottom_controls_layout = new QHBoxLayout;
|
||||||
help_reset_layout->addWidget(m_reset_btn, 0, Qt::AlignLeft);
|
bottom_controls_layout->addWidget(m_reset_btn, 0, Qt::AlignLeft);
|
||||||
help_reset_layout->addWidget(m_help_btn, 0, Qt::AlignRight);
|
bottom_controls_layout->addStretch();
|
||||||
|
bottom_controls_layout->addWidget(m_autosave_check, 0, Qt::AlignRight);
|
||||||
|
bottom_controls_layout->addWidget(m_save_btn, 0, Qt::AlignRight);
|
||||||
|
bottom_controls_layout->addWidget(m_load_btn, 0, Qt::AlignRight);
|
||||||
|
bottom_controls_layout->addWidget(m_help_btn, 0, Qt::AlignRight);
|
||||||
|
|
||||||
auto* layout = new QVBoxLayout();
|
auto* layout = new QVBoxLayout();
|
||||||
layout->addLayout(btns_layout);
|
layout->addLayout(btns_layout);
|
||||||
layout->addLayout(labels_layout);
|
layout->addLayout(labels_layout);
|
||||||
layout->addWidget(m_matching_results_table);
|
layout->addWidget(m_matching_results_table);
|
||||||
layout->addLayout(help_reset_layout);
|
layout->addLayout(bottom_controls_layout);
|
||||||
|
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
resize(515, 400);
|
resize(515, 400);
|
||||||
|
@ -115,11 +135,14 @@ void CodeDiffDialog::ConnectWidgets()
|
||||||
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||||
|
[this](Core::State state) { UpdateButtons(state != Core::State::Uninitialized); });
|
||||||
connect(m_record_btn, &QPushButton::toggled, this, &CodeDiffDialog::OnRecord);
|
connect(m_record_btn, &QPushButton::toggled, this, &CodeDiffDialog::OnRecord);
|
||||||
connect(m_include_btn, &QPushButton::pressed, [this]() { Update(true); });
|
connect(m_include_btn, &QPushButton::pressed, [this]() { Update(UpdateType::Include); });
|
||||||
connect(m_exclude_btn, &QPushButton::pressed, [this]() { Update(false); });
|
connect(m_exclude_btn, &QPushButton::pressed, [this]() { Update(UpdateType::Exclude); });
|
||||||
connect(m_matching_results_table, &QTableWidget::itemClicked, [this]() { OnClickItem(); });
|
connect(m_matching_results_table, &QTableWidget::itemClicked, [this]() { OnClickItem(); });
|
||||||
|
connect(m_save_btn, &QPushButton::pressed, this, &CodeDiffDialog::SaveDataBackup);
|
||||||
|
connect(m_load_btn, &QPushButton::pressed, this, &CodeDiffDialog::LoadDataBackup);
|
||||||
connect(m_reset_btn, &QPushButton::pressed, this, &CodeDiffDialog::ClearData);
|
connect(m_reset_btn, &QPushButton::pressed, this, &CodeDiffDialog::ClearData);
|
||||||
connect(m_help_btn, &QPushButton::pressed, this, &CodeDiffDialog::InfoDisp);
|
connect(m_help_btn, &QPushButton::pressed, this, &CodeDiffDialog::InfoDisp);
|
||||||
connect(m_matching_results_table, &CodeDiffDialog::customContextMenuRequested, this,
|
connect(m_matching_results_table, &CodeDiffDialog::customContextMenuRequested, this,
|
||||||
|
@ -133,6 +156,103 @@ void CodeDiffDialog::OnClickItem()
|
||||||
m_code_widget->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithDetailedUpdate);
|
m_code_widget->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithDetailedUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeDiffDialog::SaveDataBackup()
|
||||||
|
{
|
||||||
|
if (Core::GetState() == Core::State::Uninitialized)
|
||||||
|
{
|
||||||
|
ModalMessageBox::information(this, tr("Code Diff Tool"),
|
||||||
|
tr("Emulation must be started before saving a file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_include.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string filename =
|
||||||
|
File::GetUserPath(D_LOGS_IDX) + SConfig::GetInstance().GetGameID() + "_CodeDiff.txt";
|
||||||
|
File::IOFile f(filename, "w");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
ModalMessageBox::information(
|
||||||
|
this, tr("Code Diff Tool"),
|
||||||
|
tr("Failed to save file to: %1").arg(QString::fromStdString(filename)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy list of BLR tested functions:
|
||||||
|
std::set<u32> address_blr;
|
||||||
|
for (int i = 0; i < m_matching_results_table->rowCount(); i++)
|
||||||
|
{
|
||||||
|
if (m_matching_results_table->item(i, 4)->text() == QStringLiteral("X"))
|
||||||
|
address_blr.insert(m_matching_results_table->item(i, 4)->data(Qt::UserRole).toUInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& line : m_include)
|
||||||
|
{
|
||||||
|
bool blr = address_blr.contains(line.addr);
|
||||||
|
f.WriteString(
|
||||||
|
fmt::format("{} {} {} {:d} {}\n", line.addr, line.hits, line.total_hits, blr, line.symbol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeDiffDialog::LoadDataBackup()
|
||||||
|
{
|
||||||
|
if (Core::GetState() == Core::State::Uninitialized)
|
||||||
|
{
|
||||||
|
ModalMessageBox::information(this, tr("Code Diff Tool"),
|
||||||
|
tr("Emulation must be started before loading a file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_symbolDB.IsEmpty())
|
||||||
|
{
|
||||||
|
ModalMessageBox::warning(
|
||||||
|
this, tr("Code Diff Tool"),
|
||||||
|
tr("Symbol map not found.\n\nIf one does not exist, you can generate one from "
|
||||||
|
"the Menu bar:\nSymbols -> Generate Symbols From ->\n\tAddress | Signature "
|
||||||
|
"Database | RSO Modules"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filename =
|
||||||
|
File::GetUserPath(D_LOGS_IDX) + SConfig::GetInstance().GetGameID() + "_CodeDiff.txt";
|
||||||
|
File::IOFile f(filename, "r");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
ModalMessageBox::information(
|
||||||
|
this, tr("Code Diff Tool"),
|
||||||
|
tr("Failed to find or open file: %1").arg(QString::fromStdString(filename)));
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClearData();
|
||||||
|
|
||||||
|
std::set<u32> blr_addresses;
|
||||||
|
char line[512];
|
||||||
|
while (fgets(line, 512, f.GetHandle()))
|
||||||
|
{
|
||||||
|
bool blr = false;
|
||||||
|
Diff temp;
|
||||||
|
std::istringstream iss(line);
|
||||||
|
iss.imbue(std::locale::classic());
|
||||||
|
iss >> temp.addr >> temp.hits >> temp.total_hits >> blr >> std::ws;
|
||||||
|
std::getline(iss, temp.symbol);
|
||||||
|
|
||||||
|
if (blr)
|
||||||
|
blr_addresses.insert(temp.addr);
|
||||||
|
|
||||||
|
m_include.push_back(std::move(temp));
|
||||||
|
}
|
||||||
|
|
||||||
|
Update(UpdateType::Backup);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_matching_results_table->rowCount(); i++)
|
||||||
|
{
|
||||||
|
if (blr_addresses.contains(m_matching_results_table->item(i, 4)->data(Qt::UserRole).toUInt()))
|
||||||
|
MarkRowBLR(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeDiffDialog::ClearData()
|
void CodeDiffDialog::ClearData()
|
||||||
{
|
{
|
||||||
if (m_record_btn->isChecked())
|
if (m_record_btn->isChecked())
|
||||||
|
@ -344,7 +464,7 @@ void CodeDiffDialog::RemoveMatchingSymbolsFromIncludes(const std::vector<Diff>&
|
||||||
m_include.end());
|
m_include.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeDiffDialog::Update(bool include)
|
void CodeDiffDialog::Update(UpdateType type)
|
||||||
{
|
{
|
||||||
// Wrap everything in a pause
|
// Wrap everything in a pause
|
||||||
Core::State old_state = Core::GetState();
|
Core::State old_state = Core::GetState();
|
||||||
|
@ -352,15 +472,18 @@ void CodeDiffDialog::Update(bool include)
|
||||||
Core::SetState(Core::State::Paused);
|
Core::SetState(Core::State::Paused);
|
||||||
|
|
||||||
// Main process
|
// Main process
|
||||||
if (include)
|
if (type == UpdateType::Include)
|
||||||
{
|
{
|
||||||
OnInclude();
|
OnInclude();
|
||||||
}
|
}
|
||||||
else
|
else if (type == UpdateType::Exclude)
|
||||||
{
|
{
|
||||||
OnExclude();
|
OnExclude();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type != UpdateType::Backup && m_autosave_check->isChecked() && !m_include.empty())
|
||||||
|
SaveDataBackup();
|
||||||
|
|
||||||
const auto create_item = [](const QString& string = {}, const u32 address = 0x00000000) {
|
const auto create_item = [](const QString& string = {}, const u32 address = 0x00000000) {
|
||||||
QTableWidgetItem* item = new QTableWidgetItem(string);
|
QTableWidgetItem* item = new QTableWidgetItem(string);
|
||||||
item->setData(Qt::UserRole, address);
|
item->setData(Qt::UserRole, address);
|
||||||
|
@ -428,7 +551,9 @@ void CodeDiffDialog::InfoDisp()
|
||||||
"list "
|
"list "
|
||||||
"and any includes left over will be displayed.\nYou can continue to use "
|
"and any includes left over will be displayed.\nYou can continue to use "
|
||||||
"'Code did not get executed'/'Code has been executed' to narrow down the "
|
"'Code did not get executed'/'Code has been executed' to narrow down the "
|
||||||
"results."));
|
"results.\n\n"
|
||||||
|
"Saving will store the current list in Dolphin's Log folder (File -> Open User "
|
||||||
|
"Folder)"));
|
||||||
ModalMessageBox::information(
|
ModalMessageBox::information(
|
||||||
this, tr("Code Diff Tool Help"),
|
this, tr("Code Diff Tool Help"),
|
||||||
tr("Example:\n"
|
tr("Example:\n"
|
||||||
|
@ -497,21 +622,27 @@ void CodeDiffDialog::OnSetBLR()
|
||||||
if (!symbol)
|
if (!symbol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
MarkRowBLR(item->row());
|
||||||
|
if (m_autosave_check->isChecked())
|
||||||
|
SaveDataBackup();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
Core::CPUThreadGuard guard(system);
|
Core::CPUThreadGuard guard(system);
|
||||||
system.GetPowerPC().GetDebugInterface().SetPatch(guard, symbol->address, 0x4E800020);
|
system.GetPowerPC().GetDebugInterface().SetPatch(guard, symbol->address, 0x4E800020);
|
||||||
}
|
}
|
||||||
|
|
||||||
int row = item->row();
|
m_code_widget->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeDiffDialog::MarkRowBLR(int row)
|
||||||
|
{
|
||||||
m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red));
|
m_matching_results_table->item(row, 0)->setForeground(QBrush(Qt::red));
|
||||||
m_matching_results_table->item(row, 1)->setForeground(QBrush(Qt::red));
|
m_matching_results_table->item(row, 1)->setForeground(QBrush(Qt::red));
|
||||||
m_matching_results_table->item(row, 2)->setForeground(QBrush(Qt::red));
|
m_matching_results_table->item(row, 2)->setForeground(QBrush(Qt::red));
|
||||||
m_matching_results_table->item(row, 3)->setForeground(QBrush(Qt::red));
|
m_matching_results_table->item(row, 3)->setForeground(QBrush(Qt::red));
|
||||||
m_matching_results_table->item(row, 4)->setForeground(QBrush(Qt::red));
|
m_matching_results_table->item(row, 4)->setForeground(QBrush(Qt::red));
|
||||||
m_matching_results_table->item(row, 4)->setText(QStringLiteral("X"));
|
m_matching_results_table->item(row, 4)->setText(QStringLiteral("X"));
|
||||||
|
|
||||||
m_code_widget->Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeDiffDialog::UpdateItem()
|
void CodeDiffDialog::UpdateItem()
|
||||||
|
@ -533,3 +664,10 @@ void CodeDiffDialog::UpdateItem()
|
||||||
QString::fromStdString(symbolName).replace(QStringLiteral("\t"), QStringLiteral(" "));
|
QString::fromStdString(symbolName).replace(QStringLiteral("\t"), QStringLiteral(" "));
|
||||||
m_matching_results_table->item(row, 3)->setText(newName);
|
m_matching_results_table->item(row, 3)->setText(newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeDiffDialog::UpdateButtons(bool running)
|
||||||
|
{
|
||||||
|
m_save_btn->setEnabled(running);
|
||||||
|
m_load_btn->setEnabled(running);
|
||||||
|
m_record_btn->setEnabled(running);
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
class CodeWidget;
|
class CodeWidget;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
class QCheckBox;
|
||||||
class QTableWidget;
|
class QTableWidget;
|
||||||
|
|
||||||
struct Diff
|
struct Diff
|
||||||
|
@ -32,8 +33,17 @@ public:
|
||||||
void reject() override;
|
void reject() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class UpdateType
|
||||||
|
{
|
||||||
|
Include,
|
||||||
|
Exclude,
|
||||||
|
Backup
|
||||||
|
};
|
||||||
|
|
||||||
void CreateWidgets();
|
void CreateWidgets();
|
||||||
void ConnectWidgets();
|
void ConnectWidgets();
|
||||||
|
void SaveDataBackup();
|
||||||
|
void LoadDataBackup();
|
||||||
void ClearData();
|
void ClearData();
|
||||||
void ClearBlockCache();
|
void ClearBlockCache();
|
||||||
void OnClickItem();
|
void OnClickItem();
|
||||||
|
@ -43,7 +53,7 @@ private:
|
||||||
void OnExclude();
|
void OnExclude();
|
||||||
void RemoveMissingSymbolsFromIncludes(const std::vector<Diff>& symbol_diff);
|
void RemoveMissingSymbolsFromIncludes(const std::vector<Diff>& symbol_diff);
|
||||||
void RemoveMatchingSymbolsFromIncludes(const std::vector<Diff>& symbol_list);
|
void RemoveMatchingSymbolsFromIncludes(const std::vector<Diff>& symbol_list);
|
||||||
void Update(bool include);
|
void Update(UpdateType type);
|
||||||
void InfoDisp();
|
void InfoDisp();
|
||||||
|
|
||||||
void OnContextMenu();
|
void OnContextMenu();
|
||||||
|
@ -52,15 +62,20 @@ private:
|
||||||
void OnDelete();
|
void OnDelete();
|
||||||
void OnSetBLR();
|
void OnSetBLR();
|
||||||
|
|
||||||
|
void MarkRowBLR(int row);
|
||||||
void UpdateItem();
|
void UpdateItem();
|
||||||
|
void UpdateButtons(bool running);
|
||||||
|
|
||||||
QTableWidget* m_matching_results_table;
|
QTableWidget* m_matching_results_table;
|
||||||
|
QCheckBox* m_autosave_check;
|
||||||
QLabel* m_exclude_size_label;
|
QLabel* m_exclude_size_label;
|
||||||
QLabel* m_include_size_label;
|
QLabel* m_include_size_label;
|
||||||
QPushButton* m_exclude_btn;
|
QPushButton* m_exclude_btn;
|
||||||
QPushButton* m_include_btn;
|
QPushButton* m_include_btn;
|
||||||
QPushButton* m_record_btn;
|
QPushButton* m_record_btn;
|
||||||
QPushButton* m_reset_btn;
|
QPushButton* m_reset_btn;
|
||||||
|
QPushButton* m_save_btn;
|
||||||
|
QPushButton* m_load_btn;
|
||||||
QPushButton* m_help_btn;
|
QPushButton* m_help_btn;
|
||||||
CodeWidget* m_code_widget;
|
CodeWidget* m_code_widget;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue