Merge pull request #9541 from InusualZ/detecting-rso
Symbols: Fix RSO Modules detection algorithm
This commit is contained in:
commit
f36b1cbb2a
|
@ -5,6 +5,7 @@
|
||||||
#include "DolphinQt/MenuBar.h"
|
#include "DolphinQt/MenuBar.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
#include "DolphinQt/AboutDialog.h"
|
#include "DolphinQt/AboutDialog.h"
|
||||||
#include "DolphinQt/Host.h"
|
#include "DolphinQt/Host.h"
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
|
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
#include "DolphinQt/Updater.h"
|
#include "DolphinQt/Updater.h"
|
||||||
|
|
||||||
|
@ -1297,48 +1299,26 @@ void MenuBar::GenerateSymbolsFromRSO()
|
||||||
|
|
||||||
void MenuBar::GenerateSymbolsFromRSOAuto()
|
void MenuBar::GenerateSymbolsFromRSOAuto()
|
||||||
{
|
{
|
||||||
constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"};
|
ParallelProgressDialog progress(tr("Modules found: %1").arg(0), tr("Cancel"), 0, 0, this);
|
||||||
const AddressSpace::Accessors* accessors =
|
progress.GetRaw()->setWindowTitle(tr("Detecting RSO Modules"));
|
||||||
AddressSpace::GetAccessors(AddressSpace::Type::Effective);
|
progress.GetRaw()->setMinimumDuration(1000 * 10);
|
||||||
std::vector<std::pair<u32, std::string>> matches;
|
progress.GetRaw()->setWindowModality(Qt::WindowModal);
|
||||||
|
|
||||||
// Find filepath to elf/plf commonly used by RSO modules
|
auto future = std::async(std::launch::async, [&progress, this]() -> RSOVector {
|
||||||
for (const auto& str : search_for)
|
progress.SetValue(0);
|
||||||
{
|
auto matches = DetectRSOModules(progress);
|
||||||
u32 next = 0;
|
progress.Reset();
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
auto found_addr =
|
|
||||||
accessors->Search(next, reinterpret_cast<const u8*>(str.data()), str.size() + 1, true);
|
|
||||||
|
|
||||||
if (!found_addr.has_value())
|
return matches;
|
||||||
break;
|
});
|
||||||
next = *found_addr + 1;
|
progress.GetRaw()->exec();
|
||||||
|
|
||||||
// Get the beginning of the string
|
auto matches = future.get();
|
||||||
found_addr = accessors->Search(*found_addr, reinterpret_cast<const u8*>(""), 1, false);
|
|
||||||
if (!found_addr.has_value())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Get the string reference
|
|
||||||
const u32 ref_addr = *found_addr + 1;
|
|
||||||
const std::array<u8, 4> ref = {static_cast<u8>(ref_addr >> 24),
|
|
||||||
static_cast<u8>(ref_addr >> 16),
|
|
||||||
static_cast<u8>(ref_addr >> 8), static_cast<u8>(ref_addr)};
|
|
||||||
found_addr = accessors->Search(ref_addr, ref.data(), ref.size(), false);
|
|
||||||
if (!found_addr.has_value() || *found_addr < 16)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Go to the beginning of the RSO header
|
|
||||||
matches.emplace_back(*found_addr - 16, PowerPC::HostGetString(ref_addr, 128));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList items;
|
QStringList items;
|
||||||
for (const auto& match : matches)
|
for (const auto& match : matches)
|
||||||
{
|
{
|
||||||
const QString item = QLatin1String("%1 %2");
|
const QString item = QLatin1String("%1 %2");
|
||||||
|
|
||||||
items << item.arg(QString::number(match.first, 16), QString::fromStdString(match.second));
|
items << item.arg(QString::number(match.first, 16), QString::fromStdString(match.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,6 +1348,107 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RSOVector MenuBar::DetectRSOModules(ParallelProgressDialog& progress)
|
||||||
|
{
|
||||||
|
constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"};
|
||||||
|
|
||||||
|
const AddressSpace::Accessors* accessors =
|
||||||
|
AddressSpace::GetAccessors(AddressSpace::Type::Effective);
|
||||||
|
|
||||||
|
RSOVector matches;
|
||||||
|
|
||||||
|
// Find filepath to elf/plf commonly used by RSO modules
|
||||||
|
for (const auto& str : search_for)
|
||||||
|
{
|
||||||
|
u32 next = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (progress.WasCanceled())
|
||||||
|
{
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found_addr =
|
||||||
|
accessors->Search(next, reinterpret_cast<const u8*>(str.data()), str.size() + 1, true);
|
||||||
|
|
||||||
|
if (!found_addr.has_value())
|
||||||
|
break;
|
||||||
|
|
||||||
|
next = *found_addr + 1;
|
||||||
|
|
||||||
|
// Non-null data can precede the module name.
|
||||||
|
// Get the maximum name length that a module could have.
|
||||||
|
auto get_max_module_name_len = [found_addr] {
|
||||||
|
constexpr u32 MODULE_NAME_MAX_LENGTH = 260;
|
||||||
|
u32 len = 0;
|
||||||
|
|
||||||
|
for (; len < MODULE_NAME_MAX_LENGTH; ++len)
|
||||||
|
{
|
||||||
|
const auto res = PowerPC::HostRead_U8(*found_addr - (len + 1));
|
||||||
|
if (!std::isprint(res))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (progress.WasCanceled())
|
||||||
|
{
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto max_name_length = get_max_module_name_len();
|
||||||
|
auto found = false;
|
||||||
|
u32 module_name_length = 0;
|
||||||
|
|
||||||
|
// Look for the Module Name Offset Field based on each possible length
|
||||||
|
for (u32 i = 0; i < max_name_length; ++i)
|
||||||
|
{
|
||||||
|
if (progress.WasCanceled())
|
||||||
|
{
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto lookup_addr = (*found_addr - max_name_length) + i;
|
||||||
|
|
||||||
|
const std::array<u8, 4> ref = {
|
||||||
|
static_cast<u8>(lookup_addr >> 24), static_cast<u8>(lookup_addr >> 16),
|
||||||
|
static_cast<u8>(lookup_addr >> 8), static_cast<u8>(lookup_addr)};
|
||||||
|
|
||||||
|
// Get the field (Module Name Offset) that point to the string
|
||||||
|
const auto module_name_offset_addr =
|
||||||
|
accessors->Search(lookup_addr, ref.data(), ref.size(), false);
|
||||||
|
if (!module_name_offset_addr.has_value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// The next 4 bytes should be the module name length
|
||||||
|
module_name_length = accessors->ReadU32(*module_name_offset_addr + 4);
|
||||||
|
if (module_name_length == max_name_length - i + str.length())
|
||||||
|
{
|
||||||
|
found_addr = module_name_offset_addr;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto module_name_offset = accessors->ReadU32(*found_addr);
|
||||||
|
|
||||||
|
// Go to the beginning of the RSO header
|
||||||
|
matches.emplace_back(*found_addr - 16,
|
||||||
|
PowerPC::HostGetString(module_name_offset, module_name_length));
|
||||||
|
|
||||||
|
progress.SetLabelText(tr("Modules found: %1").arg(matches.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
void MenuBar::LoadSymbolMap()
|
void MenuBar::LoadSymbolMap()
|
||||||
{
|
{
|
||||||
std::string existing_map_file, writable_map_file;
|
std::string existing_map_file, writable_map_file;
|
||||||
|
|
|
@ -7,11 +7,15 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
class ParallelProgressDialog;
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
@ -28,6 +32,9 @@ namespace UICommon
|
||||||
class GameFile;
|
class GameFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using RSOPairEntry = std::pair<u32, std::string>;
|
||||||
|
using RSOVector = std::vector<RSOPairEntry>;
|
||||||
|
|
||||||
class MenuBar final : public QMenuBar
|
class MenuBar final : public QMenuBar
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -155,6 +162,7 @@ private:
|
||||||
void GenerateSymbolsFromSignatureDB();
|
void GenerateSymbolsFromSignatureDB();
|
||||||
void GenerateSymbolsFromRSO();
|
void GenerateSymbolsFromRSO();
|
||||||
void GenerateSymbolsFromRSOAuto();
|
void GenerateSymbolsFromRSOAuto();
|
||||||
|
RSOVector DetectRSOModules(ParallelProgressDialog& progress);
|
||||||
void LoadSymbolMap();
|
void LoadSymbolMap();
|
||||||
void LoadOtherSymbolMap();
|
void LoadOtherSymbolMap();
|
||||||
void LoadBadSymbolMap();
|
void LoadBadSymbolMap();
|
||||||
|
|
Loading…
Reference in New Issue