15#include <unordered_map>
16#include <unordered_set>
20#include "abg-internal.h"
25ABG_BEGIN_EXPORT_DECLARATIONS
27ABG_END_EXPORT_DECLARATIONS
32namespace symtab_reader
47 if (functions_ && *functions_ != symbol.
is_function())
49 if (variables_ && *variables_ != symbol.
is_variable())
51 if (public_symbols_ && *public_symbols_ != symbol.
is_public())
53 if (undefined_symbols_ && *undefined_symbols_ == symbol.
is_defined())
55 if (kernel_symbols_ && *kernel_symbols_ != symbol.
is_in_ksymtab())
75 if (is_kernel_binary_)
89 const auto it = name_symbol_map_.find(name);
90 if (it != name_symbol_map_.end())
104 const auto addr_it = addr_symbol_map_.find(symbol_addr);
105 if (addr_it != addr_symbol_map_.end())
106 return addr_it->second;
111 const auto entry_it = entry_addr_symbol_map_.find(symbol_addr);
112 if (entry_it != entry_addr_symbol_map_.end())
113 return entry_it->second;
135 if (sym_name == sym->get_name())
161 if (sym_name == sym->get_name())
182 if (s->is_function() && s->is_public())
206 if (!symbol->is_function() || !symbol->is_public())
226 if (s->is_variable() && s->is_public())
250 if (!symbol->is_variable() || !symbol->is_public())
264 collect_undefined_fns_and_vars_linkage_names();
265 if (undefined_function_linkage_names_.count(sym_name))
284 collect_undefined_fns_and_vars_linkage_names();
285 if (undefined_variable_linkage_names_.count(sym_name))
301 {
return left->get_id_string() < right->get_id_string();}
321 symbol_predicate is_suppressed)
325 symtab_ptr result(
new symtab);
326 if (!result->load_(elf_handle, env, is_suppressed))
345 symtab_ptr result(
new symtab);
346 if (!result->load_(function_symbol_map, variables_symbol_map))
354 : is_kernel_binary_(false), has_ksymtab_entries_(false),
355 cached_undefined_symbol_names_(false)
381symtab::load_(Elf* elf_handle,
383 symbol_predicate is_suppressed)
386 GElf_Ehdr* header = gelf_getehdr(elf_handle, &ehdr_mem);
389 std::cerr <<
"Could not get ELF header: Skipping symtab load.\n";
393 Elf_Scn* symtab_section = elf_helpers::find_symbol_table_section(elf_handle);
396 std::cerr <<
"No symbol table found: Skipping symtab load.\n";
400 GElf_Shdr symtab_sheader;
401 gelf_getshdr(symtab_section, &symtab_sheader);
404 if (symtab_sheader.sh_entsize == 0)
406 std::cerr <<
"Invalid symtab header found: Skipping symtab load.\n";
410 const size_t number_syms =
411 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
413 Elf_Data* symtab = elf_getdata(symtab_section, 0);
416 std::cerr <<
"Could not load elf symtab: Skipping symtab load.\n";
429 Elf_Scn* strings_section = elf_helpers::find_ksymtab_strings_section(elf_handle);
430 size_t strings_offset = 0;
431 const char* strings_data =
nullptr;
432 size_t strings_size = 0;
435 GElf_Shdr strings_sheader;
436 gelf_getshdr(strings_section, &strings_sheader);
437 strings_offset = header->e_type == ET_REL ? 0 : strings_sheader.sh_addr;
438 Elf_Data* data = elf_getdata(strings_section,
nullptr);
440 strings_data =
reinterpret_cast<const char *
>(data->d_buf);
441 strings_size = data->d_size;
444 const bool is_kernel = elf_helpers::is_linux_kernel(elf_handle);
445 std::unordered_set<std::string> exported_kernel_symbols;
446 std::unordered_map<std::string, uint32_t> crc_values;
447 std::unordered_map<std::string, std::string> namespaces;
449 for (
size_t i = 0; i < number_syms; ++i)
451 GElf_Sym *sym, sym_mem;
452 sym = gelf_getsym(symtab, i, &sym_mem);
455 std::cerr <<
"Could not load symbol with index " << i
456 <<
": Skipping symtab load.\n";
460 const char*
const name_str =
461 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
467 const std::string name = name_str;
488 if (is_kernel && name.rfind(
"__ksymtab_", 0) == 0)
490 ABG_ASSERT(exported_kernel_symbols.insert(name.substr(10)).second);
493 if (is_kernel && name.rfind(
"__crc_", 0) == 0)
496 ABG_ASSERT(elf_helpers::get_crc_for_symbol(elf_handle,
498 ABG_ASSERT(crc_values.emplace(name.substr(6), crc_value).second);
501 if (strings_section && is_kernel && name.rfind(
"__kstrtabns_", 0) == 0)
506 const size_t value = sym->st_value;
507 const size_t offset = value - strings_offset;
511 const char* first = strings_data + offset;
512 const char* last = strings_data + strings_size;
513 const char* limit = std::find(first, last, 0);
519 name.substr(12), std::string(first, limit - first)).second);
525 const int sym_type = GELF_ST_TYPE(sym->st_info);
526 if (!(sym_type == STT_FUNC
527 || sym_type == STT_GNU_IFUNC
531 || (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS)
534 || (sym_type == STT_NOTYPE && sym->st_shndx == SHN_UNDEF)
535 || sym_type == STT_TLS))
538 const bool sym_is_defined = sym->st_shndx != SHN_UNDEF;
540 const bool sym_is_common = sym->st_shndx == SHN_COMMON;
542 elf_symbol::version ver;
543 elf_helpers::get_version_for_symbol(elf_handle, i, sym_is_defined, ver);
547 (env, i, sym->st_size, name,
548 elf_helpers::stt_to_elf_symbol_type(GELF_ST_TYPE(sym->st_info)),
549 elf_helpers::stb_to_elf_symbol_binding(GELF_ST_BIND(sym->st_info)),
550 sym_is_defined, sym_is_common, ver,
551 elf_helpers::stv_to_elf_symbol_visibility
552 (GELF_ST_VISIBILITY(sym->st_other)));
557 if (!(is_suppressed && is_suppressed(symbol_sptr)))
559 symbols_.push_back(symbol_sptr);
561 symbol_sptr->set_is_suppressed(
true);
564 name_symbol_map_[name].push_back(symbol_sptr);
567 if (symbol_sptr->is_common_symbol())
569 const auto it = name_symbol_map_.find(name);
571 const elf_symbols& common_sym_instances = it->second;
573 if (common_sym_instances.size() > 1)
576 ABG_ASSERT(main_common_sym->get_name() == name);
577 ABG_ASSERT(main_common_sym->is_common_symbol());
578 ABG_ASSERT(symbol_sptr.get() != main_common_sym.get());
579 main_common_sym->add_common_instance(symbol_sptr);
582 else if (symbol_sptr->is_defined())
583 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
586 add_alternative_address_lookups(elf_handle);
588 is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
591 for (
const auto& symbol : exported_kernel_symbols)
593 const auto r = name_symbol_map_.find(symbol);
594 if (r == name_symbol_map_.end())
597 for (
const auto& elf_symbol : r->second)
598 if (elf_symbol->is_public())
599 elf_symbol->set_is_in_ksymtab(
true);
600 has_ksymtab_entries_ =
true;
604 for (
const auto& crc_entry : crc_values)
606 const auto r = name_symbol_map_.find(crc_entry.first);
607 if (r == name_symbol_map_.end())
610 for (
const auto& symbol : r->second)
611 symbol->set_crc(crc_entry.second);
615 for (
const auto& namespace_entry : namespaces)
617 const auto r = name_symbol_map_.find(namespace_entry.first);
618 if (r == name_symbol_map_.end())
621 for (
const auto& symbol : r->second)
622 symbol->set_namespace(namespace_entry.second);
626 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
647 if (function_symbol_map)
648 for (
const auto& symbol_map_entry : *function_symbol_map)
650 for (
const auto& symbol : symbol_map_entry.second)
652 if (!symbol->is_suppressed())
653 symbols_.push_back(symbol);
655 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
658 if (variables_symbol_map)
659 for (
const auto& symbol_map_entry : *variables_symbol_map)
661 for (
const auto& symbol : symbol_map_entry.second)
663 if (!symbol->is_suppressed())
664 symbols_.push_back(symbol);
666 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
670 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
703 addr_symbol_map_[addr] = new_main;
721symtab::setup_symbol_lookup_tables(Elf* elf_handle,
725 const bool is_arm32 = elf_helpers::architecture_is_arm32(elf_handle);
726 const bool is_arm64 = elf_helpers::architecture_is_arm64(elf_handle);
727 const bool is_ppc64 = elf_helpers::architecture_is_ppc64(elf_handle);
728 const bool is_ppc32 = elf_helpers::architecture_is_ppc32(elf_handle);
730 GElf_Addr symbol_value =
731 elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle,
734 if (is_arm32 && symbol_sptr->is_function())
742 symbol_value = symbol_value & (1ULL<<55)
743 ? symbol_value | (0xffULL<<56)
744 : symbol_value &~ (0xffULL<<56);
746 if (symbol_sptr->is_defined())
749 addr_symbol_map_.emplace(symbol_value, symbol_sptr);
754 result.first->second->get_main_symbol()->add_alias(symbol_sptr);
760 if ((is_ppc64 || is_ppc32) && symbol_sptr->is_function())
761 update_function_entry_address_symbol_map(elf_handle,
elf_symbol,
801symtab::update_function_entry_address_symbol_map(
802 Elf* elf_handle, GElf_Sym* native_symbol,
const elf_symbol_sptr& symbol_sptr)
804 const GElf_Addr fn_desc_addr = native_symbol->st_value;
805 const GElf_Addr fn_entry_point_addr =
806 elf_helpers::lookup_ppc64_elf_fn_entry_point_address(elf_handle,
809 const std::pair<addr_symbol_map_type::const_iterator, bool>& result =
810 entry_addr_symbol_map_.emplace(fn_entry_point_addr, symbol_sptr);
812 const addr_symbol_map_type::const_iterator it = result.first;
813 const bool was_inserted = result.second;
815 && elf_helpers::address_is_in_opd_section(elf_handle, fn_desc_addr))
832 const bool two_symbols_alias =
833 it->second->get_main_symbol()->does_alias(*symbol_sptr);
834 const bool symbol_is_foo_and_prev_symbol_is_dot_foo =
835 (it->second->get_name() == std::string(
".") + symbol_sptr->get_name());
838 || symbol_is_foo_and_prev_symbol_is_dot_foo);
840 if (symbol_is_foo_and_prev_symbol_is_dot_foo)
844 entry_addr_symbol_map_[fn_entry_point_addr] = symbol_sptr;
864symtab::add_alternative_address_lookups(Elf* elf_handle)
866 Elf_Scn* symtab_section = elf_helpers::find_symtab_section(elf_handle);
869 GElf_Shdr symtab_sheader;
870 gelf_getshdr(symtab_section, &symtab_sheader);
872 const size_t number_syms =
873 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
875 Elf_Data* symtab = elf_getdata(symtab_section, 0);
877 for (
size_t i = 0; i < number_syms; ++i)
879 GElf_Sym *sym, sym_mem;
880 sym = gelf_getsym(symtab, i, &sym_mem);
883 std::cerr <<
"Could not load symbol with index " << i
884 <<
": Skipping alternative symbol load.\n";
888 const char*
const name_str =
889 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
895 const std::string name = name_str;
900 static const std::string cfi =
".cfi";
901 if (name.size() > cfi.size()
902 && name.compare(name.size() - cfi.size(), cfi.size(), cfi) == 0)
905 const auto candidate_name = name.substr(0, name.size() - cfi.size());
912 if (symbols.size() == 1)
914 const auto& symbol_sptr = symbols[0];
915 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
927symtab::collect_undefined_fns_and_vars_linkage_names()
929 if (!cached_undefined_symbol_names_)
933 f.set_variables(
false);
934 f.set_functions(
true);
935 f.set_public_symbols(
false);
936 f.set_undefined_symbols(
true);
937 for (
auto sym : filtered_symtab(*
this, f))
938 undefined_function_linkage_names_.insert(sym->get_name());
943 f.set_variables(
true);
944 f.set_functions(
false);
945 f.set_public_symbols(
false);
946 f.set_undefined_symbols(
true);
947 for (
auto sym : filtered_symtab(*
this, f))
948 undefined_variable_linkage_names_.insert(sym->get_name());
951 cached_undefined_symbol_names_ =
true;
This contains a set of ELF utilities used by the dwarf reader.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
This contains the declarations for the symtab reader.
Abstraction of an elf symbol.
bool is_variable() const
Test if the current instance of elf_symbol is a variable symbol or not.
bool is_function() const
Test if the current instance of elf_symbol is a function symbol or not.
static elf_symbol_sptr create(const environment &e, size_t i, size_t s, const string &n, type t, binding b, bool d, bool c, const version &ve, visibility vi, bool is_in_ksymtab=false, const abg_compat::optional< uint32_t > &crc={}, const abg_compat::optional< std::string > &ns={}, bool is_suppressed=false)
Factory of instances of elf_symbol.
bool is_public() const
Test if the current instance of elf_symbol is public or not.
bool is_in_ksymtab() const
Getter of the 'is-in-ksymtab' property.
bool is_defined() const
Test if the current instance of elf_symbol is defined or not.
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Helper class to allow range-for loops on symtabs for C++11 and later code. It serves as a proxy for t...
The symtab filter is the object passed to the symtab object in order to iterate over the symbols in t...
void set_public_symbols(bool new_value=true)
Enable or disable public symbol filtering.
bool matches(const elf_symbol &symbol) const
symtab_filter implementations
void set_functions(bool new_value=true)
Enable or disable function filtering.
void set_kernel_symbols(bool new_value=true)
Enable or disable kernel symbol filtering.
void set_variables(bool new_value=true)
Enable or disable variable filtering.
void set_undefined_symbols(bool new_value=true)
Enable or disable undefined symbol filtering.
symtab is the actual data container of the symtab_reader implementation.
const elf_symbol_sptr lookup_undefined_variable_symbol(const std::string &name)
Lookup an undefined variable symbol with a given name.
const elf_symbols & lookup_symbol(const std::string &name) const
Get a vector of symbols that are associated with a certain name.
symtab_filter make_filter() const
symtab implementations
static symtab_ptr load(Elf *elf_handle, const ir::environment &env, symbol_predicate is_suppressed=NULL)
Construct a symtab object and instantiate it from an ELF handle. Also pass in the ir::environment we ...
elf_symbol_sptr function_symbol_is_undefined(const string &)
Test if a name is a the name of an undefined function symbol.
elf_symbol_sptr variable_symbol_is_undefined(const string &)
Test if a name is a the name of an undefined variable symbol.
elf_symbol_sptr function_symbol_is_exported(const string &)
Test if a given function symbol has been exported.
elf_symbol_sptr variable_symbol_is_exported(const string &)
Test if a given variable symbol has been exported.
const elf_symbol_sptr lookup_undefined_function_symbol(const std::string &name)
Lookup an undefined function symbol with a given name.
void update_main_symbol(GElf_Addr addr, const std::string &name)
Notify the symtab about the name of the main symbol at a given address.
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
shared_ptr< string_elf_symbols_map_type > string_elf_symbols_map_sptr
Convenience typedef for a shared pointer to string_elf_symbols_map_type.
Toplevel namespace for libabigail.