libabigail
abg-symtab-reader.cc
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 // Copyright (C) 2020-2023 Google, Inc.
6 //
7 // Author: Matthias Maennich
8 
9 /// @file
10 ///
11 /// This contains the definition of the symtab reader
12 
13 #include <algorithm>
14 #include <iostream>
15 #include <unordered_map>
16 #include <unordered_set>
17 
18 #include "abg-elf-helpers.h"
19 #include "abg-fwd.h"
20 #include "abg-internal.h"
21 #include "abg-tools-utils.h"
22 
23 // Though this is an internal header, we need to export the symbols to be able
24 // to test this code. TODO: find a way to export symbols just for unit tests.
25 ABG_BEGIN_EXPORT_DECLARATIONS
26 #include "abg-symtab-reader.h"
27 ABG_END_EXPORT_DECLARATIONS
28 
29 namespace abigail
30 {
31 
32 namespace symtab_reader
33 {
34 
35 /// symtab_filter implementations
36 
37 /// Determine whether a symbol is matching the filter criteria of this filter
38 /// object. In terms of a filter functionality, you would _not_ filter out
39 /// this symbol if it passes this (i.e. returns true).
40 ///
41 /// @param symbol The Elf symbol under test.
42 ///
43 /// @return whether the symbol matches all relevant / required criteria
44 bool
45 symtab_filter::matches(const elf_symbol& symbol) const
46 {
47  if (functions_ && *functions_ != symbol.is_function())
48  return false;
49  if (variables_ && *variables_ != symbol.is_variable())
50  return false;
51  if (public_symbols_ && *public_symbols_ != symbol.is_public())
52  return false;
53  if (undefined_symbols_ && *undefined_symbols_ == symbol.is_defined())
54  return false;
55  if (kernel_symbols_ && *kernel_symbols_ != symbol.is_in_ksymtab())
56  return false;
57 
58  return true;
59 }
60 
61 /// symtab implementations
62 
63 /// Obtain a suitable default filter for iterating this symtab object.
64 ///
65 /// The symtab_filter obtained is populated with some sensible default
66 /// settings, such as public_symbols(true) and kernel_symbols(true) if the
67 /// binary has been identified as Linux Kernel binary.
68 ///
69 /// @return a symtab_filter with sensible populated defaults
72 {
73  symtab_filter filter;
74  filter.set_public_symbols();
75  if (is_kernel_binary_)
76  filter.set_kernel_symbols();
77  return filter;
78 }
79 
80 /// Get a vector of symbols that are associated with a certain name
81 ///
82 /// @param name the name the symbols need to match
83 ///
84 /// @return a vector of symbols, empty if no matching symbols have been found
85 const elf_symbols&
86 symtab::lookup_symbol(const std::string& name) const
87 {
88  static const elf_symbols empty_result;
89  const auto it = name_symbol_map_.find(name);
90  if (it != name_symbol_map_.end())
91  return it->second;
92  return empty_result;
93 }
94 
95 /// Lookup a symbol by its address
96 ///
97 /// @param symbol_addr the starting address of the symbol
98 ///
99 /// @return a symbol if found, else an empty sptr
100 const elf_symbol_sptr&
101 symtab::lookup_symbol(GElf_Addr symbol_addr) const
102 {
103  static const elf_symbol_sptr empty_result;
104  const auto addr_it = addr_symbol_map_.find(symbol_addr);
105  if (addr_it != addr_symbol_map_.end())
106  return addr_it->second;
107  else
108  {
109  // check for a potential entry address mapping instead,
110  // relevant for ppc ELFv1 binaries
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;
114  }
115  return empty_result;
116 }
117 
118 /// A symbol sorting functor.
119 static struct
120 {
121  bool
122  operator()(const elf_symbol_sptr& left, const elf_symbol_sptr& right)
123  {return left->get_id_string() < right->get_id_string();}
124 } symbol_sort;
125 
126 /// Construct a symtab object and instantiate it from an ELF
127 /// handle. Also pass in the ir::environment we are living in. If
128 /// specified, the symbol_predicate will be respected when creating
129 /// the full vector of symbols.
130 ///
131 /// @param elf_handle the elf handle to load the symbol table from
132 ///
133 /// @param env the environment we are operating in
134 ///
135 /// @param is_suppressed a predicate function to determine if a symbol should
136 /// be suppressed
137 ///
138 /// @return a smart pointer handle to symtab, set to nullptr if the load was
139 /// not completed
140 symtab_ptr
141 symtab::load(Elf* elf_handle,
142  const ir::environment& env,
143  symbol_predicate is_suppressed)
144 {
145  ABG_ASSERT(elf_handle);
146 
147  symtab_ptr result(new symtab);
148  if (!result->load_(elf_handle, env, is_suppressed))
149  return {};
150 
151  return result;
152 }
153 
154 /// Construct a symtab object from existing name->symbol lookup maps.
155 /// They were possibly read from a different representation (XML maybe).
156 ///
157 /// @param function_symbol_map a map from ELF function name to elf_symbol
158 ///
159 /// @param variable_symbol_map a map from ELF variable name to elf_symbol
160 ///
161 /// @return a smart pointer handle to symtab, set to nullptr if the load was
162 /// not completed
163 symtab_ptr
165  string_elf_symbols_map_sptr variables_symbol_map)
166 {
167  symtab_ptr result(new symtab);
168  if (!result->load_(function_symbol_map, variables_symbol_map))
169  return {};
170 
171  return result;
172 }
173 
174 /// Default constructor of the @ref symtab type.
175 symtab::symtab()
176  : is_kernel_binary_(false), has_ksymtab_entries_(false)
177 {}
178 
179 /// Load the symtab representation from an Elf binary presented to us by an
180 /// Elf* handle.
181 ///
182 /// This method iterates over the entries of .symtab and collects all
183 /// interesting symbols (functions and variables).
184 ///
185 /// In case of a Linux Kernel binary, it also collects information about the
186 /// symbols exported via EXPORT_SYMBOL in the Kernel that would then end up
187 /// having a corresponding __ksymtab entry.
188 ///
189 /// Symbols that are suppressed will be omitted from the symbols_ vector, but
190 /// still be discoverable through the name->symbol and addr->symbol lookup
191 /// maps.
192 ///
193 /// @param elf_handle the elf handle to load the symbol table from
194 ///
195 /// @param env the environment we are operating in
196 ///
197 /// @param is_suppressed a predicate function to determine if a symbol should
198 /// be suppressed
199 ///
200 /// @return true if the load succeeded
201 bool
202 symtab::load_(Elf* elf_handle,
203  const ir::environment& env,
204  symbol_predicate is_suppressed)
205 {
206  GElf_Ehdr ehdr_mem;
207  GElf_Ehdr* header = gelf_getehdr(elf_handle, &ehdr_mem);
208  if (!header)
209  {
210  std::cerr << "Could not get ELF header: Skipping symtab load.\n";
211  return false;
212  }
213 
214  Elf_Scn* symtab_section = elf_helpers::find_symbol_table_section(elf_handle);
215  if (!symtab_section)
216  {
217  std::cerr << "No symbol table found: Skipping symtab load.\n";
218  return false;
219  }
220 
221  GElf_Shdr symtab_sheader;
222  gelf_getshdr(symtab_section, &symtab_sheader);
223 
224  // check for bogus section header
225  if (symtab_sheader.sh_entsize == 0)
226  {
227  std::cerr << "Invalid symtab header found: Skipping symtab load.\n";
228  return false;
229  }
230 
231  const size_t number_syms =
232  symtab_sheader.sh_size / symtab_sheader.sh_entsize;
233 
234  Elf_Data* symtab = elf_getdata(symtab_section, 0);
235  if (!symtab)
236  {
237  std::cerr << "Could not load elf symtab: Skipping symtab load.\n";
238  return false;
239  }
240 
241  // The __kstrtab_strings sections is basically an ELF strtab but does not
242  // support elf_strptr lookups. A single call to elf_getdata gives a handle to
243  // washed section data.
244  //
245  // The value of a __kstrtabns_FOO (or other similar) symbol is an address
246  // within the __kstrtab_strings section. To look up the string value, we need
247  // to translate from vmlinux load address to section offset by subtracting the
248  // base address of the section. This adjustment is not needed for loadable
249  // modules which are relocatable and so identifiable by ELF type ET_REL.
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;
254  if (strings_section)
255  {
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);
260  ABG_ASSERT(data->d_off == 0);
261  strings_data = reinterpret_cast<const char *>(data->d_buf);
262  strings_size = data->d_size;
263  }
264 
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;
269 
270  for (size_t i = 0; i < number_syms; ++i)
271  {
272  GElf_Sym *sym, sym_mem;
273  sym = gelf_getsym(symtab, i, &sym_mem);
274  if (!sym)
275  {
276  std::cerr << "Could not load symbol with index " << i
277  << ": Skipping symtab load.\n";
278  return false;
279  }
280 
281  const char* const name_str =
282  elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
283 
284  // no name, no game
285  if (!name_str)
286  continue;
287 
288  const std::string name = name_str;
289  if (name.empty())
290  continue;
291 
292  // Handle ksymtab entries. Every symbol entry that starts with __ksymtab_
293  // indicates that the symbol in question is exported through ksymtab. We
294  // do not know whether this is ksymtab_gpl or ksymtab, but that is good
295  // enough for now.
296  //
297  // We could follow up with this entry:
298  //
299  // symbol_value -> ksymtab_entry in either ksymtab_gpl or ksymtab
300  // -> addr/name/namespace (in case of PREL32: offset)
301  //
302  // That way we could also detect ksymtab<>ksymtab_gpl changes or changes
303  // of the symbol namespace.
304  //
305  // As of now this lookup is fragile, as occasionally ksymtabs are empty
306  // (seen so far for kernel modules and LTO builds). Hence we stick to the
307  // fairly safe assumption that ksymtab exported entries are having an
308  // appearence as __ksymtab_<symbol> in the symtab.
309  if (is_kernel && name.rfind("__ksymtab_", 0) == 0)
310  {
311  ABG_ASSERT(exported_kernel_symbols.insert(name.substr(10)).second);
312  continue;
313  }
314  if (is_kernel && name.rfind("__crc_", 0) == 0)
315  {
316  uint32_t crc_value;
317  ABG_ASSERT(elf_helpers::get_crc_for_symbol(elf_handle,
318  sym, crc_value));
319  ABG_ASSERT(crc_values.emplace(name.substr(6), crc_value).second);
320  continue;
321  }
322  if (strings_section && is_kernel && name.rfind("__kstrtabns_", 0) == 0)
323  {
324  // This symbol lives in the __ksymtab_strings section but st_value may
325  // be a vmlinux load address so we need to subtract the offset before
326  // looking it up in that section.
327  const size_t value = sym->st_value;
328  const size_t offset = value - strings_offset;
329  // check offset
330  ABG_ASSERT(offset < strings_size);
331  // find the terminating NULL
332  const char* first = strings_data + offset;
333  const char* last = strings_data + strings_size;
334  const char* limit = std::find(first, last, 0);
335  // check NULL found
336  ABG_ASSERT(limit < last);
337  // interpret the empty namespace name as no namespace name
338  if (first < limit)
339  ABG_ASSERT(namespaces.emplace(
340  name.substr(12), std::string(first, limit - first)).second);
341  continue;
342  }
343 
344  // filter out uninteresting entries and only keep functions/variables for
345  // now. The rest might be interesting in the future though.
346  const int sym_type = GELF_ST_TYPE(sym->st_info);
347  if (!(sym_type == STT_FUNC
348  || sym_type == STT_GNU_IFUNC
349  // If the symbol is for an OBJECT, the index of the
350  // section it refers to cannot be absolute.
351  // Otherwise that OBJECT is not a variable.
352  || (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS)
353  || sym_type == STT_TLS))
354  continue;
355 
356  const bool sym_is_defined = sym->st_shndx != SHN_UNDEF;
357  // this occurs in relocatable files.
358  const bool sym_is_common = sym->st_shndx == SHN_COMMON;
359 
360  elf_symbol::version ver;
361  elf_helpers::get_version_for_symbol(elf_handle, i, sym_is_defined, ver);
362 
363  const elf_symbol_sptr& symbol_sptr =
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)));
371 
372  // We do not take suppressed symbols into our symbol vector to avoid
373  // accidental leakage. But we ensure supressed symbols are otherwise set
374  // up for lookup.
375  if (!(is_suppressed && is_suppressed(symbol_sptr)))
376  // add to the symbol vector
377  symbols_.push_back(symbol_sptr);
378  else
379  symbol_sptr->set_is_suppressed(true);
380 
381  // add to the name->symbol lookup
382  name_symbol_map_[name].push_back(symbol_sptr);
383 
384  // add to the addr->symbol lookup
385  if (symbol_sptr->is_common_symbol())
386  {
387  const auto it = name_symbol_map_.find(name);
388  ABG_ASSERT(it != name_symbol_map_.end());
389  const elf_symbols& common_sym_instances = it->second;
390  ABG_ASSERT(!common_sym_instances.empty());
391  if (common_sym_instances.size() > 1)
392  {
393  elf_symbol_sptr main_common_sym = common_sym_instances[0];
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);
398  }
399  }
400  else if (symbol_sptr->is_defined())
401  setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
402  }
403 
404  add_alternative_address_lookups(elf_handle);
405 
406  is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
407 
408  // Now apply the ksymtab_exported attribute to the symbols we collected.
409  for (const auto& symbol : exported_kernel_symbols)
410  {
411  const auto r = name_symbol_map_.find(symbol);
412  if (r == name_symbol_map_.end())
413  continue;
414 
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;
419  }
420 
421  // Now add the CRC values
422  for (const auto& crc_entry : crc_values)
423  {
424  const auto r = name_symbol_map_.find(crc_entry.first);
425  if (r == name_symbol_map_.end())
426  continue;
427 
428  for (const auto& symbol : r->second)
429  symbol->set_crc(crc_entry.second);
430  }
431 
432  // Now add the namespaces
433  for (const auto& namespace_entry : namespaces)
434  {
435  const auto r = name_symbol_map_.find(namespace_entry.first);
436  if (r == name_symbol_map_.end())
437  continue;
438 
439  for (const auto& symbol : r->second)
440  symbol->set_namespace(namespace_entry.second);
441  }
442 
443  // sort the symbols for deterministic output
444  std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
445 
446  return true;
447 }
448 
449 /// Load the symtab representation from a function/variable lookup map pair.
450 ///
451 /// This method assumes the lookup maps are correct and sets up the data
452 /// vector as well as the name->symbol lookup map. The addr->symbol lookup
453 /// map cannot be set up in this case.
454 ///
455 /// @param function_symbol_map a map from ELF function name to elf_symbol
456 ///
457 /// @param variable_symbol_map a map from ELF variable name to elf_symbol
458 ///
459 /// @return true if the load succeeded
460 bool
461 symtab::load_(string_elf_symbols_map_sptr function_symbol_map,
462  string_elf_symbols_map_sptr variables_symbol_map)
463 
464 {
465  if (function_symbol_map)
466  for (const auto& symbol_map_entry : *function_symbol_map)
467  {
468  for (const auto& symbol : symbol_map_entry.second)
469  {
470  if (!symbol->is_suppressed())
471  symbols_.push_back(symbol);
472  }
473  ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
474  }
475 
476  if (variables_symbol_map)
477  for (const auto& symbol_map_entry : *variables_symbol_map)
478  {
479  for (const auto& symbol : symbol_map_entry.second)
480  {
481  if (!symbol->is_suppressed())
482  symbols_.push_back(symbol);
483  }
484  ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
485  }
486 
487  // sort the symbols for deterministic output
488  std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
489 
490  return true;
491 }
492 
493 /// Notify the symtab about the name of the main symbol at a given address.
494 ///
495 /// From just alone the symtab we can't guess the main symbol of a bunch of
496 /// aliased symbols that all point to the same address. During processing of
497 /// additional information (such as DWARF), this information becomes apparent
498 /// and we can adjust the addr->symbol lookup map as well as the alias
499 /// reference of the symbol objects.
500 ///
501 /// @param addr the addr that we are updating the main symbol for
502 /// @param name the name of the main symbol
503 void
504 symtab::update_main_symbol(GElf_Addr addr, const std::string& name)
505 {
506  // get one symbol (i.e. the current main symbol)
507  elf_symbol_sptr symbol = lookup_symbol(addr);
508 
509  // The caller might not know whether the addr is associated to an ELF symbol
510  // that we care about. E.g. the addr could be associated to an ELF symbol,
511  // but not one in .dynsym when looking at a DSO. Hence, early exit if the
512  // lookup failed.
513  if (!symbol)
514  return;
515 
516  // determine the new main symbol by attempting an update
517  elf_symbol_sptr new_main = symbol->update_main_symbol(name);
518 
519  // also update the default symbol we return when looked up by address
520  if (new_main)
521  addr_symbol_map_[addr] = new_main;
522 }
523 
524 /// Various adjustments and bookkeeping may be needed to provide a correct
525 /// interpretation (one that matches DWARF addresses) of raw symbol values.
526 ///
527 /// This is a sub-routine for symtab::load_and
528 /// symtab::add_alternative_address_lookups and must be called only
529 /// once (per symbol) during the execution of the former.
530 ///
531 /// @param elf_handle the ELF handle
532 ///
533 /// @param elf_symbol the ELF symbol
534 ///
535 /// @param symbol_sptr the libabigail symbol
536 ///
537 /// @return a possibly-adjusted symbol value
538 GElf_Addr
539 symtab::setup_symbol_lookup_tables(Elf* elf_handle,
540  GElf_Sym* elf_symbol,
541  const elf_symbol_sptr& symbol_sptr)
542 {
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);
547 
548  GElf_Addr symbol_value =
549  elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle,
550  elf_symbol);
551 
552  if (is_arm32 && symbol_sptr->is_function())
553  // Clear bit zero of ARM32 addresses as per "ELF for the Arm
554  // Architecture" section 5.5.3.
555  // https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
556  symbol_value &= ~1;
557 
558  if (is_arm64)
559  // Copy bit 55 over bits 56 to 63 which may be tag information.
560  symbol_value = symbol_value & (1ULL<<55)
561  ? symbol_value | (0xffULL<<56)
562  : symbol_value &~ (0xffULL<<56);
563 
564  if (symbol_sptr->is_defined())
565  {
566  const auto result =
567  addr_symbol_map_.emplace(symbol_value, symbol_sptr);
568  if (!result.second)
569  // A symbol with the same address already exists. This
570  // means this symbol is an alias of the main symbol with
571  // that address. So let's register this new alias as such.
572  result.first->second->get_main_symbol()->add_alias(symbol_sptr);
573  }
574 
575  // Please note that update_function_entry_address_symbol_map depends
576  // on the symbol aliases been setup. This is why, the
577  // elf_symbol::add_alias call is done above BEFORE this point.
578  if ((is_ppc64 || is_ppc32) && symbol_sptr->is_function())
579  update_function_entry_address_symbol_map(elf_handle, elf_symbol,
580  symbol_sptr);
581 
582  return symbol_value;
583 }
584 
585 /// Update the function entry symbol map to later allow lookups of this symbol
586 /// by entry address as well. This is relevant for ppc64 ELFv1 binaries.
587 ///
588 /// For ppc64 ELFv1 binaries, we need to build a function entry point address
589 /// -> function symbol map. This is in addition to the function pointer ->
590 /// symbol map. This is because on ppc64 ELFv1, a function pointer is
591 /// different from a function entry point address.
592 ///
593 /// On ppc64 ELFv1, the DWARF DIE of a function references the address of the
594 /// entry point of the function symbol; whereas the value of the function
595 /// symbol is the function pointer. As these addresses are different, if I we
596 /// want to get to the symbol of a function from its entry point address (as
597 /// referenced by DWARF function DIEs) we must have the two maps I mentionned
598 /// right above.
599 ///
600 /// In other words, we need a map that associates a function entry point
601 /// address with the symbol of that function, to be able to get the function
602 /// symbol that corresponds to a given function DIE, on ppc64.
603 ///
604 /// The value of the function pointer (the value of the symbol) usually refers
605 /// to the offset of a table in the .opd section. But sometimes, for a symbol
606 /// named "foo", the corresponding symbol named ".foo" (note the dot before
607 /// foo) which value is the entry point address of the function; that entry
608 /// point address refers to a region in the .text section.
609 ///
610 /// So we are only interested in values of the symbol that are in the .opd
611 /// section.
612 ///
613 /// @param elf_handle the ELF handle to operate on
614 ///
615 /// @param native_symbol the native Elf symbol to update the entry for
616 ///
617 /// @param symbol_sptr the internal symbol to associte the entry address with
618 void
619 symtab::update_function_entry_address_symbol_map(
620  Elf* elf_handle, GElf_Sym* native_symbol, const elf_symbol_sptr& symbol_sptr)
621 {
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,
625  fn_desc_addr);
626 
627  const std::pair<addr_symbol_map_type::const_iterator, bool>& result =
628  entry_addr_symbol_map_.emplace(fn_entry_point_addr, symbol_sptr);
629 
630  const addr_symbol_map_type::const_iterator it = result.first;
631  const bool was_inserted = result.second;
632  if (!was_inserted
633  && elf_helpers::address_is_in_opd_section(elf_handle, fn_desc_addr))
634  {
635  // Either
636  //
637  // 'symbol' must have been registered as an alias for
638  // it->second->get_main_symbol()
639  //
640  // Or
641  //
642  // if the name of 'symbol' is foo, then the name of it2->second is
643  // ".foo". That is, foo is the name of the symbol when it refers to the
644  // function descriptor in the .opd section and ".foo" is an internal name
645  // for the address of the entry point of foo.
646  //
647  // In the latter case, we just want to keep a reference to "foo" as .foo
648  // is an internal name.
649 
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());
654 
655  ABG_ASSERT(two_symbols_alias
656  || symbol_is_foo_and_prev_symbol_is_dot_foo);
657 
658  if (symbol_is_foo_and_prev_symbol_is_dot_foo)
659  // Let's just keep a reference of the symbol that the user sees in the
660  // source code (the one named foo). The symbol which name is prefixed
661  // with a "dot" is an artificial one.
662  entry_addr_symbol_map_[fn_entry_point_addr] = symbol_sptr;
663  }
664 }
665 
666 /// Fill up the lookup maps with alternative keys
667 ///
668 /// Due to special features like Control-Flow-Integrity (CFI), the symbol
669 /// lookup could be done indirectly. E.g. enabling CFI causes clang to
670 /// associate the DWARF information with the actual CFI protected function
671 /// (suffix .cfi) instead of with the entry symbol in the symtab.
672 ///
673 /// This function adds additional lookup keys to compensate for that.
674 ///
675 /// So far, this only implements CFI support, by adding addr->symbol pairs
676 /// where
677 /// addr : symbol value of the <foo>.cfi value
678 /// symbol : symbol_sptr looked up via "<foo>"
679 ///
680 /// @param elf_handle the ELF handle to operate on
681 void
682 symtab::add_alternative_address_lookups(Elf* elf_handle)
683 {
684  Elf_Scn* symtab_section = elf_helpers::find_symtab_section(elf_handle);
685  if (!symtab_section)
686  return;
687  GElf_Shdr symtab_sheader;
688  gelf_getshdr(symtab_section, &symtab_sheader);
689 
690  const size_t number_syms =
691  symtab_sheader.sh_size / symtab_sheader.sh_entsize;
692 
693  Elf_Data* symtab = elf_getdata(symtab_section, 0);
694 
695  for (size_t i = 0; i < number_syms; ++i)
696  {
697  GElf_Sym *sym, sym_mem;
698  sym = gelf_getsym(symtab, i, &sym_mem);
699  if (!sym)
700  {
701  std::cerr << "Could not load symbol with index " << i
702  << ": Skipping alternative symbol load.\n";
703  continue;
704  }
705 
706  const char* const name_str =
707  elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
708 
709  // no name, no game
710  if (!name_str)
711  continue;
712 
713  const std::string name = name_str;
714  if (name.empty())
715  continue;
716 
717  // Add alternative lookup addresses for CFI symbols
718  static const std::string cfi = ".cfi";
719  if (name.size() > cfi.size()
720  && name.compare(name.size() - cfi.size(), cfi.size(), cfi) == 0)
721  // ... name.ends_with(".cfi")
722  {
723  const auto candidate_name = name.substr(0, name.size() - cfi.size());
724 
725  auto symbols = lookup_symbol(candidate_name);
726  // lookup_symbol returns a vector of symbols. For this case we handle
727  // only the case that there has been exactly one match. Otherwise we
728  // can't reasonably handle it and need to bail out.
729  ABG_ASSERT(symbols.size() <= 1);
730  if (symbols.size() == 1)
731  {
732  const auto& symbol_sptr = symbols[0];
733  setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
734  }
735  }
736  }
737 }
738 
739 } // end namespace symtab_reader
740 } // end namespace abigail
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,...
Definition: abg-fwd.h:1589
This contains the declarations for the symtab reader.
Abstraction of an elf symbol.
Definition: abg-ir.h:900
bool is_variable() const
Test if the current instance of elf_symbol is a variable symbol or not.
Definition: abg-ir.cc:2119
bool is_function() const
Test if the current instance of elf_symbol is a function symbol or not.
Definition: abg-ir.cc:2110
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.
Definition: abg-ir.cc:1902
bool is_public() const
Test if the current instance of elf_symbol is public or not.
Definition: abg-ir.cc:2094
bool is_in_ksymtab() const
Getter of the 'is-in-ksymtab' property.
Definition: abg-ir.cc:2127
bool is_defined() const
Test if the current instance of elf_symbol is defined or not.
Definition: abg-ir.cc:2072
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition: abg-ir.h:140
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.
Definition: abg-ir.h:863
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition: abg-ir.h:881
shared_ptr< string_elf_symbols_map_type > string_elf_symbols_map_sptr
Convenience typedef for a shared pointer to string_elf_symbols_map_type.
Definition: abg-ir.h:890
Toplevel namespace for libabigail.