You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.8 KiB
127 lines
3.8 KiB
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "common/bit_field.h"
|
|
#include "common/common_funcs.h"
|
|
#include "common/elf.h"
|
|
#include "core/arm/symbols.h"
|
|
#include "core/core.h"
|
|
#include "core/memory.h"
|
|
|
|
using namespace Common::ELF;
|
|
|
|
namespace Core {
|
|
namespace Symbols {
|
|
|
|
struct ModuleHeaderLocation {
|
|
u32 version;
|
|
u32 header_offset;
|
|
u32 version_offset;
|
|
};
|
|
static_assert(sizeof(ModuleHeaderLocation) == 0x0C);
|
|
struct ModuleHeader {
|
|
u32 signature;
|
|
u32 dynamic_offset;
|
|
u32 bss_start_offset;
|
|
u32 bss_end_offset;
|
|
u32 exception_info_start_offset;
|
|
u32 exception_info_end_offset;
|
|
u32 module_offset;
|
|
u32 relro_start_offset;
|
|
u32 full_relro_end_offset;
|
|
u32 nx_debug_link_start_offset;
|
|
u32 nx_debug_link_end_offset;
|
|
u32 note_gnu_build_id_start_offset;
|
|
u32 note_gnu_build_id_end_offset;
|
|
};
|
|
static_assert(sizeof(ModuleHeader) == 0x34);
|
|
|
|
struct Mod32 {
|
|
using Sym = Elf32_Sym;
|
|
using Dyn = Elf32_Dyn;
|
|
};
|
|
struct Mod64 {
|
|
using Sym = Elf64_Sym;
|
|
using Dyn = Elf64_Dyn;
|
|
};
|
|
|
|
template <typename M, typename F>
|
|
static Symbols GetSymbols(F&& ReadBytes) {
|
|
const auto Read8 = [&](u64 index) {
|
|
u8 ret;
|
|
ReadBytes(&ret, index, sizeof(u8));
|
|
return ret;
|
|
};
|
|
ModuleHeaderLocation loc{};
|
|
ReadBytes(&loc, 0, sizeof(ModuleHeaderLocation));
|
|
ModuleHeader hdr;
|
|
ReadBytes(&hdr, loc.header_offset, sizeof(ModuleHeader));
|
|
if (hdr.signature != Common::MakeMagic('M', 'O', 'D', '0')) {
|
|
return {};
|
|
}
|
|
|
|
VAddr strtab_offs{};
|
|
VAddr symtab_offs{};
|
|
u64 syment_size = sizeof(typename M::Sym);
|
|
VAddr dynamic_offset = loc.header_offset + hdr.dynamic_offset;
|
|
while (true) {
|
|
typename M::Dyn dyn;
|
|
ReadBytes(&dyn, dynamic_offset, sizeof(typename M::Dyn));
|
|
dynamic_offset += sizeof(typename M::Dyn);
|
|
if (dyn.d_tag == ElfDtNull) {
|
|
break;
|
|
}
|
|
if (dyn.d_tag == ElfDtStrtab) {
|
|
strtab_offs = dyn.d_un.d_ptr;
|
|
} else if (dyn.d_tag == ElfDtSymtab) {
|
|
symtab_offs = dyn.d_un.d_ptr;
|
|
} else if (dyn.d_tag == ElfDtSyment) {
|
|
syment_size = dyn.d_un.d_val;
|
|
}
|
|
}
|
|
if (strtab_offs > 0 && symtab_offs > 0) {
|
|
Symbols out;
|
|
VAddr symbol_index = symtab_offs;
|
|
while (symbol_index < strtab_offs) {
|
|
typename M::Sym symbol{};
|
|
ReadBytes(&symbol, symbol_index, sizeof(typename M::Sym));
|
|
VAddr offs = strtab_offs + symbol.st_name;
|
|
std::string name{};
|
|
for (u8 c = Read8(offs); c != 0; c = Read8(++offs))
|
|
name += char(c);
|
|
symbol_index += syment_size;
|
|
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
|
|
}
|
|
return out;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
|
|
const auto f = [base, &memory](void* ptr, size_t offset, size_t size) {
|
|
memory.ReadBlock(base + offset, ptr, size);
|
|
};
|
|
return is_64 ? GetSymbols<Mod64>(f) : GetSymbols<Mod32>(f);
|
|
}
|
|
|
|
Symbols GetSymbols(std::span<const u8> data, bool is_64) {
|
|
const auto f = [data](void* ptr, size_t offset, size_t size) {
|
|
std::memcpy(ptr, data.data() + offset, size);
|
|
};
|
|
return is_64 ? GetSymbols<Mod64>(f) : GetSymbols<Mod32>(f);
|
|
}
|
|
|
|
std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr) {
|
|
const auto it = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& e) {
|
|
auto const [start, size] = e.second;
|
|
auto const end = start + size;
|
|
return addr >= start && addr < end;
|
|
});
|
|
return it != symbols.cend() ? std::optional<std::string>{it->first} : std::nullopt;
|
|
}
|
|
|
|
} // namespace Symbols
|
|
} // namespace Core
|