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 <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGuiApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
|
@ -16,7 +18,11 @@
|
|||
#include <QTableWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Debugger/PPCDebugInterface.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
|
@ -55,12 +61,15 @@ void CodeDiffDialog::reject()
|
|||
|
||||
void CodeDiffDialog::CreateWidgets()
|
||||
{
|
||||
bool running = Core::GetState() != Core::State::Uninitialized;
|
||||
|
||||
auto* btns_layout = new QGridLayout;
|
||||
m_exclude_btn = new QPushButton(tr("Code did not get executed"));
|
||||
m_include_btn = new QPushButton(tr("Code has been executed"));
|
||||
m_record_btn = new QPushButton(tr("Start Recording"));
|
||||
m_record_btn->setCheckable(true);
|
||||
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
||||
m_record_btn->setEnabled(running);
|
||||
m_exclude_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(4, 65);
|
||||
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->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_help_btn = new QPushButton(tr("Help"));
|
||||
m_help_btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
auto* help_reset_layout = new QHBoxLayout;
|
||||
help_reset_layout->addWidget(m_reset_btn, 0, Qt::AlignLeft);
|
||||
help_reset_layout->addWidget(m_help_btn, 0, Qt::AlignRight);
|
||||
auto* bottom_controls_layout = new QHBoxLayout;
|
||||
bottom_controls_layout->addWidget(m_reset_btn, 0, Qt::AlignLeft);
|
||||
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();
|
||||
layout->addLayout(btns_layout);
|
||||
layout->addLayout(labels_layout);
|
||||
layout->addWidget(m_matching_results_table);
|
||||
layout->addLayout(help_reset_layout);
|
||||
layout->addLayout(bottom_controls_layout);
|
||||
|
||||
setLayout(layout);
|
||||
resize(515, 400);
|
||||
|
@ -115,11 +135,14 @@ void CodeDiffDialog::ConnectWidgets()
|
|||
m_record_btn->setStyleSheet(RECORD_BUTTON_STYLESHEET);
|
||||
});
|
||||
#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_include_btn, &QPushButton::pressed, [this]() { Update(true); });
|
||||
connect(m_exclude_btn, &QPushButton::pressed, [this]() { Update(false); });
|
||||
connect(m_include_btn, &QPushButton::pressed, [this]() { Update(UpdateType::Include); });
|
||||
connect(m_exclude_btn, &QPushButton::pressed, [this]() { Update(UpdateType::Exclude); });
|
||||
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_help_btn, &QPushButton::pressed, this, &CodeDiffDialog::InfoDisp);
|
||||
connect(m_matching_results_table, &CodeDiffDialog::customContextMenuRequested, this,
|
||||
|
@ -133,6 +156,103 @@ void CodeDiffDialog::OnClickItem()
|
|||
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()
|
||||
{
|
||||
if (m_record_btn->isChecked())
|
||||
|
@ -344,7 +464,7 @@ void CodeDiffDialog::RemoveMatchingSymbolsFromIncludes(const std::vector<Diff>&
|
|||
m_include.end());
|
||||
}
|
||||
|
||||
void CodeDiffDialog::Update(bool include)
|
||||
void CodeDiffDialog::Update(UpdateType type)
|
||||
{
|
||||
// Wrap everything in a pause
|
||||
Core::State old_state = Core::GetState();
|
||||
|
@ -352,15 +472,18 @@ void CodeDiffDialog::Update(bool include)
|
|||
Core::SetState(Core::State::Paused);
|
||||
|
||||
// Main process
|
||||
if (include)
|
||||
if (type == UpdateType::Include)
|
||||
{
|
||||
OnInclude();
|
||||
}
|
||||
else
|
||||
else if (type == UpdateType::Exclude)
|
||||
{
|
||||
OnExclude();
|
||||
}
|
||||
|
||||
if (type != UpdateType::Backup && m_autosave_check->isChecked() && !m_include.empty())
|
||||
SaveDataBackup();
|
||||
|
||||
const auto create_item = [](const QString& string = {}, const u32 address = 0x00000000) {
|
||||
QTableWidgetItem* item = new QTableWidgetItem(string);
|
||||
item->setData(Qt::UserRole, address);
|
||||
|
@ -428,7 +551,9 @@ void CodeDiffDialog::InfoDisp()
|
|||
"list "
|
||||
"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 "
|
||||
"results."));
|
||||
"results.\n\n"
|
||||
"Saving will store the current list in Dolphin's Log folder (File -> Open User "
|
||||
"Folder)"));
|
||||
ModalMessageBox::information(
|
||||
this, tr("Code Diff Tool Help"),
|
||||
tr("Example:\n"
|
||||
|
@ -497,21 +622,27 @@ void CodeDiffDialog::OnSetBLR()
|
|||
if (!symbol)
|
||||
return;
|
||||
|
||||
MarkRowBLR(item->row());
|
||||
if (m_autosave_check->isChecked())
|
||||
SaveDataBackup();
|
||||
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
Core::CPUThreadGuard guard(system);
|
||||
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, 1)->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, 4)->setForeground(QBrush(Qt::red));
|
||||
m_matching_results_table->item(row, 4)->setText(QStringLiteral("X"));
|
||||
|
||||
m_code_widget->Update();
|
||||
}
|
||||
|
||||
void CodeDiffDialog::UpdateItem()
|
||||
|
@ -533,3 +664,10 @@ void CodeDiffDialog::UpdateItem()
|
|||
QString::fromStdString(symbolName).replace(QStringLiteral("\t"), QStringLiteral(" "));
|
||||
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 QLabel;
|
||||
class QPushButton;
|
||||
class QCheckBox;
|
||||
class QTableWidget;
|
||||
|
||||
struct Diff
|
||||
|
@ -32,8 +33,17 @@ public:
|
|||
void reject() override;
|
||||
|
||||
private:
|
||||
enum class UpdateType
|
||||
{
|
||||
Include,
|
||||
Exclude,
|
||||
Backup
|
||||
};
|
||||
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
void SaveDataBackup();
|
||||
void LoadDataBackup();
|
||||
void ClearData();
|
||||
void ClearBlockCache();
|
||||
void OnClickItem();
|
||||
|
@ -43,7 +53,7 @@ private:
|
|||
void OnExclude();
|
||||
void RemoveMissingSymbolsFromIncludes(const std::vector<Diff>& symbol_diff);
|
||||
void RemoveMatchingSymbolsFromIncludes(const std::vector<Diff>& symbol_list);
|
||||
void Update(bool include);
|
||||
void Update(UpdateType type);
|
||||
void InfoDisp();
|
||||
|
||||
void OnContextMenu();
|
||||
|
@ -52,15 +62,20 @@ private:
|
|||
void OnDelete();
|
||||
void OnSetBLR();
|
||||
|
||||
void MarkRowBLR(int row);
|
||||
void UpdateItem();
|
||||
void UpdateButtons(bool running);
|
||||
|
||||
QTableWidget* m_matching_results_table;
|
||||
QCheckBox* m_autosave_check;
|
||||
QLabel* m_exclude_size_label;
|
||||
QLabel* m_include_size_label;
|
||||
QPushButton* m_exclude_btn;
|
||||
QPushButton* m_include_btn;
|
||||
QPushButton* m_record_btn;
|
||||
QPushButton* m_reset_btn;
|
||||
QPushButton* m_save_btn;
|
||||
QPushButton* m_load_btn;
|
||||
QPushButton* m_help_btn;
|
||||
CodeWidget* m_code_widget;
|
||||
|
||||
|
|
Loading…
Reference in New Issue