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;
123 {
return left->get_id_string() < right->get_id_string();}
143 symbol_predicate is_suppressed)
147 symtab_ptr result(
new symtab);
148 if (!result->load_(elf_handle, env, is_suppressed))
167 symtab_ptr result(
new symtab);
168 if (!result->load_(function_symbol_map, variables_symbol_map))
176 : is_kernel_binary_(false), has_ksymtab_entries_(false)
202symtab::load_(Elf* elf_handle,
204 symbol_predicate is_suppressed)
207 GElf_Ehdr* header = gelf_getehdr(elf_handle, &ehdr_mem);
210 std::cerr <<
"Could not get ELF header: Skipping symtab load.\n";
214 Elf_Scn* symtab_section = elf_helpers::find_symbol_table_section(elf_handle);
217 std::cerr <<
"No symbol table found: Skipping symtab load.\n";
221 GElf_Shdr symtab_sheader;
222 gelf_getshdr(symtab_section, &symtab_sheader);
225 if (symtab_sheader.sh_entsize == 0)
227 std::cerr <<
"Invalid symtab header found: Skipping symtab load.\n";
231 const size_t number_syms =
232 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
234 Elf_Data* symtab = elf_getdata(symtab_section, 0);
237 std::cerr <<
"Could not load elf symtab: Skipping symtab load.\n";
250 Elf_Scn* strings_section = elf_helpers::find_ksymtab_strings_section(elf_handle);
251 size_t strings_offset = 0;
252 const char* strings_data =
nullptr;
253 size_t strings_size = 0;
256 GElf_Shdr strings_sheader;
257 gelf_getshdr(strings_section, &strings_sheader);
258 strings_offset = header->e_type == ET_REL ? 0 : strings_sheader.sh_addr;
259 Elf_Data* data = elf_getdata(strings_section,
nullptr);
261 strings_data =
reinterpret_cast<const char *
>(data->d_buf);
262 strings_size = data->d_size;
265 const bool is_kernel = elf_helpers::is_linux_kernel(elf_handle);
266 std::unordered_set<std::string> exported_kernel_symbols;
267 std::unordered_map<std::string, uint32_t> crc_values;
268 std::unordered_map<std::string, std::string> namespaces;
270 for (
size_t i = 0; i < number_syms; ++i)
272 GElf_Sym *sym, sym_mem;
273 sym = gelf_getsym(symtab, i, &sym_mem);
276 std::cerr <<
"Could not load symbol with index " << i
277 <<
": Skipping symtab load.\n";
281 const char*
const name_str =
282 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
288 const std::string name = name_str;
309 if (is_kernel && name.rfind(
"__ksymtab_", 0) == 0)
311 ABG_ASSERT(exported_kernel_symbols.insert(name.substr(10)).second);
314 if (is_kernel && name.rfind(
"__crc_", 0) == 0)
317 ABG_ASSERT(elf_helpers::get_crc_for_symbol(elf_handle,
319 ABG_ASSERT(crc_values.emplace(name.substr(6), crc_value).second);
322 if (strings_section && is_kernel && name.rfind(
"__kstrtabns_", 0) == 0)
327 const size_t value = sym->st_value;
328 const size_t offset = value - strings_offset;
332 const char* first = strings_data + offset;
333 const char* last = strings_data + strings_size;
334 const char* limit = std::find(first, last, 0);
340 name.substr(12), std::string(first, limit - first)).second);
346 const int sym_type = GELF_ST_TYPE(sym->st_info);
347 if (!(sym_type == STT_FUNC
348 || sym_type == STT_GNU_IFUNC
352 || (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS)
353 || sym_type == STT_TLS))
356 const bool sym_is_defined = sym->st_shndx != SHN_UNDEF;
358 const bool sym_is_common = sym->st_shndx == SHN_COMMON;
360 elf_symbol::version ver;
361 elf_helpers::get_version_for_symbol(elf_handle, i, sym_is_defined, ver);
365 (env, i, sym->st_size, name,
366 elf_helpers::stt_to_elf_symbol_type(GELF_ST_TYPE(sym->st_info)),
367 elf_helpers::stb_to_elf_symbol_binding(GELF_ST_BIND(sym->st_info)),
368 sym_is_defined, sym_is_common, ver,
369 elf_helpers::stv_to_elf_symbol_visibility
370 (GELF_ST_VISIBILITY(sym->st_other)));
375 if (!(is_suppressed && is_suppressed(symbol_sptr)))
377 symbols_.push_back(symbol_sptr);
379 symbol_sptr->set_is_suppressed(
true);
382 name_symbol_map_[name].push_back(symbol_sptr);
385 if (symbol_sptr->is_common_symbol())
387 const auto it = name_symbol_map_.find(name);
389 const elf_symbols& common_sym_instances = it->second;
391 if (common_sym_instances.size() > 1)
394 ABG_ASSERT(main_common_sym->get_name() == name);
395 ABG_ASSERT(main_common_sym->is_common_symbol());
396 ABG_ASSERT(symbol_sptr.get() != main_common_sym.get());
397 main_common_sym->add_common_instance(symbol_sptr);
400 else if (symbol_sptr->is_defined())
401 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
404 add_alternative_address_lookups(elf_handle);
406 is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
409 for (
const auto& symbol : exported_kernel_symbols)
411 const auto r = name_symbol_map_.find(symbol);
412 if (r == name_symbol_map_.end())
415 for (
const auto& elf_symbol : r->second)
416 if (elf_symbol->is_public())
417 elf_symbol->set_is_in_ksymtab(
true);
418 has_ksymtab_entries_ =
true;
422 for (
const auto& crc_entry : crc_values)
424 const auto r = name_symbol_map_.find(crc_entry.first);
425 if (r == name_symbol_map_.end())
428 for (
const auto& symbol : r->second)
429 symbol->set_crc(crc_entry.second);
433 for (
const auto& namespace_entry : namespaces)
435 const auto r = name_symbol_map_.find(namespace_entry.first);
436 if (r == name_symbol_map_.end())
439 for (
const auto& symbol : r->second)
440 symbol->set_namespace(namespace_entry.second);
444 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
465 if (function_symbol_map)
466 for (
const auto& symbol_map_entry : *function_symbol_map)
468 for (
const auto& symbol : symbol_map_entry.second)
470 if (!symbol->is_suppressed())
471 symbols_.push_back(symbol);
473 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
476 if (variables_symbol_map)
477 for (
const auto& symbol_map_entry : *variables_symbol_map)
479 for (
const auto& symbol : symbol_map_entry.second)
481 if (!symbol->is_suppressed())
482 symbols_.push_back(symbol);
484 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
488 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
521 addr_symbol_map_[addr] = new_main;
539symtab::setup_symbol_lookup_tables(Elf* elf_handle,
543 const bool is_arm32 = elf_helpers::architecture_is_arm32(elf_handle);
544 const bool is_arm64 = elf_helpers::architecture_is_arm64(elf_handle);
545 const bool is_ppc64 = elf_helpers::architecture_is_ppc64(elf_handle);
546 const bool is_ppc32 = elf_helpers::architecture_is_ppc32(elf_handle);
548 GElf_Addr symbol_value =
549 elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle,
552 if (is_arm32 && symbol_sptr->is_function())
560 symbol_value = symbol_value & (1ULL<<55)
561 ? symbol_value | (0xffULL<<56)
562 : symbol_value &~ (0xffULL<<56);
564 if (symbol_sptr->is_defined())
567 addr_symbol_map_.emplace(symbol_value, symbol_sptr);
572 result.first->second->get_main_symbol()->add_alias(symbol_sptr);
578 if ((is_ppc64 || is_ppc32) && symbol_sptr->is_function())
579 update_function_entry_address_symbol_map(elf_handle,
elf_symbol,
619symtab::update_function_entry_address_symbol_map(
620 Elf* elf_handle, GElf_Sym* native_symbol,
const elf_symbol_sptr& symbol_sptr)
622 const GElf_Addr fn_desc_addr = native_symbol->st_value;
623 const GElf_Addr fn_entry_point_addr =
624 elf_helpers::lookup_ppc64_elf_fn_entry_point_address(elf_handle,
627 const std::pair<addr_symbol_map_type::const_iterator, bool>& result =
628 entry_addr_symbol_map_.emplace(fn_entry_point_addr, symbol_sptr);
630 const addr_symbol_map_type::const_iterator it = result.first;
631 const bool was_inserted = result.second;
633 && elf_helpers::address_is_in_opd_section(elf_handle, fn_desc_addr))
650 const bool two_symbols_alias =
651 it->second->get_main_symbol()->does_alias(*symbol_sptr);
652 const bool symbol_is_foo_and_prev_symbol_is_dot_foo =
653 (it->second->get_name() == std::string(
".") + symbol_sptr->get_name());
656 || symbol_is_foo_and_prev_symbol_is_dot_foo);
658 if (symbol_is_foo_and_prev_symbol_is_dot_foo)
662 entry_addr_symbol_map_[fn_entry_point_addr] = symbol_sptr;
682symtab::add_alternative_address_lookups(Elf* elf_handle)
684 Elf_Scn* symtab_section = elf_helpers::find_symtab_section(elf_handle);
687 GElf_Shdr symtab_sheader;
688 gelf_getshdr(symtab_section, &symtab_sheader);
690 const size_t number_syms =
691 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
693 Elf_Data* symtab = elf_getdata(symtab_section, 0);
695 for (
size_t i = 0; i < number_syms; ++i)
697 GElf_Sym *sym, sym_mem;
698 sym = gelf_getsym(symtab, i, &sym_mem);
701 std::cerr <<
"Could not load symbol with index " << i
702 <<
": Skipping alternative symbol load.\n";
706 const char*
const name_str =
707 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
713 const std::string name = name_str;
718 static const std::string cfi =
".cfi";
719 if (name.size() > cfi.size()
720 && name.compare(name.size() - cfi.size(), cfi.size(), cfi) == 0)
723 const auto candidate_name = name.substr(0, name.size() - cfi.size());
730 if (symbols.size() == 1)
732 const auto& symbol_sptr = symbols[0];
733 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
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...
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_kernel_symbols(bool new_value=true)
Enable or disable kernel symbol filtering.
symtab is the actual data container of the symtab_reader implementation.
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 ...
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.