diff --git a/Source/Core/Core/HW/AddressSpace.cpp b/Source/Core/Core/HW/AddressSpace.cpp index 3a98414c30..c84f62a7ef 100644 --- a/Source/Core/Core/HW/AddressSpace.cpp +++ b/Source/Core/Core/HW/AddressSpace.cpp @@ -68,8 +68,8 @@ Accessors::iterator Accessors::end() const return nullptr; } -std::optional Accessors::Search(u32 haystack_start, u8* needle_start, u32 needle_size, - bool forwards) const +std::optional Accessors::Search(u32 haystack_start, const u8* needle_start, + std::size_t needle_size, bool forwards) const { return std::nullopt; } @@ -91,7 +91,7 @@ struct EffectiveAddressSpaceAccessors : Accessors void WriteU64(u32 address, u64 value) override { PowerPC::HostWrite_U64(value, address); } float ReadF32(u32 address) const override { return PowerPC::HostRead_F32(address); }; - bool Matches(u32 haystack_start, u8* needle_start, u32 needle_size) const + bool Matches(u32 haystack_start, const u8* needle_start, std::size_t needle_size) const { u32 page_base = haystack_start & 0xfffff000; u32 offset = haystack_start & 0x0000fff; @@ -121,7 +121,7 @@ struct EffectiveAddressSpaceAccessors : Accessors return false; } - u32 chunk_size = std::min(0x1000 - offset, needle_size); + std::size_t chunk_size = std::min(0x1000 - offset, needle_size); if (memcmp(needle_start, page_ptr + offset, chunk_size) != 0) { return false; @@ -134,7 +134,7 @@ struct EffectiveAddressSpaceAccessors : Accessors return (needle_size == 0); } - std::optional Search(u32 haystack_start, u8* needle_start, u32 needle_size, + std::optional Search(u32 haystack_start, const u8* needle_start, std::size_t needle_size, bool forward) const override { u32 haystack_address = haystack_start; @@ -190,7 +190,7 @@ struct AuxiliaryAddressSpaceAccessors : Accessors iterator end() const override { return DSP::GetARAMPtr() + GetSize(); } - std::optional Search(u32 haystack_offset, u8* needle_start, u32 needle_size, + std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, bool forward) const override { if (!IsValidAddress(haystack_offset)) @@ -264,7 +264,7 @@ struct CompositeAddressSpaceAccessors : Accessors return it->accessors->WriteU8(address, value); } - std::optional Search(u32 haystack_offset, u8* needle_start, u32 needle_size, + std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, bool forward) const override { for (const AccessorMapping& mapping : m_accessor_mappings) @@ -320,10 +320,11 @@ struct SmallBlockAccessors : Accessors return (*alloc_base == nullptr) ? nullptr : (*alloc_base + size); } - std::optional Search(u32 haystack_offset, u8* needle_start, u32 needle_size, + std::optional Search(u32 haystack_offset, const u8* needle_start, std::size_t needle_size, bool forward) const override { - if (!IsValidAddress(haystack_offset) || !IsValidAddress(haystack_offset + needle_size - 1)) + if (!IsValidAddress(haystack_offset) || + !IsValidAddress(haystack_offset + static_cast(needle_size) - 1)) { return std::nullopt; } diff --git a/Source/Core/Core/HW/AddressSpace.h b/Source/Core/Core/HW/AddressSpace.h index a02989010a..9577669bdc 100644 --- a/Source/Core/Core/HW/AddressSpace.h +++ b/Source/Core/Core/HW/AddressSpace.h @@ -40,8 +40,8 @@ struct Accessors virtual iterator begin() const; virtual iterator end() const; - virtual std::optional Search(u32 haystack_offset, u8* needle_start, u32 needle_size, - bool forward) const; + virtual std::optional Search(u32 haystack_offset, const u8* needle_start, + std::size_t needle_size, bool forward) const; virtual ~Accessors(); }; diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 75b01caba0..3f4564c27f 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -25,6 +25,7 @@ #include "Core/Core.h" #include "Core/Debugger/RSO.h" #include "Core/HLE/HLE.h" +#include "Core/HW/AddressSpace.h" #include "Core/HW/WiiSave.h" #include "Core/HW/Wiimote.h" #include "Core/IOS/ES/ES.h" @@ -1205,6 +1206,12 @@ void MenuBar::GenerateSymbolsFromSignatureDB() void MenuBar::GenerateSymbolsFromRSO() { + // i18n: RSO refers to a proprietary format for shared objects (like DLL files). + const int ret = + ModalMessageBox::question(this, tr("RSO auto-detection"), tr("Auto-detect RSO modules?")); + if (ret == QMessageBox::Yes) + return GenerateSymbolsFromRSOAuto(); + QString text = QInputDialog::getText(this, tr("Input"), tr("Enter the RSO module address:")); bool good; uint address = text.toUInt(&good, 16); @@ -1227,6 +1234,79 @@ 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; + + // 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); + + if (!found_addr.has_value()) + break; + next = *found_addr + 1; + + // 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)); + } + } + + 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)); + } + + if (items.empty()) + { + ModalMessageBox::warning(this, tr("Error"), tr("Unable to auto-detect RSO module")); + return; + } + + bool ok; + const QString item = QInputDialog::getItem( + this, tr("Input"), tr("Select the RSO module address:"), items, 0, false, &ok); + + if (!ok) + return; + + RSOChainView rso_chain; + const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16); + if (rso_chain.Load(address)) + { + rso_chain.Apply(&g_symbolDB); + emit NotifySymbolsUpdated(); + } + else + { + ModalMessageBox::warning(this, tr("Error"), tr("Failed to load RSO module at %1").arg(address)); + } +} + void MenuBar::LoadSymbolMap() { std::string existing_map_file, writable_map_file; diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index 3bdf6debcb..71c24fc837 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -153,6 +153,7 @@ private: void GenerateSymbolsFromAddress(); void GenerateSymbolsFromSignatureDB(); void GenerateSymbolsFromRSO(); + void GenerateSymbolsFromRSOAuto(); void LoadSymbolMap(); void LoadOtherSymbolMap(); void LoadBadSymbolMap();