From 490db42e44ba2eeb58f6bd04606dc9df5fa4087c Mon Sep 17 00:00:00 2001 From: InusualZ Date: Sat, 27 Feb 2021 20:04:45 +0000 Subject: [PATCH 1/2] Fix detecting rso modules --- Source/Core/DolphinQt/MenuBar.cpp | 149 +++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 34 deletions(-) diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index a0fd1a0988..5b590abf14 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -5,6 +5,7 @@ #include "DolphinQt/MenuBar.h" #include +#include #include #include @@ -52,6 +53,7 @@ #include "DolphinQt/AboutDialog.h" #include "DolphinQt/Host.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" +#include "DolphinQt/QtUtils/ParallelProgressDialog.h" #include "DolphinQt/Settings.h" #include "DolphinQt/Updater.h" @@ -1297,48 +1299,26 @@ void MenuBar::GenerateSymbolsFromRSO() void MenuBar::GenerateSymbolsFromRSOAuto() { - constexpr std::array search_for = {".elf", ".plf"}; - const AddressSpace::Accessors* accessors = - AddressSpace::GetAccessors(AddressSpace::Type::Effective); - std::vector> matches; + ParallelProgressDialog progress(tr("Modules found: %1").arg(0), tr("Cancel"), 0, 0, this); + progress.GetRaw()->setWindowTitle(tr("Detecting RSO Modules")); + progress.GetRaw()->setMinimumDuration(1000 * 10); + progress.GetRaw()->setWindowModality(Qt::WindowModal); - // Find filepath to elf/plf commonly used by RSO modules - for (const auto& str : search_for) - { - u32 next = 0; - while (true) - { - auto found_addr = - accessors->Search(next, reinterpret_cast(str.data()), str.size() + 1, true); + auto future = std::async(std::launch::async, [&progress, this]() -> RSOVector { + progress.SetValue(0); + auto matches = DetectRSOModules(progress); + progress.Reset(); - if (!found_addr.has_value()) - break; - next = *found_addr + 1; + return matches; + }); + progress.GetRaw()->exec(); - // Get the beginning of the string - found_addr = accessors->Search(*found_addr, reinterpret_cast(""), 1, false); - if (!found_addr.has_value()) - continue; - - // Get the string reference - const u32 ref_addr = *found_addr + 1; - const std::array ref = {static_cast(ref_addr >> 24), - static_cast(ref_addr >> 16), - static_cast(ref_addr >> 8), static_cast(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)); - } - } + auto matches = future.get(); QStringList items; for (const auto& match : matches) { const QString item = QLatin1String("%1 %2"); - 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 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(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 ref = { + static_cast(lookup_addr >> 24), static_cast(lookup_addr >> 16), + static_cast(lookup_addr >> 8), static_cast(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() { std::string existing_map_file, writable_map_file; From c37d8267151492a312707e8a9213de6e506d6771 Mon Sep 17 00:00:00 2001 From: InusualZ Date: Sat, 27 Feb 2021 22:40:17 +0000 Subject: [PATCH 2/2] Display a progress bar to notify the user, about the work is being done --- Source/Core/DolphinQt/MenuBar.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index c0364edbd9..51845448bf 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -7,11 +7,15 @@ #include #include #include +#include #include #include +#include "Common/CommonTypes.h" + class QMenu; +class ParallelProgressDialog; namespace Core { @@ -28,6 +32,9 @@ namespace UICommon class GameFile; } +using RSOPairEntry = std::pair; +using RSOVector = std::vector; + class MenuBar final : public QMenuBar { Q_OBJECT @@ -155,6 +162,7 @@ private: void GenerateSymbolsFromSignatureDB(); void GenerateSymbolsFromRSO(); void GenerateSymbolsFromRSOAuto(); + RSOVector DetectRSOModules(ParallelProgressDialog& progress); void LoadSymbolMap(); void LoadOtherSymbolMap(); void LoadBadSymbolMap();