diff --git a/core/libs/prx/libkernel/Module/src/ModuleInfo.cpp b/core/libs/prx/libkernel/Module/src/ModuleInfo.cpp index 66dc83653..b83f9a11f 100644 --- a/core/libs/prx/libkernel/Module/src/ModuleInfo.cpp +++ b/core/libs/prx/libkernel/Module/src/ModuleInfo.cpp @@ -22,7 +22,9 @@ #else #include #include +#include #include +#include #endif extern "C" std::int32_t ModuleIdForImage_nid_no_patch(const void* native); @@ -81,6 +83,24 @@ bool Contains(const dl_phdr_info& image, std::uintptr_t begin, std::uint64_t siz return false; } +struct FrameTableCache { + std::mutex mutex; + unsigned long long unloads = 0; + std::unordered_map tables; +}; + +EhFrame::Tables FrameTables(const dl_phdr_info& image, std::uintptr_t header) { + static auto& cache = *new FrameTableCache(); + std::lock_guard lock(cache.mutex); + if (cache.unloads != image.dlpi_subs) { + cache.tables.clear(); + cache.unloads = image.dlpi_subs; + } + if (const auto found = cache.tables.find(header); found != cache.tables.end()) return found->second; + const auto contains = [&](std::uintptr_t begin, std::uint64_t size) { return Contains(image, begin, size); }; + return cache.tables.emplace(header, EhFrame::ReadTables(contains, header, Caller)).first->second; +} + std::string ImageName(const dl_phdr_info& image) { std::string path = image.dlpi_name ? image.dlpi_name : ""; if (path.empty()) { @@ -111,8 +131,7 @@ void Fill(const dl_phdr_info& image, TInfo& info) { info.tls_size = ToU32(header.p_memsz, "TLS size"); info.tls_align = ToU32(header.p_align, "TLS alignment"); } else if (header.p_type == PT_GNU_EH_FRAME) { - const auto contains = [&](std::uintptr_t begin, std::uint64_t size) { return Contains(image, begin, size); }; - const auto tables = EhFrame::ReadTables(contains, address, Caller); + const auto tables = FrameTables(image, address); info.eh_frame_hdr_addr = address; info.eh_frame_hdr_size = ToU32(header.p_memsz, "eh_frame_hdr size"); info.eh_frame_addr = tables.frames; diff --git a/core/libs/tests/GuestModuleInfo.cpp b/core/libs/tests/GuestModuleInfo.cpp index b63e20a04..40eacdf81 100644 --- a/core/libs/tests/GuestModuleInfo.cpp +++ b/core/libs/tests/GuestModuleInfo.cpp @@ -114,5 +114,16 @@ int main(int argc, char** argv) { ModuleInfoEx unset{}; unset.st_size = 0xf0000; Require(sceKernelGetModuleInfoFromAddr(reinterpret_cast(add), 2, &unset) == 0 && unset.st_size == sizeof(ModuleInfoEx)); + const auto again = Query(add, 0); + Require(again.eh_frame_hdr_addr == info.eh_frame_hdr_addr && again.eh_frame_hdr_size == info.eh_frame_hdr_size); + Require(again.eh_frame_addr == info.eh_frame_addr && again.eh_frame_size == info.eh_frame_size); Require(dlclose_nid_postfix(module) == 0); + void* reloaded = dlopen_nid_postfix(argv[1], 2); + Require(reloaded != nullptr); + const void* reloadedAdd = dlsym_nid_postfix(reloaded, "GuestModuleAdd"); + Require(reloadedAdd != nullptr); + const auto fresh = Query(reloadedAdd, 0); + Require(fresh.eh_frame_size == info.eh_frame_size && fresh.eh_frame_hdr_size == info.eh_frame_hdr_size); + Require(fresh.eh_frame_addr - fresh.segments[0].address == info.eh_frame_addr - info.segments[0].address); + Require(dlclose_nid_postfix(reloaded) == 0); }