From b29242862bb650bd3c0d3dbad0466a30d2d015e5 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 8 Apr 2022 23:53:42 -0400 Subject: [PATCH] core: extract symbol reading --- src/core/CMakeLists.txt | 2 + src/core/arm/arm_interface.cpp | 141 +++--------------------- src/core/arm/symbols.cpp | 190 +++++++++++++++++++++++++++++++++ src/core/arm/symbols.h | 27 +++++ 4 files changed, 231 insertions(+), 129 deletions(-) create mode 100644 src/core/arm/symbols.cpp create mode 100644 src/core/arm/symbols.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 81eaf0942..ffbda7925 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -13,6 +13,8 @@ add_library(core STATIC arm/dynarmic/arm_exclusive_monitor.h arm/exclusive_monitor.cpp arm/exclusive_monitor.h + arm/symbols.cpp + arm/symbols.h constants.cpp constants.h core.cpp diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 0951e1976..08bf1201d 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -8,134 +8,13 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" +#include "core/arm/symbols.h" #include "core/core.h" +#include "core/hle/kernel/k_process.h" #include "core/loader/loader.h" #include "core/memory.h" namespace Core { -namespace { - -constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; -constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; -constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; -constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; - -enum class ELFSymbolType : u8 { - None = 0, - Object = 1, - Function = 2, - Section = 3, - File = 4, - Common = 5, - TLS = 6, -}; - -enum class ELFSymbolBinding : u8 { - Local = 0, - Global = 1, - Weak = 2, -}; - -enum class ELFSymbolVisibility : u8 { - Default = 0, - Internal = 1, - Hidden = 2, - Protected = 3, -}; - -struct ELFSymbol { - u32 name_index; - union { - u8 info; - - BitField<0, 4, ELFSymbolType> type; - BitField<4, 4, ELFSymbolBinding> binding; - }; - ELFSymbolVisibility visibility; - u16 sh_index; - u64 value; - u64 size; -}; -static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); - -using Symbols = std::vector>; - -Symbols GetSymbols(VAddr text_offset, Core::Memory::Memory& memory) { - const auto mod_offset = text_offset + memory.Read32(text_offset + 4); - - if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || - memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { - return {}; - } - - const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset; - - VAddr string_table_offset{}; - VAddr symbol_table_offset{}; - u64 symbol_entry_size{}; - - VAddr dynamic_index = dynamic_offset; - while (true) { - const u64 tag = memory.Read64(dynamic_index); - const u64 value = memory.Read64(dynamic_index + 0x8); - dynamic_index += 0x10; - - if (tag == ELF_DYNAMIC_TAG_NULL) { - break; - } - - if (tag == ELF_DYNAMIC_TAG_STRTAB) { - string_table_offset = value; - } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { - symbol_table_offset = value; - } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { - symbol_entry_size = value; - } - } - - if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) { - return {}; - } - - const auto string_table_address = text_offset + string_table_offset; - const auto symbol_table_address = text_offset + symbol_table_offset; - - Symbols out; - - VAddr symbol_index = symbol_table_address; - while (symbol_index < string_table_address) { - ELFSymbol symbol{}; - memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); - - VAddr string_offset = string_table_address + symbol.name_index; - std::string name; - for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) { - name += static_cast(c); - } - - symbol_index += symbol_entry_size; - out.push_back({symbol, name}); - } - - return out; -} - -std::optional GetSymbolName(const Symbols& symbols, VAddr func_address) { - const auto iter = - std::find_if(symbols.begin(), symbols.end(), [func_address](const auto& pair) { - const auto& symbol = pair.first; - const auto end_address = symbol.value + symbol.size; - return func_address >= symbol.value && func_address < end_address; - }); - - if (iter == symbols.end()) { - return std::nullopt; - } - - return iter->second; -} - -} // Anonymous namespace constexpr u64 SEGMENT_BASE = 0x7100000000ull; @@ -169,9 +48,11 @@ std::vector ARM_Interface::GetBacktraceFromContex return {}; } - std::map symbols; + std::map symbols; for (const auto& module : modules) { - symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); + symbols.insert_or_assign(module.second, + Symbols::GetSymbols(module.first, system.Memory(), + system.CurrentProcess()->Is64BitProcess())); } for (auto& entry : out) { @@ -193,7 +74,7 @@ std::vector ARM_Interface::GetBacktraceFromContex const auto symbol_set = symbols.find(entry.module); if (symbol_set != symbols.end()) { - const auto symbol = GetSymbolName(symbol_set->second, entry.offset); + const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); if (symbol.has_value()) { // TODO(DarkLordZach): Add demangling of symbol names. entry.name = *symbol; @@ -225,9 +106,11 @@ std::vector ARM_Interface::GetBacktrace() const { return {}; } - std::map symbols; + std::map symbols; for (const auto& module : modules) { - symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); + symbols.insert_or_assign(module.second, + Symbols::GetSymbols(module.first, system.Memory(), + system.CurrentProcess()->Is64BitProcess())); } for (auto& entry : out) { @@ -249,7 +132,7 @@ std::vector ARM_Interface::GetBacktrace() const { const auto symbol_set = symbols.find(entry.module); if (symbol_set != symbols.end()) { - const auto symbol = GetSymbolName(symbol_set->second, entry.offset); + const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); if (symbol.has_value()) { // TODO(DarkLordZach): Add demangling of symbol names. entry.name = *symbol; 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 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "core/arm/symbols.h" +#include "core/core.h" +#include "core/memory.h" + +namespace Core { +namespace { + +constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; +constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; +constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; +constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; + +enum class ELFSymbolType : u8 { + None = 0, + Object = 1, + Function = 2, + Section = 3, + File = 4, + Common = 5, + TLS = 6, +}; + +enum class ELFSymbolBinding : u8 { + Local = 0, + Global = 1, + Weak = 2, +}; + +enum class ELFSymbolVisibility : u8 { + Default = 0, + Internal = 1, + Hidden = 2, + Protected = 3, +}; + +struct ELF64Symbol { + u32 name_index; + union { + u8 info; + + BitField<0, 4, ELFSymbolType> type; + BitField<4, 4, ELFSymbolBinding> binding; + }; + ELFSymbolVisibility visibility; + u16 sh_index; + u64 value; + u64 size; +}; +static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size."); + +struct ELF32Symbol { + u32 name_index; + u32 value; + u32 size; + union { + u8 info; + + BitField<0, 4, ELFSymbolType> type; + BitField<4, 4, ELFSymbolBinding> binding; + }; + ELFSymbolVisibility visibility; + u16 sh_index; +}; +static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size."); + +} // Anonymous namespace + +namespace Symbols { + +template +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 == ELF_DYNAMIC_TAG_NULL) { + break; + } + + if (tag == ELF_DYNAMIC_TAG_STRTAB) { + string_table_offset = value; + } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { + symbol_table_offset = value; + } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { + 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.name_index; + std::string name; + for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { + name += static_cast(c); + } + + symbol_index += symbol_entry_size; + out[name] = std::make_pair(symbol.value, symbol.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(ReadBytes); + } else { + return GetSymbols(ReadBytes); + } +} + +Symbols GetSymbols(std::span 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(ReadBytes); + } else { + return GetSymbols(ReadBytes); + } +} + +std::optional 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; +} + +} // namespace Symbols +} // namespace Core diff --git a/src/core/arm/symbols.h b/src/core/arm/symbols.h new file mode 100644 index 000000000..99e6a9f8e --- /dev/null +++ b/src/core/arm/symbols.h @@ -0,0 +1,27 @@ +// Copyright 2022 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include + +#include "common/common_types.h" + +namespace Core::Memory { +class Memory; +} // namespace Core::Memory + +namespace Core::Symbols { + +using Symbols = std::map, std::less<>>; + +Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64 = true); +Symbols GetSymbols(std::span data, bool is_64 = true); +std::optional GetSymbolName(const Symbols& symbols, VAddr addr); + +} // namespace Core::Symbols