Devtools: Add Module Viewer (#2976)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / linux-sdl-gcc (push) Blocked by required conditions
Build and Release / linux-qt-gcc (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions

* impl

* add User or Sysmodule detection

* fix compiler warning

* clang

* fix string

* add HLE

* prevent crash

* fix mutex

* remove ref in arg

* cleanup

* move gamefolder to elfinfo
This commit is contained in:
Fire Cube 2025-05-24 14:15:10 +02:00 committed by GitHub
parent 10d09ac977
commit 149898193f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 162 additions and 0 deletions

View file

@ -622,6 +622,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/widget/imgui_memory_editor.h
src/core/devtools/widget/memory_map.cpp
src/core/devtools/widget/memory_map.h
src/core/devtools/widget/module_list.cpp
src/core/devtools/widget/module_list.h
src/core/devtools/widget/reg_popup.cpp
src/core/devtools/widget/reg_popup.h
src/core/devtools/widget/reg_view.cpp

View file

@ -71,6 +71,7 @@ class ElfInfo {
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
std::filesystem::path game_folder{};
public:
static constexpr u32 FW_15 = 0x1500000;
@ -123,6 +124,10 @@ public:
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path;
}
[[nodiscard]] const std::filesystem::path& GetGameFolder() const {
return game_folder;
}
};
} // namespace Common

View file

@ -17,6 +17,7 @@
#include "widget/frame_dump.h"
#include "widget/frame_graph.h"
#include "widget/memory_map.h"
#include "widget/module_list.h"
#include "widget/shader_list.h"
extern std::unique_ptr<Vulkan::Presenter> presenter;
@ -40,6 +41,7 @@ static bool just_opened_options = false;
static Widget::MemoryMapViewer memory_map;
static Widget::ShaderList shader_list;
static Widget::ModuleList module_list;
// clang-format off
static std::string help_text =
@ -108,6 +110,9 @@ void L::DrawMenuBar() {
if (MenuItem("Memory map")) {
memory_map.open = true;
}
if (MenuItem("Module list")) {
module_list.open = true;
}
ImGui::EndMenu();
}
@ -256,6 +261,9 @@ void L::DrawAdvanced() {
if (shader_list.open) {
shader_list.Draw();
}
if (module_list.open) {
module_list.Draw();
}
}
void L::DrawSimple() {

View file

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "module_list.h"
#include <imgui.h>
#include "common.h"
#include "core/debug_state.h"
#include "imgui/imgui_std.h"
using namespace ImGui;
namespace Core::Devtools::Widget {
void ModuleList::Draw() {
SetNextWindowSize({550.0f, 600.0f}, ImGuiCond_FirstUseEver);
if (!Begin("Module List", &open)) {
End();
return;
}
if (BeginTable("ModuleTable", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
ImGuiTableFlags_RowBg)) {
TableSetupColumn("Modulname", ImGuiTableColumnFlags_WidthStretch);
TableHeadersRow();
std::scoped_lock lock(modules_mutex);
for (const auto& module : modules) {
TableNextRow();
TableSetColumnIndex(0);
TextUnformatted(module.name.c_str());
TableSetColumnIndex(1);
if (module.is_sys_module) {
TextColored({0.2f, 0.6f, 0.8f, 1.0f}, "System Module");
} else {
TextColored({0.8f, 0.4f, 0.2f, 1.0f}, "Game Module");
}
TableSetColumnIndex(2);
if (module.is_lle) {
TextColored({0.4f, 0.7f, 0.4f, 1.0f}, "LLE");
} else {
TextColored({0.7f, 0.4f, 0.5f, 1.0f}, "HLE");
}
}
EndTable();
}
End();
}
} // namespace Core::Devtools::Widget

View file

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <algorithm>
#include <filesystem>
#include <mutex>
#include <string>
#include <vector>
#include "common/elf_info.h"
#include "common/path_util.h"
namespace Core::Devtools::Widget {
class ModuleList {
public:
ModuleList() = default;
~ModuleList() = default;
void Draw();
bool open = false;
static bool IsSystemModule(const std::filesystem::path& path) {
const auto sys_modules_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();
const auto path_str = abs_path.string();
const auto sys_path_str = abs_sys_path.string();
return path_str.starts_with(sys_path_str);
}
static bool IsSystemModule(const std::string& name) {
const auto game_modules_path = Common::ElfInfo::Instance().GetGameFolder() / "sce_module";
const auto prx_path = game_modules_path / name;
if (!std::filesystem::exists(prx_path)) {
return true;
}
return false;
}
static void AddModule(const std::string& name, std::filesystem::path path) {
if (name == "eboot.bin") {
return;
}
std::scoped_lock lock(modules_mutex);
modules.push_back({name, IsSystemModule(path), true});
}
static void AddModule(std::string name) {
name = name + ".prx";
std::scoped_lock lock(modules_mutex);
bool is_sys_module = IsSystemModule(name);
bool is_lle = false;
auto it = std::find_if(modules.begin(), modules.end(),
[&name, is_sys_module, is_lle](const ModuleInfo& entry) {
return entry.name == name && !entry.is_lle;
});
if (it == modules.end()) {
modules.push_back({name, is_sys_module, is_lle});
}
}
private:
struct ModuleInfo {
std::string name;
bool is_sys_module;
bool is_lle;
};
static inline std::mutex modules_mutex;
static inline std::vector<ModuleInfo> modules;
};
} // namespace Core::Devtools::Widget

View file

@ -12,6 +12,7 @@
#include "common/thread.h"
#include "core/aerolib/aerolib.h"
#include "core/aerolib/stubs.h"
#include "core/devtools/widget/module_list.h"
#include "core/libraries/kernel/memory.h"
#include "core/libraries/kernel/threads.h"
#include "core/linker.h"
@ -147,6 +148,9 @@ s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
num_static_modules += !is_dynamic;
m_modules.emplace_back(std::move(module));
Core::Devtools::Widget::ModuleList::AddModule(elf_name.filename().string(), elf_name);
return m_modules.size() - 1;
}
@ -325,6 +329,9 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul
}
if (record) {
*return_info = *record;
Core::Devtools::Widget::ModuleList::AddModule(sr.library);
return true;
}

View file

@ -25,6 +25,7 @@
#include "common/polyfill_thread.h"
#include "common/scm_rev.h"
#include "common/singleton.h"
#include "core/devtools/widget/module_list.h"
#include "core/file_format/psf.h"
#include "core/file_format/trp.h"
#include "core/file_sys/fs.h"
@ -188,6 +189,8 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
game_info.splash_path = pic1_path;
}
game_info.game_folder = game_folder;
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
std::string window_title = "";
std::string remote_url(Common::g_scm_remote_url);