diff options
Diffstat (limited to 'src/core/arm/symbols.cpp')
| -rw-r--r-- | src/core/arm/symbols.cpp | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/core/arm/symbols.cpp b/src/core/arm/symbols.cpp new file mode 100644 index 000000000..26c44f0c7 --- /dev/null +++ b/src/core/arm/symbols.cpp | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | // Copyright 2022 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/bit_field.h" | ||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "core/arm/symbols.h" | ||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/memory.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | namespace { | ||
| 13 | |||
| 14 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | ||
| 15 | constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; | ||
| 16 | constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; | ||
| 17 | constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; | ||
| 18 | |||
| 19 | enum class ELFSymbolType : u8 { | ||
| 20 | None = 0, | ||
| 21 | Object = 1, | ||
| 22 | Function = 2, | ||
| 23 | Section = 3, | ||
| 24 | File = 4, | ||
| 25 | Common = 5, | ||
| 26 | TLS = 6, | ||
| 27 | }; | ||
| 28 | |||
| 29 | enum class ELFSymbolBinding : u8 { | ||
| 30 | Local = 0, | ||
| 31 | Global = 1, | ||
| 32 | Weak = 2, | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum class ELFSymbolVisibility : u8 { | ||
| 36 | Default = 0, | ||
| 37 | Internal = 1, | ||
| 38 | Hidden = 2, | ||
| 39 | Protected = 3, | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct ELF64Symbol { | ||
| 43 | u32 name_index; | ||
| 44 | union { | ||
| 45 | u8 info; | ||
| 46 | |||
| 47 | BitField<0, 4, ELFSymbolType> type; | ||
| 48 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 49 | }; | ||
| 50 | ELFSymbolVisibility visibility; | ||
| 51 | u16 sh_index; | ||
| 52 | u64 value; | ||
| 53 | u64 size; | ||
| 54 | }; | ||
| 55 | static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size."); | ||
| 56 | |||
| 57 | struct ELF32Symbol { | ||
| 58 | u32 name_index; | ||
| 59 | u32 value; | ||
| 60 | u32 size; | ||
| 61 | union { | ||
| 62 | u8 info; | ||
| 63 | |||
| 64 | BitField<0, 4, ELFSymbolType> type; | ||
| 65 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 66 | }; | ||
| 67 | ELFSymbolVisibility visibility; | ||
| 68 | u16 sh_index; | ||
| 69 | }; | ||
| 70 | static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size."); | ||
| 71 | |||
| 72 | } // Anonymous namespace | ||
| 73 | |||
| 74 | namespace Symbols { | ||
| 75 | |||
| 76 | template <typename Word, typename ELFSymbol, typename ByteReader> | ||
| 77 | static Symbols GetSymbols(ByteReader ReadBytes) { | ||
| 78 | const auto Read8{[&](u64 index) { | ||
| 79 | u8 ret; | ||
| 80 | ReadBytes(&ret, index, sizeof(u8)); | ||
| 81 | return ret; | ||
| 82 | }}; | ||
| 83 | |||
| 84 | const auto Read32{[&](u64 index) { | ||
| 85 | u32 ret; | ||
| 86 | ReadBytes(&ret, index, sizeof(u32)); | ||
| 87 | return ret; | ||
| 88 | }}; | ||
| 89 | |||
| 90 | const auto ReadWord{[&](u64 index) { | ||
| 91 | Word ret; | ||
| 92 | ReadBytes(&ret, index, sizeof(Word)); | ||
| 93 | return ret; | ||
| 94 | }}; | ||
| 95 | |||
| 96 | const u32 mod_offset = Read32(4); | ||
| 97 | |||
| 98 | if (Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { | ||
| 99 | return {}; | ||
| 100 | } | ||
| 101 | |||
| 102 | VAddr string_table_offset{}; | ||
| 103 | VAddr symbol_table_offset{}; | ||
| 104 | u64 symbol_entry_size{}; | ||
| 105 | |||
| 106 | const auto dynamic_offset = Read32(mod_offset + 0x4) + mod_offset; | ||
| 107 | |||
| 108 | VAddr dynamic_index = dynamic_offset; | ||
| 109 | while (true) { | ||
| 110 | const Word tag = ReadWord(dynamic_index); | ||
| 111 | const Word value = ReadWord(dynamic_index + sizeof(Word)); | ||
| 112 | dynamic_index += 2 * sizeof(Word); | ||
| 113 | |||
| 114 | if (tag == ELF_DYNAMIC_TAG_NULL) { | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | |||
| 118 | if (tag == ELF_DYNAMIC_TAG_STRTAB) { | ||
| 119 | string_table_offset = value; | ||
| 120 | } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { | ||
| 121 | symbol_table_offset = value; | ||
| 122 | } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { | ||
| 123 | symbol_entry_size = value; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) { | ||
| 128 | return {}; | ||
| 129 | } | ||
| 130 | |||
| 131 | Symbols out; | ||
| 132 | |||
| 133 | VAddr symbol_index = symbol_table_offset; | ||
| 134 | while (symbol_index < string_table_offset) { | ||
| 135 | ELFSymbol symbol{}; | ||
| 136 | ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); | ||
| 137 | |||
| 138 | VAddr string_offset = string_table_offset + symbol.name_index; | ||
| 139 | std::string name; | ||
| 140 | for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { | ||
| 141 | name += static_cast<char>(c); | ||
| 142 | } | ||
| 143 | |||
| 144 | symbol_index += symbol_entry_size; | ||
| 145 | out[name] = std::make_pair(symbol.value, symbol.size); | ||
| 146 | } | ||
| 147 | |||
| 148 | return out; | ||
| 149 | } | ||
| 150 | |||
| 151 | Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) { | ||
| 152 | const auto ReadBytes{ | ||
| 153 | [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; | ||
| 154 | |||
| 155 | if (is_64) { | ||
| 156 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | ||
| 157 | } else { | ||
| 158 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | Symbols GetSymbols(std::span<const u8> data, bool is_64) { | ||
| 163 | const auto ReadBytes{[&](void* ptr, size_t offset, size_t size) { | ||
| 164 | std::memcpy(ptr, data.data() + offset, size); | ||
| 165 | }}; | ||
| 166 | |||
| 167 | if (is_64) { | ||
| 168 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | ||
| 169 | } else { | ||
| 170 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr) { | ||
| 175 | const auto iter = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& pair) { | ||
| 176 | const auto& [name, sym_info] = pair; | ||
| 177 | const auto& [start_address, size] = sym_info; | ||
| 178 | const auto end_address = start_address + size; | ||
| 179 | return addr >= start_address && addr < end_address; | ||
| 180 | }); | ||
| 181 | |||
| 182 | if (iter == symbols.cend()) { | ||
| 183 | return std::nullopt; | ||
| 184 | } | ||
| 185 | |||
| 186 | return iter->first; | ||
| 187 | } | ||
| 188 | |||
| 189 | } // namespace Symbols | ||
| 190 | } // namespace Core | ||