diff options
| author | Fernando S <fsahmkow27@gmail.com> | 2022-04-11 18:40:34 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-11 18:40:34 +0200 | 
| commit | b86cfe159fe8fd4256a83db6fc4913a83ac37f00 (patch) | |
| tree | 8b49faf932128e9b281e7789bbbaa3eb5a3905af | |
| parent | 4ad6bca31c231ce55268859f8c201372c2895f2d (diff) | |
| parent | b29242862bb650bd3c0d3dbad0466a30d2d015e5 (diff) | |
Merge pull request #8180 from liamwhite/symbols
core: extract symbol reading
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 141 | ||||
| -rw-r--r-- | src/core/arm/symbols.cpp | 190 | ||||
| -rw-r--r-- | src/core/arm/symbols.h | 27 | 
4 files changed, 231 insertions, 129 deletions
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<std::pair<ELFSymbol, std::string>>; - -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<char>(c); -        } - -        symbol_index += symbol_entry_size; -        out.push_back({symbol, name}); -    } - -    return out; -} - -std::optional<std::string> 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::BacktraceEntry> ARM_Interface::GetBacktraceFromContex          return {};      } -    std::map<std::string, Symbols> symbols; +    std::map<std::string, Symbols::Symbols> 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::BacktraceEntry> 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::BacktraceEntry> ARM_Interface::GetBacktrace() const {          return {};      } -    std::map<std::string, Symbols> symbols; +    std::map<std::string, Symbols::Symbols> 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::BacktraceEntry> 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 <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 == 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<char>(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<u64, ELF64Symbol>(ReadBytes); +    } else { +        return GetSymbols<u32, ELF32Symbol>(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, ELF64Symbol>(ReadBytes); +    } else { +        return GetSymbols<u32, ELF32Symbol>(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; +} + +} // 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 <map> +#include <optional> +#include <span> +#include <string> +#include <utility> + +#include "common/common_types.h" + +namespace Core::Memory { +class Memory; +} // namespace Core::Memory + +namespace Core::Symbols { + +using Symbols = std::map<std::string, std::pair<VAddr, std::size_t>, std::less<>>; + +Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64 = true); +Symbols GetSymbols(std::span<const u8> data, bool is_64 = true); +std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr); + +} // namespace Core::Symbols  | 
