diff --git a/include/Makefile.am b/include/Makefile.am index b5475252..639906aa 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -25,6 +25,7 @@ abg-version.h \ abg-viz-common.h \ abg-viz-dot.h \ abg-viz-svg.h \ -abg-regex.h +abg-regex.h \ +abg-symtab-reader.h EXTRA_DIST = abg-version.h.in diff --git a/include/abg-comparison.h b/include/abg-comparison.h index 51a78d29..d107bf9f 100644 --- a/include/abg-comparison.h +++ b/include/abg-comparison.h @@ -418,10 +418,9 @@ enum diff_category /// present as a child of a other nodes in the diff tree. REDUNDANT_CATEGORY = 1 << 13, - /// This means that a diff node in the sub-tree carries a class type - /// that was declaration-only and that is now defined, or vice - /// versa. - CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14, + /// This means that a diff node in the sub-tree carries a type that + /// was declaration-only and that is now defined, or vice versa. + TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14, /// A diff node in this category is a function parameter type which /// top cv-qualifiers change. @@ -447,6 +446,7 @@ enum diff_category /// array type of a global variable, but the ELF size of the /// variable didn't change. BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 20, + /// A special enumerator that is the logical 'or' all the /// enumerators above. /// @@ -467,7 +467,7 @@ enum diff_category | SIZE_OR_OFFSET_CHANGE_CATEGORY | VIRTUAL_MEMBER_CHANGE_CATEGORY | REDUNDANT_CATEGORY - | CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY + | TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY | FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY | FN_PARM_TYPE_CV_CHANGE_CATEGORY | FN_RETURN_TYPE_CV_CHANGE_CATEGORY diff --git a/include/abg-corpus.h b/include/abg-corpus.h index 410a9c24..f517986d 100644 --- a/include/abg-corpus.h +++ b/include/abg-corpus.h @@ -170,26 +170,14 @@ class corpus operator==(const corpus&) const; void - set_fun_symbol_map(string_elf_symbols_map_sptr); + set_symtab(symtab_reader::symtab_sptr); - void - set_undefined_fun_symbol_map(string_elf_symbols_map_sptr); - - void - set_var_symbol_map(string_elf_symbols_map_sptr); - - void - set_undefined_var_symbol_map(string_elf_symbols_map_sptr); - - const string_elf_symbols_map_sptr - get_fun_symbol_map_sptr() const; + const symtab_reader::symtab_sptr& + get_symtab() const; virtual const string_elf_symbols_map_type& get_fun_symbol_map() const; - const string_elf_symbols_map_sptr - get_undefined_fun_symbol_map_sptr() const; - const string_elf_symbols_map_type& get_undefined_fun_symbol_map() const; @@ -199,15 +187,9 @@ class corpus const elf_symbols& get_sorted_undefined_fun_symbols() const; - const string_elf_symbols_map_sptr - get_var_symbol_map_sptr() const; - virtual const string_elf_symbols_map_type& get_var_symbol_map() const; - const string_elf_symbols_map_sptr - get_undefined_var_symbol_map_sptr() const; - const string_elf_symbols_map_type& get_undefined_var_symbol_map() const; diff --git a/include/abg-cxx-compat.h b/include/abg-cxx-compat.h index 71417718..cab2883b 100644 --- a/include/abg-cxx-compat.h +++ b/include/abg-cxx-compat.h @@ -23,6 +23,8 @@ #ifndef __ABG_CXX_COMPAT_H #define __ABG_CXX_COMPAT_H +// C++11 support (mostly via tr1 if compiled with earlier standard) + #if __cplusplus >= 201103L #include @@ -39,13 +41,32 @@ #endif +// C++17 support (via custom implementations if compiled with earlier standard) + +#if __cplusplus >= 201703L + +#include + +#else + +#include // for throwing std::runtime_error("bad_optional_access") + +#endif + namespace abg_compat { #if __cplusplus >= 201103L // +using std::bind; +using std::function; using std::hash; +namespace placeholders +{ +using namespace std::placeholders; +} + // using std::shared_ptr; using std::weak_ptr; @@ -61,8 +82,15 @@ using std::unordered_set; #else // +using std::tr1::bind; +using std::tr1::function; using std::tr1::hash; +namespace placeholders +{ +using namespace std::tr1::placeholders; +} + // using std::tr1::shared_ptr; using std::tr1::weak_ptr; @@ -77,6 +105,78 @@ using std::tr1::unordered_set; #endif +#if __cplusplus >= 201703L + +using std::optional; + +#else + +// + +/// Simplified implementation of std::optional just enough to be used as a +/// replacement for our purposes and when compiling with pre C++17. +/// +/// The implementation intentionally does not support a whole lot of features +/// to minimize the maintainence effort with this. +template class optional +{ + bool has_value_; + T value_; + +public: + optional() : has_value_(false), value_() {} + optional(const T& value) : has_value_(true), value_(value) {} + + bool + has_value() const + { + return has_value_; + } + + const T& + value() const + { + if (!has_value_) + throw std::runtime_error("bad_optional_access"); + return value_; + } + + const T + value_or(const T& default_value) const + { + if (!has_value_) + return default_value; + return value_; + } + + const T& + operator*() const + { return value_; } + + T& + operator*() + { return value_; } + + const T* + operator->() const + { return &value_; } + + T* + operator->() + { return &value_; } + + optional& + operator=(const T& value) + { + has_value_ = true; + value_ = value; + return *this; + } + + explicit operator bool() const { return has_value_; } +}; + +#endif } #endif // __ABG_CXX_COMPAT_H diff --git a/include/abg-dwarf-reader.h b/include/abg-dwarf-reader.h index d0329aed..3f062e04 100644 --- a/include/abg-dwarf-reader.h +++ b/include/abg-dwarf-reader.h @@ -195,12 +195,6 @@ set_drop_undefined_syms(read_context& ctxt, void set_do_log(read_context& ctxt, bool f); -void -set_ignore_symbol_table(read_context &ctxt, bool f); - -bool -get_ignore_symbol_table(const read_context &ctxt); - void set_environment(read_context& ctxt, ir::environment*); diff --git a/include/abg-fwd.h b/include/abg-fwd.h index f6e0c5b2..07ab0b9f 100644 --- a/include/abg-fwd.h +++ b/include/abg-fwd.h @@ -152,7 +152,7 @@ typedef weak_ptr typedef_decl_wptr; class enum_type_decl; -/// Convenience typedef for shared pointer on enum_type_decl. +/// Convenience typedef for shared pointer to a @ref enum_type_decl. typedef shared_ptr enum_type_decl_sptr; class class_or_union; @@ -1331,6 +1331,14 @@ typedef vector suppressions_type; } // end namespace suppr +namespace symtab_reader +{ + +class symtab; +typedef abg_compat::shared_ptr symtab_sptr; + +} // end namespace symtab_reader + void dump(const decl_base_sptr, std::ostream&); diff --git a/include/abg-ir.h b/include/abg-ir.h index ebcc4b81..6c368f03 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -851,8 +851,11 @@ class elf_symbol bool d, bool c, const version& ve, - visibility vi, - bool is_linux_string_cst = false); + visibility vi, + bool is_linux_string_cst = false, + bool is_in_ksymtab = false, + uint64_t crc = 0, + bool is_suppressed = false); elf_symbol(const elf_symbol&); @@ -865,17 +868,20 @@ class elf_symbol create(); 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_linux_string_cst = false); + 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_linux_string_cst = false, + bool is_in_ksymtab = false, + uint64_t crc = 0, + bool is_suppressed = false); const environment* get_environment() const; @@ -943,6 +949,24 @@ class elf_symbol bool is_variable() const; + bool + is_in_ksymtab() const; + + void + set_is_in_ksymtab(bool is_in_ksymtab); + + uint64_t + get_crc() const; + + void + set_crc(uint64_t crc); + + bool + is_suppressed() const; + + void + set_is_suppressed(bool is_suppressed); + const elf_symbol_sptr get_main_symbol() const; @@ -952,6 +976,9 @@ class elf_symbol bool is_main_symbol() const; + elf_symbol_sptr + update_main_symbol(const std::string&); + elf_symbol_sptr get_next_alias() const; @@ -1391,6 +1418,9 @@ class decl_base : public virtual type_or_decl_base const interned_string& peek_qualified_name() const; + void + clear_qualified_name(); + void set_qualified_name(const interned_string&) const; @@ -2024,6 +2054,7 @@ class qualified_type_def : public virtual type_base, public virtual decl_base protected: string build_name(bool, bool internal = false) const; + virtual void on_canonical_type_set(); public: @@ -2126,6 +2157,9 @@ class pointer_type_def : public virtual type_base, public virtual decl_base // Forbidden. pointer_type_def(); +protected: + virtual void on_canonical_type_set(); + public: /// A hasher for instances of pointer_type_def @@ -2180,6 +2214,9 @@ class reference_type_def : public virtual type_base, public virtual decl_base // Forbidden. reference_type_def(); +protected: + virtual void on_canonical_type_set(); + public: /// Hasher for intances of reference_type_def. @@ -3068,6 +3105,9 @@ class function_type : public virtual type_base struct priv; typedef shared_ptr priv_sptr; +protected: + virtual void on_canonical_type_set(); + public: /// Hasher for an instance of function_type struct hash; diff --git a/include/abg-symtab-reader.h b/include/abg-symtab-reader.h new file mode 100644 index 00000000..9065b6ad --- /dev/null +++ b/include/abg-symtab-reader.h @@ -0,0 +1,429 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . +// +// Author: Matthias Maennich + +/// @file +/// +/// This contains the declarations for the symtab reader. + +#ifndef __ABG_SYMTAB_READER_H__ +#define __ABG_SYMTAB_READER_H__ + +#include + +#include +#include + +#include "abg-cxx-compat.h" +#include "abg-ir.h" + +namespace abigail +{ +namespace symtab_reader +{ + +class symtab_filter_builder; + +/// The symtab filter is the object passed to the symtab object in order to +/// iterate over the symbols in the symtab while applying filters. +/// +/// The general idea is that it consists of a set of optionally enforced flags, +/// such as 'functions' or 'variables'. If not set, those are not filtered for, +/// neither inclusive nor exclusive. If set they are all ANDed together. +class symtab_filter +{ +public: + // The symtab_filter_builder helps us to build filters efficiently, hence + // let's be nice and grant access to our internals. + friend class symtab_filter_builder; + + // Default constructor disabling all features. + symtab_filter() {} + + /// Determine whether a symbol is matching the filter criteria of this filter + /// object. In terms of a filter functionality, you would _not_ filter out + /// this symbol if it passes this (i.e. returns true). + /// + /// @param symbol The Elf symbol under test. + /// + /// @return whether the symbol matches all relevant / required criteria + bool + matches(const elf_symbol_sptr& symbol) const; + +private: + // The symbol is a function (FUNC) + abg_compat::optional functions_; + + // The symbol is a variables (OBJECT) + abg_compat::optional variables_; + + // The symbol is publicly accessible (global/weak with default/protected + // visibility) + abg_compat::optional public_symbols_; + + // The symbols is not defined (declared) + abg_compat::optional undefined_symbols_; + + // The symbol is listed in the ksymtab (for Linux Kernel binaries). + abg_compat::optional kernel_symbols_; +}; + +/// Helper class to provide an attractive interface to build symtab_filters. +/// +/// When constructed, the helper instantiates a default symtab_filter and +/// allows modifications to it via builder pattern / fluent interface. +/// +/// When assigned to a symtab_filter instance, it converts by returning the +/// locally build symtab_filter instance. +/// +/// Example usage: +/// +/// const symtab_filter filter = +/// symtab_filter_builder().functions().kernel_symbols(); +/// +/// In that case we would filter for the conjunction of function symbols that +/// also appear in the ksymtab (i.e. kernel symbols). +class symtab_filter_builder +{ +public: + /// Enable inclusive / exclusive filtering for functions. + symtab_filter_builder& + functions(bool value = true) + { filter_.functions_ = value; return *this; } + + /// Enable inclusive / exclusive filtering for variables. + symtab_filter_builder& + variables(bool value = true) + { filter_.variables_ = value; return *this; } + + /// Enable inclusive / exclusive filtering for public symbols. + symtab_filter_builder& + public_symbols(bool value = true) + { filter_.public_symbols_ = value; return *this; } + + /// Enable inclusive / exclusive filtering for undefined symbols. + symtab_filter_builder& + undefined_symbols(bool value = true) + { filter_.undefined_symbols_ = value; return *this; } + + /// Enable inclusive / exclusive filtering for kernel symbols. + symtab_filter_builder& + kernel_symbols(bool value = true) + { filter_.kernel_symbols_ = value; return *this; } + + /// Convert seamlessly to a symtab_filter instance. + /// + /// We could possibly validate the filter constellations here. For now, we + /// just return the local filter instance. + operator symtab_filter() { return filter_; } + +private: + /// Local symtab_filter instance that we build and eventually pass on. + symtab_filter filter_; +}; + +/// Base iterator for our custom iterator based on whatever the const_iterator +/// is for a vector of symbols. +/// As of writing this, std::vector::const_iterator. +typedef elf_symbols::const_iterator base_iterator; + +/// An iterator to walk a vector of elf_symbols filtered by symtab_filter. +/// +/// The implementation inherits all properties from the vector's +/// const_iterator, but intercepts where necessary to allow effective +/// filtering. This makes it a STL compatible iterator for general purpose +/// usage. +class symtab_iterator : public base_iterator +{ +public: + typedef base_iterator::value_type value_type; + typedef base_iterator::reference reference; + typedef base_iterator::pointer pointer; + typedef base_iterator::difference_type difference_type; + typedef std::forward_iterator_tag iterator_category; + + /// Construct the iterator based on a pair of underlying iterators and a + /// symtab_filter object. Immediately fast forward to the next element that + /// matches the criteria (if any). + symtab_iterator(base_iterator begin, + base_iterator end, + const symtab_filter& filter = symtab_filter()) + : base_iterator(begin), end_(end), filter_(filter) + { skip_to_next(); } + + /// Pre-increment operator to advance to the next matching element. + symtab_iterator& + operator++() + { + base_iterator::operator++(); + skip_to_next(); + return *this; + } + + /// Post-increment operator to advance to the next matching element. + symtab_iterator + operator++(int) + { + symtab_iterator result(*this); + ++(*this); + return result; + } + +private: + /// The end of the underlying iterator. + const base_iterator end_; + + /// The symtab_filter used to determine when to advance. + const symtab_filter& filter_; + + /// Skip to the next element that matches the filter criteria (if any). Hold + /// off when reaching the end of the underlying iterator. + void + skip_to_next() + { + while (*this != end_ && !filter_.matches(**this)) + ++(*this); + } +}; + +/// Convenience declaration of a shared_ptr +class symtab; +typedef abg_compat::shared_ptr symtab_sptr; + +/// symtab is the actual data container of the symtab_reader implementation. +/// +/// The symtab is instantiated either via an Elf handle (from binary) or from a +/// set of existing symbol maps (usually when instantiated from XML). It will +/// then discover the symtab, possibly the ksymtab (for Linux Kernel binaries) +/// and setup the data containers and lookup maps for later perusal. +/// +/// The symtab is supposed to be used in a const context as all information is +/// already computed at construction time. Symbols are stored sorted to allow +/// deterministic reading of the entries. +/// +/// An example use of the symtab class is +/// +/// const symtab_sptr tab = symtab::load(elf_handle, env); +/// const symtab_filter filter = tab->make_filter() +/// .public_symbols() +/// .functions(); +/// +/// for (symtab::const_iterator I = tab.begin(filter), E = tab.end(); +/// I != E; ++I) +/// { +/// std::cout << (*I)->get_name() << "\n"; +/// } +/// +/// C++11 and later allows a more brief syntax for the same: +/// +/// for (const auto& symbol : filtered_symtab(*tab, filter)) +/// { +/// std::cout << symbol->get_name() << "\n"; +/// } +/// +/// This uses the filtered_symtab proxy object to capture the filter. +class symtab +{ +public: + typedef abg_compat::function symbol_predicate; + + /// Indicate whether any (kernel) symbols have been seen at construction. + /// + /// @return true if there are symbols detected earlier. + bool + has_symbols() const + { return is_kernel_binary_ ? has_ksymtab_entries_ : !symbols_.empty(); } + + /// Obtain a suitable default filter for iterating this symtab object. + /// + /// The symtab_filter_build obtained is populated with some sensible default + /// settings, such as public_symbols(true) and kernel_symbols(true) if the + /// binary has been identified as Linux Kernel binary. + /// + /// @return a symtab_filter_builder with sensible populated defaults + symtab_filter_builder + make_filter() const; + + /// The (only) iterator type we offer is a const_iterator implemented by the + /// symtab_iterator. + typedef symtab_iterator const_iterator; + + /// Obtain an iterator to the beginning of the symtab according to the filter + /// criteria. Whenever this iterator advances, it skips elements that do not + /// match the filter criteria. + /// + /// @param filter the symtab_filter to match symbols against + /// + /// @return a filtering const_iterator of the underlying type + const_iterator + begin(const symtab_filter& filter) const + { return symtab_iterator(symbols_.begin(), symbols_.end(), filter); } + + /// Obtain an iterator to the end of the symtab. + /// + /// @return an end iterator + const_iterator + end() const + { return symtab_iterator(symbols_.end(), symbols_.end()); } + + /// Get a vector of symbols that are associated with a certain name + /// + /// @param name the name the symbols need to match + /// + /// @return a vector of symbols, empty if no matching symbols have been found + const elf_symbols& + lookup_symbol(const std::string& name) const; + + /// Lookup a symbol by its address + /// + /// @param symbol_addr the starting address of the symbol + /// + /// @return a symbol if found, else an empty sptr + const elf_symbol_sptr& + lookup_symbol(GElf_Addr symbol_addr) const; + + /// Construct a symtab object and instantiate from an ELF handle. Also pass + /// in an ir::environment handle to interact with the context we are living + /// in. If specified, the symbol_predicate will be respected when creating + /// the full vector of symbols. + static symtab_sptr + load(Elf* elf_handle, + ir::environment* env, + symbol_predicate is_suppressed = NULL); + + /// Construct a symtab object from existing name->symbol lookup maps. + /// They were possibly read from a different representation (XML maybe). + static symtab_sptr + load(string_elf_symbols_map_sptr function_symbol_map, + string_elf_symbols_map_sptr variables_symbol_map); + + /// Notify the symtab about the name of the main symbol at a given address. + /// + /// From just alone the symtab we can't guess the main symbol of a bunch of + /// aliased symbols that all point to the same address. During processing of + /// additional information (such as DWARF), this information becomes apparent + /// and we can adjust the addr->symbol lookup map as well as the alias + /// reference of the symbol objects. + /// + /// @param addr the addr that we are updating the main symbol for + /// @param name the name of the main symbol + void + update_main_symbol(GElf_Addr addr, const std::string& name); + +private: + /// Default constructor. Private to enforce creation by factory methods. + symtab(); + + /// The vector of symbols we discovered. + elf_symbols symbols_; + + /// Whether this is a Linux Kernel binary + bool is_kernel_binary_; + + /// Whether this kernel_binary has ksymtab entries + /// + /// A kernel module might not have a ksymtab if it does not export any + /// symbols. In order to quickly decide whether the symbol table is empty, we + /// remember whether we ever saw ksymtab entries. + bool has_ksymtab_entries_; + + /// Lookup map name->symbol(s) + typedef abg_compat::unordered_map > + name_symbol_map_type; + name_symbol_map_type name_symbol_map_; + + /// Lookup map name->symbol + typedef abg_compat::unordered_map + addr_symbol_map_type; + addr_symbol_map_type addr_symbol_map_; + + /// Lookup map function entry address -> symbol + addr_symbol_map_type entry_addr_symbol_map_; + + /// Load the symtab representation from an Elf binary presented to us by an + /// Elf* handle. + /// + /// This method iterates over the entries of .symtab and collects all + /// interesting symbols (functions and variables). + /// + /// In case of a Linux Kernel binary, it also collects information about the + /// symbols exported via EXPORT_SYMBOL in the Kernel that would then end up + /// having a corresponding __ksymtab entry. + /// + /// Symbols that are suppressed will be omitted from the symbols_ vector, but + /// still be discoverable through the name->symbol and addr->symbol lookup + /// maps. + bool + load_(Elf* elf_handle, ir::environment* env, symbol_predicate is_suppressed); + + /// Load the symtab representation from a function/variable lookup map pair. + /// + /// This method assumes the lookup maps are correct and sets up the data + /// vector as well as the name->symbol lookup map. The addr->symbol lookup + /// map cannot be set up in this case. + bool + load_(string_elf_symbols_map_sptr function_symbol_map, + string_elf_symbols_map_sptr variables_symbol_map); + + void + update_function_entry_address_symbol_map(Elf* elf_handle, + GElf_Sym* native_symbol, + const elf_symbol_sptr& symbol_sptr); +}; + +/// Helper class to allow range-for loops on symtabs for C++11 and later code. +/// It serves as a proxy for the symtab iterator and provides a begin() method +/// without arguments, as required for range-for loops (and possibly other +/// iterator based transformations). +/// +/// Example usage: +/// +/// for (const auto& symbol : filtered_symtab(tab, filter)) +/// { +/// std::cout << symbol->get_name() << "\n"; +/// } +/// +class filtered_symtab +{ + const symtab& tab_; + const symtab_filter filter_; + +public: + /// Construct the proxy object keeping references to the underlying symtab + /// and the filter object. + filtered_symtab(const symtab& tab, const symtab_filter& filter) + : tab_(tab), filter_(filter) { } + + /// Pass through symtab.begin(), but also pass on the filter. + symtab::const_iterator + begin() const + { return tab_.begin(filter_); } + + /// Pass through symtab.end(). + symtab::const_iterator + end() const + { return tab_.end(); } +}; + +} // end namespace symtab_reader +} // end namespace abigail + +#endif // __ABG_SYMTAB_READER_H__ diff --git a/src/Makefile.am b/src/Makefile.am index 1153a5f8..dff17d9c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ abg-tools-utils.cc \ abg-elf-helpers.h \ abg-elf-helpers.cc \ abg-regex.cc \ +abg-symtab-reader.cc \ $(CXX11_SOURCES) libabigail_la_LIBADD = $(DEPS_LIBS) diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc index 5f9dd6fe..702d223f 100644 --- a/src/abg-comp-filter.cc +++ b/src/abg-comp-filter.cc @@ -961,8 +961,8 @@ has_class_decl_only_def_change(const class_or_union_sptr& first, /// other one is defined. /// /// @param diff the diff node to consider. -//// -//// @return true if the class_or_union_diff carries a change in which +/// +/// @return true if the class_or_union_diff carries a change in which /// the two classes are different by the fact that one is a decl-only /// and the other one is defined. bool @@ -1518,7 +1518,7 @@ categorize_harmless_diff_node(diff *d, bool pre) s = is_decl(d->second_subject()); if (has_class_decl_only_def_change(d)) - category |= CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY; + category |= TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY; if (access_changed(f, s)) category |= ACCESS_CHANGE_CATEGORY; diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc index adfe2992..d0f1d21b 100644 --- a/src/abg-comparison.cc +++ b/src/abg-comparison.cc @@ -2957,7 +2957,7 @@ get_default_harmless_categories_bitmap() | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY - | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY + | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY @@ -3108,11 +3108,11 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } - if (c & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY) + if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) { if (emitted_a_category) o << "|"; - o << "CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY"; + o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY"; emitted_a_category |= true; } @@ -3132,7 +3132,7 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } - if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY) + if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY) { if (emitted_a_category) o << "|"; @@ -3140,7 +3140,7 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } - if (c & VAR_TYPE_CV_CHANGE_CATEGORY) + if (c & VAR_TYPE_CV_CHANGE_CATEGORY) { if (emitted_a_category) o << "|"; @@ -3148,7 +3148,7 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } - if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY) + if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY) { if (emitted_a_category) o << "|"; @@ -3156,7 +3156,7 @@ operator<<(ostream& o, diff_category c) emitted_a_category |= true; } - if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY) + if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY) { if (emitted_a_category) o << "|"; diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h index ee8c8239..fcb6d7a6 100644 --- a/src/abg-corpus-priv.h +++ b/src/abg-corpus-priv.h @@ -30,8 +30,10 @@ #define __ABG_CORPUS_PRIV_H__ #include "abg-internal.h" +#include "abg-ir.h" #include "abg-regex.h" #include "abg-sptr-utils.h" +#include "abg-symtab-reader.h" namespace abigail { @@ -696,16 +698,7 @@ struct corpus::priv string_tu_map_type path_tu_map; vector fns; vector vars; - string_elf_symbols_map_sptr var_symbol_map; - string_elf_symbols_map_sptr undefined_var_symbol_map; - elf_symbols sorted_var_symbols; - elf_symbols sorted_undefined_var_symbols; - string_elf_symbols_map_sptr fun_symbol_map; - string_elf_symbols_map_sptr undefined_fun_symbol_map; - elf_symbols sorted_fun_symbols; - elf_symbols sorted_undefined_fun_symbols; - elf_symbols unrefed_fun_symbols; - elf_symbols unrefed_var_symbols; + symtab_reader::symtab_sptr symtab_; // The type maps contained in this data member are populated if the // corpus follows the One Definition Rule and thus if there is only // one copy of a type with a given name, per corpus. Otherwise, if @@ -725,6 +718,17 @@ struct corpus::priv private: priv(); + mutable abg_compat::optional sorted_var_symbols; + mutable abg_compat::optional var_symbol_map; + mutable abg_compat::optional sorted_undefined_var_symbols; + mutable abg_compat::optional undefined_var_symbol_map; + mutable abg_compat::optional unrefed_var_symbols; + mutable abg_compat::optional sorted_fun_symbols; + mutable abg_compat::optional fun_symbol_map; + mutable abg_compat::optional sorted_undefined_fun_symbols; + mutable abg_compat::optional undefined_fun_symbol_map; + mutable abg_compat::optional unrefed_fun_symbols; + public: priv(const string & p, environment* e) @@ -735,15 +739,42 @@ struct corpus::priv pub_type_pretty_reprs_() {} - void - build_unreferenced_symbols_tables(); - type_maps& get_types(); const type_maps& get_types() const; + const elf_symbols& + get_sorted_fun_symbols() const; + + const string_elf_symbols_map_type& + get_fun_symbol_map() const; + + const elf_symbols& + get_sorted_undefined_fun_symbols() const; + + const string_elf_symbols_map_type& + get_undefined_fun_symbol_map() const; + + const elf_symbols& + get_unreferenced_function_symbols() const; + + const elf_symbols& + get_sorted_var_symbols() const; + + const string_elf_symbols_map_type& + get_var_symbol_map() const; + + const elf_symbols& + get_sorted_undefined_var_symbols() const; + + const string_elf_symbols_map_type& + get_undefined_var_symbol_map() const; + + const elf_symbols& + get_unreferenced_variable_symbols() const; + unordered_set* get_public_types_pretty_representations(); diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc index 9e90b994..1f72904d 100644 --- a/src/abg-corpus.cc +++ b/src/abg-corpus.cc @@ -38,6 +38,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS #include "abg-ir.h" #include "abg-reader.h" #include "abg-sptr-utils.h" +#include "abg-symtab-reader.h" #include "abg-tools-utils.h" #include "abg-writer.h" @@ -316,141 +317,286 @@ struct comp_elf_symbols_functor // +/// Get the maps that associate a name to a certain kind of type. +type_maps& +corpus::priv::get_types() +{return types_;} -/// Build the tables of symbols that are not referenced by any -/// function or variables of corpus::get_functions() or -/// corpus::get_variables(). +/// Get the maps that associate a name to a certain kind of type. +const type_maps& +corpus::priv::get_types() const +{return types_;} + +/// Return a sorted vector of function symbols for this corpus. /// -/// Note that this function considers the list of function and -/// variable symbols to keep, that is provided by -/// corpus::get_sym_ids_of_fns_to_keep() and -/// corpus::get_sym_ids_of_vars_to_keep(). If a given unreferenced -/// function or variable symbol is not in the list of variable and -/// function symbols to keep, then that symbol is dropped and will not -/// be part of the resulting table of unreferenced symbol that is -/// built. -/// -/// The built tables are accessible from -/// corpus::get_unreferenced_function_symbols() and -/// corpus::get_unreferenced_variable_symbols(). -void -corpus::priv::build_unreferenced_symbols_tables() +/// Note that the first time this function is called, the symbols are +/// sorted and cached. Subsequent invocations of this function return +/// the cached vector that was built previously. +/// +/// @return the sorted list of function symbols. +const elf_symbols& +corpus::priv::get_sorted_fun_symbols() const { - unordered_map refed_funs, refed_vars; - elf_symbol_sptr sym; + if (!sorted_fun_symbols) + { + const symtab_reader::symtab_filter filter = + symtab_->make_filter().functions(); - for (vector::const_iterator f = fns.begin(); - f != fns.end(); - ++f) - if ((sym = (*f)->get_symbol())) - { - refed_funs[sym->get_id_string()] = true; - for (elf_symbol_sptr a = sym->get_next_alias(); - a && !a->is_main_symbol(); - a = a->get_next_alias()) - refed_funs[a->get_id_string()] = true; - } + sorted_fun_symbols = elf_symbols(symtab_->begin(filter), symtab_->end()); + } + return *sorted_fun_symbols; +} - for (vector::const_iterator v = vars.begin(); - v != vars.end(); - ++v) - if ((sym = (*v)->get_symbol())) - { - refed_vars[sym->get_id_string()] = true; - for (elf_symbol_sptr a = sym->get_next_alias(); - a && !a->is_main_symbol(); - a = a->get_next_alias()) - refed_vars[a->get_id_string()] = true; - } +const string_elf_symbols_map_type& +corpus::priv::get_fun_symbol_map() const +{ + if (!fun_symbol_map) + { + fun_symbol_map = string_elf_symbols_map_type(); + for (elf_symbols::const_iterator iter = get_sorted_fun_symbols().begin(), + end = get_sorted_fun_symbols().end(); + iter != end; ++iter) + { + (*fun_symbol_map)[(*iter)->get_name()].push_back(*iter); + } + } + return *fun_symbol_map; +} - if (fun_symbol_map) +/// Getter for a sorted vector of the function symbols undefined in +/// this corpus. +/// +/// @return a vector of the function symbols undefined in this corpus, +/// sorted by name and then version. +const elf_symbols& +corpus::priv::get_sorted_undefined_fun_symbols() const +{ + if (!sorted_undefined_fun_symbols) { - // Let's assume that the size of the unreferenced symbols vector - // is roughly smaller than the size of the symbol table. - unrefed_fun_symbols.reserve(fun_symbol_map->size()); - for (string_elf_symbols_map_type::const_iterator i - = fun_symbol_map->begin(); - i != fun_symbol_map->end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); - ++s) - { - string sym_id = (*s)->get_id_string(); - if (refed_funs.find(sym_id) == refed_funs.end()) + const symtab_reader::symtab_filter filter = symtab_->make_filter() + .functions() + .undefined_symbols() + .public_symbols(false); + + sorted_undefined_fun_symbols = + elf_symbols(symtab_->begin(filter), symtab_->end()); + } + return *sorted_undefined_fun_symbols; +} + +const string_elf_symbols_map_type& +corpus::priv::get_undefined_fun_symbol_map() const +{ + if (!undefined_fun_symbol_map) + { + undefined_fun_symbol_map = string_elf_symbols_map_type(); + for (elf_symbols::const_iterator + iter = get_sorted_undefined_fun_symbols().begin(), + end = get_sorted_undefined_fun_symbols().end(); + iter != end; ++iter) + { + (*undefined_fun_symbol_map)[(*iter)->get_name()].push_back(*iter); + } + } + return *undefined_fun_symbol_map; +} + + + +/// Return a list of symbols that are not referenced by any function of +/// corpus::get_functions(). +/// +/// Note that this function considers the list of function symbols to keep, +/// that is provided by corpus::get_sym_ids_of_fns_to_keep(). If a given +/// unreferenced function symbol is not in the list of functions to keep, then +/// that symbol is dropped and will not be part of the resulting table of +/// unreferenced symbol that is built. +const elf_symbols& +corpus::priv::get_unreferenced_function_symbols() const +{ + if (!unrefed_fun_symbols) + { + unrefed_fun_symbols = elf_symbols(); + if (symtab_) + { + unordered_map refed_funs; + elf_symbol_sptr sym; + + for (vector::const_iterator f = fns.begin(); + f != fns.end(); ++f) + if ((sym = (*f)->get_symbol())) { - bool keep = sym_id_fns_to_keep.empty(); - for (vector::const_iterator i = - sym_id_fns_to_keep.begin(); - i != sym_id_fns_to_keep.end(); - ++i) - { - if (*i == sym_id) - { - keep = true; - break; - } - } - if (keep) - unrefed_fun_symbols.push_back(*s); + refed_funs[sym->get_id_string()] = true; + for (elf_symbol_sptr a = sym->get_next_alias(); + a && !a->is_main_symbol(); a = a->get_next_alias()) + refed_funs[a->get_id_string()] = true; } - } - comp_elf_symbols_functor comp; - std::sort(unrefed_fun_symbols.begin(), - unrefed_fun_symbols.end(), - comp); + symtab_reader::symtab_filter filter = + symtab_->make_filter().functions(); + for (symtab_reader::symtab::const_iterator iter = + symtab_->begin(filter); + iter != symtab_->end(); iter++) + { + const elf_symbol_sptr& symbol = *iter; + const std::string sym_id = symbol->get_id_string(); + + if (refed_funs.find(sym_id) == refed_funs.end()) + { + bool keep = sym_id_fns_to_keep.empty(); + for (vector::const_iterator i = + sym_id_fns_to_keep.begin(); + i != sym_id_fns_to_keep.end(); ++i) + { + if (*i == sym_id) + { + keep = true; + break; + } + } + if (keep) + unrefed_fun_symbols->push_back(symbol); + } + } + } } + return *unrefed_fun_symbols; +} - if (var_symbol_map) +/// Getter for the sorted vector of variable symbols for this corpus. +/// +/// Note that the first time this function is called, it computes the +/// sorted vector, caches the result and returns it. Subsequent +/// invocations of this function just return the cached vector. +/// +/// @return the sorted vector of variable symbols for this corpus. +const elf_symbols& +corpus::priv::get_sorted_var_symbols() const +{ + if (!sorted_var_symbols) { - // Let's assume that the size of the unreferenced symbols vector - // is roughly smaller than the size of the symbol table. - unrefed_var_symbols.reserve(var_symbol_map->size()); - for (string_elf_symbols_map_type::const_iterator i - = var_symbol_map->begin(); - i != var_symbol_map->end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); - ++s) - { - string sym_id = (*s)->get_id_string(); - if (refed_vars.find(sym_id) == refed_vars.end()) + const symtab_reader::symtab_filter filter = + symtab_->make_filter().variables(); + + sorted_var_symbols = elf_symbols(symtab_->begin(filter), symtab_->end()); + } + return *sorted_var_symbols; +} + +const string_elf_symbols_map_type& +corpus::priv::get_var_symbol_map() const +{ + if (!var_symbol_map) + { + var_symbol_map = string_elf_symbols_map_type(); + for (elf_symbols::const_iterator iter = get_sorted_var_symbols().begin(), + end = get_sorted_var_symbols().end(); + iter != end; ++iter) + { + (*var_symbol_map)[(*iter)->get_name()].push_back(*iter); + } + } + return *var_symbol_map; +} + +/// Getter for a sorted vector of the variable symbols undefined in +/// this corpus. +/// +/// @return a vector of the variable symbols undefined in this corpus, +/// sorted by name and then version. +const elf_symbols& +corpus::priv::get_sorted_undefined_var_symbols() const +{ + if (!sorted_undefined_var_symbols) + { + const symtab_reader::symtab_filter filter = symtab_->make_filter() + .variables() + .undefined_symbols() + .public_symbols(false); + + sorted_undefined_var_symbols = + elf_symbols(symtab_->begin(filter), symtab_->end()); + } + return *sorted_undefined_var_symbols; +} + +const string_elf_symbols_map_type& +corpus::priv::get_undefined_var_symbol_map() const +{ + if (!undefined_var_symbol_map) + { + undefined_var_symbol_map = string_elf_symbols_map_type(); + for (elf_symbols::const_iterator + iter = get_sorted_undefined_var_symbols().begin(), + end = get_sorted_undefined_var_symbols().end(); + iter != end; ++iter) + { + (*undefined_var_symbol_map)[(*iter)->get_name()].push_back(*iter); + } + } + return *undefined_var_symbol_map; +} + +/// Return a list of symbols that are not referenced by any variable of +/// corpus::get_variables(). +/// +/// Note that this function considers the list of variable symbols to keep, +/// that is provided by corpus::get_sym_ids_of_vars_to_keep(). If a given +/// unreferenced variable symbol is not in the list of variable to keep, then +/// that symbol is dropped and will not be part of the resulting table of +/// unreferenced symbol that is built. +const elf_symbols& +corpus::priv::get_unreferenced_variable_symbols() const +{ + if (!unrefed_var_symbols) + { + unrefed_var_symbols = elf_symbols(); + if (symtab_) + { + unordered_map refed_vars; + elf_symbol_sptr sym; + + for (vector::const_iterator f = vars.begin(); + f != vars.end(); ++f) + if ((sym = (*f)->get_symbol())) { - bool keep = sym_id_vars_to_keep.empty(); - for (vector::const_iterator i = - sym_id_vars_to_keep.begin(); - i != sym_id_vars_to_keep.end(); - ++i) - { - if (*i == sym_id) - { - keep = true; - break; - } - } - if (keep) - unrefed_var_symbols.push_back(*s); + refed_vars[sym->get_id_string()] = true; + for (elf_symbol_sptr a = sym->get_next_alias(); + a && !a->is_main_symbol(); a = a->get_next_alias()) + refed_vars[a->get_id_string()] = true; } - } - comp_elf_symbols_functor comp; - std::sort(unrefed_var_symbols.begin(), - unrefed_var_symbols.end(), - comp); + symtab_reader::symtab_filter filter = + symtab_->make_filter().variables(); + for (symtab_reader::symtab::const_iterator iter = + symtab_->begin(filter); + iter != symtab_->end(); iter++) + { + const elf_symbol_sptr& symbol = *iter; + const std::string sym_id = symbol->get_id_string(); + + if (refed_vars.find(sym_id) == refed_vars.end()) + { + bool keep = sym_id_vars_to_keep.empty(); + for (vector::const_iterator i = + sym_id_vars_to_keep.begin(); + i != sym_id_vars_to_keep.end(); ++i) + { + if (*i == sym_id) + { + keep = true; + break; + } + } + if (keep) + unrefed_var_symbols->push_back(symbol); + } + } + } } + return *unrefed_var_symbols; } -/// Get the maps that associate a name to a certain kind of type. -type_maps& -corpus::priv::get_types() -{return types_;} - -/// Get the maps that associate a name to a certain kind of type. -const type_maps& -corpus::priv::get_types() const -{return types_;} /// Getter of the set of pretty representation of types that are /// reachable from public interfaces (global functions and variables). @@ -876,10 +1022,7 @@ corpus::is_empty() const } } return (members_empty - && priv_->fun_symbol_map - && priv_->fun_symbol_map->empty() - && priv_->var_symbol_map - && priv_->var_symbol_map->empty() + && !get_symtab()->has_symbols() && priv_->soname.empty() && priv_->needed.empty()); } @@ -905,69 +1048,20 @@ corpus::operator==(const corpus& other) const && j == other.get_translation_units().end()); } -/// Setter of the function symbols map. -/// -/// @param map a shared pointer to the new function symbols map. -void -corpus::set_fun_symbol_map(string_elf_symbols_map_sptr map) -{priv_->fun_symbol_map = map;} - -/// Setter for the map of function symbols that are undefined in this -/// corpus. -/// -/// @param map a new map for function symbols not defined in this -/// corpus. The key of the map is the name of the function symbol. -/// The value is a vector of all the function symbols that have the -/// same name. void -corpus::set_undefined_fun_symbol_map(string_elf_symbols_map_sptr map) -{priv_->undefined_fun_symbol_map = map;} +corpus::set_symtab(symtab_reader::symtab_sptr symtab) +{priv_->symtab_ = symtab;} -/// Setter of the variable symbols map. -/// -/// @param map a shared pointer to the new variable symbols map. -void -corpus::set_var_symbol_map(string_elf_symbols_map_sptr map) -{priv_->var_symbol_map = map;} - -/// Setter for the map of variable symbols that are undefined in this -/// corpus. -/// -/// @param map a new map for variable symbols not defined in this -/// corpus. The key of the map is the name of the variable symbol. -/// The value is a vector of all the variable symbols that have the -/// same name. -void -corpus::set_undefined_var_symbol_map(string_elf_symbols_map_sptr map) -{priv_->undefined_var_symbol_map = map;} - -/// Getter for the function symbols map. -/// -/// @return a shared pointer to the function symbols map. -const string_elf_symbols_map_sptr -corpus::get_fun_symbol_map_sptr() const -{ - if (!priv_->fun_symbol_map) - priv_->fun_symbol_map.reset(new string_elf_symbols_map_type); - return priv_->fun_symbol_map; -} +const symtab_reader::symtab_sptr& +corpus::get_symtab() const +{ return priv_->symtab_; } /// Getter for the function symbols map. /// /// @return a reference to the function symbols map. const string_elf_symbols_map_type& corpus::get_fun_symbol_map() const -{return *get_fun_symbol_map_sptr();} - -/// Getter for the map of function symbols that are undefined in this -/// corpus. -/// -/// @return the map of function symbols not defined in this corpus. -/// The key of the map is the name of the function symbol. The value -/// is a vector of all the function symbols that have the same name. -const string_elf_symbols_map_sptr -corpus::get_undefined_fun_symbol_map_sptr() const -{return priv_->undefined_fun_symbol_map;} +{return priv_->get_fun_symbol_map();} /// Getter for the map of function symbols that are undefined in this /// corpus. @@ -977,134 +1071,30 @@ corpus::get_undefined_fun_symbol_map_sptr() const /// is a vector of all the function symbols that have the same name. const string_elf_symbols_map_type& corpus::get_undefined_fun_symbol_map() const -{return *get_undefined_fun_symbol_map_sptr();} - -/// Functor to sort instances of @ref elf_symbol. -struct elf_symbol_comp_functor -{ - - /// Return true if the first argument is less than the second one. - /// - /// @param l the first parameter to consider. - /// - /// @param r the second parameter to consider. - /// - /// @return true if @p l is less than @p r - bool - operator()(elf_symbol& l, elf_symbol& r) - {return (l.get_id_string() < r.get_id_string());} - - /// Return true if the first argument is less than the second one. - /// - /// @param l the first parameter to consider. - /// - /// @param r the second parameter to consider. - /// - /// @return true if @p l is less than @p r - bool - operator()(elf_symbol* l, elf_symbol* r) - {return operator()(*l, *r);} - - /// Return true if the first argument is less than the second one. - /// - /// @param l the first parameter to consider. - /// - /// @param r the second parameter to consider. - /// - /// @return true if @p l is less than @p r - bool - operator()(elf_symbol_sptr l, elf_symbol_sptr r) - {return operator()(*l, *r);} -}; // end struct elf_symbol_comp_functor +{return priv_->get_undefined_fun_symbol_map();} -/// Return a sorted vector of function symbols for this corpus. -/// -/// Note that the first time this function is called, the symbols are -/// sorted and cached. Subsequent invocations of this function return -/// the cached vector that was built previously. -/// -/// @return the sorted list of function symbols. const elf_symbols& corpus::get_sorted_fun_symbols() const -{ - if (priv_->sorted_fun_symbols.empty() - && !get_fun_symbol_map().empty()) - { - priv_->sorted_fun_symbols.reserve(get_fun_symbol_map().size()); - for (string_elf_symbols_map_type::const_iterator i = - get_fun_symbol_map().begin(); - i != get_fun_symbol_map().end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); - ++s) - priv_->sorted_fun_symbols.push_back(*s); - - elf_symbol_comp_functor comp; - std::sort(priv_->sorted_fun_symbols.begin(), - priv_->sorted_fun_symbols.end(), - comp); - } - return priv_->sorted_fun_symbols; -} +{ return priv_->get_sorted_fun_symbols(); } -/// Getter for a sorted vector of the function symbols undefined in -/// this corpus. -/// -/// @return a vector of the function symbols undefined in this corpus, -/// sorted by name and then version. const elf_symbols& corpus::get_sorted_undefined_fun_symbols() const -{ - if (priv_->sorted_undefined_fun_symbols.empty() - && !get_undefined_fun_symbol_map().empty()) - { - priv_->sorted_undefined_fun_symbols.reserve - (get_undefined_fun_symbol_map().size()); - for (string_elf_symbols_map_type::const_iterator i = - get_undefined_fun_symbol_map().begin(); - i != get_undefined_fun_symbol_map().end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); - ++s) - priv_->sorted_undefined_fun_symbols.push_back(*s); - - elf_symbol_comp_functor comp; - std::sort(priv_->sorted_undefined_fun_symbols.begin(), - priv_->sorted_undefined_fun_symbols.end(), - comp); - } - return priv_->sorted_undefined_fun_symbols; -} +{ return priv_->get_sorted_undefined_fun_symbols(); } -/// Getter for the variable symbols map. -/// -/// @return a shared pointer to the variable symbols map. -const string_elf_symbols_map_sptr -corpus::get_var_symbol_map_sptr() const -{ - if (!priv_->var_symbol_map) - priv_->var_symbol_map.reset(new string_elf_symbols_map_type); - return priv_->var_symbol_map; -} +const elf_symbols& +corpus::get_sorted_var_symbols() const +{ return priv_->get_sorted_var_symbols(); } + +const elf_symbols& +corpus::get_sorted_undefined_var_symbols() const +{ return priv_->get_sorted_undefined_var_symbols(); } /// Getter for the variable symbols map. /// /// @return a reference to the variabl symbols map. const string_elf_symbols_map_type& corpus::get_var_symbol_map() const -{return *get_var_symbol_map_sptr();} - -/// Getter for the map of variable symbols that are undefined in this -/// corpus. -/// -/// @return the map of variable symbols not defined in this corpus. -/// The key of the map is the name of the variable symbol. The value -/// is a vector of all the variable symbols that have the same name. -const string_elf_symbols_map_sptr -corpus::get_undefined_var_symbol_map_sptr() const -{return priv_->undefined_var_symbol_map;} +{return priv_->get_var_symbol_map();} /// Getter for the map of variable symbols that are undefined in this /// corpus. @@ -1114,66 +1104,7 @@ corpus::get_undefined_var_symbol_map_sptr() const /// is a vector of all the variable symbols that have the same name. const string_elf_symbols_map_type& corpus::get_undefined_var_symbol_map() const -{return *get_undefined_var_symbol_map_sptr();} - -/// Getter for the sorted vector of variable symbols for this corpus. -/// -/// Note that the first time this function is called, it computes the -/// sorted vector, caches the result and returns it. Subsequent -/// invocations of this function just return the cached vector. -/// -/// @return the sorted vector of variable symbols for this corpus. -const elf_symbols& -corpus::get_sorted_var_symbols() const -{ - if (priv_->sorted_var_symbols.empty() - && !get_var_symbol_map().empty()) - { - priv_->sorted_var_symbols.reserve(get_var_symbol_map().size()); - for (string_elf_symbols_map_type::const_iterator i = - get_var_symbol_map().begin(); - i != get_var_symbol_map().end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); ++s) - priv_->sorted_var_symbols.push_back(*s); - - elf_symbol_comp_functor comp; - std::sort(priv_->sorted_var_symbols.begin(), - priv_->sorted_var_symbols.end(), - comp); - } - return priv_->sorted_var_symbols; -} - -/// Getter for a sorted vector of the variable symbols undefined in -/// this corpus. -/// -/// @return a vector of the variable symbols undefined in this corpus, -/// sorted by name and then version. -const elf_symbols& -corpus::get_sorted_undefined_var_symbols() const -{ - if (priv_->sorted_undefined_var_symbols.empty() - && !get_undefined_var_symbol_map().empty()) - { - priv_->sorted_undefined_var_symbols.reserve - (get_undefined_var_symbol_map().size()); - for (string_elf_symbols_map_type::const_iterator i = - get_undefined_var_symbol_map().begin(); - i != get_undefined_var_symbol_map().end(); - ++i) - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); ++s) - priv_->sorted_undefined_var_symbols.push_back(*s); - - elf_symbol_comp_functor comp; - std::sort(priv_->sorted_undefined_var_symbols.begin(), - priv_->sorted_undefined_var_symbols.end(), - comp); - } - return priv_->sorted_undefined_var_symbols; -} +{return priv_->get_undefined_var_symbol_map();} /// Look in the function symbols map for a symbol with a given name. /// @@ -1417,12 +1348,7 @@ corpus::sort_variables() /// function exported by the current corpus. const elf_symbols& corpus::get_unreferenced_function_symbols() const -{ - if (priv_->unrefed_fun_symbols.empty() - && priv_->unrefed_var_symbols.empty()) - priv_->build_unreferenced_symbols_tables(); - return priv_->unrefed_fun_symbols; -} +{ return priv_->get_unreferenced_function_symbols(); } /// Getter of the set of variable symbols that are not referenced by /// any variable exported by the current corpus. @@ -1435,12 +1361,7 @@ corpus::get_unreferenced_function_symbols() const /// variable exported by the current corpus. const elf_symbols& corpus::get_unreferenced_variable_symbols() const -{ - if (priv_->unrefed_fun_symbols.empty() - && priv_->unrefed_var_symbols.empty()) - priv_->build_unreferenced_symbols_tables(); - return priv_->unrefed_var_symbols; -} +{ return priv_->get_unreferenced_variable_symbols(); } /// Accessor for the regex patterns describing the functions to drop /// from the public decl table. diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc index 80cb6638..2acb6954 100644 --- a/src/abg-default-reporter.cc +++ b/src/abg-default-reporter.cc @@ -98,9 +98,10 @@ default_reporter::report(const enum_diff& d, ostream& out, enum_type_decl_sptr first = d.first_enum(), second = d.second_enum(); - report_name_size_and_alignment_changes(first, second, d.context(), + const diff_context_sptr& ctxt = d.context(); + report_name_size_and_alignment_changes(first, second, ctxt, out, indent); - maybe_report_diff_for_member(first, second, d.context(), out, indent); + maybe_report_diff_for_member(first, second, ctxt, out, indent); //underlying type d.underlying_type_diff()->report(out, indent); @@ -165,12 +166,12 @@ default_reporter::report(const enum_diff& d, ostream& out, << "' from value '" << i->first.get_value() << "' to '" << i->second.get_value() << "'"; - report_loc_info(second, *d.context(), out); + report_loc_info(second, *ctxt, out); out << "\n"; } } - if (d.context()->show_leaf_changes_only()) + if (ctxt->show_leaf_changes_only()) maybe_report_interfaces_impacted_by_diff(&d, out, indent); d.reported_once(true); @@ -844,8 +845,8 @@ default_reporter::report(const class_or_union_diff& d, const diff_context_sptr& ctxt = d.context(); - // Report class decl-only -> definition change. - if (ctxt->get_allowed_category() & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY) + // Report class decl-only <-> definition change. + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) if (filtering::has_class_decl_only_def_change(first, second)) { string was = diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index 21363810..d125cc98 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -50,6 +50,7 @@ #include "abg-suppression-priv.h" #include "abg-corpus-priv.h" #include "abg-elf-helpers.h" + #include "abg-internal.h" // @@ -57,6 +58,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS #include "abg-dwarf-reader.h" #include "abg-sptr-utils.h" +#include "abg-symtab-reader.h" #include "abg-tools-utils.h" ABG_END_EXPORT_DECLARATIONS @@ -289,10 +291,6 @@ static bool operator<(const imported_unit_point& l, const imported_unit_point& r) {return l.offset_of_import < r.offset_of_import;} -static void -add_symbol_to_map(const elf_symbol_sptr& sym, - string_elf_symbols_map_type& map); - static bool get_parent_die(const read_context& ctxt, const Dwarf_Die* die, @@ -1920,92 +1918,6 @@ struct dwarf_expr_eval_context // // --------------------------------------- -/// An enum for the diffent kinds of linux kernel specific symbol -/// tables. -enum kernel_symbol_table_kind -{ - /// This is for an undefined kind of kernel symbol table. - KERNEL_SYMBOL_TABLE_KIND_UNDEFINED, - - /// The __ksymtab symbol table. - KERNEL_SYMBOL_TABLE_KIND_KSYMTAB, - - /// The __ksymtab_gpl symbol table. - KERNEL_SYMBOL_TABLE_KIND_KSYMTAB_GPL -}; - -/// An enum which specifies the format of the kernel symbol table -/// (__ksymtab or __ksymtab_gpl). -enum ksymtab_format -{ - /// This enumerator means that no __ksymtab format has been - /// determined yet. - UNDEFINED_KSYMTAB_FORMAT, - - /// Before Linux v4.19, the format of the __ksymtab (and the - /// __ksymtab_gpl) section was the following. - /// - /// It's an array of entries. Each entry describes a symbol. Each - /// entry is made of two words. each is of the word size of the - /// architecture. (8-bytes on a 64 bits arch and 4-bytes on a 32 - /// bits arch) The first word is the address of a symbol. The - /// second one is the address of a static global variable symbol - /// which value is the string representing the symbol name. That - /// string is in the __ksymtab_strings section. - /// - /// So we are mostly interested in the symbol address part of each - /// entry. - /// - /// Thus this enumerator means that we have the pre v4.19 __ksymtab - /// section format. - PRE_V4_19_KSYMTAB_FORMAT, - - /// Since, Linux v4.19, the format of the __ksymtab section has - /// changed. The commit that changed is - /// https://github.com/torvalds/linux/commit/7290d58095712a89f845e1bca05334796dd49ed2. - /// - /// The __ksymtab and __ksymtab_gpl sections each are an array of - /// entries. Each entry describes a symbol. Each entry is made of - /// two words. Each word is 4-bytes length. The first word is the - /// 'place-relative' address of a symbol. The second one is the - /// 'place-relative' address of a static global variable symbol - /// which value is the string representing the symbol name. That - /// string is in the __ksymtab_strings section. - /// - /// Below is the description of what a "place-relative address" - /// means. For that, we are going to define the meaning of four - /// values: 'N', 'S', 'O', and 'A'. - /// - /// *** 'N' and '0' *** - /// Suppose 'N' is the value of the number stored at offset 'O' (big - /// oh, not zero) in the __ksymtab section. - /// - /// *** 'S'*** - /// That N designates a symbol in the symtab section which value is - /// S. So S is the symbol value (in the .symtab symbol table) - /// referred to by the number N found at offset 'O'. - /// - /// *** 'A' *** - /// Also, suppose the __ksymtab section will be loaded at memory - /// address A, as indicated by the 'address' field of the section - /// header describing the __ksymtab section. - /// - /// So here is the formula that gives us S, from N: - /// - /// S = N + O + A. - /// - /// Storing addresses this way does away with the need to have - /// relocations for the __ksymtab section. So in effect, vmlinux - /// binaries implementing this new format of __ksymtab won't have - /// any .rela__ksymtab relocation section for the __ksymtab section - /// in particular (nor any relocation section at all). - /// - /// - /// Note that we are mostly interested in the symbol address part of - /// each entry. - V4_19_KSYMTAB_FORMAT -}; // end enum ksymtab_format - /// The context used to build ABI corpus from debug info in DWARF /// format. /// @@ -2024,7 +1936,6 @@ class read_context environment* env; bool load_in_linux_kernel_mode; bool load_all_types; - bool ignore_symbol_table; bool show_stats; bool do_log; @@ -2032,7 +1943,6 @@ class read_context : env(), load_in_linux_kernel_mode(), load_all_types(), - ignore_symbol_table(), show_stats(), do_log() {} @@ -2159,30 +2069,6 @@ class read_context mutable Elf* elf_handle_; string elf_path_; mutable Elf_Scn* symtab_section_; - // The "Official procedure descriptor section, aka .opd", used in - // ppc64 elf v1 binaries. This section contains the procedure - // descriptors on that platform. - mutable Elf_Scn* opd_section_; - /// The format of the special __ksymtab section from the linux - /// kernel binary. - mutable ksymtab_format ksymtab_format_; - /// The size of one entry of the __ksymtab section. - mutable size_t ksymtab_entry_size_; - /// The number of entries in the __ksymtab section. - mutable size_t nb_ksymtab_entries_; - /// The number of entries in the __ksymtab_gpl section. - mutable size_t nb_ksymtab_gpl_entries_; - /// The special __ksymtab and __ksymtab_gpl sections from linux - /// kernel or module binaries. The former is used to store - /// references to symbols exported using the EXPORT_SYMBOL macro - /// from the linux kernel. The latter is used to store references - /// to symbols exported using the EXPORT_SYMBOL_GPL macro from the - /// linux kernel. - mutable Elf_Scn* ksymtab_section_; - mutable Elf_Scn* ksymtab_reloc_section_; - mutable Elf_Scn* ksymtab_gpl_section_; - mutable Elf_Scn* ksymtab_gpl_reloc_section_; - mutable Elf_Scn* ksymtab_strings_section_; Dwarf_Die* cur_tu_die_; mutable dwarf_expr_eval_context dwarf_expr_eval_context_; // A set of maps (one per kind of die source) that associates a decl @@ -2252,23 +2138,6 @@ class read_context offset_offset_map_type alternate_die_parent_map_; offset_offset_map_type type_section_die_parent_map_; list var_decls_to_add_; - addr_elf_symbol_sptr_map_sptr fun_addr_sym_map_; - // On PPC64, the function entry point address is different from the - // GElf_Sym::st_value value, which is the address of the descriptor - // of the function. The map below thus associates the address of - // the entry point to the function symbol. If we are not on ppc64, - // then this map ought to be empty. Only the fun_addr_sym_map_ is - // used in that case. On ppc64, though, both maps are used. - addr_elf_symbol_sptr_map_sptr fun_entry_addr_sym_map_; - string_elf_symbols_map_sptr fun_syms_; - addr_elf_symbol_sptr_map_sptr var_addr_sym_map_; - string_elf_symbols_map_sptr var_syms_; - string_elf_symbols_map_sptr undefined_fun_syms_; - string_elf_symbols_map_sptr undefined_var_syms_; - address_set_sptr linux_exported_fn_syms_; - address_set_sptr linux_exported_var_syms_; - address_set_sptr linux_exported_gpl_fn_syms_; - address_set_sptr linux_exported_gpl_var_syms_; vector dt_needed_; string dt_soname_; string elf_architecture_; @@ -2277,6 +2146,9 @@ class read_context bool drop_undefined_syms_; read_context(); +private: + mutable symtab_reader::symtab_sptr symtab_; + public: /// Constructor of read_context. @@ -2363,16 +2235,6 @@ class read_context elf_handle_ = 0; elf_path_ = elf_path; symtab_section_ = 0; - opd_section_ = 0; - ksymtab_format_ = UNDEFINED_KSYMTAB_FORMAT; - ksymtab_entry_size_ = 0; - nb_ksymtab_entries_ = 0; - nb_ksymtab_gpl_entries_ = 0; - ksymtab_section_ = 0; - ksymtab_reloc_section_ = 0; - ksymtab_gpl_section_ = 0; - ksymtab_gpl_reloc_section_ = 0; - ksymtab_strings_section_ = 0; cur_tu_die_ = 0; exported_decls_builder_ = 0; @@ -2411,21 +2273,12 @@ class read_context alternate_die_parent_map_.clear(); type_section_die_parent_map_.clear(); var_decls_to_add_.clear(); - fun_addr_sym_map_.reset(); - fun_entry_addr_sym_map_.reset(); - fun_syms_.reset(); - var_addr_sym_map_.reset(); - var_syms_.reset(); - undefined_fun_syms_.reset(); - undefined_var_syms_.reset(); - linux_exported_fn_syms_.reset(); - linux_exported_var_syms_.reset(); - linux_exported_gpl_fn_syms_.reset(); - linux_exported_gpl_var_syms_.reset(); dt_needed_.clear(); dt_soname_.clear(); elf_architecture_.clear(); + symtab_.reset(); + clear_per_translation_unit_data(); memset(&offline_callbacks_, 0, sizeof(offline_callbacks_)); @@ -5022,1849 +4875,171 @@ class read_context scope_decl* current_scope() { - if (scope_stack().empty()) - { - if (cur_transl_unit()) - scope_stack().push(cur_transl_unit()->get_global_scope().get()); - } - return scope_stack().top(); - } - - list& - var_decls_to_re_add_to_tree() - {return var_decls_to_add_;} - - /// The section containing the symbol table from the current ELF - /// file. - /// - /// Note that after it's first invocation, this function caches the - /// symbol table that it found. Subsequent invocations just return - /// the cached symbol table section. - /// - /// @return the symbol table section if found - Elf_Scn* - find_symbol_table_section() const - { - if (!symtab_section_) - symtab_section_ = elf_helpers::find_symbol_table_section(elf_handle()); - return symtab_section_; - } - - /// Return the "Official Procedure descriptors section." This - /// section is named .opd, and is usually present only on PPC64 - /// ELFv1 binaries. - /// - /// @return the .opd section, if found. Return nil otherwise. - Elf_Scn* - find_opd_section() const - { - if (!opd_section_) - opd_section_ = elf_helpers::find_opd_section(elf_handle()); - return opd_section_; - } - - /// Return the __ksymtab section of a linux kernel ELF file (either - /// a vmlinux binary or a kernel module). - /// - /// @return the __ksymtab section if found, nil otherwise. - Elf_Scn* - find_ksymtab_section() const - { - if (!ksymtab_section_) - ksymtab_section_ = elf_helpers::find_ksymtab_section(elf_handle()); - return ksymtab_section_; - } - - /// Return the __ksymtab_gpl section of a linux kernel ELF file - /// (either a vmlinux binary or a kernel module). - /// - /// @return the __ksymtab_gpl section if found, nil otherwise. - Elf_Scn* - find_ksymtab_gpl_section() const - { - if (!ksymtab_gpl_section_) - ksymtab_gpl_section_ = - elf_helpers::find_ksymtab_gpl_section(elf_handle()); - return ksymtab_gpl_section_; - } - - /// Return the .rel{a,}__ksymtab section of a linux kernel ELF file (either - /// a vmlinux binary or a kernel module). - /// - /// @return the .rel{a,}__ksymtab section if found, nil otherwise. - Elf_Scn* - find_ksymtab_reloc_section() const - { - if (!ksymtab_reloc_section_) - ksymtab_reloc_section_ = - find_relocation_section(elf_handle(), find_ksymtab_section()); - return ksymtab_reloc_section_; - } - - /// Return the .rel{a,}__ksymtab_gpl section of a linux kernel ELF file - /// (either a vmlinux binary or a kernel module). - /// - /// @return the .rel{a,}__ksymtab_gpl section if found, nil otherwise. - Elf_Scn* - find_ksymtab_gpl_reloc_section() const - { - if (!ksymtab_gpl_reloc_section_) - ksymtab_gpl_reloc_section_ = - find_relocation_section(elf_handle(), find_ksymtab_gpl_section()); - return ksymtab_gpl_reloc_section_; - } - - /// Return the __ksymtab_strings section of a linux kernel ELF file - /// (either a vmlinux binary or a kernel module). - /// - /// @return the __ksymtab_strings section if found, nil otherwise. - Elf_Scn* - find_ksymtab_strings_section() const - { - if (!ksymtab_strings_section_) - ksymtab_strings_section_ = - dwarf_reader::find_ksymtab_strings_section(elf_handle()); - return ksymtab_strings_section_; - } - - /// Return either a __ksymtab or a __ksymtab_gpl section, in case - /// only the __ksymtab_gpl exists. - /// - /// @return the __ksymtab section if it exists, or the - /// __ksymtab_gpl; or NULL if neither is found. - Elf_Scn* - find_any_ksymtab_section() const - { - Elf_Scn *result = find_ksymtab_section(); - if (!result) - result = find_ksymtab_gpl_section(); - return result; - } - - /// Return either a .rel{a,}__ksymtab or a .rel{a,}__ksymtab_gpl section - /// - /// @return the .rel{a,}__ksymtab section if it exists, or the - /// .rel{a,}__ksymtab_gpl; or NULL if neither is found. - Elf_Scn* - find_any_ksymtab_reloc_section() const - { - Elf_Scn *result = find_ksymtab_reloc_section(); - if (!result) - result = find_ksymtab_gpl_reloc_section(); - return result; - } - - /// Lookup an elf symbol, referred to by its index, from the .symtab - /// section. - /// - /// The resulting symbol returned is an instance of a GElf_Sym, from - /// the libelf library. - /// - /// @param symbol_index the index of the symbol to look up. - /// - /// @param elf_sym out parameter. This is set to the resulting ELF - /// symbol iff the function returns TRUE, meaning the symbol was - /// found. - /// - /// @return TRUE iff the symbol was found. - bool - lookup_native_elf_symbol_from_index(size_t symbol_index, GElf_Sym &elf_sym) - { - Elf_Scn* symtab_section = find_symbol_table_section(); - if (!symtab_section) - return false; - - Elf_Data* symtab = elf_getdata(symtab_section, 0); - ABG_ASSERT(symtab); - - if (!gelf_getsym(symtab, symbol_index, &elf_sym)) - return false; - - return true; - } - - /// Given the index of a symbol into the symbol table of an ELF - /// file, look the symbol up, build an instace of @ref elf_symbol - /// and return it. - /// - /// @param symbol_index the index of the symbol into the symbol - /// table of the current elf file. - /// - /// @return the elf symbol found or nil if none was found. - elf_symbol_sptr - lookup_elf_symbol_from_index(size_t symbol_index) - { - GElf_Sym s; - elf_symbol_sptr result = - lookup_elf_symbol_from_index(symbol_index, s); - return result; - } - - /// Lookup an ELF symbol given its index into the .symtab section. - /// - /// This function returns both the native symbol (from libelf) and - /// the @p abigail::ir::elf_symbol instance, which is the - /// libabigail-specific representation of the symbol. - /// - /// @param symbol_index the index of the symbol to look for. - /// - /// @param native_sym output parameter. This is set to the native - /// ELF symbol found iff the function returns a non-nil value. - /// - /// @return an instance of libabigail::ir::elf_symbol representing - /// the ELF symbol found, iff one was found. Otherwise, returns - /// nil. - elf_symbol_sptr - lookup_elf_symbol_from_index(size_t symbol_index, - GElf_Sym &native_sym) - { - if (!lookup_native_elf_symbol_from_index(symbol_index, native_sym)) - return elf_symbol_sptr(); - - Elf_Scn* symtab_section = find_symbol_table_section(); - if (!symtab_section) - return elf_symbol_sptr(); - - GElf_Shdr header_mem; - GElf_Shdr* symtab_sheader = gelf_getshdr(symtab_section, - &header_mem); - - Elf_Data* symtab = elf_getdata(symtab_section, 0); - ABG_ASSERT(symtab); - - bool sym_is_defined = native_sym.st_shndx != SHN_UNDEF; - bool sym_is_common = native_sym.st_shndx == SHN_COMMON; // this occurs in - // relocatable - // files. - const char* name_str = elf_strptr(elf_handle(), - symtab_sheader->sh_link, - native_sym.st_name); - if (name_str == 0) - name_str = ""; - - elf_symbol::version ver; - elf_helpers::get_version_for_symbol(elf_handle(), symbol_index, - sym_is_defined, ver); - - elf_symbol::visibility vis = - stv_to_elf_symbol_visibility(GELF_ST_VISIBILITY(native_sym.st_other)); - - Elf_Scn *strings_section = find_ksymtab_strings_section(); - size_t strings_ndx = strings_section - ? elf_ndxscn(strings_section) - : 0; - - elf_symbol_sptr sym = - elf_symbol::create(env(), symbol_index, native_sym.st_size, - name_str, stt_to_elf_symbol_type - (GELF_ST_TYPE(native_sym.st_info)), - stb_to_elf_symbol_binding - (GELF_ST_BIND(native_sym.st_info)), - sym_is_defined, sym_is_common, ver, vis, - native_sym.st_shndx == strings_ndx); - return sym; - } - - /// Read 8 bytes and convert their value into an uint64_t. - /// - /// @param bytes the array of bytes to read the next 8 bytes from. - /// Note that this array must be at least 8 bytes long. - /// - /// @param result where to store the resuting uint64_t that was read. - /// - /// @param is_big_endian if true, read the 8 bytes in Big Endian - /// mode, otherwise, read them in Little Endian. - /// - /// @param true if the 8 bytes could be read, false otherwise. - bool - read_uint64_from_array_of_bytes(const uint8_t *bytes, - bool is_big_endian, - uint64_t &result) const - { - return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result); - } - - /// Read N bytes and convert their value into an integer type T. - /// - /// Note that N cannot be bigger than 8 for now. The type passed needs to be - /// at least of the size of number_of_bytes. - /// - /// @param bytes the array of bytes to read the next 8 bytes from. - /// Note that this array must be at least 8 bytes long. - /// - /// @param number_of_bytes the number of bytes to read. This number - /// cannot be bigger than 8. - /// - /// @param is_big_endian if true, read the 8 bytes in Big Endian - /// mode, otherwise, read them in Little Endian. - /// - /// @param result where to store the resuting integer that was read. - /// - /// - /// @param true if the 8 bytes could be read, false otherwise. - template - bool - read_int_from_array_of_bytes(const uint8_t *bytes, - unsigned char number_of_bytes, - bool is_big_endian, - T &result) const - { - if (!bytes) - return false; - - ABG_ASSERT(number_of_bytes <= 8); - ABG_ASSERT(number_of_bytes <= sizeof(T)); - - T res = 0; - - const uint8_t *cur = bytes; - if (is_big_endian) - { - // In Big Endian, the most significant byte is at the lowest - // address. - const uint8_t* msb = cur; - res = *msb; - - // Now read the remaining least significant bytes. - for (uint i = 1; i < number_of_bytes; ++i) - res = (res << 8) | ((T)msb[i]); - } - else - { - // In Little Endian, the least significant byte is at the - // lowest address. - const uint8_t* lsb = cur; - res = *lsb; - // Now read the remaining most significant bytes. - for (uint i = 1; i < number_of_bytes; ++i) - res = res | (((T)lsb[i]) << i * 8); - } - - result = res; - return true; - } - - /// Lookup the address of the function entry point that corresponds - /// to the address of a given function descriptor. - /// - /// On PPC64, a function pointer is the address of a function - /// descriptor. Function descriptors are located in the .opd - /// section. Each function descriptor is a triplet of three - /// addresses, each one on 64 bits. Among those three address only - /// the first one is of any interest to us: the address of the entry - /// point of the function. - /// - /// This function returns the address of the entry point of the - /// function whose descriptor's address is given. - /// - /// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES - /// - /// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en - /// - /// @param fn_desc_address the address of the function descriptor to - /// consider. - /// - /// @return the address of the entry point of the function whose - /// descriptor has the address @p fn_desc_address. If there is no - /// .opd section (e.g because we are not on ppc64) or more generally - /// if the function descriptor could not be found then this function - /// just returns the address of the fuction descriptor. - GElf_Addr - lookup_ppc64_elf_fn_entry_point_address(GElf_Addr fn_desc_address) const - { - if (!elf_handle()) - return fn_desc_address; - - if (!architecture_is_ppc64(elf_handle())) - return fn_desc_address; - - bool is_big_endian = architecture_is_big_endian(elf_handle()); - - Elf_Scn *opd_section = find_opd_section(); - if (!opd_section) - return fn_desc_address; - - GElf_Shdr header_mem; - // The section header of the .opd section. - GElf_Shdr *opd_sheader = gelf_getshdr(opd_section, &header_mem); - - // The offset of the function descriptor entry, in the .opd - // section. - size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr; - Elf_Data *elf_data = elf_rawdata(opd_section, 0); - - // Ensure that the opd_section has at least 8 bytes, starting from - // the offset we want read the data from. - if (elf_data->d_size <= fn_desc_offset + 8) - return fn_desc_address; - - // A pointer to the data of the .opd section, that we can actually - // do something with. - uint8_t * bytes = (uint8_t*) elf_data->d_buf; - - // The resulting address we are looking for is going to be formed - // in this variable. - GElf_Addr result = 0; - ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset, - is_big_endian, result)); - - return result; - } - - /// Given the address of the beginning of a function, lookup the - /// symbol of the function, build an instance of @ref elf_symbol out - /// of it and return it. - /// - /// @param symbol_start_addr the address of the beginning of the - /// function to consider. - /// - /// @param sym the resulting symbol. This is set iff the function - /// returns true. - /// - /// @return the elf symbol found at address @p symbol_start_addr, or - /// nil if none was found. - elf_symbol_sptr - lookup_elf_fn_symbol_from_address(GElf_Addr symbol_start_addr) const - { - addr_elf_symbol_sptr_map_type::const_iterator i, - nil = fun_entry_addr_sym_map().end(); - - if ((i = fun_entry_addr_sym_map().find(symbol_start_addr)) == nil) - return elf_symbol_sptr(); - - return i->second; - } - - /// Given the address of a global variable, lookup the symbol of the - /// variable, build an instance of @ref elf_symbol out of it and - /// return it. - /// - /// @param symbol_start_addr the address of the beginning of the - /// variable to consider. - /// - /// @param the symbol found, iff the function returns true. - /// - /// @return the elf symbol found or nil if none was found. - elf_symbol_sptr - lookup_elf_var_symbol_from_address(GElf_Addr symbol_start_addr) const - { - addr_elf_symbol_sptr_map_type::const_iterator i, - nil = var_addr_sym_map().end(); - - if ((i = var_addr_sym_map().find(symbol_start_addr)) == nil) - return elf_symbol_sptr(); - - return i->second; - } - - /// Lookup an elf symbol, knowing its address. - /// - /// This function first looks for a function symbol having this - /// address; if it doesn't find any, then it looks for a variable - /// symbol. - /// - /// @param symbol_addr the address of the symbol of the symbol we - /// are looking for. Note that the address is a relative offset - /// starting from the beginning of the .text section. Addresses - /// that are presen in the symbol table (the one named .symtab). - /// - /// @return the elf symbol if found, or nil otherwise. - elf_symbol_sptr - lookup_elf_symbol_from_address(GElf_Addr symbol_addr) const - { - elf_symbol_sptr result = lookup_elf_fn_symbol_from_address(symbol_addr); - if (!result) - result = lookup_elf_var_symbol_from_address(symbol_addr); - return result; - } - - /// Look in the symbol tables of the underying elf file and see if - /// we find a symbol of a given name of function type. - /// - /// @param sym_name the name of the symbol to look for. - /// - /// @param syms the public function symbols that were found, with - /// the name @p sym_name. - /// - /// @return true iff the symbol was found. - bool - lookup_public_function_symbol_from_elf(const string& sym_name, - vector& syms) - { - return dwarf_reader::lookup_public_function_symbol_from_elf(env(), - elf_handle(), - sym_name, - syms); - } - - /// Test if a given function symbol has been exported. - /// - /// @param symbol_address the address of the symbol we are looking - /// for. Note that this address must be a relative offset from the - /// beginning of the .text section, just like the kind of addresses - /// that are present in the .symtab section. - /// - /// @returnthe elf symbol if found, or nil otherwise. - elf_symbol_sptr - function_symbol_is_exported(GElf_Addr symbol_address) const - { - elf_symbol_sptr symbol = lookup_elf_fn_symbol_from_address(symbol_address); - if (!symbol) - return symbol; - - if (!symbol->is_public()) - return elf_symbol_sptr(); - - address_set_sptr set; - bool looking_at_linux_kernel_binary = - load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); - - if (looking_at_linux_kernel_binary) - { - if ((set = linux_exported_fn_syms())) - { - if (set->find(symbol_address) != set->end()) - return symbol; - } - if ((set = linux_exported_gpl_fn_syms())) - { - if (set->find(symbol_address) != set->end()) - return symbol; - } - return elf_symbol_sptr(); - } - - return symbol; - } - - /// Test if a given variable symbol has been exported. - /// - /// @param symbol_address the address of the symbol we are looking - /// for. Note that this address must be a relative offset from the - /// beginning of the .text section, just like the kind of addresses - /// that are present in the .symtab section. - /// - /// @returnthe elf symbol if found, or nil otherwise. - elf_symbol_sptr - variable_symbol_is_exported(GElf_Addr symbol_address) const - { - elf_symbol_sptr symbol = lookup_elf_var_symbol_from_address(symbol_address); - if (!symbol) - return symbol; - - if (!symbol->is_public()) - return elf_symbol_sptr(); - - address_set_sptr set; - bool looking_at_linux_kernel_binary = - load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); - - if (looking_at_linux_kernel_binary) - { - if ((set = linux_exported_var_syms())) - { - if (set->find(symbol_address) != set->end()) - return symbol; - } - if ((set = linux_exported_gpl_var_syms())) - { - if (set->find(symbol_address) != set->end()) - return symbol; - } - return elf_symbol_sptr(); - } - - return symbol; - } - - /// Getter for a pointer to the map that associates the address of - /// an entry point of a function with the symbol of that function. - /// - /// Note that on non-"PPC64 ELFv1" binaries, this map is the same as - /// the one that assciates the address of a function with the symbol - /// of that function. - /// - /// @return a pointer to the map that associates the address of an - /// entry point of a function with the symbol of that function. - addr_elf_symbol_sptr_map_sptr& - fun_entry_addr_sym_map_sptr() - { - if (!fun_entry_addr_sym_map_ && !fun_addr_sym_map_) - maybe_load_symbol_maps(); - if (architecture_is_ppc64(elf_handle())) - return fun_entry_addr_sym_map_; - return fun_addr_sym_map_; - } - - /// Getter for a pointer to the map that associates the address of - /// an entry point of a function with the symbol of that function. - /// - /// Note that on non-"PPC64 ELFv1" binaries, this map is the same as - /// the one that assciates the address of a function with the symbol - /// of that function. - /// - /// @return a pointer to the map that associates the address of an - /// entry point of a function with the symbol of that function. - const addr_elf_symbol_sptr_map_sptr& - fun_entry_addr_sym_map_sptr() const - {return const_cast(this)->fun_entry_addr_sym_map_sptr();} - - - /// Getter for the map that associates the address of an entry point - /// of a function with the symbol of that function. - /// - /// Note that on non-"PPC64 ELFv1" binaries, this map is the same as - /// the one that assciates the address of a function with the symbol - /// of that function. - /// - /// @return the map that associates the address of an entry point of - /// a function with the symbol of that function. - addr_elf_symbol_sptr_map_type& - fun_entry_addr_sym_map() - {return *fun_entry_addr_sym_map_sptr();} - - /// Getter for the map that associates the address of an entry point - /// of a function with the symbol of that function. - /// - /// Note that on non-"PPC64 ELFv1" binaries, this map is the same as - /// the one that assciates the address of a function with the symbol - /// of that function. - /// - /// @return the map that associates the address of an entry point of - /// a function with the symbol of that function. - const addr_elf_symbol_sptr_map_type& - fun_entry_addr_sym_map() const - { return *fun_entry_addr_sym_map_sptr();} - - /// Getter for the map of function symbols (name -> sym). - /// - /// @return a shared pointer to the map of function symbols. - const string_elf_symbols_map_sptr& - fun_syms_sptr() const - { - maybe_load_symbol_maps(); - return fun_syms_; - } - - /// Getter for the map of function symbols (name -> sym). - /// - /// @return a reference to the map of function symbols. - string_elf_symbols_map_type& - fun_syms() - { - maybe_load_symbol_maps(); - return *fun_syms_; - } - - /// Getter for the map of variable symbols (name -> sym) - /// - /// @return a shared pointer to the map of variable symbols. - const string_elf_symbols_map_sptr - var_syms_sptr() const - { - maybe_load_symbol_maps(); - return var_syms_; - } - - /// Getter for the map of variable symbols (name -> sym) - /// - /// @return a reference to the map of variable symbols. - string_elf_symbols_map_type& - var_syms() - { - maybe_load_symbol_maps(); - return *var_syms_; - } - - /// Getter for the map of undefined function symbols (name -> vector - /// of symbols). - /// - /// @return a (smart) pointer to the map of undefined function - /// symbols. - const string_elf_symbols_map_sptr& - undefined_fun_syms_sptr() const - { - maybe_load_symbol_maps(); - return undefined_fun_syms_; - } - - /// Getter for the map of undefined variable symbols (name -> vector - /// of symbols). - /// - /// @return a (smart) pointer to the map of undefined variable - /// symbols. - const string_elf_symbols_map_sptr& - undefined_var_syms_sptr() const - { - maybe_load_symbol_maps(); - return undefined_var_syms_; - } - - /// Getter for the set of addresses of function symbols that are - /// explicitely exported, for a linux kernel (module) binary. These - /// are the addresses of function symbols present in the __ksymtab - /// section - address_set_sptr& - linux_exported_fn_syms() - {return linux_exported_fn_syms_;} - - /// Getter for the set of addresses of functions that are - /// explicitely exported, for a linux kernel (module) binary. These - /// are the addresses of function symbols present in the __ksymtab - /// section. - /// - /// @return the set of addresses of exported function symbols. - const address_set_sptr& - linux_exported_fn_syms() const - {return const_cast(this)->linux_exported_fn_syms();} - - /// Create an empty set of addresses of functions exported from a - /// linux kernel (module) binary, or return the one that already - /// exists. - /// - /// @return the set of addresses of exported function symbols. - address_set_sptr& - create_or_get_linux_exported_fn_syms() - { - if (!linux_exported_fn_syms_) - linux_exported_fn_syms_.reset(new address_set_type); - return linux_exported_fn_syms_; - } - - /// Getter for the set of addresses of v ariables that are - /// explicitely exported, for a linux kernel (module) binary. These - /// are the addresses of variable symbols present in the __ksymtab - /// section. - /// - /// @return the set of addresses of exported variable symbols. - address_set_sptr& - linux_exported_var_syms() - {return linux_exported_var_syms_;} - - /// Getter for the set of addresses of variables that are - /// explicitely exported, for a linux kernel (module) binary. These - /// are the addresses of variable symbols present in the __ksymtab - /// section. - /// - /// @return the set of addresses of exported variable symbols. - const address_set_sptr& - linux_exported_var_syms() const - {return const_cast(this)->linux_exported_var_syms();} - - - /// Create an empty set of addresses of variables exported from a - /// linux kernel (module) binary, or return the one that already - /// exists. - /// - /// @return the set of addresses of exported variable symbols. - address_set_sptr& - create_or_get_linux_exported_var_syms() - { - if (!linux_exported_var_syms_) - linux_exported_var_syms_.reset(new address_set_type); - return linux_exported_var_syms_; - } - - - /// Getter for the set of addresses of function symbols that are - /// explicitely exported as GPL, for a linux kernel (module) binary. - /// These are the addresses of function symbols present in the - /// __ksymtab_gpl section. - address_set_sptr& - linux_exported_gpl_fn_syms() - {return linux_exported_gpl_fn_syms_;} - - /// Getter for the set of addresses of function symbols that are - /// explicitely exported as GPL, for a linux kernel (module) binary. - /// These are the addresses of function symbols present in the - /// __ksymtab_gpl section. - const address_set_sptr& - linux_exported_gpl_fn_syms() const - {return const_cast(this)->linux_exported_gpl_fn_syms();} - - /// Create an empty set of addresses of GPL functions exported from - /// a linux kernel (module) binary, or return the one that already - /// exists. - /// - /// @return the set of addresses of exported function symbols. - address_set_sptr& - create_or_get_linux_exported_gpl_fn_syms() - { - if (!linux_exported_gpl_fn_syms_) - linux_exported_gpl_fn_syms_.reset(new address_set_type); - return linux_exported_gpl_fn_syms_; - } - - /// Getter for the set of addresses of variable symbols that are - /// explicitely exported as GPL, for a linux kernel (module) binary. - /// These are the addresses of variable symbols present in the - /// __ksymtab_gpl section. - address_set_sptr& - linux_exported_gpl_var_syms() - {return linux_exported_gpl_var_syms_;} - - /// Getter for the set of addresses of variable symbols that are - /// explicitely exported as GPL, for a linux kernel (module) binary. - /// These are the addresses of variable symbols present in the - /// __ksymtab_gpl section. - const address_set_sptr& - linux_exported_gpl_var_syms() const - {return const_cast(this)->linux_exported_gpl_var_syms();} - - /// Create an empty set of addresses of GPL variables exported from - /// a linux kernel (module) binary, or return the one that already - /// exists. - /// - /// @return the set of addresses of exported variable symbols. - address_set_sptr& - create_or_get_linux_exported_gpl_var_syms() - { - if (!linux_exported_gpl_var_syms_) - linux_exported_gpl_var_syms_.reset(new address_set_type); - return linux_exported_gpl_var_syms_; - } - - /// Getter for the ELF dt_needed tag. - const vector& - dt_needed() const - {return dt_needed_;} - - /// Getter for the ELF dt_soname tag. - const string& - dt_soname() const - {return dt_soname_;} - - /// Getter for the ELF architecture of the current file. - const string& - elf_architecture() const - {return elf_architecture_;} - - /// Getter for the map of global variables symbol address -> global - /// variable symbol index. - /// - /// @return the map. Note that this initializes the map once when - /// its nedded. - const addr_elf_symbol_sptr_map_type& - var_addr_sym_map() const - {return const_cast(this)->var_addr_sym_map();} - - /// Getter for the map of global variables symbol address -> global - /// variable symbol index. - /// - /// @return the map. Note that this initializes the map once when - /// its nedded. - addr_elf_symbol_sptr_map_type& - var_addr_sym_map() - { - if (!var_addr_sym_map_) - maybe_load_symbol_maps(); - return *var_addr_sym_map_; - } - - /// Load the maps address -> function symbol, address -> variable - /// symbol and the maps of function and variable undefined symbols. - /// - /// @param load_fun_map whether to load the address to function map. - /// - /// @param load_var_map whether to laod the address to variable map. - /// - /// @param load_undefined_fun_map whether to load the undefined - /// function map. - /// - /// @param load_undefined_var_map whether to laod the undefined - /// variable map. - /// - /// @return return true iff the maps have be loaded. - bool - load_symbol_maps_from_symtab_section(bool load_fun_map, - bool load_var_map, - bool load_undefined_fun_map, - bool load_undefined_var_map) - { - Elf_Scn* symtab_section = find_symbol_table_section(); - if (!symtab_section) - return false; - - GElf_Shdr header_mem; - GElf_Shdr* symtab_sheader = gelf_getshdr(symtab_section, - &header_mem); - - // check for bogus section header - if (symtab_sheader->sh_entsize == 0) - return false; - - size_t nb_syms = symtab_sheader->sh_size / symtab_sheader->sh_entsize; - - Elf_Data* symtab = elf_getdata(symtab_section, 0); - if (!symtab) - return false; - - GElf_Ehdr elf_header; - ABG_ASSERT(gelf_getehdr(elf_handle(), &elf_header)); - - bool is_ppc64 = architecture_is_ppc64(elf_handle()); - - for (size_t i = 0; i < nb_syms; ++i) - { - GElf_Sym* sym, sym_mem; - sym = gelf_getsym(symtab, i, &sym_mem); - ABG_ASSERT(sym); - - if ((load_fun_map || load_undefined_fun_map) - && (GELF_ST_TYPE(sym->st_info) == STT_FUNC - || GELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC)) - { - elf_symbol_sptr symbol = lookup_elf_symbol_from_index(i); - ABG_ASSERT(symbol); - ABG_ASSERT(symbol->is_function()); - - // If the symbol was suppressed by a suppression - // specification then drop it on the floor. - if (is_elf_symbol_suppressed(symbol)) - continue; - - if (load_fun_map && symbol->is_public()) - { - (*fun_syms_)[symbol->get_name()].push_back(symbol); - - { - GElf_Addr symbol_value = - maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle(), - sym); - - addr_elf_symbol_sptr_map_type::const_iterator it = - fun_addr_sym_map_->find(symbol_value); - if (it == fun_addr_sym_map_->end()) - (*fun_addr_sym_map_)[symbol_value] = symbol; - else //if (sym->st_value != 0) - it->second->get_main_symbol()->add_alias(symbol); - - if (is_ppc64) - { - // For ppc64 ELFv1 binaries, we need to build a - // function entry point address -> function - // symbol map. This is in addition to the - // function pointer -> symbol map. This is - // because on ppc64 ELFv1, a function pointer is - // different from a function entry point - // address. - // - // On ppc64 ELFv1, the DWARF DIE of a function - // references the address of the entry point of - // the function symbol; whereas the value of the - // function symbol is the function pointer. As - // these addresses are different, if I we want - // to get to the symbol of a function from its - // entry point address (as referenced by DWARF - // function DIEs) we must have the two maps I - // mentionned right above. - // - // In other words, we need a map that associates - // a function enty point address with the symbol - // of that function, to be able to get the - // function symbol that corresponds to a given - // function DIE, on ppc64. - // - // The value of the function pointer (the value - // of the symbol) usually refers to the offset - // of a table in the .opd section. But - // sometimes, for a symbol named "foo", the - // corresponding symbol named ".foo" (note the - // dot before foo) which value is the entry - // point address of the function; that entry - // point address refers to a region in the .text - // section. - // - // So we are only interested in values of the - // symbol that are in the .opd section. - GElf_Addr fn_desc_addr = sym->st_value; - GElf_Addr fn_entry_point_addr = - lookup_ppc64_elf_fn_entry_point_address(fn_desc_addr); - addr_elf_symbol_sptr_map_type::const_iterator it2 = - fun_entry_addr_sym_map().find(fn_entry_point_addr); - - if (it2 == fun_entry_addr_sym_map().end()) - fun_entry_addr_sym_map()[fn_entry_point_addr] = symbol; - else if (address_is_in_opd_section(fn_desc_addr)) - { - // Either - // - // 'symbol' must have been registered as an - // alias for it2->second->get_main_symbol(), - // right before the "if (ppc64)" statement. - // - // Or - // - // if the name of 'symbol' is foo, then the - // name of it2->second is ".foo". That is, - // foo is the name of the symbol when it - // refers to the function descriptor in the - // .opd section and ".foo" is an internal - // name for the address of the entry point - // of foo. - // - // In the latter case, we just want to keep - // a refernce to "foo" as .foo is an - // internal name. - - bool two_symbols_alias = - it2->second->get_main_symbol()->does_alias(*symbol); - bool symbol_is_foo_and_prev_symbol_is_dot_foo = - (it2->second->get_name() - == string(".") + symbol->get_name()); - - ABG_ASSERT(two_symbols_alias - || symbol_is_foo_and_prev_symbol_is_dot_foo); - - if (symbol_is_foo_and_prev_symbol_is_dot_foo) - // Let's just keep a reference of the - // symbol that the user sees in the source - // code (the one named foo). The symbol - // which name is prefixed with a "dot" is - // an artificial one. - fun_entry_addr_sym_map()[fn_entry_point_addr] = symbol; - } - } - } - } - else if (load_undefined_fun_map && !symbol->is_defined()) - (*undefined_fun_syms_)[symbol->get_name()].push_back(symbol); - } - else if ((load_var_map || load_undefined_var_map) - && (GELF_ST_TYPE(sym->st_info) == STT_OBJECT - || GELF_ST_TYPE(sym->st_info) == STT_TLS) - // If the symbol is for an OBJECT, the index of the - // section it refers to cannot be absolute. - // Otherwise that OBJECT is not a variable. - && (sym->st_shndx != SHN_ABS - || GELF_ST_TYPE(sym->st_info) != STT_OBJECT )) - { - elf_symbol_sptr symbol = lookup_elf_symbol_from_index(i); - ABG_ASSERT(symbol); - ABG_ASSERT(symbol->is_variable()); - - if (load_var_map && symbol->is_public()) - { - (*var_syms_)[symbol->get_name()].push_back(symbol); - - if (symbol->is_common_symbol()) - { - string_elf_symbols_map_type::iterator it = - var_syms_->find(symbol->get_name()); - ABG_ASSERT(it != var_syms_->end()); - const elf_symbols& common_sym_instances = it->second; - ABG_ASSERT(!common_sym_instances.empty()); - if (common_sym_instances.size() > 1) - { - elf_symbol_sptr main_common_sym = - common_sym_instances[0]; - ABG_ASSERT(main_common_sym->get_name() - == symbol->get_name()); - ABG_ASSERT(main_common_sym->is_common_symbol()); - ABG_ASSERT(symbol.get() != main_common_sym.get()); - main_common_sym->add_common_instance(symbol); - } - } - else - { - GElf_Addr symbol_value = - maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle(), - sym); - addr_elf_symbol_sptr_map_type::const_iterator it = - var_addr_sym_map_->find(symbol_value); - if (it == var_addr_sym_map_->end()) - (*var_addr_sym_map_)[symbol_value] = symbol; - else - it->second->get_main_symbol()->add_alias(symbol); - } - } - else if (load_undefined_var_map && !symbol->is_defined()) - (*undefined_var_syms_)[symbol->get_name()].push_back(symbol); - } - } - return true; - } - - /// Try reading the first __ksymtab section entry. - /// - /// We lookup the symbol from the raw section passed as an argument. For - /// that, consider endianess and adjust for potential Elf relocations before - /// looking up the symbol in the .symtab section. - // - /// Optionally, support position relative relocations by considering the - /// ksymtab entry as 32 bit and applying the relocation relative to the - /// section header (i.e. the symbol position as we are reading the first - /// symbol). - /// - /// @param section the ksymtab section to consider. - /// - /// @param position_relative_relocations if true, then consider that - /// the section designated by @p section contains position-relative - /// relocated symbol addresses. - /// - /// @param symbol_offset if different from zero - /// If symbol_offset is != 0, adjust the position we consider the section - /// start. That is useful to read the ksymtab with a slight offset. - /// - /// Note, this function does not support relocatable ksymtab entries (as for - /// example in kernel modules). Using this function for ksymtabs where - /// relocations need to be applied for the entries we are reading here, will - /// yield wrong results. - /// - /// @return the symbol resulting from the lookup of the symbol address we - /// got from reading the first entry of the ksymtab or null if no such entry - /// could be found. - elf_symbol_sptr - try_reading_first_ksymtab_entry(Elf_Scn* section, - bool position_relative_relocations, - int symbol_offset = 0) const - { - Elf_Data* elf_data = elf_rawdata(section, 0); - uint8_t* bytes = reinterpret_cast(elf_data->d_buf); - bool is_big_endian = architecture_is_big_endian(elf_handle()); - elf_symbol_sptr symbol; - GElf_Addr symbol_address = 0; - - unsigned char symbol_value_size; - if (position_relative_relocations) - symbol_value_size = sizeof(int32_t); - else - symbol_value_size = get_architecture_word_size(elf_handle()); - - const int read_offset = (symbol_offset * symbol_value_size); - bytes += read_offset; - - if (position_relative_relocations) - { - int32_t offset = 0; - ABG_ASSERT(read_int_from_array_of_bytes(bytes, symbol_value_size, - is_big_endian, offset)); - GElf_Shdr section_header; - gelf_getshdr(section, §ion_header); - // the actual symbol address is relative to its position. Since we do - // not know the position, we take the beginning of the section, add the - // read_offset that we might have and finally apply the offset we - // read from the section. - symbol_address = section_header.sh_addr + read_offset + offset; - } - else - ABG_ASSERT(read_int_from_array_of_bytes(bytes, symbol_value_size, - is_big_endian, symbol_address)); - - symbol_address = maybe_adjust_fn_sym_address(symbol_address); - symbol = lookup_elf_symbol_from_address(symbol_address); - return symbol; - } - - /// Try reading the first __ksymtab section entry as if it is in the - /// pre-v4_19 format, that is without position relative relocations. - /// - /// @return the symbol resulting from the lookup of the symbol - /// address we got from reading the first entry of the ksymtab - /// section assuming the pre-v4.19 format. If null, it means the - /// __ksymtab section is not in the pre-v4.19 format. - elf_symbol_sptr - try_reading_first_ksymtab_entry_using_pre_v4_19_format() const - { - Elf_Scn *section = find_any_ksymtab_section(); - return try_reading_first_ksymtab_entry(section, false); - } - - /// Try reading the first __ksymtab section entry as if it is in the - /// v4_19 format, that is with position relative relocations. - /// - /// @return the symbol resulting from the lookup of the symbol - /// address we got from reading the first entry of the ksymtab - /// section assuming the v4.19 format. If null, it means the - /// __ksymtab section is not in the v4.19 format. - elf_symbol_sptr - try_reading_first_ksymtab_entry_using_v4_19_format() const - { - Elf_Scn *section = find_any_ksymtab_section(); - return try_reading_first_ksymtab_entry(section, true); - } - - /// Try to determine the format of the __ksymtab and __ksymtab_gpl - /// sections of Linux kernel modules. - /// - /// This is important because we need to know the format of these - /// sections to be able to read from them. - /// - /// @return the format the __ksymtab[_gpl] sections. - enum ksymtab_format - get_ksymtab_format_module() const - { - Elf_Scn *section = find_any_ksymtab_reloc_section(); - - ABG_ASSERT(section); - - // Libdwfl has a weird quirk where, in the process of obtaining an Elf - // descriptor via dwfl_module_getelf(), it will apply all relocations it - // knows how to and it will zero the relocation info after applying it. If - // the .rela__ksymtab* section contained only simple (absolute) relocations, - // they will have been all applied and sh_size will be 0. For arches that - // support relative ksymtabs, simple relocations only appear in pre-4.19 - // kernel modules. - GElf_Shdr section_mem; - GElf_Shdr *section_shdr = gelf_getshdr(section, §ion_mem); - if (section_shdr->sh_size == 0) - return PRE_V4_19_KSYMTAB_FORMAT; - - bool is_relasec = (section_shdr->sh_type == SHT_RELA); - - // If we still have a normal non-zeroed relocation section, we can guess - // what format the ksymtab is in depending on what types of relocs it - // contains. - - uint64_t type; - Elf_Data *section_data = elf_getdata(section, 0); - if (is_relasec) - { - GElf_Rela rela; - gelf_getrela(section_data, 0, &rela); - type = GELF_R_TYPE(rela.r_info); - } - else - { - GElf_Rel rel; - gelf_getrel(section_data, 0, &rel); - type = GELF_R_TYPE(rel.r_info); - } - - // Sigh, I dislike the arch-dependent code here, but this seems to be a - // reliable heuristic for kernel modules for now. Relative ksymtabs only - // supported on x86 and arm64 as of v4.19. - ksymtab_format format; - switch (type) - { - case R_X86_64_64: // Same as R_386_32, fallthrough -#ifdef HAVE_R_AARCH64_ABS64_MACRO - case R_AARCH64_ABS64: -#endif - format = PRE_V4_19_KSYMTAB_FORMAT; - break; - case R_X86_64_PC32: // Same as R_386_PC32, fallthrough -#ifdef HAVE_R_AARCH64_PREL32_MACRO - case R_AARCH64_PREL32: -#endif - format = V4_19_KSYMTAB_FORMAT; - break; - default: - // Fall back to other methods of determining the ksymtab format. - format = UNDEFINED_KSYMTAB_FORMAT; - break; - } - return format; - } - - /// Determine the format of the __ksymtab and __ksymtab_gpl - /// sections. - /// - /// This is important because we need the know the format of these - /// sections to be able to read from them. - /// - /// @return the format the __ksymtab[_gpl] sections. - enum ksymtab_format - get_ksymtab_format() const - { - if (!find_any_ksymtab_section()) - ksymtab_format_ = UNDEFINED_KSYMTAB_FORMAT; - else - { - if (ksymtab_format_ == UNDEFINED_KSYMTAB_FORMAT) - { - // Since Linux kernel modules are relocatable, we can first try - // using a heuristic based on relocations to guess the ksymtab format. - if (is_linux_kernel_module(elf_handle())) - { - ksymtab_format_ = get_ksymtab_format_module(); - if (ksymtab_format_ != UNDEFINED_KSYMTAB_FORMAT) - return ksymtab_format_; - } - - // If it's not a kernel module or we couldn't determine its format - // with relocations, fall back to the heuristics below. - - // OK this is a dirty little heuristic to determine the - // format of the ksymtab section. - // - // We try to read the first ksymtab entry assuming a - // pre-v4.19 format. If that succeeds then we are in the - // pr-v4.19 format. Otherwise, try reading it assuming a - // v4.19 format. For now, we just support - // PRE_V4_19_KSYMTAB_FORMAT and V4_19_KSYMTAB_FORMAT. - if (try_reading_first_ksymtab_entry_using_pre_v4_19_format()) - ksymtab_format_ = PRE_V4_19_KSYMTAB_FORMAT; - else if (try_reading_first_ksymtab_entry_using_v4_19_format()) - ksymtab_format_ = V4_19_KSYMTAB_FORMAT; - else - // If a new format emerges, then we need to add its - // support above. - ABG_ASSERT_NOT_REACHED; - } - } - return ksymtab_format_; - } - - /// Getter of the size of the symbol value part of an entry of the - /// ksymtab section. - /// - /// @return the size of the symbol value part of the entry of the - /// ksymtab section. - unsigned char - get_ksymtab_symbol_value_size() const - { - unsigned char result = 0; - ksymtab_format format = get_ksymtab_format(); - if (format == UNDEFINED_KSYMTAB_FORMAT) - ; - else if (format == PRE_V4_19_KSYMTAB_FORMAT) - result = get_architecture_word_size(elf_handle()); - else if (format == V4_19_KSYMTAB_FORMAT) - result = 4; - else - ABG_ASSERT_NOT_REACHED; - - return result; - } - - /// Getter of the size of one entry of the ksymtab section. - /// - /// @return the size of one entry of the ksymtab section. - unsigned char - get_ksymtab_entry_size() const - { - if (ksymtab_entry_size_ == 0) - { - const unsigned char symbol_size = get_ksymtab_symbol_value_size(); - Elf_Scn* ksymtab = find_any_ksymtab_section(); - if (ksymtab) - { - GElf_Shdr ksymtab_shdr; - gelf_getshdr(ksymtab, &ksymtab_shdr); - - // ksymtab entries have the following layout - // - // struct { - // T symbol_address; // .symtab entry - // T name_address; // .strtab entry - // } - // - // with T being a suitable type to represent the absolute, - // relocatable or position relative value of the address. T's size - // is determined by get_ksymtab_symbol_value_size(). - // - // Since Kernel v5.4, the entries have the following layout - // - // struct { - // T symbol_address; // .symtab entry - // T name_address; // .strtab entry - // T namespace; // .strtab entry - // } - // - // To determine the ksymtab entry size, find the next entry that - // refers to a valid .symtab entry. The offset to that one is what - // we are searching for. - for (unsigned entries = 2; entries <= 3; ++entries) - { - const unsigned candidate_size = entries * symbol_size; - - // if there is exactly one entry, section size == entry size - // (this looks like an optimization, but in fact it prevents - // from illegal reads if there is actually only one entry) - if (ksymtab_shdr.sh_size == candidate_size) - { - ksymtab_entry_size_ = candidate_size; - break; - } - - // otherwise check whether the symbol following the candidate - // number of entries is a valid ELF symbol. For that we read - // the ksymtab with the given offset and if the symbol is - // valid, we found our entry size. - const ksymtab_format format = get_ksymtab_format(); - if (try_reading_first_ksymtab_entry - (ksymtab, format == V4_19_KSYMTAB_FORMAT, entries)) - { - ksymtab_entry_size_ = candidate_size; - break; - } - } - ABG_ASSERT(ksymtab_entry_size_ != 0); - } - } - - return ksymtab_entry_size_; - } - - /// Getter of the number of entries that are present in the ksymtab - /// section. - /// - /// @return the number of entries that are present in the ksymtab - /// section. - size_t - get_nb_ksymtab_entries() const - { - if (nb_ksymtab_entries_ == 0) - { - Elf_Scn *section = find_ksymtab_section(); - if (section) - { - GElf_Shdr header_mem; - GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); - size_t entry_size = get_ksymtab_entry_size(); - ABG_ASSERT(entry_size); - nb_ksymtab_entries_ = section_header->sh_size / entry_size; - } - } - return nb_ksymtab_entries_; - } - - /// Getter of the number of entries that are present in the - /// ksymtab_gpl section. - /// - /// @return the number of entries that are present in the - /// ksymtab_gpl section. - size_t - get_nb_ksymtab_gpl_entries() - { - if (nb_ksymtab_gpl_entries_ == 0) - { - Elf_Scn *section = find_ksymtab_gpl_section(); - if (section) - { - GElf_Shdr header_mem; - GElf_Shdr *section_header = gelf_getshdr(section, &header_mem); - size_t entry_size = get_ksymtab_entry_size(); - ABG_ASSERT(entry_size); - nb_ksymtab_gpl_entries_ = section_header->sh_size / entry_size; - } - } - return nb_ksymtab_gpl_entries_; - } - - /// Test if a given ELF symbol was suppressed by a suppression - /// specification. - /// - /// @param symbol the ELF symbol to consider. - /// - /// @return true iff @p symbol is suppressed. - bool - is_elf_symbol_suppressed(const elf_symbol_sptr& symbol) const - { - return (symbol - && suppr::is_elf_symbol_suppressed(*this, - symbol->get_name(), - symbol->get_type())); - } - - /// Populate the symbol map by reading exported symbols from the - /// ksymtab directly. - /// - /// @param section the ksymtab section to read from - /// - /// @param exported_fns_set the set of exported functions - /// - /// @param exported_vars_set the set of exported variables - /// - /// @param nb_entries the number of ksymtab entries to read - /// - /// @return true upon successful completion, false otherwise. - bool - populate_symbol_map_from_ksymtab(Elf_Scn *section, - address_set_sptr exported_fns_set, - address_set_sptr exported_vars_set, - size_t nb_entries) - { - // The data of the section. - Elf_Data *elf_data = elf_rawdata(section, 0); - - // An array-of-bytes view of the elf data above. Something we can - // actually program with. Phew. - uint8_t *bytes = reinterpret_cast(elf_data->d_buf); - - // This is where to store an address of a symbol that we read from - // the section. - GElf_Addr symbol_address = 0, adjusted_symbol_address = 0; - - // So the section is an array of entries. Each entry describes a - // symbol. Each entry is made of two words. - // - // The first word is the address of a symbol. The second one is - // the address of a static global variable symbol which value is - // the string representing the symbol name. That string is in the - // __ksymtab_strings section. Here, we are only interested in the - // first entry. - // - // Lets thus walk the array of entries, and let's read just the - // symbol address part of each entry. - bool is_big_endian = architecture_is_big_endian(elf_handle()); - elf_symbol_sptr symbol; - unsigned char symbol_value_size = get_ksymtab_symbol_value_size(); - - for (size_t i = 0, entry_offset = 0; - i < nb_entries; - ++i, entry_offset = get_ksymtab_entry_size() * i) - { - symbol_address = 0; - ABG_ASSERT(read_int_from_array_of_bytes(&bytes[entry_offset], - symbol_value_size, - is_big_endian, - symbol_address)); - - // Starting from linux kernel v4.19, it can happen that the - // address value read from the ksymtab[_gpl] section might - // need some decoding to get the real symbol address that has - // a meaning in the .symbol section. - symbol_address = - maybe_adjust_sym_address_from_v4_19_ksymtab(symbol_address, - entry_offset, section); - - // We might also want to adjust the symbol address, depending - // on if we are looking at an ET_REL, an executable or a - // shared object binary. - adjusted_symbol_address = maybe_adjust_fn_sym_address(symbol_address); - - if (adjusted_symbol_address == 0) - // The resulting symbol address is zero, not sure this - // valid; ignore it. - continue; - - // OK now the symbol address should be in a suitable form to - // be used to look the symbol up in the usual .symbol section - // (aka ELF symbol table). - symbol = lookup_elf_symbol_from_address(adjusted_symbol_address); - if (!symbol) - { - adjusted_symbol_address = - maybe_adjust_var_sym_address(symbol_address); - symbol = lookup_elf_symbol_from_address(adjusted_symbol_address); - if (!symbol) - // This must be a symbol that is of type neither FUNC - // (function) nor OBJECT (variable). There are for intance, - // symbols of type 'NOTYPE' in the ksymtab symbol table. I - // am not sure what those are. - continue; - } - - // If the symbol was suppressed by a suppression - // specification then drop it on the floor. - if (is_elf_symbol_suppressed(symbol)) - continue; - - address_set_sptr set; - if (symbol->is_function()) - { - ABG_ASSERT(lookup_elf_fn_symbol_from_address - (adjusted_symbol_address)); - set = exported_fns_set; - } - else if (symbol->is_variable()) - { - ABG_ASSERT(lookup_elf_var_symbol_from_address - (adjusted_symbol_address)); - set = exported_vars_set; - } - else - ABG_ASSERT_NOT_REACHED; - set->insert(adjusted_symbol_address); - } - return true; - } - - /// Populate the symbol map by extracting the exported symbols from a - /// ksymtab rela section. - /// - /// @param section the ksymtab section to read from - /// - /// @param exported_fns_set the set of exported functions - /// - /// @param exported_vars_set the set of exported variables - /// - /// @return true upon successful completion, false otherwise. - bool - populate_symbol_map_from_ksymtab_reloc(Elf_Scn *reloc_section, - address_set_sptr exported_fns_set, - address_set_sptr exported_vars_set) - { - GElf_Shdr reloc_section_mem; - GElf_Shdr *reloc_section_shdr = gelf_getshdr(reloc_section, - &reloc_section_mem); - size_t reloc_count = - reloc_section_shdr->sh_size / reloc_section_shdr->sh_entsize; - - Elf_Data *reloc_section_data = elf_getdata(reloc_section, 0); - - bool is_relasec = (reloc_section_shdr->sh_type == SHT_RELA); - elf_symbol_sptr symbol; - GElf_Sym native_symbol; - for (unsigned int i = 0; i < reloc_count; i++) - { - if (is_relasec) - { - GElf_Rela rela; - gelf_getrela(reloc_section_data, i, &rela); - symbol = lookup_elf_symbol_from_index(GELF_R_SYM(rela.r_info), - native_symbol); - } - else - { - GElf_Rel rel; - gelf_getrel(reloc_section_data, i, &rel); - symbol = lookup_elf_symbol_from_index(GELF_R_SYM(rel.r_info), - native_symbol); - } - - ABG_ASSERT(symbol); - - // If the symbol is a linux string constant then ignore it. - if (symbol->get_is_linux_string_cst()) - continue; - - if (!symbol->is_function() && !symbol->is_variable()) - { - if (do_log()) - { - if (symbol->get_type() == elf_symbol::NOTYPE_TYPE) - cerr << "skipping NOTYPE symbol " - << symbol->get_name() - << " shndx: " - << symbol->get_index() - << " @" - << elf_path() - << "\n"; - else if (symbol->get_type() == elf_symbol::SECTION_TYPE) - cerr << "skipping SECTION symbol " - << "shndx: " - << symbol->get_index() - << " @" - << elf_path() - << "\n"; - } - continue; - } - - // If the symbol was suppressed by a suppression - // specification then drop it on the floor. - if (is_elf_symbol_suppressed(symbol)) - continue; - - // If we are looking at an ET_REL (relocatable) binary, then - // the symbol value of native_symbol is relative to the - // section that symbol is defined in. We need to translate it - // into an absolute (okay, binary-relative, rather) address. - GElf_Addr symbol_address = - maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle(), - &native_symbol); - - address_set_sptr set; - if (symbol->is_function()) - { - ABG_ASSERT(lookup_elf_fn_symbol_from_address(symbol_address)); - set = exported_fns_set; - } - else if (symbol->is_variable()) - { - ABG_ASSERT(lookup_elf_var_symbol_from_address(symbol_address)); - set = exported_vars_set; - } - else - ABG_ASSERT_NOT_REACHED; - set->insert(symbol_address); - } - return true; - } - - /// Load a given kernel symbol table. - /// - /// One can thus retrieve the resulting symbols by using the - /// accessors read_context::linux_exported_fn_syms(), - /// read_context::linux_exported_var_syms(), - /// read_context::linux_exported_gpl_fn_syms(), or - /// read_context::linux_exported_gpl_var_syms(). - /// - /// @param kind the kind of kernel symbol table to load. - /// - /// @return true upon successful completion, false otherwise. - bool - load_kernel_symbol_table(kernel_symbol_table_kind kind) - { - Elf_Scn *section = 0, *reloc_section = 0; - address_set_sptr linux_exported_fns_set, linux_exported_vars_set; - - switch (kind) - { - case KERNEL_SYMBOL_TABLE_KIND_UNDEFINED: - break; - case KERNEL_SYMBOL_TABLE_KIND_KSYMTAB: - section = find_ksymtab_section(); - reloc_section = find_ksymtab_reloc_section(); - linux_exported_fns_set = create_or_get_linux_exported_fn_syms(); - linux_exported_vars_set = create_or_get_linux_exported_var_syms(); - break; - case KERNEL_SYMBOL_TABLE_KIND_KSYMTAB_GPL: - section = find_ksymtab_gpl_section(); - reloc_section = find_ksymtab_gpl_reloc_section(); - linux_exported_fns_set = create_or_get_linux_exported_gpl_fn_syms(); - linux_exported_vars_set = create_or_get_linux_exported_gpl_var_syms(); - break; - } - - if (!linux_exported_vars_set || !linux_exported_fns_set || !section) - return false; - - ksymtab_format format = get_ksymtab_format(); - - // Although pre-v4.19 kernel modules can have a relocation section for the - // __ksymtab section, libdwfl zeroes the rela section after applying - // "simple" absolute relocations via dwfl_module_getelf(). For v4.19 and - // above, we get PC-relative relocations so dwfl_module_getelf() doesn't - // apply those relocations and we're safe to read the relocation section to - // determine which exported symbols are in the ksymtab. - if (!reloc_section || format == PRE_V4_19_KSYMTAB_FORMAT) + if (scope_stack().empty()) { - size_t nb_entries = 0; - if (kind == KERNEL_SYMBOL_TABLE_KIND_KSYMTAB) - nb_entries = get_nb_ksymtab_entries(); - else if (kind == KERNEL_SYMBOL_TABLE_KIND_KSYMTAB_GPL) - nb_entries = get_nb_ksymtab_gpl_entries(); - - if (!nb_entries) - return false; - - return populate_symbol_map_from_ksymtab( - section, linux_exported_fns_set, linux_exported_vars_set, - nb_entries); + if (cur_transl_unit()) + scope_stack().push(cur_transl_unit()->get_global_scope().get()); } - else - return populate_symbol_map_from_ksymtab_reloc(reloc_section, - linux_exported_fns_set, - linux_exported_vars_set); + return scope_stack().top(); } - /// Load the special __ksymtab section. This is for linux kernel - /// (module) files. - /// - /// @return true upon successful completion, false otherwise. - bool - load_ksymtab_symbols() - { - return load_kernel_symbol_table(KERNEL_SYMBOL_TABLE_KIND_KSYMTAB); - } + list& + var_decls_to_re_add_to_tree() + {return var_decls_to_add_;} - /// Load the special __ksymtab_gpl section. This is for linux kernel - /// (module) files. + /// The section containing the symbol table from the current ELF + /// file. /// - /// @return true upon successful completion, false otherwise. - bool - load_ksymtab_gpl_symbols() + /// Note that after it's first invocation, this function caches the + /// symbol table that it found. Subsequent invocations just return + /// the cached symbol table section. + /// + /// @return the symbol table section if found + Elf_Scn* + find_symbol_table_section() const { - return load_kernel_symbol_table(KERNEL_SYMBOL_TABLE_KIND_KSYMTAB_GPL); + if (!symtab_section_) + symtab_section_ = elf_helpers::find_symbol_table_section(elf_handle()); + return symtab_section_; } - /// Load linux kernel (module) specific exported symbol sections. + /// Lookup an elf symbol, referred to by its index, from the .symtab + /// section. + /// + /// The resulting symbol returned is an instance of a GElf_Sym, from + /// the libelf library. + /// + /// @param symbol_index the index of the symbol to look up. /// - /// @return true upon successful completion, false otherwise. + /// @param elf_sym out parameter. This is set to the resulting ELF + /// symbol iff the function returns TRUE, meaning the symbol was + /// found. + /// + /// @return TRUE iff the symbol was found. bool - load_linux_specific_exported_symbol_maps() + lookup_native_elf_symbol_from_index(size_t symbol_index, GElf_Sym &elf_sym) { - bool loaded = false; - if (!linux_exported_fn_syms_ - || !linux_exported_var_syms_) - loaded |= load_ksymtab_symbols(); + Elf_Scn* symtab_section = find_symbol_table_section(); + if (!symtab_section) + return false; + + Elf_Data* symtab = elf_getdata(symtab_section, 0); + ABG_ASSERT(symtab); - if (!linux_exported_gpl_fn_syms_ - || !linux_exported_gpl_var_syms_) - loaded |= load_ksymtab_gpl_symbols(); + if (!gelf_getsym(symtab, symbol_index, &elf_sym)) + return false; - return loaded; + return true; } - /// Load the maps of function symbol address -> function symbol, - /// global variable symbol address -> variable symbol and also the - /// maps of function and variable undefined symbols. + /// Test if a given function symbol has been exported. /// - /// All these maps are loaded only if they are not loaded already. + /// @param symbol_address the address of the symbol we are looking + /// for. Note that this address must be a relative offset from the + /// beginning of the .text section, just like the kind of addresses + /// that are present in the .symtab section. /// - /// @return true iff everything went fine. - bool - load_symbol_maps() + /// @returnthe elf symbol if found, or nil otherwise. + elf_symbol_sptr + function_symbol_is_exported(GElf_Addr symbol_address) const { - bool load_fun_map = !fun_addr_sym_map_ ; - bool load_var_map = !var_addr_sym_map_; - bool load_undefined_fun_map = !undefined_fun_syms_; - bool load_undefined_var_map = !undefined_var_syms_; + elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address); + if (!symbol) + return symbol; - if (!fun_syms_) - fun_syms_.reset(new string_elf_symbols_map_type); + if (!symbol->is_function() || !symbol->is_public()) + return elf_symbol_sptr(); - if (!fun_addr_sym_map_) - fun_addr_sym_map_.reset(new addr_elf_symbol_sptr_map_type); + address_set_sptr set; + bool looking_at_linux_kernel_binary = + load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); - if (!fun_entry_addr_sym_map_ && architecture_is_ppc64(elf_handle())) - fun_entry_addr_sym_map_.reset(new addr_elf_symbol_sptr_map_type); + if (looking_at_linux_kernel_binary) + { + if (symbol->is_in_ksymtab()) + return symbol; + return elf_symbol_sptr(); + } - if (!var_syms_) - var_syms_.reset(new string_elf_symbols_map_type); + return symbol; + } - if (!var_addr_sym_map_) - var_addr_sym_map_.reset(new addr_elf_symbol_sptr_map_type); + /// Test if a given variable symbol has been exported. + /// + /// @param symbol_address the address of the symbol we are looking + /// for. Note that this address must be a relative offset from the + /// beginning of the .text section, just like the kind of addresses + /// that are present in the .symtab section. + /// + /// @returnthe elf symbol if found, or nil otherwise. + elf_symbol_sptr + variable_symbol_is_exported(GElf_Addr symbol_address) const + { + elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address); + if (!symbol) + return symbol; - if (!undefined_fun_syms_) - undefined_fun_syms_.reset(new string_elf_symbols_map_type); + if (!symbol->is_variable() || !symbol->is_public()) + return elf_symbol_sptr(); - if (!undefined_var_syms_) - undefined_var_syms_.reset(new string_elf_symbols_map_type); + address_set_sptr set; + bool looking_at_linux_kernel_binary = + load_in_linux_kernel_mode() && is_linux_kernel(elf_handle()); - if (!options_.ignore_symbol_table) + if (looking_at_linux_kernel_binary) { - if (load_symbol_maps_from_symtab_section(load_fun_map, - load_var_map, - load_undefined_fun_map, - load_undefined_var_map)) - { - if (load_in_linux_kernel_mode() && is_linux_kernel(elf_handle())) - return load_linux_specific_exported_symbol_maps(); - return true; - } - return false; + if (symbol->is_in_ksymtab()) + return symbol; + return elf_symbol_sptr(); } - return true; + + return symbol; } - /// Return true if an address is in the ".opd" section that is - /// present on the ppc64 platform. - /// - /// @param addr the address to consider. - /// - /// @return true iff @p addr is designates a word that is in the - /// ".opd" section. - bool - address_is_in_opd_section(Dwarf_Addr addr) + const symtab_reader::symtab_sptr& + symtab() const { - Elf_Scn * opd_section = find_opd_section(); - if (!opd_section) - return false; - if (address_is_in_section(addr, opd_section)) - return true; - return false; + using namespace abg_compat::placeholders; + if (!symtab_) + symtab_ = symtab_reader::symtab::load( + elf_handle(), options_.env, + abg_compat::bind(&read_context::is_elf_symbol_suppressed, this, _1)); + if (!symtab_) + { + std::cerr << "Symbol table of '" << elf_path_ + << "' could not be loaded\n"; + } + return symtab_; } - /// Load the symbol maps if necessary. + /// Getter for the ELF dt_needed tag. + const vector& + dt_needed() const + {return dt_needed_;} + + /// Getter for the ELF dt_soname tag. + const string& + dt_soname() const + {return dt_soname_;} + + /// Getter for the ELF architecture of the current file. + const string& + elf_architecture() const + {return elf_architecture_;} + + /// Test if a given ELF symbol was suppressed by a suppression + /// specification. + /// + /// @param symbol the ELF symbol to consider. /// - /// @return true iff the symbol maps has been loaded by this - /// invocation. + /// @return true iff @p symbol is suppressed. bool - maybe_load_symbol_maps() const + is_elf_symbol_suppressed(const elf_symbol_sptr& symbol) const { - if (!fun_addr_sym_map_ - || !var_addr_sym_map_ - || !fun_syms_ - || !var_syms_ - || !undefined_fun_syms_ - || !undefined_var_syms_) - return const_cast(this)->load_symbol_maps(); - return false; + return (symbol + && suppr::is_elf_symbol_suppressed(*this, + symbol->get_name(), + symbol->get_type())); } /// Load the DT_NEEDED and DT_SONAME elf TAGS. @@ -6906,36 +5081,6 @@ class read_context load_elf_architecture(); } - /// Convert the value of the symbol address part of a post V4.19 - /// ksymtab entry (that contains place-relative addresses) into its - /// corresponding symbol value in the .symtab section. The value of - /// the symbol in .symtab equals to addr_offset + address-of-ksymtab - /// + addr. - /// - /// @param addr the address read from the ksymtab section. - /// - /// @param addr_offset the offset at which @p addr was read. - /// - /// @param ksymtab_section the kymstab section @p addr was read - /// from. - GElf_Addr - maybe_adjust_sym_address_from_v4_19_ksymtab(GElf_Addr addr, - size_t addr_offset, - Elf_Scn *ksymtab_section) const - { - GElf_Addr result = addr; - - if (get_ksymtab_format() == V4_19_KSYMTAB_FORMAT) - { - int32_t offset = addr; - GElf_Shdr mem; - GElf_Shdr *section_header = gelf_getshdr(ksymtab_section, &mem); - result = offset + section_header->sh_addr + addr_offset; - } - - return result; - } - /// This is a sub-routine of maybe_adjust_fn_sym_address and /// maybe_adjust_var_sym_address. /// @@ -7030,26 +5175,6 @@ class read_context return addr; } - /// Test if a given address is in a given section. - /// - /// @param addr the address to consider. - /// - /// @param section the section to consider. - bool - address_is_in_section(Dwarf_Addr addr, Elf_Scn* section) const - { - if (!section) - return false; - - GElf_Shdr sheader_mem; - GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem); - - if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size) - return true; - - return false; - } - /// For a relocatable (*.o) elf file, this function expects an /// absolute address, representing a global variable symbol. It /// then extracts the address of the {.data,.data1,.rodata,.bss} @@ -7788,46 +5913,6 @@ void set_do_log(read_context& ctxt, bool f) {ctxt.do_log(f);} -/// Setter of the "set_ignore_symbol_table" flag. -/// -/// This flag tells if we should load information about ELF symbol -/// tables. Not loading the symbol tables is a speed optimization -/// that is done when the set of symbols we care about is provided -/// off-hand. This is the case when we are supposed to analyze a -/// Linux kernel binary. In that case, because we have the white list -/// of functions/variable symbols we care about, we don't need to -/// analyze the symbol table; things are thus faster in that case. -/// -/// By default, the symbol table is analyzed so this boolean is set to -/// false. -/// -/// @param ctxt the read context to consider. -/// -/// @param f the new value of the flag. -void -set_ignore_symbol_table(read_context &ctxt, bool f) -{ctxt.options_.ignore_symbol_table = f;} - -/// Getter of the "set_ignore_symbol_table" flag. -/// -/// This flag tells if we should load information about ELF symbol -/// tables. Not loading the symbol tables is a speed optimization -/// that is done when the set of symbols we care about is provided -/// off-hand. This is the case when we are supposed to analyze a -/// Linux kernel binary. In that case, because we have the white list -/// of functions/variable symbols we care about, we don't need to -/// analyze the symbol table; things are thus faster in that case. -/// -/// By default, the symbol table is analyzed so this boolean is set to -/// false. -/// -/// @param ctxt the read context to consider. -/// -/// @return the value of the flag. -bool -get_ignore_symbol_table(const read_context& ctxt) -{return ctxt.options_.ignore_symbol_table;} - /// Test if a given DIE is anonymous /// /// @param die the DIE to consider. @@ -12803,14 +10888,14 @@ build_enum_type(read_context& ctxt, location loc; die_loc_and_name(ctxt, die, loc, name, linkage_name); - bool enum_is_anonymous = false; + bool is_anonymous = false; // If the enum is anonymous, let's give it a name. if (name.empty()) { name = get_internal_anonymous_die_prefix_name(die); ABG_ASSERT(!name.empty()); // But we remember that the type is anonymous. - enum_is_anonymous = true; + is_anonymous = true; if (size_t s = scope->get_num_anonymous_member_enums()) name = build_internal_anonymous_die_name(name, s); @@ -12822,7 +10907,7 @@ build_enum_type(read_context& ctxt, // representation (name) and location can be later detected as being // for the same type. - if (!enum_is_anonymous) + if (!is_anonymous) { if (use_odr) { @@ -12855,6 +10940,7 @@ build_enum_type(read_context& ctxt, uint64_t size = 0; if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size)) size *= 8; + bool is_artificial = die_is_artificial(die); // for now we consider that underlying types of enums are all anonymous bool enum_underlying_type_is_anonymous= true; @@ -12887,8 +10973,6 @@ build_enum_type(read_context& ctxt, while (dwarf_siblingof(&child, &child) == 0); } - bool is_artificial = die_is_artificial(die); - // DWARF up to version 4 (at least) doesn't seem to carry the // underlying type, so let's create an artificial one here, which // sole purpose is to be passed to the constructor of the @@ -12904,7 +10988,7 @@ build_enum_type(read_context& ctxt, t = dynamic_pointer_cast(d); ABG_ASSERT(t); result.reset(new enum_type_decl(name, loc, t, enms, linkage_name)); - result->set_is_anonymous(enum_is_anonymous); + result->set_is_anonymous(is_anonymous); result->set_is_artificial(is_artificial); ctxt.associate_die_to_type(die, result, where_offset); return result; @@ -14777,33 +12861,6 @@ build_or_get_var_decl_if_not_suppressed(read_context& ctxt, return var; } -/// Create a variable symbol with a given name. -/// -/// @param sym_name the name of the variable symbol. -/// -/// @param env the environment to create the default symbol in. -/// -/// @return the newly created symbol. -static elf_symbol_sptr -create_default_var_sym(const string& sym_name, const environment *env) -{ - elf_symbol::version ver; - elf_symbol::visibility vis = elf_symbol::DEFAULT_VISIBILITY; - elf_symbol_sptr result = - elf_symbol::create(env, - /*symbol index=*/ 0, - /*symbol size=*/ 0, - sym_name, - /*symbol type=*/ elf_symbol::OBJECT_TYPE, - /*symbol binding=*/ elf_symbol::GLOBAL_BINDING, - /*symbol is defined=*/ true, - /*symbol is common=*/ false, - /*symbol version=*/ ver, - /*symbol_visibility=*/vis, - /*is_linux_string_cst=*/false); - return result; -} - /// Build a @ref var_decl out of a DW_TAG_variable DIE. /// /// @param ctxt the read context to use. @@ -14875,22 +12932,14 @@ build_var_decl(read_context& ctxt, if (!result->get_symbol()) { elf_symbol_sptr var_sym; - if (get_ignore_symbol_table(ctxt)) + Dwarf_Addr var_addr; + if (ctxt.get_variable_address(die, var_addr)) { - string var_name = - result->get_linkage_name().empty() - ? result->get_name() - : result->get_linkage_name(); - - var_sym = create_default_var_sym(var_name, ctxt.env()); - ABG_ASSERT(var_sym); - add_symbol_to_map(var_sym, ctxt.var_syms()); - } - else - { - Dwarf_Addr var_addr; - if (ctxt.get_variable_address(die, var_addr)) - var_sym = var_sym = ctxt.variable_symbol_is_exported(var_addr); + ctxt.symtab()->update_main_symbol(var_addr, + result->get_linkage_name().empty() + ? result->get_name() + : result->get_linkage_name()); + var_sym = ctxt.variable_symbol_is_exported(var_addr); } if (var_sym) @@ -14952,15 +13001,17 @@ function_is_suppressed(const read_context& ctxt, Dwarf_Addr fn_addr; if (!ctxt.get_function_address(function_die, fn_addr)) return true; - if (!get_ignore_symbol_table(ctxt)) - { - // We were not instructed to ignore (avoid loading) the - // symbol table, so we can rely on its presence to see if - // the address corresponds to the address of an exported - // function symbol. - if (!ctxt.function_symbol_is_exported(fn_addr)) - return true; - } + + elf_symbol_sptr symbol = ctxt.function_symbol_is_exported(fn_addr); + if (!symbol) + return true; + if (!symbol->is_suppressed()) + return false; + if (symbol->has_aliases() && symbol->is_main_symbol()) + for (elf_symbol_sptr a = symbol->get_next_alias(); + !a->is_main_symbol(); a = a->get_next_alias()) + if (!a->is_suppressed()) + return false; } return suppr::function_is_suppressed(ctxt, qualified_name, @@ -15063,15 +13114,17 @@ variable_is_suppressed(const read_context& ctxt, Dwarf_Addr var_addr = 0; if (!ctxt.get_variable_address(variable_die, var_addr)) return true; - if (!get_ignore_symbol_table(ctxt)) - { - // We were not instructed to ignore (avoid loading) the - // symbol table, so we can rely on its presence to see if - // the address corresponds to the address of an exported - // variable symbol. - if (!ctxt.variable_symbol_is_exported(var_addr)) - return true; - } + + elf_symbol_sptr symbol = ctxt.variable_symbol_is_exported(var_addr); + if (!symbol) + return true; + if (!symbol->is_suppressed()) + return false; + if (symbol->has_aliases() && symbol->is_main_symbol()) + for (elf_symbol_sptr a = symbol->get_next_alias(); + !a->is_main_symbol(); a = a->get_next_alias()) + if (!a->is_suppressed()) + return false; } return suppr::variable_is_suppressed(ctxt, qualified_name, @@ -15322,22 +13375,14 @@ build_function_decl(read_context& ctxt, if (!result->get_symbol()) { elf_symbol_sptr fn_sym; - if (get_ignore_symbol_table(ctxt)) - { - string fn_name = - result->get_linkage_name().empty() - ? result->get_name() - : result->get_linkage_name(); - - fn_sym = create_default_fn_sym(fn_name, ctxt.env()); - ABG_ASSERT(fn_sym); - add_symbol_to_map(fn_sym, ctxt.fun_syms()); - } - else + Dwarf_Addr fn_addr; + if (ctxt.get_function_address(die, fn_addr)) { - Dwarf_Addr fn_addr; - if (ctxt.get_function_address(die, fn_addr)) - fn_sym = ctxt.function_symbol_is_exported(fn_addr); + ctxt.symtab()->update_main_symbol(fn_addr, + result->get_linkage_name().empty() + ? result->get_name() + : result->get_linkage_name()); + fn_sym = ctxt.function_symbol_is_exported(fn_addr); } if (fn_sym) @@ -15368,85 +13413,6 @@ build_function_decl(read_context& ctxt, return result; } -/// Add a set of addresses (representing function symbols) to a -/// function symbol name -> symbol map. -/// -/// For a given symbol address, the function retrieves the name of the -/// symbol as well as the symbol itself and inserts an entry {symbol -/// name, symbol} into a map of symbol name -> symbol map. -/// -/// @param syms the set of symbol addresses to consider. -/// -/// @param map the map to populate. -/// -/// @param ctxt the context in which we are loading a given ELF file. -static void -add_fn_symbols_to_map(address_set_type& syms, - string_elf_symbols_map_type& map, - read_context& ctxt) -{ - for (address_set_type::iterator i = syms.begin(); i != syms.end(); ++i) - { - elf_symbol_sptr sym = ctxt.lookup_elf_fn_symbol_from_address(*i); - ABG_ASSERT(sym); - string_elf_symbols_map_type::iterator it = - ctxt.fun_syms().find(sym->get_name()); - ABG_ASSERT(it != ctxt.fun_syms().end()); - map.insert(*it); - } -} - -/// Add a symbol to a symbol map. -/// -/// @param sym the symbol to add. -/// -/// @param map the symbol map to add the symbol into. -static void -add_symbol_to_map(const elf_symbol_sptr& sym, - string_elf_symbols_map_type& map) -{ - if (!sym) - return; - - string_elf_symbols_map_type::iterator it = map.find(sym->get_name()); - if (it == map.end()) - { - elf_symbols syms; - syms.push_back(sym); - map[sym->get_name()] = syms; - } - else - it->second.push_back(sym); -} - -/// Add a set of addresses (representing variable symbols) to a -/// variable symbol name -> symbol map. -/// -/// For a given symbol address, the variable retrieves the name of the -/// symbol as well as the symbol itself and inserts an entry {symbol -/// name, symbol} into a map of symbol name -> symbol map. -/// -/// @param syms the set of symbol addresses to consider. -/// -/// @param map the map to populate. -/// -/// @param ctxt the context in which we are loading a given ELF file. -static void -add_var_symbols_to_map(address_set_type& syms, - string_elf_symbols_map_type& map, - read_context& ctxt) -{ - for (address_set_type::iterator i = syms.begin(); i != syms.end(); ++i) - { - elf_symbol_sptr sym = ctxt.lookup_elf_var_symbol_from_address(*i); - ABG_ASSERT(sym); - string_elf_symbols_map_type::iterator it = - ctxt.var_syms().find(sym->get_name()); - ABG_ASSERT(it != ctxt.var_syms().end()); - map.insert(*it); - } -} - /// Read all @ref abigail::translation_unit possible from the debug info /// accessible through a DWARF Front End Library handle, and stuff /// them into a libabigail ABI Corpus. @@ -15482,47 +13448,7 @@ read_debug_info_into_corpus(read_context& ctxt) group->add_corpus(ctxt.current_corpus()); // Set symbols information to the corpus. - if (!get_ignore_symbol_table(ctxt)) - { - if (ctxt.load_in_linux_kernel_mode() - && is_linux_kernel(ctxt.elf_handle())) - { - string_elf_symbols_map_sptr exported_fn_symbols_map - (new string_elf_symbols_map_type); - add_fn_symbols_to_map(*ctxt.linux_exported_fn_syms(), - *exported_fn_symbols_map, - ctxt); - add_fn_symbols_to_map(*ctxt.linux_exported_gpl_fn_syms(), - *exported_fn_symbols_map, - ctxt); - ctxt.current_corpus()->set_fun_symbol_map(exported_fn_symbols_map); - - string_elf_symbols_map_sptr exported_var_symbols_map - (new string_elf_symbols_map_type); - add_var_symbols_to_map(*ctxt.linux_exported_var_syms(), - *exported_var_symbols_map, - ctxt); - add_var_symbols_to_map(*ctxt.linux_exported_gpl_var_syms(), - *exported_var_symbols_map, - ctxt); - ctxt.current_corpus()->set_var_symbol_map(exported_var_symbols_map); - } - else - { - ctxt.current_corpus()->set_fun_symbol_map(ctxt.fun_syms_sptr()); - ctxt.current_corpus()->set_var_symbol_map(ctxt.var_syms_sptr()); - } - - ctxt.current_corpus()->set_undefined_fun_symbol_map - (ctxt.undefined_fun_syms_sptr()); - ctxt.current_corpus()->set_undefined_var_symbol_map - (ctxt.undefined_var_syms_sptr()); - } - else - { - ctxt.current_corpus()->set_fun_symbol_map(ctxt.fun_syms_sptr()); - ctxt.current_corpus()->set_var_symbol_map(ctxt.var_syms_sptr()); - } + ctxt.current_corpus()->set_symtab(ctxt.symtab()); // Get out now if no debug info is found. if (!ctxt.dwarf()) @@ -16731,12 +14657,8 @@ read_corpus_from_elf(read_context& ctxt, status& status) ctxt.load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture - if (!get_ignore_symbol_table(ctxt)) - { - // Read the symbols for publicly defined decls - if (!ctxt.load_symbol_maps()) - status |= STATUS_NO_SYMBOLS_FOUND; - } + if (!ctxt.symtab() || !ctxt.symtab()->has_symbols()) + status |= STATUS_NO_SYMBOLS_FOUND; if (// If no elf symbol was found ... status & STATUS_NO_SYMBOLS_FOUND diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc index ed768d22..6e2495af 100644 --- a/src/abg-elf-helpers.cc +++ b/src/abg-elf-helpers.cc @@ -863,6 +863,153 @@ architecture_is_big_endian(Elf* elf_handle) return is_big_endian; } +/// Read N bytes and convert their value into an integer type T. +/// +/// Note that N cannot be bigger than 8 for now. The type passed needs to be at +/// least of the size of number_of_bytes. +/// +/// @param bytes the array of bytes to read the next 8 bytes from. +/// Note that this array must be at least 8 bytes long. +/// +/// @param number_of_bytes the number of bytes to read. This number +/// cannot be bigger than 8. +/// +/// @param is_big_endian if true, read the 8 bytes in Big Endian +/// mode, otherwise, read them in Little Endian. +/// +/// @param result where to store the resuting integer that was read. +/// +/// +/// @param true if the 8 bytes could be read, false otherwise. +template +bool +read_int_from_array_of_bytes(const uint8_t* bytes, + unsigned char number_of_bytes, + bool is_big_endian, + T& result) +{ + if (!bytes) + return false; + + ABG_ASSERT(number_of_bytes <= 8); + ABG_ASSERT(number_of_bytes <= sizeof(T)); + + T res = 0; + + const uint8_t* cur = bytes; + if (is_big_endian) + { + // In Big Endian, the most significant byte is at the lowest + // address. + const uint8_t* msb = cur; + res = *msb; + + // Now read the remaining least significant bytes. + for (uint i = 1; i < number_of_bytes; ++i) + res = (res << 8) | ((T)msb[i]); + } + else + { + // In Little Endian, the least significant byte is at the + // lowest address. + const uint8_t* lsb = cur; + res = *lsb; + // Now read the remaining most significant bytes. + for (uint i = 1; i < number_of_bytes; ++i) + res = res | (((T)lsb[i]) << i * 8); + } + + result = res; + return true; +} + +/// Read 8 bytes and convert their value into an uint64_t. +/// +/// @param bytes the array of bytes to read the next 8 bytes from. +/// Note that this array must be at least 8 bytes long. +/// +/// @param result where to store the resuting uint64_t that was read. +/// +/// @param is_big_endian if true, read the 8 bytes in Big Endian +/// mode, otherwise, read them in Little Endian. +/// +/// @param true if the 8 bytes could be read, false otherwise. +bool +read_uint64_from_array_of_bytes(const uint8_t* bytes, + bool is_big_endian, + uint64_t& result) +{ + return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result); +} + + +/// Lookup the address of the function entry point that corresponds +/// to the address of a given function descriptor. +/// +/// On PPC64, a function pointer is the address of a function +/// descriptor. Function descriptors are located in the .opd +/// section. Each function descriptor is a triplet of three +/// addresses, each one on 64 bits. Among those three address only +/// the first one is of any interest to us: the address of the entry +/// point of the function. +/// +/// This function returns the address of the entry point of the +/// function whose descriptor's address is given. +/// +/// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES +/// +/// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en +/// +/// @param fn_desc_address the address of the function descriptor to +/// consider. +/// +/// @return the address of the entry point of the function whose +/// descriptor has the address @p fn_desc_address. If there is no +/// .opd section (e.g because we are not on ppc64) or more generally +/// if the function descriptor could not be found then this function +/// just returns the address of the fuction descriptor. +GElf_Addr +lookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, GElf_Addr fn_desc_address) +{ + if (!elf_handle) + return fn_desc_address; + + if (!architecture_is_ppc64(elf_handle)) + return fn_desc_address; + + bool is_big_endian = architecture_is_big_endian(elf_handle); + + Elf_Scn* opd_section = find_opd_section(elf_handle); + if (!opd_section) + return fn_desc_address; + + GElf_Shdr header_mem; + // The section header of the .opd section. + GElf_Shdr* opd_sheader = gelf_getshdr(opd_section, &header_mem); + + // The offset of the function descriptor entry, in the .opd + // section. + size_t fn_desc_offset = fn_desc_address - opd_sheader->sh_addr; + Elf_Data* elf_data = elf_rawdata(opd_section, 0); + + // Ensure that the opd_section has at least 8 bytes, starting from + // the offset we want read the data from. + if (elf_data->d_size <= fn_desc_offset + 8) + return fn_desc_address; + + // A pointer to the data of the .opd section, that we can actually + // do something with. + uint8_t* bytes = (uint8_t*)elf_data->d_buf; + + // The resulting address we are looking for is going to be formed + // in this variable. + GElf_Addr result = 0; + ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset, + is_big_endian, result)); + + return result; +} + /// Test if the ELF binary denoted by a given ELF handle is a Linux /// Kernel Module. /// @@ -1027,5 +1174,44 @@ maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym) return addr + section_header.sh_addr; } +/// Test if a given address is in a given section. +/// +/// @param addr the address to consider. +/// +/// @param section the section to consider. +bool +address_is_in_section(Dwarf_Addr addr, Elf_Scn* section) +{ + if (!section) + return false; + + GElf_Shdr sheader_mem; + GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem); + + if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size) + return true; + + return false; +} + +/// Return true if an address is in the ".opd" section that is +/// present on the ppc64 platform. +/// +/// @param addr the address to consider. +/// +/// @return true iff @p addr is designates a word that is in the +/// ".opd" section. +bool +address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr) +{ + Elf_Scn * opd_section = find_opd_section(elf_handle); + if (!opd_section) + return false; + if (address_is_in_section(addr, opd_section)) + return true; + return false; +} + + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h index 647c9270..20466485 100644 --- a/src/abg-elf-helpers.h +++ b/src/abg-elf-helpers.h @@ -27,6 +27,7 @@ #include "config.h" +#include #include #include @@ -148,6 +149,10 @@ architecture_is_ppc64(Elf* elf_handle); bool architecture_is_big_endian(Elf* elf_handle); +GElf_Addr +lookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, + GElf_Addr fn_desc_address); + // // Helpers for Linux Kernel Binaries // @@ -177,6 +182,9 @@ is_dso(Elf* elf_handle); GElf_Addr maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym); +bool +address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr); + } // end namespace elf_helpers } // end namespace abigail diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 217d42d8..268d478c 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -24,13 +24,14 @@ /// /// Definitions for the Internal Representation artifacts of libabigail. -#include -#include -#include #include +#include +#include #include -#include #include +#include +#include +#include #include "abg-cxx-compat.h" #include "abg-internal.h" @@ -1300,6 +1301,9 @@ struct elf_symbol::priv // STT_COMMON definition of that name that has the largest size. bool is_common_; bool is_linux_string_cst_; + bool is_in_ksymtab_; + uint64_t crc_; + bool is_suppressed_; elf_symbol_wptr main_symbol_; elf_symbol_wptr next_alias_; elf_symbol_wptr next_common_instance_; @@ -1314,20 +1318,26 @@ struct elf_symbol::priv visibility_(elf_symbol::DEFAULT_VISIBILITY), is_defined_(false), is_common_(false), - is_linux_string_cst_(false) + is_linux_string_cst_(false), + is_in_ksymtab_(false), + crc_(0), + is_suppressed_(false) {} - priv(const environment* e, - size_t i, - size_t s, - const string& n, - elf_symbol::type t, - elf_symbol::binding b, - bool d, - bool c, - const elf_symbol::version& ve, - elf_symbol::visibility vi, - bool is_linux_string_cst) + priv(const environment* e, + size_t i, + size_t s, + const string& n, + elf_symbol::type t, + elf_symbol::binding b, + bool d, + bool c, + const elf_symbol::version& ve, + elf_symbol::visibility vi, + bool is_linux_string_cst, + bool is_in_ksymtab, + uint64_t crc, + bool is_suppressed) : env_(e), index_(i), size_(s), @@ -1338,7 +1348,10 @@ struct elf_symbol::priv visibility_(vi), is_defined_(d), is_common_(c), - is_linux_string_cst_(is_linux_string_cst) + is_linux_string_cst_(is_linux_string_cst), + is_in_ksymtab_(is_in_ksymtab), + crc_(crc), + is_suppressed_(is_suppressed) { if (!is_common_) is_common_ = type_ == COMMON_TYPE; @@ -1384,19 +1397,34 @@ elf_symbol::elf_symbol() /// /// @param is_linux_string_cst true if the symbol is a Linux Kernel /// string constant defined in the __ksymtab_strings section. -elf_symbol::elf_symbol(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_linux_string_cst) - : priv_(new priv(e, i, s, n, t, b, d, - c, ve, vi, is_linux_string_cst)) +elf_symbol::elf_symbol(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_linux_string_cst, + bool is_in_ksymtab, + uint64_t crc, + bool is_suppressed) + : priv_(new priv(e, + i, + s, + n, + t, + b, + d, + c, + ve, + vi, + is_linux_string_cst, + is_in_ksymtab, + crc, + is_suppressed)) {} /// Factory of instances of @ref elf_symbol. @@ -1443,20 +1471,24 @@ elf_symbol::create() /// @return a (smart) pointer to a newly created instance of @ref /// elf_symbol. elf_symbol_sptr -elf_symbol::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_linux_string_cst) -{ - elf_symbol_sptr sym(new elf_symbol(e, i, s, n, t, b, d, c, ve, - vi, is_linux_string_cst)); +elf_symbol::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_linux_string_cst, + bool is_in_ksymtab, + uint64_t crc, + bool is_suppressed) +{ + elf_symbol_sptr sym(new elf_symbol(e, i, s, n, t, b, d, c, ve, vi, + is_linux_string_cst, + is_in_ksymtab, crc, is_suppressed)); sym->priv_->main_symbol_ = sym; return sym; } @@ -1477,7 +1509,9 @@ textually_equals(const elf_symbol&l, && l.is_public() == r.is_public() && l.is_defined() == r.is_defined() && l.is_common_symbol() == r.is_common_symbol() - && l.get_version() == r.get_version()); + && l.get_version() == r.get_version() + && (l.get_crc() == 0 || r.get_crc() == 0 + || l.get_crc() == r.get_crc())); if (equals && l.is_variable()) // These are variable symbols. Let's compare their symbol size. @@ -1676,6 +1710,30 @@ bool elf_symbol::is_variable() const {return get_type() == OBJECT_TYPE || get_type() == TLS_TYPE;} +bool +elf_symbol::is_in_ksymtab() const +{return priv_->is_in_ksymtab_;} + +void +elf_symbol::set_is_in_ksymtab(bool is_in_ksymtab) +{priv_->is_in_ksymtab_ = is_in_ksymtab;} + +uint64_t +elf_symbol::get_crc() const +{return priv_->crc_;} + +void +elf_symbol::set_crc(uint64_t crc) +{priv_->crc_ = crc;} + +bool +elf_symbol::is_suppressed() const +{return priv_->is_suppressed_;} + +void +elf_symbol::set_is_suppressed(bool is_suppressed) +{priv_->is_suppressed_ = is_suppressed;} + /// @name Elf symbol aliases /// /// An alias A for an elf symbol S is a symbol that is defined at the @@ -1704,14 +1762,14 @@ elf_symbol::is_variable() const ///@return the main symbol. const elf_symbol_sptr elf_symbol::get_main_symbol() const -{return elf_symbol_sptr(priv_->main_symbol_);} +{return priv_->main_symbol_.lock();} /// Get the main symbol of an alias chain. /// ///@return the main symbol. elf_symbol_sptr elf_symbol::get_main_symbol() -{return elf_symbol_sptr(priv_->main_symbol_);} +{return priv_->main_symbol_.lock();} /// Tests whether this symbol is the main symbol. /// @@ -1788,6 +1846,48 @@ elf_symbol::add_alias(const elf_symbol_sptr& alias) alias->priv_->main_symbol_ = get_main_symbol(); } +/// Update the main symbol for a group of aliased symbols +/// +/// If after the construction of the symbols (in order of discovery), the +/// actual main symbol can be identified (e.g. as the symbol that actually is +/// defined in the code), this method offers a way of updating the main symbol +/// through one of the aliased symbols. +/// +/// For that, locate the new main symbol by name and update all references to +/// the main symbol among the group of aliased symbols. +/// +/// @param name the name of the main symbol +/// +/// @return the new main elf_symbol +elf_symbol_sptr +elf_symbol::update_main_symbol(const std::string& name) +{ + + if (!has_aliases() || (is_main_symbol() && get_name() == name)) + return get_main_symbol(); + + // find the new main symbol + elf_symbol_sptr new_main; + for (elf_symbol_sptr a = get_next_alias(); a.get() != this; + a = a->get_next_alias()) + if (a->get_name() == name) + { + new_main = a; + break; + } + + if (!new_main) + return get_main_symbol(); + + // now update all main symbol references + for (elf_symbol_sptr a = get_next_alias(); + a->get_main_symbol() != new_main; + a = a->get_next_alias()) + a->priv_->main_symbol_ = new_main; + + return new_main; +} + /// Return true if the symbol is a common one. /// /// @return true iff the symbol is common. @@ -3535,6 +3635,15 @@ const interned_string& decl_base::peek_qualified_name() const {return priv_->qualified_name_;} +/// Clear the qualified name of this decl. +/// +/// This is useful to ensure that the cache for the qualified name of +/// the decl is refreshed right after type canonicalization, for +/// instance. +void +decl_base::clear_qualified_name() +{priv_->qualified_name_.clear();} + /// Setter for the qualified name. /// /// @param n the new qualified name. @@ -11904,26 +12013,19 @@ type_base::get_canonical_type_for(type_base_sptr t) // Compare types by considering that decl-only classes don't // equal their definition. env->decl_only_class_equals_definition(false); - if (types_defined_same_linux_kernel_corpus_public(**it, *t)) - { - result = *it; - break; - } - if (*it == t) + bool equal = types_defined_same_linux_kernel_corpus_public(**it, *t) + || *it == t; + // Restore the state of the on-the-fly-canonicalization and + // the decl-only-class-being-equal-to-a-matching-definition + // flags. + env->do_on_the_fly_canonicalization(false); + env->decl_only_class_equals_definition + (saved_decl_only_class_equals_definition); + if (equal) { - // Restore the state of the on-the-fly-canonicalization - // and the - // decl-only-class-being-equal-to-a-matching-definition - // flags, as we are getting out of the loop. - env->do_on_the_fly_canonicalization(false); - env->decl_only_class_equals_definition - (saved_decl_only_class_equals_definition); result = *it; break; } - env->do_on_the_fly_canonicalization(false); - env->decl_only_class_equals_definition - (saved_decl_only_class_equals_definition); } if (!result) { @@ -13105,6 +13207,17 @@ qualified_type_def::build_name(bool fully_qualified, bool internal) const fully_qualified, internal); } +/// This function is automatically invoked whenever an instance of +/// this type is canonicalized. +/// +/// It's an overload of the virtual type_base::on_canonical_type_set. +/// +/// We put here what is thus meant to be executed only at the point of +/// type canonicalization. +void +qualified_type_def::on_canonical_type_set() +{clear_qualified_name();} + /// Constructor of the qualified_type_def /// /// @param type the underlying type @@ -13502,6 +13615,17 @@ struct pointer_type_def::priv {} }; //end struct pointer_type_def +/// This function is automatically invoked whenever an instance of +/// this type is canonicalized. +/// +/// It's an overload of the virtual type_base::on_canonical_type_set. +/// +/// We put here what is thus meant to be executed only at the point of +/// type canonicalization. +void +pointer_type_def::on_canonical_type_set() +{clear_qualified_name();} + pointer_type_def::pointer_type_def(const type_base_sptr& pointed_to, size_t size_in_bits, size_t align_in_bits, @@ -13783,6 +13907,17 @@ operator!=(const pointer_type_def_sptr& l, const pointer_type_def_sptr& r) // +/// This function is automatically invoked whenever an instance of +/// this type is canonicalized. +/// +/// It's an overload of the virtual type_base::on_canonical_type_set. +/// +/// We put here what is thus meant to be executed only at the point of +/// type canonicalization. +void +reference_type_def::on_canonical_type_set() +{clear_qualified_name();} + reference_type_def::reference_type_def(const type_base_sptr pointed_to, bool lvalue, size_t size_in_bits, @@ -16232,6 +16367,20 @@ struct function_type::priv } };// end struc function_type::priv +/// This function is automatically invoked whenever an instance of +/// this type is canonicalized. +/// +/// It's an overload of the virtual type_base::on_canonical_type_set. +/// +/// We put here what is thus meant to be executed only at the point of +/// type canonicalization. +void +function_type::on_canonical_type_set() +{ + priv_->cached_name_.clear(); + priv_->internal_cached_name_.clear(); +} + /// The most straightforward constructor for the function_type class. /// /// @param return_type the return type of the function type. diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc index 0c20ee41..783ffbc0 100644 --- a/src/abg-leaf-reporter.cc +++ b/src/abg-leaf-reporter.cc @@ -461,7 +461,7 @@ leaf_reporter::report(const class_or_union_diff& d, const diff_context_sptr& ctxt = d.context(); // Report class decl-only -> definition change. - if (ctxt->get_allowed_category() & CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY) + if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY) if (filtering::has_class_decl_only_def_change(first, second)) { string was = diff --git a/src/abg-reader.cc b/src/abg-reader.cc index eb74659f..d71e2d43 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -47,6 +47,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS #include "abg-libxml-utils.h" #include "abg-reader.h" #include "abg-corpus.h" +#include "abg-symtab-reader.h" #ifdef WITH_ZIP_ARCHIVE #include "abg-libzip-utils.h" @@ -1149,8 +1150,7 @@ static elf_symbol_sptr build_elf_symbol(read_context&, const xmlNodePtr, bool); static elf_symbol_sptr -build_elf_symbol_from_reference(read_context&, const xmlNodePtr, - bool); +build_elf_symbol_from_reference(read_context&, const xmlNodePtr); static string_elf_symbols_map_sptr build_elf_symbol_db(read_context&, const xmlNodePtr, bool); @@ -1973,16 +1973,7 @@ read_corpus_from_input(read_context& ctxt) // Note that it's possible that both fn_sym_db and var_sym_db // are nil, due to potential suppression specifications. That's // fine. - if (fn_sym_db) - { - corp.set_fun_symbol_map(fn_sym_db); - fn_sym_db.reset(); - } - if (var_sym_db) - { - corp.set_var_symbol_map(var_sym_db); - var_sym_db.reset(); - } + corp.set_symtab(symtab_reader::symtab::load(fn_sym_db, var_sym_db)); } ctxt.get_environment()->canonicalization_is_done(false); @@ -2844,6 +2835,10 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node, is_default_version = true; } + uint64_t crc = 0; + if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "crc")) + crc = strtoull(CHAR_STR(s), NULL, 0); + elf_symbol::type type = elf_symbol::NOTYPE_TYPE; read_elf_symbol_type(node, type); @@ -2855,7 +2850,8 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node, elf_symbol::version version(version_string, is_default_version); - if (drop_if_suppressed && suppr::is_elf_symbol_suppressed(ctxt, name, type)) + const bool is_suppressed = suppr::is_elf_symbol_suppressed(ctxt, name, type); + if (drop_if_suppressed && is_suppressed) return elf_symbol_sptr(); const environment* env = ctxt.get_environment(); @@ -2864,6 +2860,12 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node, is_defined, is_common, version, visibility, /*is_linux_string_cst=*/false); + + e->set_is_suppressed(is_suppressed); + + if (crc != 0) + e->set_crc(crc); + return e; } @@ -2881,8 +2883,7 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node, /// /// @return a shared pointer the resutling elf_symbol. static elf_symbol_sptr -build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node, - bool function_symbol) +build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node) { elf_symbol_sptr nil; @@ -2901,20 +2902,13 @@ build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node, if (name.empty()) return nil; - string_elf_symbols_map_sptr sym_db = - (function_symbol) - ? ctxt.get_corpus()->get_fun_symbol_map_sptr() - : ctxt.get_corpus()->get_var_symbol_map_sptr(); + const elf_symbols& symbols = + ctxt.get_corpus()->get_symtab()->lookup_symbol(name); - string_elf_symbols_map_type::const_iterator i = sym_db->find(name); - if (i != sym_db->end()) - { - for (elf_symbols::const_iterator s = i->second.begin(); - s != i->second.end(); - ++s) - if ((*s)->get_id_string() == sym_id) - return *s; - } + for (elf_symbols::const_iterator symbol = symbols.begin(); + symbol != symbols.end(); ++symbol) + if ((*symbol)->get_id_string() == sym_id) + return *symbol; } return nil; @@ -2959,7 +2953,7 @@ build_elf_symbol_db(read_context& ctxt, elf_symbol_sptr sym; for (xmlNodePtr n = node->children; n; n = n->next) { - if ((sym = build_elf_symbol(ctxt, n, /*drop_if_suppress=*/true))) + if ((sym = build_elf_symbol(ctxt, n, /*drop_if_suppress=*/false))) { id_sym_map[sym->get_id_string()] = sym; xml_node_ptr_elf_symbol_map[n] = sym; @@ -3165,8 +3159,7 @@ build_function_decl(read_context& ctxt, ctxt.push_decl_to_current_scope(fn_decl, add_to_current_scope); - elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node, - /*function_sym=*/true); + elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node); if (sym) fn_decl->set_symbol(sym); @@ -3397,8 +3390,7 @@ build_var_decl(read_context& ctxt, locus, mangled_name, vis, bind)); - elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node, - /*function_sym=*/false); + elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node); if (sym) decl->set_symbol(sym); diff --git a/src/abg-reporter-priv.cc b/src/abg-reporter-priv.cc index 9f2c5a4a..2ca48c21 100644 --- a/src/abg-reporter-priv.cc +++ b/src/abg-reporter-priv.cc @@ -57,8 +57,7 @@ emit_num_value(uint64_t value, const diff_context& ctxt, ostream& out) out << std::hex << std::showbase ; else out << std::dec; - out << value; - out << std::dec << std::noshowbase; + out << value << std::dec << std::noshowbase; } /// Convert a bits value into a byte value if the current diff context @@ -1194,6 +1193,21 @@ maybe_report_diff_for_symbol(const elf_symbol_sptr& symbol1, reported = true; } + if (symbol1->get_crc() != 0 && symbol2->get_crc() != 0 + && symbol1->get_crc() != symbol2->get_crc()) + { + if (reported) + out << ",\n" << indent << "its CRC (modversions) changed from "; + else + out << "\n" << indent << "CRC value (modversions) changed from "; + + out << std::showbase << std::hex + << symbol1->get_crc() << " to " << symbol2->get_crc() + << std::noshowbase << std::dec; + + reported = true; + } + if (reported) out << "\n"; diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc new file mode 100644 index 00000000..42481710 --- /dev/null +++ b/src/abg-symtab-reader.cc @@ -0,0 +1,494 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2013-2020 Red Hat, Inc. +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . +// +// Author: Matthias Maennich + +/// @file +/// +/// This contains the definition of the symtab reader + +#include +#include + +#include "abg-cxx-compat.h" +#include "abg-elf-helpers.h" +#include "abg-fwd.h" +#include "abg-internal.h" +#include "abg-tools-utils.h" + +ABG_BEGIN_EXPORT_DECLARATIONS +#include "abg-symtab-reader.h" +ABG_END_EXPORT_DECLARATIONS + +namespace abigail +{ + +namespace symtab_reader +{ + +/// symtab_filter implementations + +bool +symtab_filter::matches(const elf_symbol_sptr& symbol) const +{ + if (functions_ && *functions_ != symbol->is_function()) + return false; + if (variables_ && *variables_ != symbol->is_variable()) + return false; + if (public_symbols_ && *public_symbols_ != symbol->is_public()) + return false; + if (undefined_symbols_ && *undefined_symbols_ == symbol->is_defined()) + return false; + if (kernel_symbols_ && *kernel_symbols_ != symbol->is_in_ksymtab()) + return false; + + return true; +} + +/// symtab implementations + +symtab_filter_builder +symtab::make_filter() const +{ + symtab_filter_builder builder; + builder.public_symbols(); + if (is_kernel_binary_) + builder.kernel_symbols(); + return builder; +} + +const elf_symbols& +symtab::lookup_symbol(const std::string& name) const +{ + static const elf_symbols empty_result; + const name_symbol_map_type::const_iterator it = name_symbol_map_.find(name); + if (it != name_symbol_map_.end()) + { + return it->second; + } + return empty_result; +} + +const elf_symbol_sptr& +symtab::lookup_symbol(GElf_Addr symbol_addr) const +{ + static const elf_symbol_sptr empty_result; + const addr_symbol_map_type::const_iterator addr_it = + addr_symbol_map_.find(symbol_addr); + if (addr_it != addr_symbol_map_.end()) + return addr_it->second; + else + { + const addr_symbol_map_type::const_iterator entry_it = + entry_addr_symbol_map_.find(symbol_addr); + if (entry_it != entry_addr_symbol_map_.end()) + return entry_it->second; + } + return empty_result; +} + +/// A symbol sorting functor. +static struct +{ + bool + operator()(const elf_symbol_sptr& left, const elf_symbol_sptr& right) + { return left->get_id_string() < right->get_id_string(); } +} symbol_sort; + +symtab_sptr +symtab::load(Elf* elf_handle, + ir::environment* env, + symbol_predicate is_suppressed) +{ + ABG_ASSERT(elf_handle); + ABG_ASSERT(env); + + symtab_sptr result(new symtab); + if (!result->load_(elf_handle, env, is_suppressed)) + return symtab_sptr(); + + return result; +} + +symtab_sptr +symtab::load(string_elf_symbols_map_sptr function_symbol_map, + string_elf_symbols_map_sptr variables_symbol_map) +{ + symtab_sptr result(new symtab); + if (!result->load_(function_symbol_map, variables_symbol_map)) + return symtab_sptr(); + + return result; +} + +symtab::symtab() : is_kernel_binary_(false), has_ksymtab_entries_(false) {} + +bool +symtab::load_(Elf* elf_handle, + ir::environment* env, + symbol_predicate is_suppressed) +{ + + Elf_Scn* symtab_section = elf_helpers::find_symbol_table_section(elf_handle); + if (!symtab_section) + { + std::cerr << "No symbol table found: Skipping symtab load.\n"; + return false; + } + + GElf_Shdr symtab_sheader; + gelf_getshdr(symtab_section, &symtab_sheader); + + // check for bogus section header + if (symtab_sheader.sh_entsize == 0) + { + std::cerr << "Invalid symtab header found: Skipping symtab load.\n"; + return false; + } + + const size_t number_syms = + symtab_sheader.sh_size / symtab_sheader.sh_entsize; + + Elf_Data* symtab = elf_getdata(symtab_section, 0); + if (!symtab) + { + std::cerr << "Could not load elf symtab: Skipping symtab load.\n"; + return false; + } + + const bool is_kernel = elf_helpers::is_linux_kernel(elf_handle); + abg_compat::unordered_set exported_kernel_symbols; + abg_compat::unordered_map crc_values; + + const bool is_ppc64 = elf_helpers::architecture_is_ppc64(elf_handle); + + for (size_t i = 0; i < number_syms; ++i) + { + GElf_Sym *sym, sym_mem; + sym = gelf_getsym(symtab, i, &sym_mem); + if (!sym) + { + std::cerr << "Could not load symbol with index " << i + << ": Skipping symtab load.\n"; + return false; + } + + const char* name_str = + elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name); + + // no name, no game + if (!name_str) + continue; + + // Handle ksymtab entries. Every symbol entry that starts with __ksymtab_ + // indicates that the symbol in question is exported through ksymtab. We + // do not know whether this is ksymtab_gpl or ksymtab, but that is good + // enough for now. + // + // We could follow up with this entry: + // + // symbol_value -> ksymtab_entry in either ksymtab_gpl or ksymtab + // -> addr/name/namespace (in case of PREL32: offset) + // + // That way we could also detect ksymtab<>ksymtab_gpl changes or changes + // of the symbol namespace. + // + // As of now this lookup is fragile, as occasionally ksymtabs are empty + // (seen so far for kernel modules and LTO builds). Hence we stick to the + // fairly safe assumption that ksymtab exported entries are having an + // appearence as __ksymtab_ in the symtab. + const std::string name = name_str; + if (is_kernel && name.rfind("__ksymtab_", 0) == 0) + { + ABG_ASSERT(exported_kernel_symbols.insert(name.substr(10)).second); + continue; + } + if (is_kernel && name.rfind("__crc_", 0) == 0) + { + ABG_ASSERT( + crc_values.insert(std::make_pair(name.substr(6), sym->st_value)) + .second); + continue; + } + + // filter out uninteresting entries and only keep functions/variables for + // now. The rest might be interesting in the future though. + const int sym_type = GELF_ST_TYPE(sym->st_info); + if (!(sym_type == STT_FUNC + || sym_type == STT_GNU_IFUNC + // If the symbol is for an OBJECT, the index of the + // section it refers to cannot be absolute. + // Otherwise that OBJECT is not a variable. + || (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS) + || sym_type == STT_TLS)) + continue; + + const bool sym_is_defined = sym->st_shndx != SHN_UNDEF; + // this occurs in relocatable files. + const bool sym_is_common = sym->st_shndx == SHN_COMMON; + + elf_symbol::version ver; + elf_helpers::get_version_for_symbol(elf_handle, i, sym_is_defined, ver); + + const elf_symbol_sptr& symbol_sptr = elf_symbol::create( + env, i, sym->st_size, name, + elf_helpers::stt_to_elf_symbol_type(GELF_ST_TYPE(sym->st_info)), + elf_helpers::stb_to_elf_symbol_binding(GELF_ST_BIND(sym->st_info)), + sym_is_defined, sym_is_common, ver, + elf_helpers::stv_to_elf_symbol_visibility( + GELF_ST_VISIBILITY(sym->st_other)), + false); // TODO: is_linux_strings_cstr + + // We do not take suppressed symbols into our symbol vector to avoid + // accidental leakage. But we ensure supressed symbols are otherwise set + // up for lookup. + if (!(is_suppressed && is_suppressed(symbol_sptr))) + // add to the symbol vector + symbols_.push_back(symbol_sptr); + else + symbol_sptr->set_is_suppressed(true); + + // add to the name->symbol lookup + name_symbol_map_[name].push_back(symbol_sptr); + + // add to the addr->symbol lookup + if (symbol_sptr->is_common_symbol()) + { + const name_symbol_map_type::iterator it = + name_symbol_map_.find(name); + ABG_ASSERT(it != name_symbol_map_.end()); + const elf_symbols& common_sym_instances = it->second; + ABG_ASSERT(!common_sym_instances.empty()); + if (common_sym_instances.size() > 1) + { + elf_symbol_sptr main_common_sym = common_sym_instances[0]; + ABG_ASSERT(main_common_sym->get_name() == name); + ABG_ASSERT(main_common_sym->is_common_symbol()); + ABG_ASSERT(symbol_sptr.get() != main_common_sym.get()); + main_common_sym->add_common_instance(symbol_sptr); + } + } + else if (symbol_sptr->is_defined()) + { + const GElf_Addr symbol_value = + elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle, + sym); + + if (is_ppc64 && symbol_sptr->is_function()) + update_function_entry_address_symbol_map(elf_handle, sym, + symbol_sptr); + + const std::pair result = + addr_symbol_map_.insert( + std::make_pair(symbol_value, symbol_sptr)); + if (!result.second) + result.first->second->get_main_symbol()->add_alias(symbol_sptr); + } + } + + is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle); + + // Now apply the ksymtab_exported attribute to the symbols we collected. + for (abg_compat::unordered_set::const_iterator + it = exported_kernel_symbols.begin(), + en = exported_kernel_symbols.end(); + it != en; ++it) + { + const name_symbol_map_type::const_iterator r = + name_symbol_map_.find(*it); + if (r == name_symbol_map_.end()) + continue; + + for (elf_symbols::const_iterator sym_it = r->second.begin(), + sym_end = r->second.end(); + sym_it != sym_end; ++sym_it) + { + if ((*sym_it)->is_public()) + (*sym_it)->set_is_in_ksymtab(true); + } + has_ksymtab_entries_ = true; + } + + // Now add the CRC values + for (abg_compat::unordered_map::const_iterator + it = crc_values.begin(), + end = crc_values.end(); + it != end; ++it) + { + const name_symbol_map_type::const_iterator r = + name_symbol_map_.find(it->first); + if (r == name_symbol_map_.end()) + continue; + + for (elf_symbols::const_iterator sym_it = r->second.begin(), + sym_end = r->second.end(); + sym_it != sym_end; ++sym_it) + (*sym_it)->set_crc(it->second); + } + + // sort the symbols for deterministic output + std::sort(symbols_.begin(), symbols_.end(), symbol_sort); + + return true; +} + +bool +symtab::load_(string_elf_symbols_map_sptr function_symbol_map, + string_elf_symbols_map_sptr variables_symbol_map) + +{ + if (function_symbol_map) + for (string_elf_symbols_map_type::const_iterator + it = function_symbol_map->begin(), + end = function_symbol_map->end(); + it != end; ++it) + { + for (elf_symbols::const_iterator sym_it = it->second.begin(), + sym_end = it->second.end(); + sym_it != sym_end; ++sym_it) + { + if (!(*sym_it)->is_suppressed()) + symbols_.push_back(*sym_it); + } + ABG_ASSERT(name_symbol_map_.insert(*it).second); + } + + if (variables_symbol_map) + for (string_elf_symbols_map_type::const_iterator + it = variables_symbol_map->begin(), + end = variables_symbol_map->end(); + it != end; ++it) + { + for (elf_symbols::const_iterator sym_it = it->second.begin(), + sym_end = it->second.end(); + sym_it != sym_end; ++sym_it) + { + if (!(*sym_it)->is_suppressed()) + symbols_.push_back(*sym_it); + } + ABG_ASSERT(name_symbol_map_.insert(*it).second); + } + + // sort the symbols for deterministic output + std::sort(symbols_.begin(), symbols_.end(), symbol_sort); + + return true; +} + +void +symtab::update_main_symbol(GElf_Addr addr, const std::string& name) +{ + // get one symbol (i.e. the current main symbol) + elf_symbol_sptr symbol = lookup_symbol(addr); + + // The caller might not know whether the addr is associated to an ELF symbol + // that we care about. E.g. the addr could be associated to an ELF symbol, + // but not one in .dynsym when looking at a DSO. Hence, early exit if the + // lookup failed. + if (!symbol) + return; + + // determine the new main symbol by attempting an update + elf_symbol_sptr new_main = symbol->update_main_symbol(name); + + // also update the default symbol we return when looked up by address + if (new_main) + addr_symbol_map_[addr] = new_main; +} + +void +symtab::update_function_entry_address_symbol_map( + Elf* elf_handle, + GElf_Sym* native_symbol, + const elf_symbol_sptr& symbol_sptr) +{ + + // For ppc64 ELFv1 binaries, we need to build a function entry point address + // -> function symbol map. This is in addition to the function pointer -> + // symbol map. This is because on ppc64 ELFv1, a function pointer is + // different from a function entry point address. + // + // On ppc64 ELFv1, the DWARF DIE of a function references the address of the + // entry point of the function symbol; whereas the value of the function + // symbol is the function pointer. As these addresses are different, if I we + // want to get to the symbol of a function from its entry point address (as + // referenced by DWARF function DIEs) we must have the two maps I mentionned + // right above. + // + // In other words, we need a map that associates a function entry point + // address with the symbol of that function, to be able to get the function + // symbol that corresponds to a given function DIE, on ppc64. + // + // The value of the function pointer (the value of the symbol) usually refers + // to the offset of a table in the .opd section. But sometimes, for a symbol + // named "foo", the corresponding symbol named ".foo" (note the dot before + // foo) which value is the entry point address of the function; that entry + // point address refers to a region in the .text section. + // + // So we are only interested in values of the symbol that are in the .opd + // section. + const GElf_Addr fn_desc_addr = native_symbol->st_value; + const GElf_Addr fn_entry_point_addr = + elf_helpers::lookup_ppc64_elf_fn_entry_point_address(elf_handle, + fn_desc_addr); + + const std::pair& result = + entry_addr_symbol_map_.insert( + std::make_pair(fn_entry_point_addr, symbol_sptr)); + + const addr_symbol_map_type::const_iterator it = result.first; + const bool was_inserted = result.second; + if (!was_inserted + && elf_helpers::address_is_in_opd_section(elf_handle, fn_desc_addr)) + { + // Either + // + // 'symbol' must have been registered as an alias for + // it->second->get_main_symbol() + // + // Or + // + // if the name of 'symbol' is foo, then the name of it2->second is + // ".foo". That is, foo is the name of the symbol when it refers to the + // function descriptor in the .opd section and ".foo" is an internal name + // for the address of the entry point of foo. + // + // In the latter case, we just want to keep a reference to "foo" as .foo + // is an internal name. + + const bool two_symbols_alias = + it->second->get_main_symbol()->does_alias(*symbol_sptr); + const bool symbol_is_foo_and_prev_symbol_is_dot_foo = + (it->second->get_name() == std::string(".") + symbol_sptr->get_name()); + + ABG_ASSERT(two_symbols_alias + || symbol_is_foo_and_prev_symbol_is_dot_foo); + + if (symbol_is_foo_and_prev_symbol_is_dot_foo) + // Let's just keep a reference of the symbol that the user sees in the + // source code (the one named foo). The symbol which name is prefixed + // with a "dot" is an artificial one. + entry_addr_symbol_map_[fn_entry_point_addr] = symbol_sptr; + } +} + +} // end namespace symtab_reader +} // end namespace abigail diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc index dfbec879..9116a97a 100644 --- a/src/abg-tools-utils.cc +++ b/src/abg-tools-utils.cc @@ -2563,12 +2563,6 @@ build_corpus_group_from_kernel_dist_under(const string& root, << t << "\n"; - // If we have been given a whitelist of functions and - // variable symbols to look at, then we can avoid loading - // and analyzing the ELF symbol table. - bool do_ignore_symbol_table = !kabi_wl_paths.empty(); - set_ignore_symbol_table(*ctxt, do_ignore_symbol_table); - group.reset(new corpus_group(env.get(), root)); set_read_context_corpus_group(*ctxt, group); @@ -2608,13 +2602,6 @@ build_corpus_group_from_kernel_dist_under(const string& root, /*read_all_types=*/false, /*linux_kernel_mode=*/true); - // If we have been given a whitelist of functions and - // variable symbols to look at, then we can avoid loading - // and analyzing the ELF symbol table. - bool do_ignore_symbol_table = !kabi_wl_paths.empty(); - - set_ignore_symbol_table(*ctxt, do_ignore_symbol_table); - load_generate_apply_suppressions(*ctxt, suppr_paths, kabi_wl_paths, supprs); diff --git a/src/abg-writer.cc b/src/abg-writer.cc index ce0bae2d..f7a773de 100644 --- a/src/abg-writer.cc +++ b/src/abg-writer.cc @@ -26,14 +26,15 @@ /// native XML format is named "abixml". #include "config.h" +#include #include +#include #include +#include #include -#include #include -#include #include -#include +#include #include "abg-cxx-compat.h" #include "abg-tools-utils.h" @@ -1693,26 +1694,42 @@ write_elf_symbol_visibility(elf_symbol::visibility v, ostream& o) /// /// @return true upon successful completion. static bool -write_elf_symbol_aliases(const elf_symbol& sym, ostream& o) +write_elf_symbol_aliases(const elf_symbol& sym, ostream& out) { if (!sym.is_main_symbol() || !sym.has_aliases()) return false; - bool emitted = false; - o << " alias='"; - for (elf_symbol_sptr s = sym.get_next_alias(); - !s->is_main_symbol(); + + std::vector aliases; + for (elf_symbol_sptr s = sym.get_next_alias(); s && !s->is_main_symbol(); s = s->get_next_alias()) { - if (s->get_next_alias()->is_main_symbol()) - o << s->get_id_string() << "'"; - else - o << s->get_id_string() << ","; + if (s->is_suppressed()) + continue; + + if (sym.is_in_ksymtab() != s->is_in_ksymtab()) + continue; + + aliases.push_back(s->get_id_string()); + } + + if (!aliases.empty()) + { + out << " alias='"; + std::string separator; + for (std::vector::const_iterator it = aliases.begin(), + end = aliases.end(); + it != end; ++it) + { + out << separator << *it; + separator = ","; + } - emitted = true; + out << "'"; + return true; } - return emitted; + return false; } /// Write an XML attribute for the reference to a symbol for the @@ -1726,7 +1743,10 @@ write_elf_symbol_aliases(const elf_symbol& sym, ostream& o) static bool write_elf_symbol_reference(const elf_symbol& sym, ostream& o) { - o << " elf-symbol-id='" << sym.get_id_string() << "'"; + auto actual_sym = &sym; + while (actual_sym->is_suppressed() && actual_sym->has_aliases()) + actual_sym = actual_sym->get_next_alias().get(); + o << " elf-symbol-id='" << actual_sym->get_id_string() << "'"; return true; } @@ -3040,6 +3060,11 @@ write_elf_symbol(const elf_symbol_sptr& sym, if (sym->is_common_symbol()) o << " is-common='yes'"; + if (sym->get_crc() != 0) + o << " crc='" + << std::hex << std::showbase << sym->get_crc() << "'" + << std::dec << std::noshowbase; + o << "/>"; return true; diff --git a/tests/Makefile.am b/tests/Makefile.am index c2d4d1dc..06872532 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -50,6 +50,7 @@ runtestkmiwhitelist \ runtestlookupsyms \ runtestreadwrite \ runtestsymtab \ +runtestsymtabreader \ runtesttoolsutils \ $(FEDABIPKGDIFF_TEST) \ $(ZIP_ARCHIVE_TESTS) \ @@ -158,6 +159,9 @@ runtestcxxcompat_LDADD = libcatch.la $(top_builddir)/src/libabigail.la runtestsymtab_SOURCES = test-symtab.cc runtestsymtab_LDADD = libtestutils.la libcatch.la $(top_builddir)/src/libabigail.la +runtestsymtabreader_SOURCES = test-symtab-reader.cc +runtestsymtabreader_LDADD = libcatch.la $(top_builddir)/src/libabigail.la + runtestsvg_SOURCES=test-svg.cc runtestsvg_LDADD=$(top_builddir)/src/libabigail.la diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 8ccd50a0..bcfc3796 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -35,6 +35,7 @@ test-read-write/test28-without-std-fns-ref.xml \ test-read-write/test28-drop-std-vars.abignore \ test-read-write/test28-without-std-vars-ref.xml \ test-read-write/test28-without-std-vars.xml \ +test-read-write/test-crc.xml \ \ test-write-read-archive/test0.xml \ test-write-read-archive/test1.xml \ @@ -57,6 +58,7 @@ test-core-diff/report11.txt \ test-core-diff/report12.txt \ test-core-diff/report13.txt \ \ +test-abidiff/empty-report.txt \ test-abidiff/test-enum0-v0.cc.bi \ test-abidiff/test-enum0-v1.cc.bi \ test-abidiff/test-enum0-report.txt \ @@ -77,17 +79,18 @@ test-abidiff/test-var0-v1.cc.bi \ test-abidiff/test-var0-report.txt \ test-abidiff/test-PR18166-libtirpc.so \ test-abidiff/test-PR18166-libtirpc.so.abi \ -test-abidiff/test-PR18166-libtirpc.so.report.txt \ test-abidiff/test-PR18791-report0.txt \ test-abidiff/test-PR18791-v0.so.abi \ test-abidiff/test-PR18791-v1.so.abi \ -test-abidiff/test-PR24552-report0.txt \ test-abidiff/test-PR24552-v0.abi \ test-abidiff/test-PR24552-v1.abi \ test-abidiff/test-empty-corpus-0.xml \ test-abidiff/test-empty-corpus-1.xml \ test-abidiff/test-empty-corpus-2.xml \ -test-abidiff/test-empty-corpus-report.txt \ +test-abidiff/test-crc-0.xml \ +test-abidiff/test-crc-1.xml \ +test-abidiff/test-crc-2.xml \ +test-abidiff/test-crc-report.txt \ \ test-abidiff-exit/test1-voffset-change-report0.txt \ test-abidiff-exit/test1-voffset-change-report1.txt \ @@ -158,6 +161,9 @@ test-abidiff-exit/test-fun-param-v0.o \ test-abidiff-exit/test-fun-param-v1.abi \ test-abidiff-exit/test-fun-param-v1.c \ test-abidiff-exit/test-fun-param-v1.o \ +test-abidiff-exit/test-missing-alias-report.txt \ +test-abidiff-exit/test-missing-alias.abi \ +test-abidiff-exit/test-missing-alias.suppr \ \ test-diff-dwarf/test0-v0.cc \ test-diff-dwarf/test0-v0.o \ @@ -411,6 +417,14 @@ test-read-dwarf/test3.c \ test-read-dwarf/test3.so \ test-read-dwarf/test3.so.abi \ test-read-dwarf/test3.so.hash.abi \ +test-read-dwarf/test3-alias-1.so.hash.abi \ +test-read-dwarf/test3-alias-1.suppr \ +test-read-dwarf/test3-alias-2.so.hash.abi \ +test-read-dwarf/test3-alias-2.suppr \ +test-read-dwarf/test3-alias-3.so.hash.abi \ +test-read-dwarf/test3-alias-3.suppr \ +test-read-dwarf/test3-alias-4.so.hash.abi \ +test-read-dwarf/test3-alias-4.suppr \ test-read-dwarf/test4.c \ test-read-dwarf/test4.so \ test-read-dwarf/test4.so.abi \ @@ -1760,6 +1774,8 @@ test-kmi-whitelist/whitelist-with-duplicate-entry \ test-kmi-whitelist/whitelist-with-two-sections \ \ test-symtab/basic/Makefile \ +test-symtab/basic/aliases.c \ +test-symtab/basic/aliases.so \ test-symtab/basic/empty.c \ test-symtab/basic/empty.so \ test-symtab/basic/link_against_me.c \ @@ -1768,6 +1784,10 @@ test-symtab/basic/no_debug_info.c \ test-symtab/basic/no_debug_info.so \ test-symtab/basic/one_function_one_variable.c \ test-symtab/basic/one_function_one_variable.so \ +test-symtab/basic/one_function_one_variable_variable.whitelist \ +test-symtab/basic/one_function_one_variable_function.whitelist \ +test-symtab/basic/one_function_one_variable_irrelevant.whitelist \ +test-symtab/basic/one_function_one_variable_all.whitelist \ test-symtab/basic/one_function_one_variable_undefined.c \ test-symtab/basic/one_function_one_variable_undefined.so \ test-symtab/basic/single_function.c \ @@ -1837,4 +1857,7 @@ test-symtab/kernel-5.6/single_function_gpl.ko \ test-symtab/kernel-5.6/single_variable.c \ test-symtab/kernel-5.6/single_variable.ko \ test-symtab/kernel-5.6/single_variable_gpl.c \ -test-symtab/kernel-5.6/single_variable_gpl.ko +test-symtab/kernel-5.6/single_variable_gpl.ko \ +test-symtab/kernel-modversions/Makefile \ +test-symtab/kernel-modversions/one_of_each.c \ +test-symtab/kernel-modversions/one_of_each.ko diff --git a/tests/data/test-abidiff-exit/test-missing-alias-report.txt b/tests/data/test-abidiff-exit/test-missing-alias-report.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/data/test-abidiff-exit/test-missing-alias.abi b/tests/data/test-abidiff-exit/test-missing-alias.abi new file mode 100644 index 00000000..07a13f5e --- /dev/null +++ b/tests/data/test-abidiff-exit/test-missing-alias.abi @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/data/test-abidiff-exit/test-missing-alias.suppr b/tests/data/test-abidiff-exit/test-missing-alias.suppr new file mode 100644 index 00000000..bcebae43 --- /dev/null +++ b/tests/data/test-abidiff-exit/test-missing-alias.suppr @@ -0,0 +1,4 @@ +[suppress_function] + symbol_name_not_regexp = ^__foo$ + drop = true + diff --git a/tests/data/test-abidiff/test-PR18166-libtirpc.so.report.txt b/tests/data/test-abidiff/empty-report.txt similarity index 100% rename from tests/data/test-abidiff/test-PR18166-libtirpc.so.report.txt rename to tests/data/test-abidiff/empty-report.txt diff --git a/tests/data/test-abidiff/test-PR24552-report0.txt b/tests/data/test-abidiff/test-PR24552-report0.txt deleted file mode 100644 index a9d032e7..00000000 --- a/tests/data/test-abidiff/test-PR24552-report0.txt +++ /dev/null @@ -1,3 +0,0 @@ -Functions changes summary: 0 Removed, 0 Changed, 0 Added function -Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - diff --git a/tests/data/test-abidiff/test-crc-0.xml b/tests/data/test-abidiff/test-crc-0.xml new file mode 100644 index 00000000..a5cdee7a --- /dev/null +++ b/tests/data/test-abidiff/test-crc-0.xml @@ -0,0 +1,1601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-abidiff/test-crc-1.xml b/tests/data/test-abidiff/test-crc-1.xml new file mode 100644 index 00000000..9e1289ce --- /dev/null +++ b/tests/data/test-abidiff/test-crc-1.xml @@ -0,0 +1,1601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-abidiff/test-crc-2.xml b/tests/data/test-abidiff/test-crc-2.xml new file mode 100644 index 00000000..bf21ca6f --- /dev/null +++ b/tests/data/test-abidiff/test-crc-2.xml @@ -0,0 +1,1601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-abidiff/test-crc-report.txt b/tests/data/test-abidiff/test-crc-report.txt new file mode 100644 index 00000000..4572a207 --- /dev/null +++ b/tests/data/test-abidiff/test-crc-report.txt @@ -0,0 +1,9 @@ +Functions changes summary: 0 Removed, 1 Changed, 0 Added function +Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + +1 function with some indirect sub-type change: + + [C] 'function void exported_function()' has some indirect sub-type changes: + + CRC value (modversions) changed from 0xe52d5bcf to 0xe52d5bd0 + diff --git a/tests/data/test-abidiff/test-empty-corpus-report.txt b/tests/data/test-abidiff/test-empty-corpus-report.txt deleted file mode 100644 index a9d032e7..00000000 --- a/tests/data/test-abidiff/test-empty-corpus-report.txt +++ /dev/null @@ -1,3 +0,0 @@ -Functions changes summary: 0 Removed, 0 Changed, 0 Added function -Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - diff --git a/tests/data/test-annotate/test15-pr18892.so.abi b/tests/data/test-annotate/test15-pr18892.so.abi index 4e93c02d..cb593b41 100644 --- a/tests/data/test-annotate/test15-pr18892.so.abi +++ b/tests/data/test-annotate/test15-pr18892.so.abi @@ -193,7 +193,7 @@ - + @@ -207,45 +207,45 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -253,7 +253,7 @@ - + @@ -261,69 +261,69 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -341,7 +341,7 @@ - + @@ -353,19 +353,19 @@ - + - + - + - + - + @@ -373,67 +373,67 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -441,25 +441,25 @@ - + - + - + - + - + - + - + - + @@ -467,39 +467,39 @@ - + - + - + - + - + - + - + - + - + - + @@ -509,43 +509,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -555,7 +555,7 @@ - + @@ -569,21 +569,21 @@ - + - + - + - + - + @@ -591,13 +591,13 @@ - + - + - + @@ -607,9 +607,9 @@ - + - + @@ -621,19 +621,19 @@ - + - + - + - + - + @@ -641,49 +641,49 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -695,19 +695,19 @@ - + - + - + - + @@ -719,23 +719,23 @@ - + - + - + - + - + @@ -745,7 +745,7 @@ - + @@ -761,93 +761,93 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2223,11 +2223,11 @@ - + - + @@ -2407,11 +2407,11 @@ - + - + @@ -2429,13 +2429,13 @@ - + - + - + @@ -2443,7 +2443,7 @@ - + @@ -2451,7 +2451,7 @@ - + @@ -2459,69 +2459,69 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2539,7 +2539,7 @@ - + @@ -2551,19 +2551,19 @@ - + - + - + - + - + @@ -2571,67 +2571,67 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2639,25 +2639,25 @@ - + - + - + - + - + - + - + - + @@ -2665,39 +2665,39 @@ - + - + - + - + - + - + - + - + - + - + @@ -2707,43 +2707,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -2753,7 +2753,7 @@ - + @@ -2767,21 +2767,21 @@ - + - + - + - + - + @@ -2789,13 +2789,13 @@ - + - + - + @@ -2805,9 +2805,9 @@ - + - + @@ -2819,19 +2819,19 @@ - + - + - + - + - + @@ -2839,49 +2839,49 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -2893,19 +2893,19 @@ - + - + - + - + @@ -2917,23 +2917,23 @@ - + - + - + - + - + @@ -2943,7 +2943,7 @@ - + @@ -2959,73 +2959,73 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -12798,7 +12798,7 @@ - + @@ -12807,7 +12807,7 @@ - + @@ -12816,7 +12816,7 @@ - + @@ -19261,7 +19261,7 @@ - + @@ -19289,7 +19289,7 @@ - + @@ -19309,7 +19309,7 @@ - + @@ -19336,7 +19336,7 @@ - + @@ -19345,7 +19345,7 @@ - + @@ -19359,14 +19359,14 @@ - + - + @@ -19377,7 +19377,7 @@ - + @@ -19388,7 +19388,7 @@ - + @@ -19421,7 +19421,7 @@ - + @@ -19441,7 +19441,7 @@ - + @@ -19450,21 +19450,21 @@ - + - + - + @@ -19484,7 +19484,7 @@ - + @@ -19504,7 +19504,7 @@ - + @@ -19513,7 +19513,7 @@ - + @@ -19531,7 +19531,7 @@ - + @@ -19540,7 +19540,7 @@ - + @@ -19569,7 +19569,7 @@ - + @@ -19578,7 +19578,7 @@ - + @@ -19587,7 +19587,7 @@ - + @@ -19598,7 +19598,7 @@ - + @@ -19607,7 +19607,7 @@ - + @@ -19630,7 +19630,7 @@ - + @@ -19639,7 +19639,7 @@ - + @@ -19648,7 +19648,7 @@ - + @@ -19675,7 +19675,7 @@ - + @@ -19711,7 +19711,7 @@ - + @@ -19738,7 +19738,7 @@ - + @@ -19770,14 +19770,14 @@ - + - + @@ -19813,14 +19813,14 @@ - + - + @@ -19845,7 +19845,7 @@ - + @@ -19874,7 +19874,7 @@ - + @@ -19887,7 +19887,7 @@ - + @@ -19933,7 +19933,7 @@ - + @@ -19944,7 +19944,7 @@ - + @@ -19962,7 +19962,7 @@ - + @@ -19973,7 +19973,7 @@ - + @@ -19984,7 +19984,7 @@ - + @@ -20015,7 +20015,7 @@ - + @@ -20039,7 +20039,7 @@ - + @@ -20054,7 +20054,7 @@ - + @@ -20067,7 +20067,7 @@ - + @@ -20078,7 +20078,7 @@ - + @@ -20089,7 +20089,7 @@ - + @@ -20100,14 +20100,14 @@ - + - + @@ -20156,7 +20156,7 @@ - + @@ -20174,14 +20174,14 @@ - + - + @@ -20203,7 +20203,7 @@ - + @@ -20212,7 +20212,7 @@ - + @@ -20288,7 +20288,7 @@ - + @@ -20305,7 +20305,7 @@ - + @@ -20368,7 +20368,7 @@ - + @@ -20397,7 +20397,7 @@ - + @@ -20430,7 +20430,7 @@ - + @@ -20443,7 +20443,7 @@ - + @@ -20465,7 +20465,7 @@ - + @@ -20496,7 +20496,7 @@ - + @@ -20505,7 +20505,7 @@ - + @@ -20514,7 +20514,7 @@ - + @@ -20532,7 +20532,7 @@ - + @@ -20543,7 +20543,7 @@ - + @@ -20554,7 +20554,7 @@ - + @@ -20564,7 +20564,7 @@ - + @@ -20575,7 +20575,7 @@ - + @@ -20585,7 +20585,7 @@ - + @@ -20594,7 +20594,7 @@ - + @@ -20602,7 +20602,7 @@ - + @@ -20634,7 +20634,7 @@ - + @@ -20644,7 +20644,7 @@ - + @@ -20653,7 +20653,7 @@ - + @@ -20672,7 +20672,7 @@ - + @@ -20688,7 +20688,7 @@ - + @@ -20697,7 +20697,7 @@ - + @@ -20713,14 +20713,14 @@ - + - + @@ -20736,14 +20736,14 @@ - + - + @@ -20758,7 +20758,7 @@ - + @@ -20771,7 +20771,7 @@ - + @@ -20795,7 +20795,7 @@ - + @@ -20808,7 +20808,7 @@ - + @@ -20821,7 +20821,7 @@ - + @@ -20832,7 +20832,7 @@ - + @@ -20845,7 +20845,7 @@ - + @@ -20858,7 +20858,7 @@ - + @@ -20895,7 +20895,7 @@ - + @@ -20915,7 +20915,7 @@ - + @@ -20933,7 +20933,7 @@ - + @@ -20973,7 +20973,7 @@ - + @@ -21000,7 +21000,7 @@ - + @@ -21009,7 +21009,7 @@ - + @@ -21041,7 +21041,7 @@ - + @@ -21061,7 +21061,7 @@ - + @@ -21074,7 +21074,7 @@ - + @@ -21094,7 +21094,7 @@ - + @@ -21108,7 +21108,7 @@ - + @@ -21122,7 +21122,7 @@ - + @@ -21175,14 +21175,14 @@ - + - + @@ -21206,7 +21206,7 @@ - + @@ -21251,14 +21251,14 @@ - + - + @@ -21281,7 +21281,7 @@ - + @@ -21292,7 +21292,7 @@ - + @@ -21327,7 +21327,7 @@ - + @@ -21341,7 +21341,7 @@ - + @@ -21352,7 +21352,7 @@ - + @@ -21372,7 +21372,7 @@ - + @@ -21381,7 +21381,7 @@ - + @@ -21417,7 +21417,7 @@ - + @@ -21468,7 +21468,7 @@ - + @@ -21477,7 +21477,7 @@ - + @@ -21497,7 +21497,7 @@ - + @@ -21517,7 +21517,7 @@ - + @@ -21528,7 +21528,7 @@ - + @@ -21564,7 +21564,7 @@ - + @@ -21587,14 +21587,14 @@ - + - + @@ -21605,7 +21605,7 @@ - + @@ -21628,7 +21628,7 @@ - + @@ -21673,7 +21673,7 @@ - + @@ -21687,7 +21687,7 @@ - + @@ -21696,7 +21696,7 @@ - + @@ -21740,7 +21740,7 @@ - + @@ -21754,7 +21754,7 @@ - + @@ -21772,7 +21772,7 @@ - + @@ -21786,7 +21786,7 @@ - + @@ -21905,7 +21905,7 @@ - + @@ -21938,7 +21938,7 @@ - + @@ -21958,7 +21958,7 @@ - + @@ -21985,7 +21985,7 @@ - + @@ -22029,7 +22029,7 @@ - + @@ -22122,14 +22122,14 @@ - + - + @@ -22143,7 +22143,7 @@ - + @@ -22152,7 +22152,7 @@ - + @@ -22170,14 +22170,14 @@ - + - + @@ -22195,7 +22195,7 @@ - + @@ -22204,7 +22204,7 @@ - + @@ -22247,7 +22247,7 @@ - + @@ -22263,7 +22263,7 @@ - + @@ -26271,7 +26271,7 @@ - + @@ -26289,7 +26289,7 @@ - + diff --git a/tests/data/test-annotate/test17-pr19027.so.abi b/tests/data/test-annotate/test17-pr19027.so.abi index 4937e36e..42d5f812 100644 --- a/tests/data/test-annotate/test17-pr19027.so.abi +++ b/tests/data/test-annotate/test17-pr19027.so.abi @@ -36663,7 +36663,7 @@ - + @@ -36785,7 +36785,7 @@ - + @@ -36802,7 +36802,7 @@ - + diff --git a/tests/data/test-annotate/test18-pr19037-libvtkRenderingLIC-6.1.so.abi b/tests/data/test-annotate/test18-pr19037-libvtkRenderingLIC-6.1.so.abi index 0f42c9cc..d5ab3e3d 100644 --- a/tests/data/test-annotate/test18-pr19037-libvtkRenderingLIC-6.1.so.abi +++ b/tests/data/test-annotate/test18-pr19037-libvtkRenderingLIC-6.1.so.abi @@ -5095,11 +5095,11 @@ - + - + @@ -8298,7 +8298,7 @@ - + diff --git a/tests/data/test-annotate/test19-pr19023-libtcmalloc_and_profiler.so.abi b/tests/data/test-annotate/test19-pr19023-libtcmalloc_and_profiler.so.abi index 5b1f7134..c2c23376 100644 --- a/tests/data/test-annotate/test19-pr19023-libtcmalloc_and_profiler.so.abi +++ b/tests/data/test-annotate/test19-pr19023-libtcmalloc_and_profiler.so.abi @@ -1098,15 +1098,15 @@ - + - + - + - + @@ -1124,11 +1124,11 @@ - + - + @@ -1138,19 +1138,19 @@ - + - + - + @@ -1164,7 +1164,7 @@ - + @@ -1174,23 +1174,23 @@ - + - + - + - + - + - + @@ -1204,19 +1204,19 @@ - + - + - + - + @@ -41638,7 +41638,7 @@ - + @@ -41655,7 +41655,7 @@ - + @@ -41666,14 +41666,14 @@ - + - + @@ -41698,7 +41698,7 @@ - + @@ -41721,7 +41721,7 @@ - + @@ -41751,14 +41751,14 @@ - + - + @@ -41774,14 +41774,14 @@ - + - + diff --git a/tests/data/test-annotate/test2.so.abi b/tests/data/test-annotate/test2.so.abi index cc40ccd0..072834a1 100644 --- a/tests/data/test-annotate/test2.so.abi +++ b/tests/data/test-annotate/test2.so.abi @@ -7,13 +7,13 @@ - + - + - + - + @@ -55,7 +55,7 @@ - + @@ -96,7 +96,7 @@ - + diff --git a/tests/data/test-annotate/test20-pr19025-libvtkParallelCore-6.1.so.abi b/tests/data/test-annotate/test20-pr19025-libvtkParallelCore-6.1.so.abi index 14178e8d..dc009c8a 100644 --- a/tests/data/test-annotate/test20-pr19025-libvtkParallelCore-6.1.so.abi +++ b/tests/data/test-annotate/test20-pr19025-libvtkParallelCore-6.1.so.abi @@ -6555,7 +6555,7 @@ - + @@ -7693,11 +7693,11 @@ - + - + diff --git a/tests/data/test-annotate/test3.so.abi b/tests/data/test-annotate/test3.so.abi index cbcb456d..ca379074 100644 --- a/tests/data/test-annotate/test3.so.abi +++ b/tests/data/test-annotate/test3.so.abi @@ -4,7 +4,7 @@ - + @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/tests/data/test-diff-dwarf/test12-report.txt b/tests/data/test-diff-dwarf/test12-report.txt index e69de29b..62dd8337 100644 --- a/tests/data/test-diff-dwarf/test12-report.txt +++ b/tests/data/test-diff-dwarf/test12-report.txt @@ -0,0 +1,7 @@ +Functions changes summary: 0 Removed, 0 Changed, 1 Added function +Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + +1 Added function: + + [A] 'function int _foo3(int, int)' + diff --git a/tests/data/test-diff-dwarf/test42-PR21296-clanggcc-report0.txt b/tests/data/test-diff-dwarf/test42-PR21296-clanggcc-report0.txt index 087cfd4e..47250ac7 100644 --- a/tests/data/test-diff-dwarf/test42-PR21296-clanggcc-report0.txt +++ b/tests/data/test-diff-dwarf/test42-PR21296-clanggcc-report0.txt @@ -9,9 +9,7 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable [C] 'method STR::~STR(int)' has some indirect sub-type changes: linkage names of method STR::~STR(int) - changed from '_ZN3STRD1Ev, _ZN3STRD2Ev' to '_ZN3STRD2Ev' - - name of symbol changed from _ZN3STRD1Ev to _ZN3STRD2Ev + changed from '_ZN3STRD2Ev, _ZN3STRD1Ev' to '_ZN3STRD2Ev' parameter 1 of type 'int' was removed [C] 'function std::tuple my_forward_as_tuple(STR&&)' has some indirect sub-type changes: diff --git a/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt b/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt index 62785044..00e19379 100644 --- a/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt +++ b/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt @@ -266,20 +266,18 @@ ================ end of changes of 'libtbbmalloc.so.2'=============== ================ changes of 'libtbbmalloc_proxy.so.2'=============== - Functions changes summary: 1 Removed, 0 Changed, 5 Added functions + Functions changes summary: 1 Removed, 0 Changed, 3 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable 1 Removed function: [D] 'function bool __TBB_internal_find_original_malloc(int, const char**, void**)' {__TBB_internal_find_original_malloc} - 5 Added functions: + 3 Added functions: [A] 'function void __libc_free(void*)' {__libc_free} [A] 'function void* __libc_realloc(void*, size_t)' {__libc_realloc} - [A] 'function void* calloc(size_t, size_t)' {__libc_calloc, aliases calloc} [A] 'function size_t malloc_usable_size(void*)' {malloc_usable_size} - [A] 'function void* valloc(size_t)' {__libc_valloc, aliases valloc} ================ end of changes of 'libtbbmalloc_proxy.so.2'=============== diff --git a/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-1.txt b/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-1.txt index bef715b6..b201cb46 100644 --- a/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-1.txt +++ b/tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-1.txt @@ -140,20 +140,18 @@ ================ end of changes of 'libtbbmalloc.so.2'=============== ================ changes of 'libtbbmalloc_proxy.so.2'=============== - Functions changes summary: 1 Removed, 0 Changed, 5 Added functions + Functions changes summary: 1 Removed, 0 Changed, 3 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable 1 Removed function: [D] 'function bool __TBB_internal_find_original_malloc(int, const char**, void**)' {__TBB_internal_find_original_malloc} - 5 Added functions: + 3 Added functions: [A] 'function void __libc_free(void*)' {__libc_free} [A] 'function void* __libc_realloc(void*, size_t)' {__libc_realloc} - [A] 'function void* calloc(size_t, size_t)' {__libc_calloc, aliases calloc} [A] 'function size_t malloc_usable_size(void*)' {malloc_usable_size} - [A] 'function void* valloc(size_t)' {__libc_valloc, aliases valloc} ================ end of changes of 'libtbbmalloc_proxy.so.2'=============== diff --git a/tests/data/test-diff-suppr/test23-alias-filter-4.suppr b/tests/data/test-diff-suppr/test23-alias-filter-4.suppr index 2a7e5893..16edb095 100644 --- a/tests/data/test-diff-suppr/test23-alias-filter-4.suppr +++ b/tests/data/test-diff-suppr/test23-alias-filter-4.suppr @@ -1,3 +1,3 @@ [suppress_function] - symbol_name_regexp = function1 - allow_other_aliases = no \ No newline at end of file + symbol_name_regexp = __private_function + allow_other_aliases = no diff --git a/tests/data/test-diff-suppr/test23-alias-filter-report-0.txt b/tests/data/test-diff-suppr/test23-alias-filter-report-0.txt index 0788d489..8b06f315 100644 --- a/tests/data/test-diff-suppr/test23-alias-filter-report-0.txt +++ b/tests/data/test-diff-suppr/test23-alias-filter-report-0.txt @@ -4,8 +4,8 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable 1 function with some indirect sub-type change: [C] 'function void __private_function(S*)' has some indirect sub-type changes: - Please note that the symbol of this function is function1@VERSION_1.0 - and it aliases symbols: __private_function@PRIVATE_1.0, function2@VERSION_1.0 + Please note that the symbol of this function is __private_function@PRIVATE_1.0 + and it aliases symbols: function2@VERSION_1.0, function1@VERSION_1.0 parameter 1 of type 'S*' has sub-type changes: in pointed to type 'typedef S': underlying type 'struct S' changed: diff --git a/tests/data/test-diff-suppr/test23-alias-filter-report-2.txt b/tests/data/test-diff-suppr/test23-alias-filter-report-2.txt index 0788d489..8b06f315 100644 --- a/tests/data/test-diff-suppr/test23-alias-filter-report-2.txt +++ b/tests/data/test-diff-suppr/test23-alias-filter-report-2.txt @@ -4,8 +4,8 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable 1 function with some indirect sub-type change: [C] 'function void __private_function(S*)' has some indirect sub-type changes: - Please note that the symbol of this function is function1@VERSION_1.0 - and it aliases symbols: __private_function@PRIVATE_1.0, function2@VERSION_1.0 + Please note that the symbol of this function is __private_function@PRIVATE_1.0 + and it aliases symbols: function2@VERSION_1.0, function1@VERSION_1.0 parameter 1 of type 'S*' has sub-type changes: in pointed to type 'typedef S': underlying type 'struct S' changed: diff --git a/tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi b/tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi index e7cd4c9a..60086b1e 100644 --- a/tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi +++ b/tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi @@ -36,13 +36,13 @@ - - + + - - + + @@ -50,31 +50,31 @@ - + - + - - + + - - + + - + - + @@ -90,8 +90,8 @@ - - + + @@ -100,8 +100,8 @@ - - + + @@ -532,7 +532,7 @@ - + @@ -665,13 +665,13 @@ - + - + @@ -816,7 +816,7 @@ - + @@ -884,7 +884,7 @@ - + @@ -908,7 +908,7 @@ - + @@ -1685,7 +1685,7 @@ - + @@ -1849,7 +1849,7 @@ - + diff --git a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi index 28df268d..e5b2fbba 100644 --- a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi +++ b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi @@ -151,8 +151,8 @@ - - + + @@ -7133,7 +7133,7 @@ - + diff --git a/tests/data/test-read-dwarf/PR25007-sdhci.ko.abi b/tests/data/test-read-dwarf/PR25007-sdhci.ko.abi index 755ea6dc..d3c0f74c 100644 --- a/tests/data/test-read-dwarf/PR25007-sdhci.ko.abi +++ b/tests/data/test-read-dwarf/PR25007-sdhci.ko.abi @@ -1,47 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - diff --git a/tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi b/tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi index bc8d8ae2..d3ac0757 100644 --- a/tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi +++ b/tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi @@ -36,8 +36,8 @@ - - + + @@ -45,24 +45,24 @@ - + - + - - + + - - - - - - + + + + + + @@ -88,16 +88,16 @@ - - + + - + - - + + - + @@ -109,10 +109,10 @@ - - - - + + + + @@ -167,30 +167,30 @@ - + - + - + - + - - + + - - + + - - + + @@ -213,27 +213,27 @@ - - + + - - + + - - + + - - + + - - + + @@ -254,24 +254,24 @@ - - - - + + + + - + - + - - + + - - + + @@ -282,8 +282,8 @@ - - + + @@ -362,9 +362,9 @@ - + - + @@ -2205,7 +2205,7 @@ - + @@ -2728,7 +2728,7 @@ - + @@ -3029,7 +3029,7 @@ - + @@ -3113,7 +3113,7 @@ - + @@ -3283,13 +3283,13 @@ - + - + @@ -3297,7 +3297,7 @@ - + @@ -3305,7 +3305,7 @@ - + @@ -6260,13 +6260,13 @@ - + - + @@ -6280,7 +6280,7 @@ - + @@ -6351,7 +6351,7 @@ - + @@ -6640,7 +6640,7 @@ - + @@ -6808,7 +6808,7 @@ - + @@ -6991,7 +6991,7 @@ - + @@ -7549,20 +7549,20 @@ - + - + - + @@ -7591,20 +7591,20 @@ - + - + - + @@ -7627,7 +7627,7 @@ - + @@ -7968,13 +7968,13 @@ - + - + @@ -8059,20 +8059,20 @@ - + - + - + @@ -8247,7 +8247,7 @@ - + @@ -8288,7 +8288,7 @@ - + @@ -8470,7 +8470,7 @@ - + @@ -8479,7 +8479,7 @@ - + @@ -8530,35 +8530,35 @@ - + - + - + - + - + @@ -8813,7 +8813,7 @@ - + @@ -8971,7 +8971,7 @@ - + @@ -8985,7 +8985,7 @@ - + @@ -9936,7 +9936,7 @@ - + diff --git a/tests/data/test-read-dwarf/test11-pr18828.so.abi b/tests/data/test-read-dwarf/test11-pr18828.so.abi index 6789be55..f3c07f9b 100644 --- a/tests/data/test-read-dwarf/test11-pr18828.so.abi +++ b/tests/data/test-read-dwarf/test11-pr18828.so.abi @@ -40,24 +40,24 @@ - - - - + + + + - + - - + + - + - - + + @@ -71,22 +71,22 @@ - - - - + + + + - - - - + + + + - - - - + + + + @@ -97,16 +97,16 @@ - - - - + + + + - - + + @@ -115,8 +115,8 @@ - - + + @@ -130,11 +130,11 @@ - - + + - - + + @@ -145,20 +145,20 @@ - - + + - - + + - - + + - - + + @@ -171,8 +171,8 @@ - - + + @@ -183,11 +183,11 @@ - + - - - + + + @@ -205,8 +205,8 @@ - - + + @@ -232,44 +232,44 @@ - - - - - - - - + + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - + + - - + + @@ -326,25 +326,25 @@ - + - - - + + + - - - - - - - - - - + + + + + + + + + + @@ -352,30 +352,30 @@ - - + + - - - - - - + + + + + + - - - - + + + + @@ -383,12 +383,12 @@ - - - - - - + + + + + + @@ -398,31 +398,31 @@ - - - - + + + + - - - - - - + + + + + + - - - - + + + + - - + + @@ -431,34 +431,34 @@ - - - - - - + + + + + + - - + + - - + + - - + + - - + + @@ -469,12 +469,12 @@ - - + + - - + + @@ -494,20 +494,20 @@ - - - - - - + + + + + + - - + + - - + + @@ -518,33 +518,33 @@ - - - - - - + + + + + + - - - - - - - - + + + + + + + + - - - - + + + + @@ -568,12 +568,12 @@ - + - + - - + + @@ -7054,7 +7054,7 @@ - + @@ -7089,7 +7089,7 @@ - + @@ -7188,14 +7188,14 @@ - + - + @@ -7840,7 +7840,7 @@ - + @@ -7939,14 +7939,14 @@ - + - + @@ -7975,14 +7975,14 @@ - + - + @@ -8538,20 +8538,20 @@ - + - + - + @@ -8600,13 +8600,13 @@ - + - + @@ -8727,20 +8727,20 @@ - + - + - + @@ -8800,7 +8800,7 @@ - + @@ -8814,7 +8814,7 @@ - + @@ -8967,7 +8967,7 @@ - + @@ -8975,7 +8975,7 @@ - + @@ -8990,7 +8990,7 @@ - + @@ -9500,7 +9500,7 @@ - + @@ -9549,7 +9549,7 @@ - + @@ -10200,14 +10200,14 @@ - + - + @@ -10248,14 +10248,14 @@ - + - + @@ -10708,7 +10708,7 @@ - + @@ -11458,7 +11458,7 @@ - + @@ -11621,7 +11621,7 @@ - + @@ -11672,7 +11672,7 @@ - + @@ -11837,7 +11837,7 @@ - + @@ -16506,7 +16506,7 @@ - + @@ -20088,7 +20088,7 @@ - + @@ -20155,7 +20155,7 @@ - + @@ -20443,11 +20443,11 @@ - + - + @@ -20507,7 +20507,7 @@ - + @@ -20771,7 +20771,7 @@ - + @@ -20841,7 +20841,7 @@ - + @@ -20934,7 +20934,7 @@ - + @@ -21067,7 +21067,7 @@ - + @@ -21109,7 +21109,7 @@ - + @@ -21267,7 +21267,7 @@ - + @@ -21280,7 +21280,7 @@ - + @@ -21463,13 +21463,13 @@ - + - + @@ -23168,7 +23168,7 @@ - + @@ -25095,7 +25095,7 @@ - + @@ -25220,7 +25220,7 @@ - + @@ -25764,14 +25764,14 @@ - + - + @@ -25940,14 +25940,14 @@ - + - + @@ -26031,7 +26031,7 @@ - + @@ -26046,21 +26046,21 @@ - + - + - + @@ -26309,14 +26309,14 @@ - + - + @@ -30237,13 +30237,13 @@ - + - + @@ -30454,14 +30454,14 @@ - + - + @@ -30848,7 +30848,7 @@ - + @@ -31418,7 +31418,7 @@ - + @@ -31605,7 +31605,7 @@ - + @@ -31854,14 +31854,14 @@ - + - + @@ -33194,7 +33194,7 @@ - + @@ -33225,7 +33225,7 @@ - + @@ -34445,14 +34445,14 @@ - + - + @@ -34854,7 +34854,7 @@ - + @@ -34894,7 +34894,7 @@ - + @@ -34953,7 +34953,7 @@ - + @@ -34975,7 +34975,7 @@ - + @@ -35035,7 +35035,7 @@ - + @@ -35050,7 +35050,7 @@ - + @@ -35201,7 +35201,7 @@ - + @@ -35226,7 +35226,7 @@ - + @@ -35293,7 +35293,7 @@ - + @@ -35318,7 +35318,7 @@ - + @@ -36146,13 +36146,13 @@ - + - + diff --git a/tests/data/test-read-dwarf/test12-pr18844.so.abi b/tests/data/test-read-dwarf/test12-pr18844.so.abi index e5bf9c0c..57e1da3f 100644 --- a/tests/data/test-read-dwarf/test12-pr18844.so.abi +++ b/tests/data/test-read-dwarf/test12-pr18844.so.abi @@ -231,47 +231,47 @@ - - + + - - + + - - + + - - - + + + - + - - + + - - + + - - - - + + + + - - + + @@ -27045,7 +27045,7 @@ - + @@ -27072,7 +27072,7 @@ - + @@ -27086,7 +27086,7 @@ - + @@ -27139,7 +27139,7 @@ - + @@ -27149,7 +27149,7 @@ - + @@ -27243,7 +27243,7 @@ - + @@ -27376,7 +27376,7 @@ - + @@ -36822,7 +36822,7 @@ - + @@ -40693,14 +40693,14 @@ - + - + diff --git a/tests/data/test-read-dwarf/test15-pr18892.so.abi b/tests/data/test-read-dwarf/test15-pr18892.so.abi index 6dc28371..c7e5f575 100644 --- a/tests/data/test-read-dwarf/test15-pr18892.so.abi +++ b/tests/data/test-read-dwarf/test15-pr18892.so.abi @@ -101,72 +101,72 @@ - + - + - - - - - - + + + + + + - - + + - + - - + + - + - + - - - - + + + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -175,209 +175,209 @@ - + - + - - - + + + - + - - + + - + - - + + - - + + - - + + - - + + - + - - + + - - + + - + - - + + - - - - - - + + + + + + - - + + - - - + + + - - - + + + - + - + - + - - + + - - - - - + + + + + - - - + + + - + - + - + - - + + - + - + - + - - + + - - + + - - - - + + + + - + - - - - - + + + + + - - - - + + + + - - - + + + - + - + - + - + - + - - + + - - + + - + - - + + - + @@ -385,50 +385,50 @@ - + - + - + - + - - - + + + - - - + + + - - - + + + - - + + - - - + + + - + - + - - - - - - + + + + + + - - + + @@ -1116,9 +1116,9 @@ - + - + @@ -1208,9 +1208,9 @@ - + - + @@ -1219,53 +1219,53 @@ - + - - + + - + - + - - - - + + + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -1274,209 +1274,209 @@ - + - + - - - + + + - + - - + + - + - - + + - - + + - - + + - - + + - + - - + + - - + + - + - - + + - - - - - - + + + + + + - - + + - - - + + + - - - + + + - + - + - + - - + + - - - - - + + + + + - - - + + + - + - + - + - - + + - + - + - + - - + + - - + + - - - - + + + + - + - - - - - + + + + + - - - - + + + + - - - + + + - + - + - + - + - + - - + + - - + + - + - - + + - + @@ -1484,40 +1484,40 @@ - + - + - + - + - - - + + + - - - + + + - - - + + + - - + + - - - + + + - + - + @@ -7414,17 +7414,17 @@ - + - + - + @@ -10937,7 +10937,7 @@ - + @@ -10952,7 +10952,7 @@ - + @@ -10963,7 +10963,7 @@ - + @@ -10978,12 +10978,12 @@ - + - + @@ -10991,23 +10991,23 @@ - + - + - + - + @@ -11025,7 +11025,7 @@ - + @@ -11036,20 +11036,20 @@ - + - + - + - + @@ -11060,7 +11060,7 @@ - + @@ -11071,12 +11071,12 @@ - + - + @@ -11086,12 +11086,12 @@ - + - + @@ -11107,28 +11107,28 @@ - + - + - + - + - + @@ -11141,17 +11141,17 @@ - + - + - + @@ -11166,7 +11166,7 @@ - + @@ -11186,7 +11186,7 @@ - + @@ -11201,7 +11201,7 @@ - + @@ -11219,11 +11219,11 @@ - + - + @@ -11243,11 +11243,11 @@ - + - + @@ -11261,7 +11261,7 @@ - + @@ -11277,14 +11277,14 @@ - + - + @@ -11309,13 +11309,13 @@ - + - + @@ -11325,19 +11325,19 @@ - + - + - + @@ -11354,7 +11354,7 @@ - + @@ -11367,7 +11367,7 @@ - + @@ -11375,36 +11375,36 @@ - + - + - + - + - + - + @@ -11431,7 +11431,7 @@ - + @@ -11441,11 +11441,11 @@ - + - + @@ -11457,12 +11457,12 @@ - + - + @@ -11503,7 +11503,7 @@ - + @@ -11512,7 +11512,7 @@ - + @@ -11546,7 +11546,7 @@ - + @@ -11562,7 +11562,7 @@ - + @@ -11580,14 +11580,14 @@ - + - + @@ -11599,7 +11599,7 @@ - + @@ -11616,17 +11616,17 @@ - + - + - + @@ -11636,47 +11636,47 @@ - + - + - + - + - + - + - + - + @@ -11694,18 +11694,18 @@ - + - + - + @@ -11716,7 +11716,7 @@ - + @@ -11725,12 +11725,12 @@ - + - + @@ -11739,11 +11739,11 @@ - + - + @@ -11752,11 +11752,11 @@ - + - + @@ -11764,14 +11764,14 @@ - + - + @@ -11784,41 +11784,41 @@ - + - + - + - + - + - + @@ -11838,7 +11838,7 @@ - + @@ -11849,7 +11849,7 @@ - + @@ -11859,7 +11859,7 @@ - + @@ -11881,7 +11881,7 @@ - + @@ -11896,12 +11896,12 @@ - + - + @@ -11919,7 +11919,7 @@ - + @@ -11930,14 +11930,14 @@ - + - + @@ -11948,7 +11948,7 @@ - + @@ -11956,7 +11956,7 @@ - + @@ -11964,7 +11964,7 @@ - + @@ -11993,11 +11993,11 @@ - + - + @@ -12010,7 +12010,7 @@ - + @@ -12035,11 +12035,11 @@ - + - + @@ -12052,13 +12052,13 @@ - + - + @@ -12077,7 +12077,7 @@ - + @@ -12085,13 +12085,13 @@ - + - + @@ -12102,12 +12102,12 @@ - + - + @@ -12127,7 +12127,7 @@ - + @@ -12155,12 +12155,12 @@ - + - + @@ -12171,7 +12171,7 @@ - + @@ -12182,13 +12182,13 @@ - + - + @@ -12208,7 +12208,7 @@ - + @@ -12221,17 +12221,17 @@ - + - + - + @@ -12244,7 +12244,7 @@ - + @@ -12269,7 +12269,7 @@ - + @@ -12277,12 +12277,12 @@ - + - + @@ -12307,7 +12307,7 @@ - + @@ -12315,7 +12315,7 @@ - + @@ -12325,7 +12325,7 @@ - + @@ -12333,7 +12333,7 @@ - + @@ -12399,7 +12399,7 @@ - + @@ -12417,7 +12417,7 @@ - + @@ -12428,7 +12428,7 @@ - + @@ -12443,7 +12443,7 @@ - + @@ -12467,7 +12467,7 @@ - + @@ -12519,11 +12519,11 @@ - + - + @@ -12531,12 +12531,12 @@ - + - + @@ -12546,11 +12546,11 @@ - + - + @@ -12560,12 +12560,12 @@ - + - + @@ -12589,7 +12589,7 @@ - + @@ -12598,7 +12598,7 @@ - + @@ -14768,7 +14768,7 @@ - + @@ -14778,7 +14778,7 @@ - + diff --git a/tests/data/test-read-dwarf/test16-pr18904.so.abi b/tests/data/test-read-dwarf/test16-pr18904.so.abi index 8706ed60..49262964 100644 --- a/tests/data/test-read-dwarf/test16-pr18904.so.abi +++ b/tests/data/test-read-dwarf/test16-pr18904.so.abi @@ -41,16 +41,16 @@ - - - - + + + + - - - - + + + + @@ -58,8 +58,8 @@ - - + + @@ -67,16 +67,16 @@ - - + + - - + + @@ -95,11 +95,11 @@ - - + + - - + + @@ -123,10 +123,10 @@ - - - - + + + + @@ -156,10 +156,10 @@ - - - - + + + + @@ -180,18 +180,18 @@ - - - - + + + + - - + + @@ -199,14 +199,14 @@ - + - + - - + + @@ -215,20 +215,20 @@ - - + + - - + + - - + + @@ -242,30 +242,30 @@ - + - + - - + + - - + + - + - + - - + + @@ -273,35 +273,35 @@ - - - - + + + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + @@ -316,8 +316,8 @@ - - + + @@ -329,30 +329,30 @@ - - + + - - - - + + + + - + - + - - + + @@ -386,20 +386,20 @@ - - - - + + + + - - + + - - + + @@ -584,57 +584,57 @@ - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - + + - - - - - - + + + + + + - - + + @@ -647,7 +647,7 @@ - + @@ -655,17 +655,17 @@ - + - + - + @@ -687,10 +687,10 @@ - - - - + + + + @@ -706,17 +706,17 @@ - - - - + + + + - - + + - - + + @@ -725,73 +725,73 @@ - - + + - - + + - - + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + @@ -819,28 +819,28 @@ - - + + - - + + - - + + - - + + - - + + @@ -859,20 +859,20 @@ - + - + - + - + - - + + @@ -881,8 +881,8 @@ - - + + @@ -892,40 +892,40 @@ - - + + - + - + - + - + - + - + - - + + - - + + @@ -934,18 +934,18 @@ - - - - + + + + - - + + @@ -956,63 +956,63 @@ - + - + - + - + - + - + - + - + - + - - - + + + - - - - - - - - - + + + + + + + + + - - + + - - + + - - - + + + @@ -1025,13 +1025,13 @@ - - - - + + + + - - + + @@ -1040,10 +1040,10 @@ - - - - + + + + @@ -1056,8 +1056,8 @@ - - + + @@ -1069,8 +1069,8 @@ - - + + @@ -1100,10 +1100,10 @@ - - - - + + + + @@ -1119,8 +1119,8 @@ - - + + @@ -1134,8 +1134,8 @@ - - + + @@ -1145,45 +1145,45 @@ - - + + - - + + - - + + - + - + - + - + - - + + - - + + @@ -1194,8 +1194,8 @@ - - + + @@ -1207,8 +1207,8 @@ - - + + @@ -1218,23 +1218,23 @@ - - + + - - + + - - + + - - + + @@ -1255,8 +1255,8 @@ - - + + @@ -1281,13 +1281,13 @@ - - - - + + + + - - + + @@ -1296,8 +1296,8 @@ - - + + @@ -1341,16 +1341,16 @@ - - + + - - + + @@ -1371,8 +1371,8 @@ - - + + @@ -1382,16 +1382,16 @@ - + - + - - - - + + + + @@ -1400,8 +1400,8 @@ - - + + @@ -1423,11 +1423,11 @@ - + - - - + + + @@ -1479,9 +1479,9 @@ - + - + @@ -1525,12 +1525,12 @@ - + - - + + - + @@ -2577,14 +2577,14 @@ - + - + @@ -2656,7 +2656,7 @@ - + @@ -2735,14 +2735,14 @@ - + - + @@ -2750,14 +2750,14 @@ - + - + @@ -2880,7 +2880,7 @@ - + @@ -2984,7 +2984,7 @@ - + @@ -3035,7 +3035,7 @@ - + @@ -3436,7 +3436,7 @@ - + @@ -3454,7 +3454,7 @@ - + @@ -4853,7 +4853,7 @@ - + @@ -5720,13 +5720,13 @@ - + - + @@ -6265,7 +6265,7 @@ - + @@ -6798,14 +6798,14 @@ - + - + @@ -6852,7 +6852,7 @@ - + @@ -6996,7 +6996,7 @@ - + @@ -7521,7 +7521,7 @@ - + @@ -7543,7 +7543,7 @@ - + @@ -7551,7 +7551,7 @@ - + @@ -7728,7 +7728,7 @@ - + @@ -8259,7 +8259,7 @@ - + @@ -8616,7 +8616,7 @@ - + @@ -8624,7 +8624,7 @@ - + @@ -8679,14 +8679,14 @@ - + - + @@ -8981,14 +8981,14 @@ - + - + @@ -9331,7 +9331,7 @@ - + @@ -9488,7 +9488,7 @@ - + @@ -9707,7 +9707,7 @@ - + @@ -9840,14 +9840,14 @@ - + - + @@ -10003,7 +10003,7 @@ - + @@ -10223,7 +10223,7 @@ - + @@ -10247,7 +10247,7 @@ - + @@ -10365,14 +10365,14 @@ - + - + @@ -10736,7 +10736,7 @@ - + @@ -11486,7 +11486,7 @@ - + @@ -11510,13 +11510,13 @@ - + - + @@ -11554,7 +11554,7 @@ - + @@ -11852,14 +11852,14 @@ - + - + @@ -11973,7 +11973,7 @@ - + @@ -11987,7 +11987,7 @@ - + @@ -12055,7 +12055,7 @@ - + @@ -12127,7 +12127,7 @@ - + @@ -12135,7 +12135,7 @@ - + @@ -12151,7 +12151,7 @@ - + @@ -12218,7 +12218,7 @@ - + @@ -12330,7 +12330,7 @@ - + @@ -12338,7 +12338,7 @@ - + @@ -12750,7 +12750,7 @@ - + @@ -13466,7 +13466,7 @@ - + @@ -13475,7 +13475,7 @@ - + @@ -13529,7 +13529,7 @@ - + @@ -13626,7 +13626,7 @@ - + @@ -13975,7 +13975,7 @@ - + @@ -14392,19 +14392,19 @@ - + - + - + @@ -14433,7 +14433,7 @@ - + @@ -14501,7 +14501,7 @@ - + @@ -15154,13 +15154,13 @@ - + - + @@ -15175,7 +15175,7 @@ - + @@ -15209,7 +15209,7 @@ - + @@ -15218,7 +15218,7 @@ - + @@ -15228,7 +15228,7 @@ - + @@ -15241,7 +15241,7 @@ - + @@ -15279,33 +15279,33 @@ - + - + - + - + - + @@ -15396,7 +15396,7 @@ - + @@ -16172,14 +16172,14 @@ - + - + @@ -16401,7 +16401,7 @@ - + @@ -16747,7 +16747,7 @@ - + @@ -16853,7 +16853,7 @@ - + @@ -17244,7 +17244,7 @@ - + @@ -17300,7 +17300,7 @@ - + @@ -18388,7 +18388,7 @@ - + @@ -18455,7 +18455,7 @@ - + @@ -18567,7 +18567,7 @@ - + @@ -18699,7 +18699,7 @@ - + @@ -18712,7 +18712,7 @@ - + @@ -18847,7 +18847,7 @@ - + @@ -18860,7 +18860,7 @@ - + @@ -19378,7 +19378,7 @@ - + @@ -19399,7 +19399,7 @@ - + @@ -19729,7 +19729,7 @@ - + @@ -19737,7 +19737,7 @@ - + @@ -20058,7 +20058,7 @@ - + @@ -20351,7 +20351,7 @@ - + @@ -20361,7 +20361,7 @@ - + @@ -20639,14 +20639,14 @@ - + - + @@ -20677,7 +20677,7 @@ - + @@ -20951,13 +20951,13 @@ - + - + @@ -21285,7 +21285,7 @@ - + @@ -21710,7 +21710,7 @@ - + @@ -21724,7 +21724,7 @@ - + @@ -21738,7 +21738,7 @@ - + @@ -21807,7 +21807,7 @@ - + @@ -22362,7 +22362,7 @@ - + @@ -22972,7 +22972,7 @@ - + @@ -22980,7 +22980,7 @@ - + @@ -23193,14 +23193,14 @@ - + - + @@ -23265,7 +23265,7 @@ - + @@ -23834,7 +23834,7 @@ - + @@ -23868,7 +23868,7 @@ - + @@ -24105,7 +24105,7 @@ - + @@ -24113,7 +24113,7 @@ - + @@ -24306,7 +24306,7 @@ - + @@ -24374,7 +24374,7 @@ - + @@ -24490,7 +24490,7 @@ - + @@ -24797,14 +24797,14 @@ - + - + @@ -24909,7 +24909,7 @@ - + @@ -26938,7 +26938,7 @@ - + @@ -27080,7 +27080,7 @@ - + @@ -27611,14 +27611,14 @@ - + - + @@ -27671,7 +27671,7 @@ - + @@ -28818,7 +28818,7 @@ - + @@ -28939,7 +28939,7 @@ - + @@ -28947,7 +28947,7 @@ - + @@ -29062,7 +29062,7 @@ - + @@ -30401,14 +30401,14 @@ - + - + @@ -30627,14 +30627,14 @@ - + - + @@ -30704,7 +30704,7 @@ - + @@ -30770,7 +30770,7 @@ - + @@ -30850,14 +30850,14 @@ - + - + @@ -30934,7 +30934,7 @@ - + @@ -31000,7 +31000,7 @@ - + @@ -31192,7 +31192,7 @@ - + @@ -31202,7 +31202,7 @@ - + @@ -31297,7 +31297,7 @@ - + @@ -31472,7 +31472,7 @@ - + @@ -31544,7 +31544,7 @@ - + @@ -31717,7 +31717,7 @@ - + @@ -31978,7 +31978,7 @@ - + @@ -31986,7 +31986,7 @@ - + @@ -32436,7 +32436,7 @@ - + @@ -32732,7 +32732,7 @@ - + @@ -33369,7 +33369,7 @@ - + @@ -33561,14 +33561,14 @@ - + - + @@ -33613,7 +33613,7 @@ - + @@ -34162,14 +34162,14 @@ - + - + @@ -34259,7 +34259,7 @@ - + @@ -34274,13 +34274,13 @@ - + - + @@ -35207,7 +35207,7 @@ - + @@ -35220,7 +35220,7 @@ - + @@ -35233,7 +35233,7 @@ - + @@ -35246,7 +35246,7 @@ - + @@ -35259,7 +35259,7 @@ - + @@ -35319,7 +35319,7 @@ - + @@ -35373,7 +35373,7 @@ - + @@ -35508,7 +35508,7 @@ - + @@ -35554,7 +35554,7 @@ - + @@ -35607,7 +35607,7 @@ - + diff --git a/tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi b/tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi index 391968eb..9110d9c7 100644 --- a/tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi +++ b/tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi @@ -553,11 +553,11 @@ - - - + + + - + @@ -566,53 +566,53 @@ - + - + - + - + - + - + - - + + - - + + - - + + - + - - + + - + @@ -26358,7 +26358,7 @@ - + @@ -26368,17 +26368,17 @@ - + - + - + @@ -26392,7 +26392,7 @@ - + @@ -26405,7 +26405,7 @@ - + @@ -26422,11 +26422,11 @@ - + - + @@ -26435,11 +26435,11 @@ - + - + diff --git a/tests/data/test-read-dwarf/test2.so.abi b/tests/data/test-read-dwarf/test2.so.abi index 98dd9a60..e3cee34c 100644 --- a/tests/data/test-read-dwarf/test2.so.abi +++ b/tests/data/test-read-dwarf/test2.so.abi @@ -6,10 +6,10 @@ - - - - + + + + @@ -35,7 +35,7 @@ - + @@ -63,7 +63,7 @@ - + diff --git a/tests/data/test-read-dwarf/test2.so.hash.abi b/tests/data/test-read-dwarf/test2.so.hash.abi index bb814f73..5e1ae6d1 100644 --- a/tests/data/test-read-dwarf/test2.so.hash.abi +++ b/tests/data/test-read-dwarf/test2.so.hash.abi @@ -6,10 +6,10 @@ - - - - + + + + @@ -35,7 +35,7 @@ - + @@ -63,7 +63,7 @@ - + diff --git a/tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi b/tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi index 438d712f..5b141a06 100644 --- a/tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi +++ b/tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi @@ -7,32 +7,32 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -736,14 +736,14 @@ - + - + - + - + @@ -837,32 +837,32 @@ - - + + - + - + - - + + - - - + + + - + - + - - + + - + @@ -949,8 +949,8 @@ - - + + @@ -985,8 +985,8 @@ - - + + @@ -1075,33 +1075,33 @@ - - - + + + - + - - + + - - - + + + - + - - + + - - + + @@ -1130,45 +1130,45 @@ - + - - + + - + - - + + - + - + - + - - + + - + - - - - - - + + + + + + - - + + @@ -1179,25 +1179,25 @@ - - + + - - + + - - - - - - + + + + + + - - + + @@ -1205,16 +1205,16 @@ - - - - + + + + - - + + - - + + @@ -1229,16 +1229,16 @@ - - + + - - + + @@ -1257,11 +1257,11 @@ - - + + - - + + @@ -1273,25 +1273,25 @@ - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - + + @@ -1304,8 +1304,8 @@ - - + + @@ -1360,8 +1360,8 @@ - - + + @@ -1420,8 +1420,8 @@ - - + + @@ -1456,8 +1456,8 @@ - - + + @@ -1493,8 +1493,8 @@ - - + + @@ -1557,36 +1557,36 @@ - - + + - - + + - - + + - - + + - - + + - - + + @@ -1597,12 +1597,12 @@ - + - - + + - + @@ -1646,8 +1646,8 @@ - - + + @@ -1683,9 +1683,9 @@ - + - + @@ -1703,9 +1703,9 @@ - + - + @@ -1721,59 +1721,59 @@ - + - + - - + + - - + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + @@ -1781,61 +1781,61 @@ - - + + - - + + - - - - + + + + - - - - + + + + - - + + - - + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + @@ -1869,8 +1869,8 @@ - - + + @@ -1909,24 +1909,24 @@ - - + + - + - + - - + + - - - - + + + + - - + + @@ -1947,37 +1947,37 @@ - + - + - - + + - - + + - - - - + + + + - - - - + + + + - - + + @@ -1995,24 +1995,24 @@ - - + + - - + + - + - + - - - - + + + + @@ -2021,16 +2021,16 @@ - - + + - - + + - - + + @@ -2044,23 +2044,23 @@ - - - - + + + + - - + + - - + + - - + + @@ -2068,33 +2068,33 @@ - - - - + + + + - - + + - - + + - - - - - - + + + + + + - - + + @@ -2108,19 +2108,19 @@ - - + + - + - + - - + + @@ -2148,12 +2148,12 @@ - + - + - - + + @@ -2173,20 +2173,20 @@ - - + + - - - - + + + + - - + + @@ -3698,7 +3698,7 @@ - + @@ -3776,7 +3776,7 @@ - + @@ -4004,7 +4004,7 @@ - + @@ -4833,13 +4833,13 @@ - + - + @@ -4996,7 +4996,7 @@ - + @@ -5036,7 +5036,7 @@ - + @@ -5080,7 +5080,7 @@ - + @@ -5223,7 +5223,7 @@ - + @@ -5473,7 +5473,7 @@ - + @@ -5815,7 +5815,7 @@ - + @@ -6685,7 +6685,7 @@ - + @@ -6779,7 +6779,7 @@ - + @@ -8715,7 +8715,7 @@ - + @@ -10155,7 +10155,7 @@ - + @@ -10182,7 +10182,7 @@ - + @@ -10470,7 +10470,7 @@ - + @@ -10728,7 +10728,7 @@ - + @@ -10749,7 +10749,7 @@ - + @@ -10803,13 +10803,13 @@ - + - + @@ -11178,7 +11178,7 @@ - + @@ -11701,7 +11701,7 @@ - + @@ -12080,7 +12080,7 @@ - + @@ -13468,14 +13468,14 @@ - + - + @@ -13489,7 +13489,7 @@ - + @@ -13498,7 +13498,7 @@ - + @@ -13526,7 +13526,7 @@ - + @@ -13534,7 +13534,7 @@ - + @@ -13543,7 +13543,7 @@ - + @@ -13608,7 +13608,7 @@ - + @@ -15376,14 +15376,14 @@ - + - + @@ -15398,7 +15398,7 @@ - + @@ -15419,7 +15419,7 @@ - + @@ -15437,7 +15437,7 @@ - + @@ -15446,7 +15446,7 @@ - + @@ -15482,7 +15482,7 @@ - + @@ -15544,7 +15544,7 @@ - + @@ -16362,7 +16362,7 @@ - + @@ -17565,7 +17565,7 @@ - + @@ -19545,7 +19545,7 @@ - + @@ -19605,7 +19605,7 @@ - + @@ -22174,7 +22174,7 @@ - + @@ -26389,7 +26389,7 @@ - + @@ -28444,7 +28444,7 @@ - + @@ -28598,14 +28598,14 @@ - + - + @@ -29017,21 +29017,21 @@ - + - + - + @@ -29044,7 +29044,7 @@ - + @@ -29060,7 +29060,7 @@ - + @@ -29635,7 +29635,7 @@ - + @@ -29884,14 +29884,14 @@ - + - + @@ -29913,7 +29913,7 @@ - + @@ -30597,7 +30597,7 @@ - + @@ -31008,7 +31008,7 @@ - + @@ -31767,7 +31767,7 @@ - + @@ -32051,7 +32051,7 @@ - + @@ -33322,7 +33322,7 @@ - + @@ -33345,7 +33345,7 @@ - + @@ -36349,7 +36349,7 @@ - + @@ -36371,7 +36371,7 @@ - + @@ -36389,7 +36389,7 @@ - + @@ -36429,7 +36429,7 @@ - + @@ -36469,7 +36469,7 @@ - + @@ -36491,7 +36491,7 @@ - + @@ -36534,7 +36534,7 @@ - + @@ -36577,7 +36577,7 @@ - + @@ -36595,7 +36595,7 @@ - + @@ -36635,7 +36635,7 @@ - + @@ -36657,7 +36657,7 @@ - + @@ -36993,7 +36993,7 @@ - + @@ -37249,7 +37249,7 @@ - + @@ -37599,7 +37599,7 @@ - + @@ -37620,7 +37620,7 @@ - + @@ -37799,7 +37799,7 @@ - + @@ -37897,7 +37897,7 @@ - + @@ -38237,7 +38237,7 @@ - + @@ -38344,7 +38344,7 @@ - + @@ -38950,7 +38950,7 @@ - + @@ -39108,7 +39108,7 @@ - + @@ -39667,14 +39667,14 @@ - + - + @@ -39841,7 +39841,7 @@ - + @@ -39985,7 +39985,7 @@ - + @@ -40000,7 +40000,7 @@ - + @@ -40023,7 +40023,7 @@ - + @@ -40163,7 +40163,7 @@ - + @@ -40184,7 +40184,7 @@ - + @@ -40317,7 +40317,7 @@ - + @@ -40480,7 +40480,7 @@ - + @@ -40501,7 +40501,7 @@ - + @@ -40638,7 +40638,7 @@ - + @@ -40646,7 +40646,7 @@ - + @@ -40900,14 +40900,14 @@ - + - + @@ -40915,7 +40915,7 @@ - + @@ -40937,7 +40937,7 @@ - + @@ -41045,7 +41045,7 @@ - + @@ -41074,7 +41074,7 @@ - + @@ -41218,7 +41218,7 @@ - + @@ -41233,7 +41233,7 @@ - + @@ -41535,14 +41535,14 @@ - + - + @@ -41550,7 +41550,7 @@ - + @@ -41573,7 +41573,7 @@ - + @@ -41864,14 +41864,14 @@ - + - + @@ -41879,7 +41879,7 @@ - + @@ -41902,7 +41902,7 @@ - + @@ -41990,14 +41990,14 @@ - + - + @@ -42230,7 +42230,7 @@ - + @@ -42251,7 +42251,7 @@ - + @@ -42436,7 +42436,7 @@ - + @@ -44632,7 +44632,7 @@ - + @@ -44658,7 +44658,7 @@ - + @@ -44702,7 +44702,7 @@ - + @@ -44723,7 +44723,7 @@ - + @@ -44799,7 +44799,7 @@ - + @@ -44854,7 +44854,7 @@ - + @@ -44913,7 +44913,7 @@ - + @@ -44930,7 +44930,7 @@ - + @@ -44951,7 +44951,7 @@ - + @@ -45250,7 +45250,7 @@ - + @@ -45265,7 +45265,7 @@ - + @@ -45273,7 +45273,7 @@ - + @@ -45281,7 +45281,7 @@ - + @@ -45289,7 +45289,7 @@ - + @@ -45298,7 +45298,7 @@ - + @@ -45307,7 +45307,7 @@ - + @@ -45330,7 +45330,7 @@ - + @@ -46537,14 +46537,14 @@ - + - + @@ -48115,7 +48115,7 @@ - + @@ -48155,7 +48155,7 @@ - + @@ -48195,7 +48195,7 @@ - + @@ -48238,7 +48238,7 @@ - + @@ -48303,7 +48303,7 @@ - + @@ -48321,7 +48321,7 @@ - + @@ -48361,7 +48361,7 @@ - + @@ -48766,7 +48766,7 @@ - + @@ -49243,7 +49243,7 @@ - + diff --git a/tests/data/test-read-dwarf/test3-alias-1.so.hash.abi b/tests/data/test-read-dwarf/test3-alias-1.so.hash.abi new file mode 100644 index 00000000..1ed4b061 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-1.so.hash.abi @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/tests/data/test-read-dwarf/test3-alias-1.suppr b/tests/data/test-read-dwarf/test3-alias-1.suppr new file mode 100644 index 00000000..b347500d --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-1.suppr @@ -0,0 +1,3 @@ +[suppress_function] + symbol_name_not_regexp = ^__foo$ + drop = true diff --git a/tests/data/test-read-dwarf/test3-alias-2.so.hash.abi b/tests/data/test-read-dwarf/test3-alias-2.so.hash.abi new file mode 100644 index 00000000..50a53f97 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-2.so.hash.abi @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-read-dwarf/test3-alias-2.suppr b/tests/data/test-read-dwarf/test3-alias-2.suppr new file mode 100644 index 00000000..b6d203d5 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-2.suppr @@ -0,0 +1,3 @@ +[suppress_function] + symbol_name_regexp = ^__foo$ + drop = true diff --git a/tests/data/test-read-dwarf/test3-alias-3.so.hash.abi b/tests/data/test-read-dwarf/test3-alias-3.so.hash.abi new file mode 100644 index 00000000..6de4d59b --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-3.so.hash.abi @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/tests/data/test-read-dwarf/test3-alias-3.suppr b/tests/data/test-read-dwarf/test3-alias-3.suppr new file mode 100644 index 00000000..66cd33a8 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-3.suppr @@ -0,0 +1,3 @@ +[suppress_function] + symbol_name_not_regexp = ^foo$ + drop = true diff --git a/tests/data/test-read-dwarf/test3-alias-4.so.hash.abi b/tests/data/test-read-dwarf/test3-alias-4.so.hash.abi new file mode 100644 index 00000000..b26d12f8 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-4.so.hash.abi @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/test-read-dwarf/test3-alias-4.suppr b/tests/data/test-read-dwarf/test3-alias-4.suppr new file mode 100644 index 00000000..25a2c437 --- /dev/null +++ b/tests/data/test-read-dwarf/test3-alias-4.suppr @@ -0,0 +1,3 @@ +[suppress_function] + symbol_name_not_regexp = ^_init$ + drop = true diff --git a/tests/data/test-read-dwarf/test3.so.abi b/tests/data/test-read-dwarf/test3.so.abi index 7357a740..96d8cc31 100644 --- a/tests/data/test-read-dwarf/test3.so.abi +++ b/tests/data/test-read-dwarf/test3.so.abi @@ -3,16 +3,16 @@ - + - + - + diff --git a/tests/data/test-read-dwarf/test3.so.hash.abi b/tests/data/test-read-dwarf/test3.so.hash.abi index e01f3959..22540639 100644 --- a/tests/data/test-read-dwarf/test3.so.hash.abi +++ b/tests/data/test-read-dwarf/test3.so.hash.abi @@ -3,16 +3,16 @@ - + - + - + diff --git a/tests/data/test-read-write/test-crc.xml b/tests/data/test-read-write/test-crc.xml new file mode 100644 index 00000000..d74bb570 --- /dev/null +++ b/tests/data/test-read-write/test-crc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/data/test-symtab/basic/aliases.c b/tests/data/test-symtab/basic/aliases.c new file mode 100644 index 00000000..319f4632 --- /dev/null +++ b/tests/data/test-symtab/basic/aliases.c @@ -0,0 +1,13 @@ +void exported_function(){} + +void exported_function_alias() __attribute__((alias("exported_function"))); +void exported_function_another_alias() __attribute__((alias("exported_function"))); +void exported_function_weak_alias() __attribute__((weak, alias("exported_function"))); +void exported_function_another_weak_alias() __attribute__((weak, alias("exported_function"))); + +int exported_variable = 42; + +extern int exported_variable_alias __attribute__((alias("exported_variable"))); +extern int exported_variable_another_alias __attribute__((alias("exported_variable"))); +extern int exported_variable_weak_alias __attribute__((weak, alias("exported_variable"))); +extern int exported_variable_another_weak_alias __attribute__((weak, alias("exported_variable"))); diff --git a/tests/data/test-symtab/basic/aliases.so b/tests/data/test-symtab/basic/aliases.so new file mode 100755 index 00000000..95a5c058 Binary files /dev/null and b/tests/data/test-symtab/basic/aliases.so differ diff --git a/tests/data/test-symtab/basic/no_debug_info.c b/tests/data/test-symtab/basic/no_debug_info.c index 5bb380ba..8ac09016 100644 --- a/tests/data/test-symtab/basic/no_debug_info.c +++ b/tests/data/test-symtab/basic/no_debug_info.c @@ -1 +1 @@ -// empty! +void exported_function(){} diff --git a/tests/data/test-symtab/basic/no_debug_info.so b/tests/data/test-symtab/basic/no_debug_info.so index 827c1eee..0b231019 100755 Binary files a/tests/data/test-symtab/basic/no_debug_info.so and b/tests/data/test-symtab/basic/no_debug_info.so differ diff --git a/tests/data/test-symtab/basic/one_function_one_variable_all.whitelist b/tests/data/test-symtab/basic/one_function_one_variable_all.whitelist new file mode 100644 index 00000000..02ea3109 --- /dev/null +++ b/tests/data/test-symtab/basic/one_function_one_variable_all.whitelist @@ -0,0 +1,3 @@ +[abi_whitelist] + exported_function + exported_variable diff --git a/tests/data/test-symtab/basic/one_function_one_variable_function.whitelist b/tests/data/test-symtab/basic/one_function_one_variable_function.whitelist new file mode 100644 index 00000000..893accc1 --- /dev/null +++ b/tests/data/test-symtab/basic/one_function_one_variable_function.whitelist @@ -0,0 +1,2 @@ +[abi_whitelist] + exported_function diff --git a/tests/data/test-symtab/basic/one_function_one_variable_irrelevant.whitelist b/tests/data/test-symtab/basic/one_function_one_variable_irrelevant.whitelist new file mode 100644 index 00000000..180ef906 --- /dev/null +++ b/tests/data/test-symtab/basic/one_function_one_variable_irrelevant.whitelist @@ -0,0 +1,2 @@ +[abi_whitelist] + irrelevant diff --git a/tests/data/test-symtab/basic/one_function_one_variable_variable.whitelist b/tests/data/test-symtab/basic/one_function_one_variable_variable.whitelist new file mode 100644 index 00000000..49d838f2 --- /dev/null +++ b/tests/data/test-symtab/basic/one_function_one_variable_variable.whitelist @@ -0,0 +1,2 @@ +[abi_whitelist] + exported_variable diff --git a/tests/data/test-symtab/kernel-modversions/Makefile b/tests/data/test-symtab/kernel-modversions/Makefile new file mode 100644 index 00000000..1479ae4b --- /dev/null +++ b/tests/data/test-symtab/kernel-modversions/Makefile @@ -0,0 +1,19 @@ +obj-m += one_of_each.o + +# Overwrite to an actual kernel dir when using this: +# +# $ make KDIR=/path/to/actual/kernel/source/dir +# +KDIR := /tmp/some/kernel/source/dir + +PWD := $(shell pwd) +default: + make -C $(KDIR) tinyconfig + cd $(KDIR) && ./scripts/config -e 64BIT -e MODULES -e MODVERSIONS -e CONFIG_DEBUG_INFO + $(MAKE) -C $(KDIR) olddefconfig + $(MAKE) -C $(KDIR) + $(MAKE) -C $(KDIR) M=$(PWD) modules + rm -rf *.mod.c *.o .*.cmd .*.d *.mod modules.order Module.symvers .tmp_versions + +clean: + rm -f *.ko diff --git a/tests/data/test-symtab/kernel-modversions/one_of_each.c b/tests/data/test-symtab/kernel-modversions/one_of_each.c new file mode 120000 index 00000000..27c87e57 --- /dev/null +++ b/tests/data/test-symtab/kernel-modversions/one_of_each.c @@ -0,0 +1 @@ +../kernel/one_of_each.c \ No newline at end of file diff --git a/tests/data/test-symtab/kernel-modversions/one_of_each.ko b/tests/data/test-symtab/kernel-modversions/one_of_each.ko new file mode 100644 index 00000000..c6f1bed5 Binary files /dev/null and b/tests/data/test-symtab/kernel-modversions/one_of_each.ko differ diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc index 4d9c1943..772baa78 100644 --- a/tests/test-abidiff-exit.cc +++ b/tests/test-abidiff-exit.cc @@ -212,6 +212,15 @@ InOutSpec in_out_specs[] = "data/test-abidiff-exit/test-fun-param-report.txt", "output/test-abidiff-exit/test-fun-param-report.txt" }, + { + "data/test-abidiff-exit/test-missing-alias.abi", + "data/test-abidiff-exit/test-missing-alias.abi", + "data/test-abidiff-exit/test-missing-alias.suppr", + "", + abigail::tools_utils::ABIDIFF_OK, + "data/test-abidiff-exit/test-missing-alias-report.txt", + "output/test-abidiff-exit/test-missing-alias-report.txt" + }, {0, 0, 0 ,0, abigail::tools_utils::ABIDIFF_OK, 0, 0} }; diff --git a/tests/test-abidiff.cc b/tests/test-abidiff.cc index dcb1401b..b4c5869d 100644 --- a/tests/test-abidiff.cc +++ b/tests/test-abidiff.cc @@ -92,7 +92,7 @@ static InOutSpec specs[] = { "data/test-abidiff/test-PR18166-libtirpc.so.abi", "data/test-abidiff/test-PR18166-libtirpc.so.abi", - "data/test-abidiff/test-PR18166-libtirpc.so.report.txt", + "data/test-abidiff/empty-report.txt", "output/test-abidiff/test-PR18166-libtirpc.so.report.txt" }, { @@ -104,26 +104,44 @@ static InOutSpec specs[] = { "data/test-abidiff/test-PR24552-v0.abi", "data/test-abidiff/test-PR24552-v1.abi", - "data/test-abidiff/test-PR24552-report0.txt", + "data/test-abidiff/empty-report.txt", "output/test-abidiff/test-PR24552-report0.txt" }, { "data/test-abidiff/test-empty-corpus-0.xml", "data/test-abidiff/test-empty-corpus-0.xml", - "data/test-abidiff/test-empty-corpus-report.txt", - "output/test-abidiff/test-empty-corpus-report.txt" + "data/test-abidiff/empty-report.txt", + "output/test-abidiff/test-empty-corpus-report-0.txt" }, { "data/test-abidiff/test-empty-corpus-1.xml", "data/test-abidiff/test-empty-corpus-1.xml", - "data/test-abidiff/test-empty-corpus-report.txt", - "output/test-abidiff/test-empty-corpus-report.txt" + "data/test-abidiff/empty-report.txt", + "output/test-abidiff/test-empty-corpus-report-1.txt" }, { "data/test-abidiff/test-empty-corpus-2.xml", "data/test-abidiff/test-empty-corpus-2.xml", - "data/test-abidiff/test-empty-corpus-report.txt", - "output/test-abidiff/test-empty-corpus-report.txt" + "data/test-abidiff/empty-report.txt", + "output/test-abidiff/test-empty-corpus-report-1.txt" + }, + { + "data/test-abidiff/test-crc-0.xml", + "data/test-abidiff/test-crc-1.xml", + "data/test-abidiff/empty-report.txt", + "output/test-abidiff/test-crc-report-0-1.txt" + }, + { + "data/test-abidiff/test-crc-1.xml", + "data/test-abidiff/test-crc-0.xml", + "data/test-abidiff/empty-report.txt", + "output/test-abidiff/test-crc-report-1-0.txt" + }, + { + "data/test-abidiff/test-crc-1.xml", + "data/test-abidiff/test-crc-2.xml", + "data/test-abidiff/test-crc-report.txt", + "output/test-abidiff/test-crc-report-1-2.txt" }, // This should be the last entry. {0, 0, 0, 0} diff --git a/tests/test-cxx-compat.cc b/tests/test-cxx-compat.cc index 0a230a54..adeb7b8d 100644 --- a/tests/test-cxx-compat.cc +++ b/tests/test-cxx-compat.cc @@ -28,3 +28,54 @@ #include "abg-cxx-compat.h" +using abg_compat::optional; + +TEST_CASE("OptionalConstruction", "[abg_compat::optional]") +{ + optional opt1; + REQUIRE_FALSE(opt1.has_value()); + + optional opt2(true); + REQUIRE(opt2.has_value()); + CHECK(opt2.value() == true); + + optional opt3(false); + REQUIRE(opt3.has_value()); + CHECK(opt3.value() == false); +} + +TEST_CASE("OptionalValue", "[abg_compat::optional]") +{ + optional opt; + REQUIRE_FALSE(opt.has_value()); + REQUIRE_THROWS(opt.value()); + + opt = true; + REQUIRE_NOTHROW(opt.value()); + CHECK(opt.value() == true); +} + +TEST_CASE("OptionalValueOr", "[abg_compat::optional]") +{ + optional opt; + REQUIRE_FALSE(opt.has_value()); + + const std::string& mine = "mine"; + // Ensure we get a copy of our own value. + CHECK(opt.value_or(mine) == mine); + + // Now set the value + const std::string& other = "other"; + opt = other; + CHECK(opt.value_or(mine) != mine); + CHECK(opt.value_or(mine) == other); +} + +TEST_CASE("OptionalDeref", "[abg_compat::optional]") +{ + optional opt("asdf"); + REQUIRE(opt.has_value()); + + CHECK(*opt == "asdf"); + CHECK(opt->size() == 4); +} diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc index 8502f827..dc11fbca 100644 --- a/tests/test-read-dwarf.cc +++ b/tests/test-read-dwarf.cc @@ -124,6 +124,38 @@ InOutSpec in_out_specs[] = "data/test-read-dwarf/test3.so.hash.abi", "output/test-read-dwarf/test3.so.hash.abi" }, + // suppress all except the main symbol of a group of aliases + { + "data/test-read-dwarf/test3.so", + "data/test-read-dwarf/test3-alias-1.suppr", + HASH_TYPE_ID_STYLE, + "data/test-read-dwarf/test3-alias-1.so.hash.abi", + "output/test-read-dwarf/test3-alias-1.so.hash.abi" + }, + // suppress the main symbol of a group of aliases + { + "data/test-read-dwarf/test3.so", + "data/test-read-dwarf/test3-alias-2.suppr", + HASH_TYPE_ID_STYLE, + "data/test-read-dwarf/test3-alias-2.so.hash.abi", + "output/test-read-dwarf/test3-alias-2.so.hash.abi" + }, + // suppress all except one non main symbol of a group of aliases + { + "data/test-read-dwarf/test3.so", + "data/test-read-dwarf/test3-alias-3.suppr", + HASH_TYPE_ID_STYLE, + "data/test-read-dwarf/test3-alias-3.so.hash.abi", + "output/test-read-dwarf/test3-alias-3.so.hash.abi" + }, + // suppress all symbols of a group of aliases + { + "data/test-read-dwarf/test3.so", + "data/test-read-dwarf/test3-alias-4.suppr", + HASH_TYPE_ID_STYLE, + "data/test-read-dwarf/test3-alias-4.so.hash.abi", + "output/test-read-dwarf/test3-alias-4.so.hash.abi" + }, { "data/test-read-dwarf/test4.so", "", diff --git a/tests/test-read-write.cc b/tests/test-read-write.cc index 7d24bee5..b768c13c 100644 --- a/tests/test-read-write.cc +++ b/tests/test-read-write.cc @@ -253,6 +253,12 @@ InOutSpec in_out_specs[] = "data/test-read-write/test28-without-std-vars-ref.xml", "output/test-read-write/test28-without-std-vars.xml" }, + { + "data/test-read-write/test-crc.xml", + "", + "data/test-read-write/test-crc.xml", + "output/test-read-write/test-crc.xml", + }, // This should be the last entry. {NULL, NULL, NULL, NULL} }; diff --git a/tests/test-symtab-reader.cc b/tests/test-symtab-reader.cc new file mode 100644 index 00000000..383166c8 --- /dev/null +++ b/tests/test-symtab-reader.cc @@ -0,0 +1,53 @@ +// -*- Mode: C++ -*- +// +// Copyright (C) 2020 Google, Inc. +// +// This file is part of the GNU Application Binary Interface Generic +// Analysis and Instrumentation Library (libabigail). This library is +// free software; you can redistribute it and/or modify it under the +// terms of the GNU Lesser General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) any +// later version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this program; see the file COPYING-LGPLV3. If +// not, see . +// +// Author: Matthias Maennich + +/// @file +/// +/// This program tests libabigail's symtab reader. + +#include "lib/catch.hpp" + +#include "abg-symtab-reader.h" + +namespace abigail +{ + +using symtab_reader::symtab_filter; +using symtab_reader::symtab_filter_builder; + +TEST_CASE("default symtab_filter matches anything", + "[symtab_reader, symtab_filter]") +{ + const symtab_filter filter; + const elf_symbol_sptr symbol; // not initialized! + CHECK(filter.matches(symbol)); +} + +TEST_CASE("default symtab_filter built with filter_builder matches anything", + "[symtab_reader, symtab_filter, symtab_filter_builder]") +{ + const symtab_filter filter = symtab_filter_builder(); + const elf_symbol_sptr symbol; // not initialized! + CHECK(filter.matches(symbol)); +} + +} // namespace abigail diff --git a/tests/test-symtab.cc b/tests/test-symtab.cc index 20e3071c..b8f72985 100644 --- a/tests/test-symtab.cc +++ b/tests/test-symtab.cc @@ -26,11 +26,14 @@ #include #include +#include #include #include "abg-corpus.h" #include "abg-dwarf-reader.h" +#include "abg-fwd.h" #include "abg-ir.h" +#include "abg-tools-utils.h" #include "lib/catch.hpp" #include "test-utils.h" @@ -41,12 +44,16 @@ using dwarf_reader::read_context_sptr; using dwarf_reader::read_corpus_from_elf; using ir::environment; using ir::environment_sptr; +using suppr::suppressions_type; static const std::string test_data_dir = std::string(abigail::tests::get_src_dir()) + "/tests/data/test-symtab/"; dwarf_reader::status -read_corpus(const std::string path, corpus_sptr& result) +read_corpus( + const std::string& path, + corpus_sptr& result, + const std::vector& whitelist_paths = std::vector()) { const std::string& absolute_path = test_data_dir + path; @@ -56,6 +63,15 @@ read_corpus(const std::string path, corpus_sptr& result) absolute_path, debug_info_root_paths, env.get(), /* load_all_type = */ true, /* linux_kernel_mode = */ true); + if (!whitelist_paths.empty()) + { + const suppressions_type& wl_suppr = + tools_utils::gen_suppr_spec_from_kernel_abi_whitelists( + whitelist_paths); + REQUIRE_FALSE(wl_suppr.empty()); + dwarf_reader::add_read_context_suppressions(*ctxt, wl_suppr); + } + dwarf_reader::status status = dwarf_reader::STATUS_UNKNOWN; result = read_corpus_from_elf(*ctxt, status); @@ -68,14 +84,9 @@ TEST_CASE("Symtab::Empty", "[symtab, basic]") const std::string binary = "basic/empty.so"; corpus_sptr corpus_ptr; const dwarf_reader::status status = read_corpus(binary, corpus_ptr); - REQUIRE(corpus_ptr); - - REQUIRE((status & dwarf_reader::STATUS_OK)); + REQUIRE(!corpus_ptr); - // TODO: Those two assertions are currently not met. Empty symtabs are - // currently treated like the error case. - // REQUIRE((status & dwarf_reader::STATUS_OK)); - // REQUIRE((status & dwarf_reader::STATUS_NO_SYMBOLS_FOUND)); + REQUIRE((status & dwarf_reader::STATUS_NO_SYMBOLS_FOUND)); } TEST_CASE("Symtab::NoDebugInfo", "[symtab, basic]") @@ -85,9 +96,9 @@ TEST_CASE("Symtab::NoDebugInfo", "[symtab, basic]") const dwarf_reader::status status = read_corpus(binary, corpus_ptr); REQUIRE(corpus_ptr); - REQUIRE(status - == (dwarf_reader::STATUS_OK - | dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)); + REQUIRE( + status + == (dwarf_reader::STATUS_OK | dwarf_reader::STATUS_DEBUG_INFO_NOT_FOUND)); } // this value indicates in the following helper method, that we do not want to @@ -96,30 +107,35 @@ TEST_CASE("Symtab::NoDebugInfo", "[symtab, basic]") #define N std::numeric_limits::max() corpus_sptr -assert_symbol_count(const std::string& path, - size_t function_symbols = 0, - size_t variable_symbols = 0, - size_t undefined_function_symbols = 0, - size_t undefined_variable_symbols = 0) +assert_symbol_count( + const std::string& path, + size_t function_symbols = 0, + size_t variable_symbols = 0, + size_t undefined_function_symbols = 0, + size_t undefined_variable_symbols = 0, + const std::vector& whitelist_paths = std::vector()) { corpus_sptr corpus_ptr; - const dwarf_reader::status status = read_corpus(path, corpus_ptr); + const dwarf_reader::status status = + read_corpus(path, corpus_ptr, whitelist_paths); REQUIRE(corpus_ptr); REQUIRE((status & dwarf_reader::STATUS_OK)); const corpus& corpus = *corpus_ptr; + size_t total_symbols = 0; + if (function_symbols != N) { CHECK(corpus.get_sorted_fun_symbols().size() == function_symbols); CHECK(corpus.get_fun_symbol_map().size() == function_symbols); - CHECK(corpus.get_fun_symbol_map_sptr()->size() == function_symbols); + total_symbols += function_symbols; } if (variable_symbols != N) { CHECK(corpus.get_sorted_var_symbols().size() == variable_symbols); CHECK(corpus.get_var_symbol_map().size() == variable_symbols); - CHECK(corpus.get_var_symbol_map_sptr()->size() == variable_symbols); + total_symbols += variable_symbols; } if (undefined_variable_symbols != N) { @@ -127,8 +143,7 @@ assert_symbol_count(const std::string& path, == undefined_function_symbols); CHECK(corpus.get_undefined_fun_symbol_map().size() == undefined_function_symbols); - CHECK(corpus.get_undefined_fun_symbol_map_sptr()->size() - == undefined_function_symbols); + total_symbols += undefined_function_symbols; } if (undefined_function_symbols != N) { @@ -136,10 +151,12 @@ assert_symbol_count(const std::string& path, == undefined_variable_symbols); CHECK(corpus.get_undefined_var_symbol_map().size() == undefined_variable_symbols); - CHECK(corpus.get_undefined_var_symbol_map_sptr()->size() - == undefined_variable_symbols); + total_symbols += undefined_variable_symbols; } + // assert the corpus reports being empty consistently with the symbol count + CHECK(corpus.is_empty() == (total_symbols == 0)); + return corpus_ptr; } @@ -205,6 +222,123 @@ TEST_CASE("Symtab::SimpleSymtabs", "[symtab, basic]") } } +TEST_CASE("Symtab::SymtabWithWhitelist", "[symtab, whitelist]") +{ + GIVEN("a binary with one function and one variable exported") + { + const std::string binary = "basic/one_function_one_variable.so"; + + GIVEN("we read the binary without any whitelists") + { + const corpus_sptr& corpus = assert_symbol_count(binary, 1, 1); + CHECK(corpus->lookup_function_symbol("exported_function")); + CHECK(!corpus->lookup_variable_symbol("exported_function")); + CHECK(corpus->lookup_variable_symbol("exported_variable")); + CHECK(!corpus->lookup_function_symbol("exported_variable")); + } + + GIVEN("we read the binary with all symbols on the whitelists") + { + std::vector whitelists; + whitelists.push_back(test_data_dir + + "basic/one_function_one_variable_all.whitelist"); + const corpus_sptr& corpus = + assert_symbol_count(binary, 1, 1, 0, 0, whitelists); + CHECK(corpus->lookup_function_symbol("exported_function")); + CHECK(!corpus->lookup_variable_symbol("exported_function")); + CHECK(corpus->lookup_variable_symbol("exported_variable")); + CHECK(!corpus->lookup_function_symbol("exported_variable")); + } + + GIVEN("we read the binary with only irrelevant symbols whitelisted") + { + std::vector whitelists; + whitelists.push_back( + test_data_dir + + "basic/one_function_one_variable_irrelevant.whitelist"); + + corpus_sptr corpus_ptr; + const dwarf_reader::status status = + read_corpus(binary, corpus_ptr, whitelists); + REQUIRE(!corpus_ptr); + REQUIRE((status & dwarf_reader::STATUS_NO_SYMBOLS_FOUND)); + } + + GIVEN("we read the binary with only the function whitelisted") + { + std::vector whitelists; + whitelists.push_back( + test_data_dir + "basic/one_function_one_variable_function.whitelist"); + const corpus_sptr& corpus = + assert_symbol_count(binary, 1, 0, 0, 0, whitelists); + CHECK(corpus->lookup_function_symbol("exported_function")); + CHECK(!corpus->lookup_variable_symbol("exported_function")); + CHECK(!corpus->lookup_variable_symbol("exported_variable")); + CHECK(!corpus->lookup_function_symbol("exported_variable")); + } + + GIVEN("we read the binary with only the variable whitelisted") + { + std::vector whitelists; + whitelists.push_back( + test_data_dir + "basic/one_function_one_variable_variable.whitelist"); + const corpus_sptr& corpus = + assert_symbol_count(binary, 0, 1, 0, 0, whitelists); + CHECK(!corpus->lookup_function_symbol("exported_function")); + CHECK(!corpus->lookup_variable_symbol("exported_function")); + CHECK(corpus->lookup_variable_symbol("exported_variable")); + CHECK(!corpus->lookup_function_symbol("exported_variable")); + } + } +} + +TEST_CASE("Symtab::AliasedFunctionSymbols", "[symtab, functions, aliases]") +{ + const std::string binary = "basic/aliases.so"; + const corpus_sptr& corpus = assert_symbol_count(binary, 5, 5); + + // The main symbol is not necessarily the one that is aliased to in the + // code So, this can't be decided by just looking at ELF. Hence acquire the + // main symbol. + const elf_symbol_sptr& main_symbol = + corpus->lookup_function_symbol("exported_function")->get_main_symbol(); + REQUIRE(main_symbol); + + // But since we know that 'exported_function' is the main symbol and this + // can be discovered from DWARF + CHECK(corpus->lookup_function_symbol("exported_function")->is_main_symbol()); + + CHECK(corpus->lookup_function_symbol("exported_function") + ->get_number_of_aliases() == 4); + + CHECK(main_symbol->has_aliases()); + CHECK(main_symbol->get_number_of_aliases() == 4); + CHECK(main_symbol->get_main_symbol() == main_symbol); +} + +TEST_CASE("Symtab::AliasedVariableSymbols", "[symtab, variables, aliases]") +{ + const std::string binary = "basic/aliases.so"; + const corpus_sptr& corpus = assert_symbol_count(binary, 5, 5); + // The main symbol is not necessarily the one that is aliased to in the + // code So, this can't be decided by just looking at ELF. Hence acquire the + // main symbol. + const elf_symbol_sptr& main_symbol = + corpus->lookup_variable_symbol("exported_variable")->get_main_symbol(); + REQUIRE(main_symbol); + + // But since we know that 'exported_function' is the main symbol and this + // can be discovered from DWARF + CHECK(corpus->lookup_variable_symbol("exported_variable")->is_main_symbol()); + + CHECK(corpus->lookup_variable_symbol("exported_variable") + ->get_number_of_aliases() == 4); + + CHECK(main_symbol->has_aliases()); + CHECK(main_symbol->get_number_of_aliases() == 4); + CHECK(main_symbol->get_main_symbol() == main_symbol); +} + static const char* kernel_versions[] = { "4.14", "4.19", "5.4", "5.6" }; static const size_t nr_kernel_versions = sizeof(kernel_versions) / sizeof(kernel_versions[0]); @@ -291,3 +425,18 @@ TEST_CASE("Symtab::SimpleKernelSymtabs", "[symtab, basic, kernel, ksymtab]") } } } + +TEST_CASE("Symtab::KernelSymtabsWithCRC", "[symtab, crc, kernel, ksymtab]") +{ + const std::string base_path = "kernel-modversions/"; + + GIVEN("a binary with one function and one variable (GPL) exported") + { + const std::string binary = base_path + "one_of_each.ko"; + const corpus_sptr& corpus = assert_symbol_count(binary, 2, 2); + CHECK(corpus->lookup_function_symbol("exported_function")->get_crc() != 0); + CHECK(corpus->lookup_function_symbol("exported_function_gpl")->get_crc() != 0); + CHECK(corpus->lookup_variable_symbol("exported_variable")->get_crc() != 0); + CHECK(corpus->lookup_variable_symbol("exported_variable_gpl")->get_crc() != 0); + } +} diff --git a/tools/abidw.cc b/tools/abidw.cc index 2cd848df..58072e70 100644 --- a/tools/abidw.cc +++ b/tools/abidw.cc @@ -828,8 +828,6 @@ main(int argc, char* argv[]) set_show_stats(ctxt, opts.show_stats); set_suppressions(ctxt, opts); abigail::dwarf_reader::set_do_log(ctxt, opts.do_log); - if (!opts.kabi_whitelist_supprs.empty()) - set_ignore_symbol_table(ctxt, true); if (opts.check_alt_debug_info_path) {