Search both the elf symbol table and dynamic symbol table

This commit is contained in:
Jeremy Rifkin 2025-01-28 23:40:08 -06:00
parent 06c9c14995
commit 9077430b6a
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
2 changed files with 78 additions and 22 deletions

View File

@ -90,12 +90,20 @@ namespace detail {
} }
optional<std::string> elf::lookup_symbol(frame_ptr pc) { optional<std::string> elf::lookup_symbol(frame_ptr pc) {
// TODO: Also search the SHT_DYNSYM at some point, maybe if(auto symtab = get_symtab()) {
auto symtab_ = get_symtab(); if(auto symbol = lookup_symbol(pc, symtab.unwrap_value())) {
if(symtab_.is_error()) { return symbol;
return nullopt; }
} }
auto& maybe_symtab = symtab_.unwrap_value(); if(auto dynamic_symtab = get_dynamic_symtab()) {
if(auto symbol = lookup_symbol(pc, dynamic_symtab.unwrap_value())) {
return symbol;
}
}
return nullopt;
}
optional<std::string> elf::lookup_symbol(frame_ptr pc, const optional<symtab_info>& maybe_symtab) {
if(!maybe_symtab) { if(!maybe_symtab) {
return nullopt; return nullopt;
} }
@ -259,18 +267,61 @@ namespace detail {
return symtab; return symtab;
} }
if(tried_to_load_symtab) { if(tried_to_load_symtab) {
return internal_error("previous strtab load failed {}", object_path); return internal_error("previous symtab load failed {}", object_path);
} }
tried_to_load_symtab = true; tried_to_load_symtab = true;
if(is_64) { if(is_64) {
return get_symtab_impl<64>(); auto res = get_symtab_impl<64>(false);
if(res.has_value()) {
symtab = std::move(res).unwrap_value();
did_load_symtab = true;
return symtab;
} else {
return std::move(res).unwrap_error();
}
} else { } else {
return get_symtab_impl<32>(); auto res = get_symtab_impl<32>(false);
if(res.has_value()) {
symtab = std::move(res).unwrap_value();
did_load_symtab = true;
return symtab;
} else {
return std::move(res).unwrap_error();
}
}
}
Result<const optional<elf::symtab_info>&, internal_error> elf::get_dynamic_symtab() {
if(did_load_dynamic_symtab) {
return dynamic_symtab;
}
if(tried_to_load_dynamic_symtab) {
return internal_error("previous dynamic symtab load failed {}", object_path);
}
tried_to_load_dynamic_symtab = true;
if(is_64) {
auto res = get_symtab_impl<64>(true);
if(res.has_value()) {
dynamic_symtab = std::move(res).unwrap_value();
did_load_dynamic_symtab = true;
return dynamic_symtab;
} else {
return std::move(res).unwrap_error();
}
} else {
auto res = get_symtab_impl<32>(true);
if(res.has_value()) {
dynamic_symtab = std::move(res).unwrap_value();
did_load_dynamic_symtab = true;
return dynamic_symtab;
} else {
return std::move(res).unwrap_error();
}
} }
} }
template<std::size_t Bits> template<std::size_t Bits>
Result<const optional<elf::symtab_info>&, internal_error> elf::get_symtab_impl() { Result<optional<elf::symtab_info>, internal_error> elf::get_symtab_impl(bool dynamic) {
// https://refspecs.linuxfoundation.org/elf/elf.pdf // https://refspecs.linuxfoundation.org/elf/elf.pdf
// page 66: only one sht_symtab and sht_dynsym section per file // page 66: only one sht_symtab and sht_dynsym section per file
// page 32: symtab spec // page 32: symtab spec
@ -281,8 +332,9 @@ namespace detail {
return std::move(sections_).unwrap_error(); return std::move(sections_).unwrap_error();
} }
const auto& sections = sections_.unwrap_value(); const auto& sections = sections_.unwrap_value();
optional<symtab_info> symbol_table;
for(const auto& section : sections) { for(const auto& section : sections) {
if(section.sh_type == SHT_SYMTAB) { if(section.sh_type == (dynamic ? SHT_DYNSYM : SHT_SYMTAB)) {
if(section.sh_entsize != sizeof(SymEntry)) { if(section.sh_entsize != sizeof(SymEntry)) {
return internal_error("elf seems corrupted, sym entry mismatch {}", object_path); return internal_error("elf seems corrupted, sym entry mismatch {}", object_path);
} }
@ -296,8 +348,8 @@ namespace detail {
if(std::fread(buffer.data(), section.sh_entsize, buffer.size(), file) != buffer.size()) { if(std::fread(buffer.data(), section.sh_entsize, buffer.size(), file) != buffer.size()) {
return internal_error("fread error while loading elf symbol table"); return internal_error("fread error while loading elf symbol table");
} }
symtab = symtab_info{}; symbol_table = symtab_info{};
symtab.unwrap().entries.reserve(buffer.size()); symbol_table.unwrap().entries.reserve(buffer.size());
for(const auto& entry : buffer) { for(const auto& entry : buffer) {
symtab_entry normalized; symtab_entry normalized;
normalized.st_name = byteswap_if_needed(entry.st_name); normalized.st_name = byteswap_if_needed(entry.st_name);
@ -306,23 +358,20 @@ namespace detail {
normalized.st_shndx = byteswap_if_needed(entry.st_shndx); normalized.st_shndx = byteswap_if_needed(entry.st_shndx);
normalized.st_value = byteswap_if_needed(entry.st_value); normalized.st_value = byteswap_if_needed(entry.st_value);
normalized.st_size = byteswap_if_needed(entry.st_size); normalized.st_size = byteswap_if_needed(entry.st_size);
symtab.unwrap().entries.push_back(normalized); symbol_table.unwrap().entries.push_back(normalized);
} }
std::sort( std::sort(
symtab.unwrap().entries.begin(), symbol_table.unwrap().entries.begin(),
symtab.unwrap().entries.end(), symbol_table.unwrap().entries.end(),
[] (const symtab_entry& a, const symtab_entry& b) { [] (const symtab_entry& a, const symtab_entry& b) {
return a.st_value < b.st_value; return a.st_value < b.st_value;
} }
); );
symtab.unwrap().strtab_link = section.sh_link; symbol_table.unwrap().strtab_link = section.sh_link;
did_load_symtab = true; break;
return symtab;
} }
} }
// OK to not have a symbol table return symbol_table;
did_load_symtab = true;
return symtab;
} }
} }
} }

View File

@ -64,6 +64,10 @@ namespace detail {
bool did_load_symtab = false; bool did_load_symtab = false;
optional<symtab_info> symtab; optional<symtab_info> symtab;
bool tried_to_load_dynamic_symtab = false;
bool did_load_dynamic_symtab = false;
optional<symtab_info> dynamic_symtab;
elf(file_wrapper file, const std::string& object_path, bool is_little_endian, bool is_64); elf(file_wrapper file, const std::string& object_path, bool is_little_endian, bool is_64);
public: public:
@ -77,6 +81,8 @@ namespace detail {
public: public:
optional<std::string> lookup_symbol(frame_ptr pc); optional<std::string> lookup_symbol(frame_ptr pc);
private:
optional<std::string> lookup_symbol(frame_ptr pc, const optional<symtab_info>& maybe_symtab);
private: private:
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
@ -93,8 +99,9 @@ namespace detail {
Result<const std::vector<char>&, internal_error> get_strtab(std::size_t index); Result<const std::vector<char>&, internal_error> get_strtab(std::size_t index);
Result<const optional<symtab_info>&, internal_error> get_symtab(); Result<const optional<symtab_info>&, internal_error> get_symtab();
Result<const optional<symtab_info>&, internal_error> get_dynamic_symtab();
template<std::size_t Bits> template<std::size_t Bits>
Result<const optional<symtab_info>&, internal_error> get_symtab_impl(); Result<optional<symtab_info>, internal_error> get_symtab_impl(bool dynamic);
}; };
} }
} }