Merge pull request #3514 from gookie-dev/perf/kernel-module-info-frame-tables

perf(libkernel): read a loaded image's unwind tables once in sceKernelGetModuleInfoFromAddr
This commit is contained in:
Adrià 2026-10-11 23:29:38 +02:00 committed by GitHub
commit 989146c3b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 2 deletions

View File

@ -22,7 +22,9 @@
#else
#include <dlfcn.h>
#include <link.h>
#include <mutex>
#include <unistd.h>
#include <unordered_map>
#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<std::uintptr_t, EhFrame::Tables> 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;

View File

@ -114,5 +114,16 @@ int main(int argc, char** argv) {
ModuleInfoEx unset{};
unset.st_size = 0xf0000;
Require(sceKernelGetModuleInfoFromAddr(reinterpret_cast<std::uintptr_t>(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);
}