// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include "common/types.h" #include "core/loader/elf.h" #include "core/loader/symbols_resolver.h" namespace Core { static constexpr size_t SCE_DBG_MAX_NAME_LENGTH = 256; static constexpr size_t SCE_DBG_MAX_SEGMENTS = 4; static constexpr size_t SCE_DBG_NUM_FINGERPRINT = 20; struct OrbisKernelModuleSegmentInfo { VAddr address; u32 size; s32 prot; }; struct OrbisKernelModuleInfo { u64 st_size = sizeof(OrbisKernelModuleInfo); std::array name; std::array segments; u32 num_segments; std::array fingerprint; }; struct OrbisKernelModuleInfoEx { u64 st_size = sizeof(OrbisKernelModuleInfoEx); std::array name; s32 id; u32 tls_index; VAddr tls_init_addr; u32 tls_init_size; u32 tls_size; u32 tls_offset; u32 tls_align; VAddr init_proc_addr; VAddr fini_proc_addr; u64 reserved1; u64 reserved2; VAddr eh_frame_hdr_addr; VAddr eh_frame_addr; u32 eh_frame_hdr_size; u32 eh_frame_size; std::array segments; u32 segment_count; }; struct ModuleInfo { bool operator==(const ModuleInfo& other) const { return version_major == other.version_major && version_minor == other.version_minor && name == other.name; } std::string name; union { u64 value; struct { u32 name_offset; u8 version_minor; u8 version_major; u16 id; }; }; std::string enc_id; }; struct LibraryInfo { bool operator==(const LibraryInfo& other) const { return version == other.version && name == other.name; } std::string name; union { u64 value; struct { u32 name_offset; u16 version; u16 id; }; }; std::string enc_id; }; struct ThreadLocalImage { u32 align; u32 image_size; u32 offset; u32 modid; VAddr image_virtual_addr; u32 init_image_size; }; struct DynamicModuleInfo { void* hash_table = nullptr; u64 hash_table_size = 0; char* str_table = nullptr; u64 str_table_size = 0; elf_symbol* symbol_table = nullptr; u64 symbol_table_total_size = 0; u64 symbol_table_entries_size = 0; u64 init_virtual_addr = 0; u64 fini_virtual_addr = 0; u64 pltgot_virtual_addr = 0; u64 init_array_virtual_addr = 0; u64 fini_array_virtual_addr = 0; u64 preinit_array_virtual_addr = 0; u64 init_array_size = 0; u64 fini_array_size = 0; u64 preinit_array_size = 0; elf_relocation* jmp_relocation_table = nullptr; u64 jmp_relocation_table_size = 0; s64 jmp_relocation_type = 0; elf_relocation* relocation_table = nullptr; u64 relocation_table_size = 0; u64 relocation_table_entries_size = 0; u64 debug = 0; u64 textrel = 0; u64 flags = 0; std::vector needed; std::vector import_modules; std::vector export_modules; std::vector import_libs; std::vector export_libs; std::string filename; }; using ModuleFunc = int (*)(size_t, const void*); class MemoryManager; class Module { public: explicit Module(Core::MemoryManager* memory, const std::filesystem::path& file, u32& max_tls_index); ~Module(); VAddr GetBaseAddress() const noexcept { return base_virtual_addr; } VAddr GetEntryAddress() const noexcept { return base_virtual_addr + elf.GetElfEntry(); } OrbisKernelModuleInfo GetModuleInfo() const noexcept { return info; } bool IsValid() const noexcept { return base_virtual_addr != 0; } bool IsSharedLib() const noexcept { return elf.IsSharedLib(); } void* FindByName(std::string_view name) { const auto symbols = export_sym.GetSymbols(); const auto it = std::ranges::find(symbols, name, &Loader::SymbolRecord::nid_name); if (it != symbols.end()) { return reinterpret_cast(it->virtual_address); } return nullptr; } template T GetProcParam() const noexcept { return reinterpret_cast(proc_param_virtual_addr); } std::span GetImportModules() const { return dynamic_info.import_modules; } std::span GetExportModules() const { return dynamic_info.export_modules; } std::span GetImportLibs() const { return dynamic_info.import_libs; } std::span GetExportLibs() const { return dynamic_info.export_libs; } void ForEachRelocation(auto&& func) { for (u32 i = 0; i < dynamic_info.relocation_table_size / sizeof(elf_relocation); i++) { func(&dynamic_info.relocation_table[i], i, false); } for (u32 i = 0; i < dynamic_info.jmp_relocation_table_size / sizeof(elf_relocation); i++) { func(&dynamic_info.jmp_relocation_table[i], i, true); } } void SetRelaBit(u32 index) { rela_bits[index >> 3] |= (1 << (index & 7)); } bool TestRelaBit(u32 index) const { return (rela_bits[index >> 3] >> (index & 7)) & 1; } s32 Start(size_t args, const void* argp, void* param); void LoadModuleToMemory(u32& max_tls_index); void LoadDynamicInfo(); void LoadSymbols(); OrbisKernelModuleInfoEx GetModuleInfoEx() const; const ModuleInfo* FindModule(std::string_view id); const LibraryInfo* FindLibrary(std::string_view id); public: Core::MemoryManager* memory; std::filesystem::path file; std::string name; Loader::Elf elf; u64 aligned_base_size{}; VAddr base_virtual_addr{}; VAddr proc_param_virtual_addr{}; VAddr eh_frame_hdr_addr{}; VAddr eh_frame_addr{}; u32 eh_frame_hdr_size{}; u32 eh_frame_size{}; DynamicModuleInfo dynamic_info{}; std::vector m_dynamic; std::vector m_dynamic_data; Loader::SymbolsResolver export_sym; Loader::SymbolsResolver import_sym; ThreadLocalImage tls{}; OrbisKernelModuleInfo info{}; std::vector rela_bits; }; } // namespace Core