libabigail
Loading...
Searching...
No Matches
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-2026 Red Hat, Inc.
5// Copyright (C) 2020-2026 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.
25ABG_BEGIN_EXPORT_DECLARATIONS
26#include "abg-symtab-reader.h"
27ABG_END_EXPORT_DECLARATIONS
28
29namespace abigail
30{
31
32namespace symtab_reader
33{
34
35using std::lock_guard;
36
37/// symtab_filter implementations
38
39/// Determine whether a symbol is matching the filter criteria of this filter
40/// object. In terms of a filter functionality, you would _not_ filter out
41/// this symbol if it passes this (i.e. returns true).
42///
43/// @param symbol The Elf symbol under test.
44///
45/// @return whether the symbol matches all relevant / required criteria
46bool
48{
49 if (functions_ && *functions_ != symbol.is_function())
50 return false;
51 if (variables_ && *variables_ != symbol.is_variable())
52 return false;
53 if (public_symbols_ && *public_symbols_ != symbol.is_public())
54 return false;
55 if (undefined_symbols_ && *undefined_symbols_ == symbol.is_defined())
56 return false;
57 if (kernel_symbols_ && *kernel_symbols_ != symbol.is_in_ksymtab())
58 return false;
59
60 return true;
61}
62
63/// symtab implementations
64
65/// Obtain a suitable default filter for iterating this symtab object.
66///
67/// The symtab_filter obtained is populated with some sensible default
68/// settings, such as public_symbols(true) and kernel_symbols(true) if the
69/// binary has been identified as Linux Kernel binary.
70///
71/// @return a symtab_filter with sensible populated defaults
74{
75 symtab_filter filter;
76 filter.set_public_symbols();
77 if (is_kernel_binary_)
78 filter.set_kernel_symbols();
79 return filter;
80}
81
82/// Get a vector of symbols that are associated with a certain name
83///
84/// @param name the name the symbols need to match
85///
86/// @return a vector of symbols, empty if no matching symbols have been found
87const elf_symbols&
88symtab::lookup_symbol(const std::string& name) const
89{
90 static const elf_symbols empty_result;
91 lock_guard<mutex> lock(map_mutex_);
92 const auto it = name_symbol_map_.find(name);
93 if (it != name_symbol_map_.end())
94 return it->second;
95 return empty_result;
96}
97
98/// Lookup a symbol by its address
99///
100/// @param symbol_addr the starting address of the symbol
101///
102/// @return a symbol if found, else an empty sptr
103const elf_symbol_sptr
104symtab::lookup_symbol(GElf_Addr symbol_addr) const
105{
106 static const elf_symbol_sptr empty_result;
107 lock_guard<mutex> lock(map_mutex_);
108 const auto addr_it = addr_symbol_map_.find(symbol_addr);
109 if (addr_it != addr_symbol_map_.end())
110 return addr_it->second;
111 else
112 {
113 // check for a potential entry address mapping instead,
114 // relevant for ppc ELFv1 binaries
115 const auto entry_it = entry_addr_symbol_map_.find(symbol_addr);
116 if (entry_it != entry_addr_symbol_map_.end())
117 return entry_it->second;
118 }
119 return empty_result;
120}
121
122/// Lookup an undefined function symbol with a given name.
123///
124/// @param sym_name the name of the function symbol to lookup.
125///
126/// @return the undefined function symbol found or nil if none was
127/// found.
128const elf_symbol_sptr
130{
131 auto it = undefined_fn_symbols_.find(sym_name);
132 if (it == undefined_fn_symbols_.end())
133 return elf_symbol_sptr();
134 return it->second;
135}
136
137/// Lookup an undefined variable symbol with a given name.
138///
139/// @param sym_name the name of the variable symbol to lookup.
140///
141/// @return the undefined variable symbol found or nil if none was
142/// found.
143const elf_symbol_sptr
145{
147 f.set_functions(false);
148 f.set_public_symbols(false);
149 f.set_undefined_symbols(true);
150 f.set_variables(true);
151
152 elf_symbol_sptr result;
153 for (auto sym : filtered_symtab(*this, f))
154 if (sym_name == sym->get_name())
155 {
156 result = sym;
157 break;
158 }
159 return result;
160}
161
162/// Test if a given function symbol has been exported.
163///
164/// Note that this doesn't test if the symbol is defined or not, but
165/// assumes the symbol is defined.
166///
167/// @param name the name of the symbol we are looking for.
168///
169/// @return the elf symbol if found, or nil otherwise.
172{
173 const elf_symbols& syms = lookup_symbol(name);
174 for (auto s : syms)
175 if (s->is_function() && s->is_public())
176 return s;
177
178 return elf_symbol_sptr();
179}
180
181/// Test if a given function symbol has been exported.
182///
183/// Note that this doesn't test if the symbol is defined or not, but
184/// assumes the symbol is defined.
185///
186/// @param symbol_address the address of the symbol we are looking
187/// for. Note that this address must be a relative offset from the
188/// beginning of the .text section, just like the kind of addresses
189/// that are present in the .symtab section.
190///
191/// @return the elf symbol if found, or nil otherwise.
193symtab::function_symbol_is_exported(const GElf_Addr symbol_address)
194{
195 elf_symbol_sptr symbol = lookup_symbol(symbol_address);
196 if (!symbol)
197 return symbol;
198
199 if (!symbol->is_function() || !symbol->is_public())
200 return elf_symbol_sptr();
201
202 return symbol;
203}
204
205/// Test if a given variable symbol has been exported.
206///
207/// Note that this assumes the symbol is exported but doesn't test for
208/// it.
209///
210/// @param name the name of the symbol we are looking
211/// for.
212///
213/// @return the elf symbol if found, or nil otherwise.
216{
217 const elf_symbols& syms = lookup_symbol(name);
218 for (auto s : syms)
219 if (s->is_variable() && s->is_public())
220 return s;
221
222 return elf_symbol_sptr();
223}
224
225/// Test if a given variable symbol has been exported.
226///
227/// Note that this assumes the symbol is exported but doesn't test for
228/// it.
229///
230/// @param symbol_address the address of the symbol we are looking
231/// for. Note that this address must be a relative offset from the
232/// beginning of the .text section, just like the kind of addresses
233/// that are present in the .symtab section.
234///
235/// @return the elf symbol if found, or nil otherwise.
237symtab::variable_symbol_is_exported(const GElf_Addr symbol_address)
238{
239 elf_symbol_sptr symbol = lookup_symbol(symbol_address);
240 if (!symbol)
241 return symbol;
242
243 if (!symbol->is_variable() || !symbol->is_public())
244 return elf_symbol_sptr();
245
246 return symbol;
247}
248
249/// Test if a name is a the name of an undefined function symbol.
250///
251/// @param sym_name the symbol name to consider.
252///
253/// @return the undefined symbol if found, nil otherwise.
256{
257 collect_undefined_fns_and_vars_linkage_names();
258 if (undefined_function_linkage_names_.count(sym_name))
259 {
261 ABG_ASSERT(sym);
262 ABG_ASSERT(sym->is_function());
263 ABG_ASSERT(!sym->is_defined());
264 return sym;
265 }
266 return elf_symbol_sptr();
267}
268
269/// Test if a name is a the name of an undefined variable symbol.
270///
271/// @param sym_name the symbol name to consider.
272///
273// @return the undefined symbol if found, nil otherwise.
276{
277 collect_undefined_fns_and_vars_linkage_names();
278 if (undefined_variable_linkage_names_.count(sym_name))
279 {
281 ABG_ASSERT(sym);
282 ABG_ASSERT(sym->is_variable());
283 ABG_ASSERT(!sym->is_defined());
284 return sym;
285 }
286 return elf_symbol_sptr();
287}
288
289/// A symbol sorting functor.
290static struct
291{
292 bool
293 operator()(const elf_symbol_sptr& left, const elf_symbol_sptr& right)
294 {return left->get_id_string() < right->get_id_string();}
295} symbol_sort;
296
297/// Construct a symtab object and instantiate it from an ELF
298/// handle. Also pass in the ir::environment we are living in. If
299/// specified, the symbol_predicate will be respected when creating
300/// the full vector of symbols.
301///
302/// @param elf_handle the elf handle to load the symbol table from
303///
304/// @param env the environment we are operating in
305///
306/// @param is_suppressed a predicate function to determine if a symbol should
307/// be suppressed
308///
309/// @return a smart pointer handle to symtab, set to nullptr if the load was
310/// not completed
311symtab_ptr
312symtab::load(Elf* elf_handle,
313 const ir::environment& env,
314 symbol_predicate is_suppressed)
315{
316 ABG_ASSERT(elf_handle);
317
318 symtab_ptr result(new symtab);
319 if (!result->load_(elf_handle, env, is_suppressed))
320 return {};
321
322 return result;
323}
324
325/// Construct a symtab object from existing name->symbol lookup maps.
326/// They were possibly read from a different representation (XML maybe).
327///
328/// @param function_symbol_map a map from ELF function name to elf_symbol
329///
330/// @param variable_symbol_map a map from ELF variable name to elf_symbol
331///
332/// @return a smart pointer handle to symtab, set to nullptr if the load was
333/// not completed
334symtab_ptr
336 string_elf_symbols_map_sptr variables_symbol_map)
337{
338 symtab_ptr result(new symtab);
339 if (!result->load_(function_symbol_map, variables_symbol_map))
340 return {};
341
342 return result;
343}
344
345/// Default constructor of the @ref symtab type.
346symtab::symtab()
347 : is_kernel_binary_(false), has_ksymtab_entries_(false),
348 cached_undefined_symbol_names_(false)
349{}
350
351/// Load the symtab representation from an Elf binary presented to us by an
352/// Elf* handle.
353///
354/// This method iterates over the entries of .symtab and collects all
355/// interesting symbols (functions and variables).
356///
357/// In case of a Linux Kernel binary, it also collects information about the
358/// symbols exported via EXPORT_SYMBOL in the Kernel that would then end up
359/// having a corresponding __ksymtab entry.
360///
361/// Symbols that are suppressed will be omitted from the symbols_ vector, but
362/// still be discoverable through the name->symbol and addr->symbol lookup
363/// maps.
364///
365/// @param elf_handle the elf handle to load the symbol table from
366///
367/// @param env the environment we are operating in
368///
369/// @param is_suppressed a predicate function to determine if a symbol should
370/// be suppressed
371///
372/// @return true if the load succeeded
373bool
374symtab::load_(Elf* elf_handle,
375 const ir::environment& env,
376 symbol_predicate is_suppressed)
377{
378 GElf_Ehdr ehdr_mem;
379 GElf_Ehdr* header = gelf_getehdr(elf_handle, &ehdr_mem);
380 if (!header)
381 {
382 std::cerr << "Could not get ELF header: Skipping symtab load.\n";
383 return false;
384 }
385
386 Elf_Scn* symtab_section = elf_helpers::find_symbol_table_section(elf_handle);
387 if (!symtab_section)
388 {
389 std::cerr << "No symbol table found: Skipping symtab load.\n";
390 return false;
391 }
392
393 GElf_Shdr symtab_sheader;
394 gelf_getshdr(symtab_section, &symtab_sheader);
395
396 // check for bogus section header
397 if (symtab_sheader.sh_entsize == 0)
398 {
399 std::cerr << "Invalid symtab header found: Skipping symtab load.\n";
400 return false;
401 }
402
403 const size_t number_syms =
404 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
405
406 Elf_Data* symtab = elf_getdata(symtab_section, 0);
407 if (!symtab)
408 {
409 std::cerr << "Could not load elf symtab: Skipping symtab load.\n";
410 return false;
411 }
412
413 // The __kstrtab_strings sections is basically an ELF strtab but does not
414 // support elf_strptr lookups. A single call to elf_getdata gives a handle to
415 // washed section data.
416 //
417 // The value of a __kstrtabns_FOO (or other similar) symbol is an address
418 // within the __kstrtab_strings section. To look up the string value, we need
419 // to translate from vmlinux load address to section offset by subtracting the
420 // base address of the section. This adjustment is not needed for loadable
421 // modules which are relocatable and so identifiable by ELF type ET_REL.
422 Elf_Scn* strings_section = elf_helpers::find_ksymtab_strings_section(elf_handle);
423 size_t strings_offset = 0;
424 const char* strings_data = nullptr;
425 size_t strings_size = 0;
426 if (strings_section)
427 {
428 GElf_Shdr strings_sheader;
429 gelf_getshdr(strings_section, &strings_sheader);
430 strings_offset = header->e_type == ET_REL ? 0 : strings_sheader.sh_addr;
431 Elf_Data* data = elf_getdata(strings_section, nullptr);
432 ABG_ASSERT(data->d_off == 0);
433 strings_data = reinterpret_cast<const char *>(data->d_buf);
434 strings_size = data->d_size;
435 }
436
437 const bool is_kernel = elf_helpers::is_linux_kernel(elf_handle);
438 std::unordered_set<std::string> exported_kernel_symbols;
439 std::unordered_map<std::string, uint32_t> crc_values;
440 std::unordered_map<std::string, std::string> namespaces;
441
442 for (size_t i = 0; i < number_syms; ++i)
443 {
444 GElf_Sym *sym, sym_mem;
445 sym = gelf_getsym(symtab, i, &sym_mem);
446 if (!sym)
447 {
448 std::cerr << "Could not load symbol with index " << i
449 << ": Skipping symtab load.\n";
450 return false;
451 }
452
453 const char* const name_str =
454 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
455
456 // no name, no game
457 if (!name_str)
458 continue;
459
460 const std::string name = name_str;
461 if (name.empty())
462 continue;
463
464 // Handle ksymtab entries. Every symbol entry that starts with __ksymtab_
465 // indicates that the symbol in question is exported through ksymtab. We
466 // do not know whether this is ksymtab_gpl or ksymtab, but that is good
467 // enough for now.
468 //
469 // We could follow up with this entry:
470 //
471 // symbol_value -> ksymtab_entry in either ksymtab_gpl or ksymtab
472 // -> addr/name/namespace (in case of PREL32: offset)
473 //
474 // That way we could also detect ksymtab<>ksymtab_gpl changes or changes
475 // of the symbol namespace.
476 //
477 // As of now this lookup is fragile, as occasionally ksymtabs are empty
478 // (seen so far for kernel modules and LTO builds). Hence we stick to the
479 // fairly safe assumption that ksymtab exported entries are having an
480 // appearence as __ksymtab_<symbol> in the symtab.
481 if (is_kernel && name.rfind("__ksymtab_", 0) == 0)
482 {
483 ABG_ASSERT(exported_kernel_symbols.insert(name.substr(10)).second);
484 continue;
485 }
486 if (is_kernel && name.rfind("__crc_", 0) == 0)
487 {
488 uint32_t crc_value;
489 ABG_ASSERT(elf_helpers::get_crc_for_symbol(elf_handle,
490 sym, crc_value));
491 ABG_ASSERT(crc_values.emplace(name.substr(6), crc_value).second);
492 continue;
493 }
494 if (strings_section && is_kernel && name.rfind("__kstrtabns_", 0) == 0)
495 {
496 // This symbol lives in the __ksymtab_strings section but st_value may
497 // be a vmlinux load address so we need to subtract the offset before
498 // looking it up in that section.
499 const size_t value = sym->st_value;
500 const size_t offset = value - strings_offset;
501 // check offset
502 ABG_ASSERT(offset < strings_size);
503 // find the terminating NULL
504 const char* first = strings_data + offset;
505 const char* last = strings_data + strings_size;
506 const char* limit = std::find(first, last, 0);
507 // check NULL found
508 ABG_ASSERT(limit < last);
509 // interpret the empty namespace name as no namespace name
510 if (first < limit)
511 ABG_ASSERT(namespaces.emplace(
512 name.substr(12), std::string(first, limit - first)).second);
513 continue;
514 }
515
516 // filter out uninteresting entries and only keep functions/variables for
517 // now. The rest might be interesting in the future though.
518 const int sym_type = GELF_ST_TYPE(sym->st_info);
519 if (!(sym_type == STT_FUNC
520 || sym_type == STT_GNU_IFUNC
521 // If the symbol is for an OBJECT, the index of the
522 // section it refers to cannot be absolute.
523 // Otherwise that OBJECT is not a variable.
524 || (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS)
525 // Undefined global variable symbols have symbol type
526 // STT_NOTYPE. No idea why.
527 || (sym_type == STT_NOTYPE && sym->st_shndx == SHN_UNDEF)
528 || sym_type == STT_TLS))
529 continue;
530
531 const bool sym_is_defined = sym->st_shndx != SHN_UNDEF;
532 // this occurs in relocatable files.
533 const bool sym_is_common = sym->st_shndx == SHN_COMMON;
534
535 elf_symbol::version ver;
536 elf_helpers::get_version_for_symbol(elf_handle, i, sym_is_defined, ver);
537
538 const elf_symbol_sptr& symbol_sptr =
540 (env, i, sym->st_size, name,
541 elf_helpers::stt_to_elf_symbol_type(GELF_ST_TYPE(sym->st_info)),
542 elf_helpers::stb_to_elf_symbol_binding(GELF_ST_BIND(sym->st_info)),
543 sym_is_defined, sym_is_common, ver,
544 elf_helpers::stv_to_elf_symbol_visibility
545 (GELF_ST_VISIBILITY(sym->st_other)));
546
547 // add to the name->symbol lookup
548 {
549 lock_guard<mutex> lock(map_mutex_);
550 name_symbol_map_[name].push_back(symbol_sptr);
551 }
552
553 // add to the addr->symbol lookup
554 if (symbol_sptr->is_common_symbol())
555 {
556 lock_guard<mutex> lock(map_mutex_);
557 const auto it = name_symbol_map_.find(name);
558 ABG_ASSERT(it != name_symbol_map_.end());
559 const elf_symbols& common_sym_instances = it->second;
560 ABG_ASSERT(!common_sym_instances.empty());
561 if (common_sym_instances.size() > 1)
562 {
563 elf_symbol_sptr main_common_sym = common_sym_instances[0];
564 ABG_ASSERT(main_common_sym->get_name() == name);
565 ABG_ASSERT(main_common_sym->is_common_symbol());
566 ABG_ASSERT(symbol_sptr.get() != main_common_sym.get());
567 main_common_sym->add_common_instance(symbol_sptr);
568 }
569 }
570 else if (symbol_sptr->is_defined())
571 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
572 }
573
574 // Now that symbols aliases have been constructed, let's determine
575 // what symbol has been suppressed or not. Suppression takes into
576 // account
577 for (auto& elem : name_symbol_map_)
578 {
579 auto& symbols = elem.second;
580 for (auto& symbol : symbols)
581 {
582 // We do not take suppressed symbols into our symbol vector
583 // to avoid accidental leakage. But we ensure supressed
584 // symbols are otherwise set up for lookup.
585 if (!(is_suppressed && is_suppressed(symbol)))
586 {
587 // add to the symbol vector
588 symbols_.push_back(symbol);
589 if (!symbol->is_defined())
590 {
591 if (symbol->is_function())
592 undefined_fn_symbols_[symbol->get_name()] = symbol;
593 else if (symbol->is_variable())
594 undefined_var_symbols_[symbol->get_name()] = symbol;
595 }
596 }
597 else
598 symbol->set_is_suppressed(true);
599 }
600 }
601
602 add_alternative_address_lookups(elf_handle);
603
604 is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
605
606 // Now apply the ksymtab_exported attribute to the symbols we
607 // collected.
608 {
609 lock_guard<mutex> lock(map_mutex_);
610 for (const auto& symbol : exported_kernel_symbols)
611 {
612 const auto r = name_symbol_map_.find(symbol);
613 if (r == name_symbol_map_.end())
614 continue;
615
616 for (const auto& elf_symbol : r->second)
617 if (elf_symbol->is_public())
618 elf_symbol->set_is_in_ksymtab(true);
619 has_ksymtab_entries_ = true;
620 }
621
622 // Now add the CRC values
623 for (const auto& crc_entry : crc_values)
624 {
625 const auto r = name_symbol_map_.find(crc_entry.first);
626 if (r == name_symbol_map_.end())
627 continue;
628
629 for (const auto& symbol : r->second)
630 symbol->set_crc(crc_entry.second);
631 }
632
633 // Now add the namespaces
634 for (const auto& namespace_entry : namespaces)
635 {
636 const auto r = name_symbol_map_.find(namespace_entry.first);
637 if (r == name_symbol_map_.end())
638 continue;
639
640 for (const auto& symbol : r->second)
641 symbol->set_namespace(namespace_entry.second);
642 }
643 }
644 // sort the symbols for deterministic output
645 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
646
647 return true;
648}
649
650/// Load the symtab representation from a function/variable lookup map pair.
651///
652/// This method assumes the lookup maps are correct and sets up the data
653/// vector as well as the name->symbol lookup map. The addr->symbol lookup
654/// map cannot be set up in this case.
655///
656/// @param function_symbol_map a map from ELF function name to elf_symbol
657///
658/// @param variable_symbol_map a map from ELF variable name to elf_symbol
659///
660/// @return true if the load succeeded
661bool
662symtab::load_(string_elf_symbols_map_sptr function_symbol_map,
663 string_elf_symbols_map_sptr variables_symbol_map)
664
665{
666 lock_guard<mutex> lock(map_mutex_);
667 if (function_symbol_map)
668 for (const auto& symbol_map_entry : *function_symbol_map)
669 {
670 for (const auto& symbol : symbol_map_entry.second)
671 {
672 if (!symbol->is_suppressed())
673 {
674 symbols_.push_back(symbol);
675 if (!symbol->is_defined())
676 undefined_fn_symbols_[symbol->get_name()] = symbol;
677 }
678 }
679 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
680 }
681
682 if (variables_symbol_map)
683 for (const auto& symbol_map_entry : *variables_symbol_map)
684 {
685 for (const auto& symbol : symbol_map_entry.second)
686 {
687 if (!symbol->is_suppressed())
688 {
689 symbols_.push_back(symbol);
690 if (!symbol->is_defined())
691 undefined_var_symbols_[symbol->get_name()] = symbol;
692 }
693 }
694 ABG_ASSERT(name_symbol_map_.insert(symbol_map_entry).second);
695 }
696
697 // sort the symbols for deterministic output
698 std::sort(symbols_.begin(), symbols_.end(), symbol_sort);
699
700 return true;
701}
702
703/// Notify the symtab about the name of the main symbol at a given address.
704///
705/// From just alone the symtab we can't guess the main symbol of a bunch of
706/// aliased symbols that all point to the same address. During processing of
707/// additional information (such as DWARF), this information becomes apparent
708/// and we can adjust the addr->symbol lookup map as well as the alias
709/// reference of the symbol objects.
710///
711/// @param addr the addr that we are updating the main symbol for
712/// @param name the name of the main symbol
713void
714symtab::update_main_symbol(GElf_Addr addr, const std::string& name)
715{
716 // get one symbol (i.e. the current main symbol)
717 elf_symbol_sptr symbol = lookup_symbol(addr);
718
719 // The caller might not know whether the addr is associated to an ELF symbol
720 // that we care about. E.g. the addr could be associated to an ELF symbol,
721 // but not one in .dynsym when looking at a DSO. Hence, early exit if the
722 // lookup failed.
723 if (!symbol)
724 return;
725
726 // determine the new main symbol by attempting an update
727 elf_symbol_sptr new_main = symbol->update_main_symbol(name);
728
729 // also update the default symbol we return when looked up by address
730 if (new_main)
731 {
732 lock_guard<mutex> lock(map_mutex_);
733 addr_symbol_map_[addr] = new_main;
734 }
735}
736
737/// Various adjustments and bookkeeping may be needed to provide a correct
738/// interpretation (one that matches DWARF addresses) of raw symbol values.
739///
740/// This is a sub-routine for symtab::load_ and
741/// symtab::add_alternative_address_lookups and must be called only
742/// once (per symbol) during the execution of the former.
743///
744/// @param elf_handle the ELF handle
745///
746/// @param elf_symbol the ELF symbol
747///
748/// @param symbol_sptr the libabigail symbol
749///
750/// @return a possibly-adjusted symbol value
751GElf_Addr
752symtab::setup_symbol_lookup_tables(Elf* elf_handle,
753 GElf_Sym* elf_symbol,
754 const elf_symbol_sptr& symbol_sptr)
755{
756 const bool is_arm32 = elf_helpers::architecture_is_arm32(elf_handle);
757 const bool is_arm64 = elf_helpers::architecture_is_arm64(elf_handle);
758 const bool is_ppc64 = elf_helpers::architecture_is_ppc64(elf_handle);
759 const bool is_ppc32 = elf_helpers::architecture_is_ppc32(elf_handle);
760
761 GElf_Addr symbol_value =
762 elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle,
763 elf_symbol);
764
765 if (is_arm32 && symbol_sptr->is_function())
766 // Clear bit zero of ARM32 addresses as per "ELF for the Arm
767 // Architecture" section 5.5.3.
768 // https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
769 symbol_value &= ~1;
770
771 if (is_arm64)
772 // Copy bit 55 over bits 56 to 63 which may be tag information.
773 symbol_value = symbol_value & (1ULL<<55)
774 ? symbol_value | (0xffULL<<56)
775 : symbol_value &~ (0xffULL<<56);
776
777 if (symbol_sptr->is_defined())
778 {
779 lock_guard<mutex> lock(map_mutex_);
780 const auto result =
781 addr_symbol_map_.emplace(symbol_value, symbol_sptr);
782 if (!result.second)
783 // A symbol with the same address already exists. This
784 // means this symbol is an alias of the main symbol with
785 // that address. So let's register this new alias as such.
786 result.first->second->get_main_symbol()->add_alias(symbol_sptr);
787 }
788
789 // Please note that update_function_entry_address_symbol_map depends
790 // on the symbol aliases been setup. This is why, the
791 // elf_symbol::add_alias call is done above BEFORE this point.
792 if ((is_ppc64 || is_ppc32) && symbol_sptr->is_function())
793 update_function_entry_address_symbol_map(elf_handle, elf_symbol,
794 symbol_sptr);
795
796 return symbol_value;
797}
798
799/// Update the function entry symbol map to later allow lookups of this symbol
800/// by entry address as well. This is relevant for ppc64 ELFv1 binaries.
801///
802/// For ppc64 ELFv1 binaries, we need to build a function entry point address
803/// -> function symbol map. This is in addition to the function pointer ->
804/// symbol map. This is because on ppc64 ELFv1, a function pointer is
805/// different from a function entry point address.
806///
807/// On ppc64 ELFv1, the DWARF DIE of a function references the address of the
808/// entry point of the function symbol; whereas the value of the function
809/// symbol is the function pointer. As these addresses are different, if I we
810/// want to get to the symbol of a function from its entry point address (as
811/// referenced by DWARF function DIEs) we must have the two maps I mentionned
812/// right above.
813///
814/// In other words, we need a map that associates a function entry point
815/// address with the symbol of that function, to be able to get the function
816/// symbol that corresponds to a given function DIE, on ppc64.
817///
818/// The value of the function pointer (the value of the symbol) usually refers
819/// to the offset of a table in the .opd section. But sometimes, for a symbol
820/// named "foo", the corresponding symbol named ".foo" (note the dot before
821/// foo) which value is the entry point address of the function; that entry
822/// point address refers to a region in the .text section.
823///
824/// So we are only interested in values of the symbol that are in the .opd
825/// section.
826///
827/// @param elf_handle the ELF handle to operate on
828///
829/// @param native_symbol the native Elf symbol to update the entry for
830///
831/// @param symbol_sptr the internal symbol to associte the entry address with
832void
833symtab::update_function_entry_address_symbol_map(
834 Elf* elf_handle, GElf_Sym* native_symbol, const elf_symbol_sptr& symbol_sptr)
835{
836 const GElf_Addr fn_desc_addr = native_symbol->st_value;
837 const GElf_Addr fn_entry_point_addr =
838 elf_helpers::lookup_ppc64_elf_fn_entry_point_address(elf_handle,
839 fn_desc_addr);
840
841 lock_guard<mutex> lock(map_mutex_);
842 const std::pair<addr_symbol_map_type::const_iterator, bool>& result =
843 entry_addr_symbol_map_.emplace(fn_entry_point_addr, symbol_sptr);
844
845 const addr_symbol_map_type::const_iterator it = result.first;
846 const bool was_inserted = result.second;
847 if (!was_inserted
848 && elf_helpers::address_is_in_opd_section(elf_handle, fn_desc_addr))
849 {
850 // Either
851 //
852 // 'symbol' must have been registered as an alias for
853 // it->second->get_main_symbol()
854 //
855 // Or
856 //
857 // if the name of 'symbol' is foo, then the name of it2->second is
858 // ".foo". That is, foo is the name of the symbol when it refers to the
859 // function descriptor in the .opd section and ".foo" is an internal name
860 // for the address of the entry point of foo.
861 //
862 // In the latter case, we just want to keep a reference to "foo" as .foo
863 // is an internal name.
864
865 const bool two_symbols_alias =
866 it->second->get_main_symbol()->does_alias(*symbol_sptr);
867 const bool symbol_is_foo_and_prev_symbol_is_dot_foo =
868 (it->second->get_name() == std::string(".") + symbol_sptr->get_name());
869
870 ABG_ASSERT(two_symbols_alias
871 || symbol_is_foo_and_prev_symbol_is_dot_foo);
872
873 if (symbol_is_foo_and_prev_symbol_is_dot_foo)
874 // Let's just keep a reference of the symbol that the user sees in the
875 // source code (the one named foo). The symbol which name is prefixed
876 // with a "dot" is an artificial one.
877 entry_addr_symbol_map_[fn_entry_point_addr] = symbol_sptr;
878 }
879}
880
881/// Fill up the lookup maps with alternative keys
882///
883/// Due to special features like Control-Flow-Integrity (CFI), the symbol
884/// lookup could be done indirectly. E.g. enabling CFI causes clang to
885/// associate the DWARF information with the actual CFI protected function
886/// (suffix .cfi) instead of with the entry symbol in the symtab.
887///
888/// This function adds additional lookup keys to compensate for that.
889///
890/// So far, this only implements CFI support, by adding addr->symbol pairs
891/// where
892/// addr : symbol value of the <foo>.cfi value
893/// symbol : symbol_sptr looked up via "<foo>"
894///
895/// @param elf_handle the ELF handle to operate on
896void
897symtab::add_alternative_address_lookups(Elf* elf_handle)
898{
899 Elf_Scn* symtab_section = elf_helpers::find_symtab_section(elf_handle);
900 if (!symtab_section)
901 return;
902 GElf_Shdr symtab_sheader;
903 gelf_getshdr(symtab_section, &symtab_sheader);
904
905 const size_t number_syms =
906 symtab_sheader.sh_size / symtab_sheader.sh_entsize;
907
908 Elf_Data* symtab = elf_getdata(symtab_section, 0);
909
910 for (size_t i = 0; i < number_syms; ++i)
911 {
912 GElf_Sym *sym, sym_mem;
913 sym = gelf_getsym(symtab, i, &sym_mem);
914 if (!sym)
915 {
916 std::cerr << "Could not load symbol with index " << i
917 << ": Skipping alternative symbol load.\n";
918 continue;
919 }
920
921 const char* const name_str =
922 elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
923
924 // no name, no game
925 if (!name_str)
926 continue;
927
928 const std::string name = name_str;
929 if (name.empty())
930 continue;
931
932 // Add alternative lookup addresses for CFI symbols
933 static const std::string cfi = ".cfi";
934 if (name.size() > cfi.size()
935 && name.compare(name.size() - cfi.size(), cfi.size(), cfi) == 0)
936 // ... name.ends_with(".cfi")
937 {
938 const auto candidate_name = name.substr(0, name.size() - cfi.size());
939
940 auto symbols = lookup_symbol(candidate_name);
941 // lookup_symbol returns a vector of symbols. For this case we handle
942 // only the case that there has been exactly one match. Otherwise we
943 // can't reasonably handle it and need to bail out.
944 ABG_ASSERT(symbols.size() <= 1);
945 if (symbols.size() == 1)
946 {
947 const auto& symbol_sptr = symbols[0];
948 setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
949 }
950 }
951 }
952}
953
954/// Collect the names of the variable and function symbols that are
955/// undefined. Cache those names into sets to speed up their lookup.
956///
957/// Once the names are cached into sets, subsequent invocations of
958/// this function are essentially a no-op.
959void
960symtab::collect_undefined_fns_and_vars_linkage_names()
961{
962 lock_guard<mutex> lock(big_mutex_);
963 if (!cached_undefined_symbol_names_)
964 {
965 {
966 symtab_filter f = make_filter();
967 f.set_variables(false);
968 f.set_functions(true);
969 f.set_public_symbols(false);
970 f.set_undefined_symbols(true);
971 for (auto sym : filtered_symtab(*this, f))
972 undefined_function_linkage_names_.insert(sym->get_name());
973 }
974
975 {
976 symtab_filter f = make_filter();
977 f.set_variables(true);
978 f.set_functions(false);
979 f.set_public_symbols(false);
980 f.set_undefined_symbols(true);
981 for (auto sym : filtered_symtab(*this, f))
982 undefined_variable_linkage_names_.insert(sym->get_name());
983 }
984 }
985 cached_undefined_symbol_names_ = true;
986}
987} // end namespace symtab_reader
988} // 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:1790
This contains the declarations for the symtab reader.
Abstraction of an elf symbol.
Definition abg-ir.h:959
bool is_variable() const
Test if the current instance of elf_symbol is a variable symbol or not.
Definition abg-ir.cc:2865
bool is_function() const
Test if the current instance of elf_symbol is a function symbol or not.
Definition abg-ir.cc:2856
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:2585
bool is_public() const
Test if the current instance of elf_symbol is public or not.
Definition abg-ir.cc:2840
bool is_in_ksymtab() const
Getter of the 'is-in-ksymtab' property.
Definition abg-ir.cc:2879
bool is_defined() const
Test if the current instance of elf_symbol is defined or not.
Definition abg-ir.cc:2812
This is an abstraction of the set of resources necessary to manage several aspects of the internal re...
Definition abg-ir.h:216
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.
Definition abg-ir.h:924
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition abg-ir.h:940
string get_name(const type_or_decl_base *tod, bool qualified)
Build and return a copy of the name of an ABI artifact that is either a type or a decl.
Definition abg-ir.cc:9888
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:949
Toplevel namespace for libabigail.