| |
| |
|
|
| #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 { |
|
|
| template <typename Word, typename ELFSymbol, typename ByteReader> |
| static Symbols GetSymbols(ByteReader ReadBytes) { |
| const auto Read8{[&](u64 index) { |
| u8 ret; |
| ReadBytes(&ret, index, sizeof(u8)); |
| return ret; |
| }}; |
|
|
| const auto Read32{[&](u64 index) { |
| u32 ret; |
| ReadBytes(&ret, index, sizeof(u32)); |
| return ret; |
| }}; |
|
|
| const auto ReadWord{[&](u64 index) { |
| Word ret; |
| ReadBytes(&ret, index, sizeof(Word)); |
| return ret; |
| }}; |
|
|
| const u32 mod_offset = Read32(4); |
|
|
| if (Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { |
| return {}; |
| } |
|
|
| VAddr string_table_offset{}; |
| VAddr symbol_table_offset{}; |
| u64 symbol_entry_size{}; |
|
|
| const auto dynamic_offset = Read32(mod_offset + 0x4) + mod_offset; |
|
|
| VAddr dynamic_index = dynamic_offset; |
| while (true) { |
| const Word tag = ReadWord(dynamic_index); |
| const Word value = ReadWord(dynamic_index + sizeof(Word)); |
| dynamic_index += 2 * sizeof(Word); |
|
|
| if (tag == ElfDtNull) { |
| break; |
| } |
|
|
| if (tag == ElfDtStrtab) { |
| string_table_offset = value; |
| } else if (tag == ElfDtSymtab) { |
| symbol_table_offset = value; |
| } else if (tag == ElfDtSyment) { |
| symbol_entry_size = value; |
| } |
| } |
|
|
| if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) { |
| return {}; |
| } |
|
|
| Symbols out; |
|
|
| VAddr symbol_index = symbol_table_offset; |
| while (symbol_index < string_table_offset) { |
| ELFSymbol symbol{}; |
| ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); |
|
|
| VAddr string_offset = string_table_offset + symbol.st_name; |
| std::string name; |
| for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { |
| name += static_cast<char>(c); |
| } |
|
|
| symbol_index += symbol_entry_size; |
| out[name] = std::make_pair(symbol.st_value, symbol.st_size); |
| } |
|
|
| return out; |
| } |
|
|
| Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) { |
| const auto ReadBytes{ |
| [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; |
|
|
| if (is_64) { |
| return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| } else { |
| return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| } |
| } |
|
|
| Symbols GetSymbols(std::span<const u8> data, bool is_64) { |
| const auto ReadBytes{[&](void* ptr, size_t offset, size_t size) { |
| std::memcpy(ptr, data.data() + offset, size); |
| }}; |
|
|
| if (is_64) { |
| return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| } else { |
| return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| } |
| } |
|
|
| std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr) { |
| const auto iter = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& pair) { |
| const auto& [name, sym_info] = pair; |
| const auto& [start_address, size] = sym_info; |
| const auto end_address = start_address + size; |
| return addr >= start_address && addr < end_address; |
| }); |
|
|
| if (iter == symbols.cend()) { |
| return std::nullopt; |
| } |
|
|
| return iter->first; |
| } |
|
|
| } |
| } |
|
|