Skip to content

Commit

Permalink
Loader: make dynsym handling more generic
Browse files Browse the repository at this point in the history
dynsym is not hardcoded to handle Elf64_Sym only anymore, and a templated ResolveSymbol function has been introduced to easily support Elf32_Sym lookup in the future.
  • Loading branch information
nickbeth committed Feb 21, 2024
1 parent 1102f42 commit bdb4e3f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
15 changes: 9 additions & 6 deletions app/src/main/cpp/skyline/loader/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace skyline::loader {

auto patch{state.nce->GetPatchData(executable.text.contents)};

span dynsym{reinterpret_cast<Elf64_Sym *>(executable.ro.contents.data() + executable.dynsym.offset), executable.dynsym.size / sizeof(Elf64_Sym)};
span dynsym{reinterpret_cast<u8 *>(executable.ro.contents.data() + executable.dynsym.offset), executable.dynsym.size};
span dynstr{reinterpret_cast<char *>(executable.ro.contents.data() + executable.dynstr.offset), executable.dynstr.size};

// Get patching info for symbols that we want to hook if symbol hooking is enabled
Expand Down Expand Up @@ -70,8 +70,8 @@ namespace skyline::loader {
.name = name,
.patchName = name + ".patch",
.hookName = name + ".hook",
.symbols = {dynsym.begin(), dynsym.end()},
.symbolStrings = {dynstr.begin(), dynstr.end()},
.symbols = dynsym,
.symbolStrings = dynstr,
};
executables.insert(std::upper_bound(executables.begin(), executables.end(), base, [](void *ptr, const ExecutableSymbolicInfo &it) { return ptr < it.patchStart; }), std::move(symbolicInfo));
}
Expand All @@ -87,13 +87,16 @@ namespace skyline::loader {
return {base, size, executableBase + executable.text.offset};
}

template<ElfSymbol ElfSym>
Loader::SymbolInfo Loader::ResolveSymbol(void *ptr) {
auto executable{std::lower_bound(executables.begin(), executables.end(), ptr, [](const ExecutableSymbolicInfo &it, void *ptr) { return it.programEnd < ptr; })};
auto symbols{executable->symbols.template cast<ElfSym>()};

if (executable != executables.end() && ptr >= executable->patchStart && ptr <= executable->programEnd) {
if (ptr >= executable->programStart) {
auto offset{reinterpret_cast<u8 *>(ptr) - reinterpret_cast<u8 *>(executable->programStart)};
auto symbol{std::find_if(executable->symbols.begin(), executable->symbols.end(), [&offset](const Elf64_Sym &sym) { return sym.st_value <= offset && sym.st_value + sym.st_size > offset; })};
if (symbol != executable->symbols.end() && symbol->st_name && symbol->st_name < executable->symbolStrings.size()) {
auto symbol{std::find_if(symbols.begin(), symbols.end(), [&offset](const ElfSym &sym) { return sym.st_value <= offset && sym.st_value + sym.st_size > offset; })};
if (symbol != symbols.end() && symbol->st_name && symbol->st_name < executable->symbolStrings.size()) {
return {executable->symbolStrings.data() + symbol->st_name, executable->name};
} else {
return {.executableName = executable->name};
Expand All @@ -109,7 +112,7 @@ namespace skyline::loader {

inline std::string GetFunctionStackTrace(Loader *loader, void *pointer) {
Dl_info info;
auto symbol{loader->ResolveSymbol(pointer)};
auto symbol{loader->ResolveSymbol64(pointer)};
if (symbol.name) {
int status{};
size_t length{};
Expand Down
20 changes: 18 additions & 2 deletions app/src/main/cpp/skyline/loader/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
#include "executable.h"

namespace skyline::loader {
/**
* @brief A concept that checks if a type is either a 32-bit or a 64-bit ELF symbol
* @tparam T The type to check
*/
template<typename T>
concept ElfSymbol = std::same_as<T, Elf32_Sym> || std::same_as<T, Elf64_Sym>;

/**
* @brief The types of ROM files
* @note This needs to be synchronized with emu.skyline.loader.BaseLoader.RomFormat
Expand Down Expand Up @@ -60,8 +67,8 @@ namespace skyline::loader {
std::string name; //!< The name of the executable
std::string patchName; //!< The name of the patch section
std::string hookName; //!< The name of the hook section
std::vector<Elf64_Sym> symbols; //!< A span over the .dynsym section
std::vector<char> symbolStrings; //!< A span over the .dynstr section
span<u8> symbols; //!< A span over the .dynsym section, this may be casted to the appropriate Elf_Sym type on demand
span<char> symbolStrings; //!< A span over the .dynstr section
};

std::vector<ExecutableSymbolicInfo> executables;
Expand Down Expand Up @@ -110,8 +117,17 @@ namespace skyline::loader {
* @return All symbolic information about the symbol for the specified address
* @note If a symbol isn't found then SymbolInfo::name will be nullptr
*/
template<ElfSymbol ElfSym>
SymbolInfo ResolveSymbol(void *ptr);

/**
* @return All symbolic information about the 64-bit symbol for the specified address
* @note If a symbol isn't found then SymbolInfo::name will be nullptr
*/
SymbolInfo ResolveSymbol64(void *ptr) {
return ResolveSymbol<Elf64_Sym>(ptr);
}

/**
* @param frame The initial stack frame or the calling function's stack frame by default
* @return A string with the stack trace based on the supplied context
Expand Down

0 comments on commit bdb4e3f

Please sign in to comment.