@@ -329,6 +329,16 @@ Options
makes ``abidw`` load *all* the types defined in the binaries, even
those that are not reachable from public declarations.
+ * ``--no-load-undefined-interfaces``
+
+ By default, ``libabigail`` (and thus ``abidw``) loads information
+ about undefined function and variable symbols as well as functions
+ and variables that are associated with those undefined symbols.
+ Those are called undefined interfaces. This option however makes
+ makes ``abidw`` avoid loading information about undefined
+ interfaces. The resulting XML file thus doesn't contain
+ information about those undefined interfaces.
+
* ``--abidiff``
Load the ABI of the ELF binary given in argument, save it in
@@ -57,6 +57,9 @@ set_write_comp_dir(write_context& ctxt, bool flag);
void
set_write_elf_needed(write_context& ctxt, bool flag);
+void
+set_write_undefined_symbols(write_context& ctxt, bool flag);
+
void
set_write_default_sizes(write_context& ctxt, bool flag);
@@ -88,6 +91,7 @@ set_common_options(write_context& ctxt, const OPTS& opts)
set_write_corpus_path(ctxt, opts.write_corpus_path);
set_write_comp_dir(ctxt, opts.write_comp_dir);
set_write_elf_needed(ctxt, opts.write_elf_needed);
+ set_write_undefined_symbols(ctxt, opts.load_undefined_interfaces);
set_write_parameter_names(ctxt, opts.write_parameter_names);
set_short_locs(ctxt, opts.short_locs);
set_write_default_sizes(ctxt, opts.default_sizes);
new file mode 100644
@@ -0,0 +1,1051 @@
+From cab35084da3550474f5349cfc2e65d36a7f3f91b Mon Sep 17 00:00:00 2001
+From: Dodji Seketeli <dodji@redhat.com>
+Date: Wed, 6 Mar 2024 13:47:14 +0100
+Subject: [PATCH] WIP: Emit & read undefined interfaces to & from ABIXML
+
+This work-in-progress patch teaches the ABIXML writer to emit
+information about undefined interfaces. It also teaches the ABIXML
+reader to read information about undefined interfaces.
+
+It introduces two new ABIXML elements:
+'undefined-elf-function-symbols' and 'undefined-elf-variable-symbols'
+to represent undefined function and variable symbols.
+
+Then, in the 'abi-instr' element functions and variables that
+reference undefined elf symbols now have an 'elf-symbol-id' attribute
+referencing the undefined symbol listed in the new
+'undefined-elf-variable-symbols' or 'undefined-elf-function-symbols'
+element.
+
+This work-in-progress branch comes on top of the users/dodji/abidb
+branch and should be merged into it at some point.
+
+TODO: add some tests.
+
+ * include/abg-writer.h (set_write_undefined_symbols): Declare new
+ function.
+ (set_common_options): Use the new set_write_undefined_symbols in
+ this function template.
+ * src/abg-corpus.cc (corpus::lookup_{function,variable}_symbol):
+ Lookup the symbol also among undefined symbols, not just among
+ defined symbols.
+ * src/abg-dwarf-reader.cc (reader::{get_die_language, die_is_in_c,
+ die_is_in_cplus_plus, die_is_in_c_or_cplusplus}): Move these
+ member functions into ...
+ (get_die_language, die_is_in_c, die_is_in_cplus_plus)
+ (die_is_in_c_or_cplusplus): ... these static non-member functions.
+ (fn_die_equal_by_linkage_name): Adjust and remove the now useless
+ reader parameter.
+ (compare_dies, get_scope_die, function_is_suppressed)
+ (variable_is_suppressed): Adjust.
+ (build_translation_unit_and_add_to_ir): When we are asked to load
+ undefined symbol, make sure to also analyze top-level class types
+ and if we are in C++, also analyze top-level unions and structs as
+ these might also have some undefined interfaces.
+ * src/abg-reader.cc (build_elf_symbol_db): Let's not construct and
+ return the symbol DB anymore. Rather, let's let the caller
+ construct it, so we can just update it with the input gathered.
+ (read_symbol_db_from_input): Support getting undefined function
+ and variable symbols from the new undefined-elf-function-symbols
+ and undefined-elf-variable-symbols elements. Note that undefined
+ and defined function symbols go into the same symbol DB whereas
+ undefined and defined variable symbols go into another symbol DB.
+ Now, we suppose that the variable & symbol DBs are allocated by
+ the caller. We pass it down to build_elf_symbol_db that populates
+ it. Maybe we should rename build_elf_symbol_db into
+ populate_elf_symbol_db.
+ (reader::read_corpus): Allocate the function
+ and variable symbol DB and let read_symbol_db_from_input populate
+ it. Sort functions and variables after reading the whole ABIXML.
+ * src/abg-writer.cc (write_context::write_context): Define new
+ data member.
+ (write_context::write_context): Initialize it.
+ (write_context::{get,set}::write_undefined_symbols): Define
+ accessors.
+ (set_write_undefined_symbols): Define a new function.
+ (write_context::decl_is_emitted): Add a new overload.
+ (write_elf_symbol_reference): Add a writer context and a corpus
+ parameter. If the symbol is not in the corpus or if the symbol is
+ undefined and we were not asked to emit undefined symbols then do
+ not emit any reference to it.
+ (write_translation_unit): Emit the undefined functions and
+ variables that belong to the current translation unit, along with
+ their reference to the undefined ELF symbol they are associated
+ to.
+ (write_var_decl, write_function_decl): Let
+ write_elf_symbol_reference decide whether it should emit the
+ reference to ELF symbol or not, as it now know how to make that
+ decision.
+ (write_corpus): Write the undefined function & variable ELF symbol
+ data bases. These in the new 'undefined-elf-function-symbols' and
+ 'undefined-elf-variable-symbols' elements.
+ * tools/abidw.cc (options::load_undefined_interfaces): Define new
+ data member.
+ (options:options): Initialize it.
+ (display_usage): Add a help string for the
+ --no-load-undefined-interfaces option.
+ (parse_command_line): Parse the --no-load-undefined-interfaces
+ option.
+ (set_generic_options): Set the
+ fe_iface::option_type::load_undefined_interfaces option.
+ * doc/manuals/abidw.rst: Document the new
+ --no-load-undefined-interfaces of abidw.
+
+Signed-off-by: Dodji Seketeli <dodji@redhat.com>
+---
+ doc/manuals/abidw.rst | 10 +++
+ include/abg-writer.h | 4 +
+ src/abg-corpus.cc | 38 +++++---
+ src/abg-dwarf-reader.cc | 189 +++++++++++++++++++++------------------
+ src/abg-reader.cc | 81 +++++++++++------
+ src/abg-writer.cc | 152 +++++++++++++++++++++++++++++--
+ tests/test-annotate.cc | 2 +-
+ tests/test-read-dwarf.cc | 2 +-
+ tools/abidw.cc | 7 ++
+ 9 files changed, 350 insertions(+), 135 deletions(-)
+
+diff --git a/doc/manuals/abidw.rst b/doc/manuals/abidw.rst
+index 1e308e66..6c399675 100644
+--- a/doc/manuals/abidw.rst
++++ b/doc/manuals/abidw.rst
+@@ -329,6 +329,16 @@ Options
+ makes ``abidw`` load *all* the types defined in the binaries, even
+ those that are not reachable from public declarations.
+
++ * ``--no-load-undefined-interfaces``
++
++ By default, ``libabigail`` (and thus ``abidw``) loads information
++ about undefined function and variable symbols as well as functions
++ and variables that are associated with those undefined symbols.
++ Those are called undefined interfaces. This option however makes
++ makes ``abidw`` avoid loading information about undefined
++ interfaces. The resulting XML file thus doesn't contain
++ information about those undefined interfaces.
++
+ * ``--abidiff``
+
+ Load the ABI of the ELF binary given in argument, save it in
+diff --git a/include/abg-writer.h b/include/abg-writer.h
+index 540487e0..45508544 100644
+--- a/include/abg-writer.h
++++ b/include/abg-writer.h
+@@ -57,6 +57,9 @@ set_write_comp_dir(write_context& ctxt, bool flag);
+ void
+ set_write_elf_needed(write_context& ctxt, bool flag);
+
++void
++set_write_undefined_symbols(write_context& ctxt, bool flag);
++
+ void
+ set_write_default_sizes(write_context& ctxt, bool flag);
+
+@@ -88,6 +91,7 @@ set_common_options(write_context& ctxt, const OPTS& opts)
+ set_write_corpus_path(ctxt, opts.write_corpus_path);
+ set_write_comp_dir(ctxt, opts.write_comp_dir);
+ set_write_elf_needed(ctxt, opts.write_elf_needed);
++ set_write_undefined_symbols(ctxt, opts.load_undefined_interfaces);
+ set_write_parameter_names(ctxt, opts.write_parameter_names);
+ set_short_locs(ctxt, opts.short_locs);
+ set_write_default_sizes(ctxt, opts.default_sizes);
+diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
+index e99b23fe..76c6bbb1 100644
+--- a/src/abg-corpus.cc
++++ b/src/abg-corpus.cc
+@@ -1208,13 +1208,16 @@ corpus::get_undefined_var_symbol_map() const
+ const elf_symbol_sptr
+ corpus::lookup_function_symbol(const string& n) const
+ {
+- if (get_fun_symbol_map().empty())
++ if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty())
+ return elf_symbol_sptr();
+
+- string_elf_symbols_map_type::const_iterator it =
+- get_fun_symbol_map().find(n);
++ string_elf_symbols_map_type::const_iterator it = get_fun_symbol_map().find(n);
+ if ( it == get_fun_symbol_map().end())
+- return elf_symbol_sptr();
++ {
++ it = get_undefined_fun_symbol_map().find(n);
++ if (it == get_undefined_fun_symbol_map().end())
++ return elf_symbol_sptr();
++ }
+ return it->second[0];
+ }
+
+@@ -1275,13 +1278,17 @@ const elf_symbol_sptr
+ corpus::lookup_function_symbol(const string& symbol_name,
+ const elf_symbol::version& version) const
+ {
+- if (get_fun_symbol_map().empty())
++ if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty())
+ return elf_symbol_sptr();
+
+ string_elf_symbols_map_type::const_iterator it =
+ get_fun_symbol_map().find(symbol_name);
+ if ( it == get_fun_symbol_map().end())
+- return elf_symbol_sptr();
++ {
++ it = get_undefined_fun_symbol_map().find(symbol_name);
++ if (it == get_undefined_fun_symbol_map().end())
++ return elf_symbol_sptr();
++ }
+
+ return find_symbol_by_version(version, it->second);
+ }
+@@ -1304,13 +1311,16 @@ corpus::lookup_function_symbol(const elf_symbol& symbol) const
+ const elf_symbol_sptr
+ corpus::lookup_variable_symbol(const string& n) const
+ {
+- if (get_var_symbol_map().empty())
++ if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty())
+ return elf_symbol_sptr();
+
+- string_elf_symbols_map_type::const_iterator it =
+- get_var_symbol_map().find(n);
++ string_elf_symbols_map_type::const_iterator it = get_var_symbol_map().find(n);
+ if ( it == get_var_symbol_map().end())
+- return elf_symbol_sptr();
++ {
++ it = get_undefined_var_symbol_map().find(n);
++ if (it == get_undefined_var_symbol_map().end())
++ return elf_symbol_sptr();
++ }
+ return it->second[0];
+ }
+
+@@ -1326,13 +1336,17 @@ const elf_symbol_sptr
+ corpus::lookup_variable_symbol(const string& symbol_name,
+ const elf_symbol::version& version) const
+ {
+- if (get_var_symbol_map().empty())
++ if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty())
+ return elf_symbol_sptr();
+
+ string_elf_symbols_map_type::const_iterator it =
+ get_var_symbol_map().find(symbol_name);
+ if ( it == get_var_symbol_map().end())
+- return elf_symbol_sptr();
++ {
++ it = get_undefined_var_symbol_map().find(symbol_name);
++ if (it == get_undefined_var_symbol_map().end())
++ return elf_symbol_sptr();
++ }
+
+ return find_symbol_by_version(version, it->second);
+ }
+diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
+index d0aa8c29..89c7be3b 100644
+--- a/src/abg-dwarf-reader.cc
++++ b/src/abg-dwarf-reader.cc
+@@ -379,6 +379,18 @@ get_scope_die(const reader& rdr,
+ size_t where_offset,
+ Dwarf_Die& scope_die);
+
++static bool
++get_die_language(const Dwarf_Die *die, translation_unit::language &lang) ;
++
++static bool
++die_is_in_c(const Dwarf_Die *die);
++
++static bool
++die_is_in_cplus_plus(const Dwarf_Die *die);
++
++static bool
++die_is_in_c_or_cplusplus(const Dwarf_Die *die);
++
+ static bool
+ die_is_anonymous(const Dwarf_Die* die);
+
+@@ -654,6 +666,75 @@ compare_dies_during_canonicalization(reader& rdr,
+ static bool
+ get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child);
+
++/// Get the language used to generate a given DIE.
++///
++/// @param die the DIE to consider.
++///
++/// @param lang the resulting language.
++///
++/// @return true iff the language of the DIE was found.
++static bool
++get_die_language(const Dwarf_Die *die, translation_unit::language &lang)
++{
++ Dwarf_Die cu_die;
++ ABG_ASSERT(dwarf_diecu(const_cast<Dwarf_Die*>(die), &cu_die, 0, 0));
++
++ uint64_t l = 0;
++ if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l))
++ return false;
++
++ lang = dwarf_language_to_tu_language(l);
++ return true;
++}
++
++/// Test if a given DIE originates from a program written in the C
++/// language.
++///
++/// @param die the DIE to consider.
++///
++/// @return true iff @p die originates from a program in the C
++/// language.
++static bool
++die_is_in_c(const Dwarf_Die *die)
++{
++ translation_unit::language l = translation_unit::LANG_UNKNOWN;
++ if (!get_die_language(die, l))
++ return false;
++ return is_c_language(l);
++}
++
++/// Test if a given DIE originates from a program written in the C++
++/// language.
++///
++/// @param die the DIE to consider.
++///
++/// @return true iff @p die originates from a program in the C++
++/// language.
++static bool
++die_is_in_cplus_plus(const Dwarf_Die *die)
++{
++ translation_unit::language l = translation_unit::LANG_UNKNOWN;
++ if (!get_die_language(die, l))
++ return false;
++ return is_cplus_plus_language(l);
++}
++
++/// Test if a given DIE originates from a program written either in
++/// C or C++.
++///
++/// @param die the DIE to consider.
++///
++/// @return true iff @p die originates from a program written either in
++/// C or C++.
++static bool
++die_is_in_c_or_cplusplus(const Dwarf_Die *die)
++{
++ translation_unit::language l = translation_unit::LANG_UNKNOWN;
++ if (!get_die_language(die, l))
++ return false;
++ return (is_cplus_plus_language(l) || is_c_language(l));
++}
++
+ /// Compare a symbol name against another name, possibly demangling
+ /// the symbol_name before performing the comparison.
+ ///
+@@ -3320,75 +3401,6 @@ public:
+ return i->second;
+ }
+
+- /// Get the language used to generate a given DIE.
+- ///
+- /// @param die the DIE to consider.
+- ///
+- /// @param lang the resulting language.
+- ///
+- /// @return true iff the language of the DIE was found.
+- bool
+- get_die_language(const Dwarf_Die *die, translation_unit::language &lang) const
+- {
+- Dwarf_Die cu_die;
+- ABG_ASSERT(dwarf_diecu(const_cast<Dwarf_Die*>(die), &cu_die, 0, 0));
+-
+- uint64_t l = 0;
+- if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l))
+- return false;
+-
+- lang = dwarf_language_to_tu_language(l);
+- return true;
+- }
+-
+- /// Test if a given DIE originates from a program written in the C
+- /// language.
+- ///
+- /// @param die the DIE to consider.
+- ///
+- /// @return true iff @p die originates from a program in the C
+- /// language.
+- bool
+- die_is_in_c(const Dwarf_Die *die) const
+- {
+- translation_unit::language l = translation_unit::LANG_UNKNOWN;
+- if (!get_die_language(die, l))
+- return false;
+- return is_c_language(l);
+- }
+-
+- /// Test if a given DIE originates from a program written in the C++
+- /// language.
+- ///
+- /// @param die the DIE to consider.
+- ///
+- /// @return true iff @p die originates from a program in the C++
+- /// language.
+- bool
+- die_is_in_cplus_plus(const Dwarf_Die *die) const
+- {
+- translation_unit::language l = translation_unit::LANG_UNKNOWN;
+- if (!get_die_language(die, l))
+- return false;
+- return is_cplus_plus_language(l);
+- }
+-
+- /// Test if a given DIE originates from a program written either in
+- /// C or C++.
+- ///
+- /// @param die the DIE to consider.
+- ///
+- /// @return true iff @p die originates from a program written either in
+- /// C or C++.
+- bool
+- die_is_in_c_or_cplusplus(const Dwarf_Die *die) const
+- {
+- translation_unit::language l = translation_unit::LANG_UNKNOWN;
+- if (!get_die_language(die, l))
+- return false;
+- return (is_cplus_plus_language(l) || is_c_language(l));
+- }
+-
+ /// Check if we can assume the One Definition Rule[1] to be relevant
+ /// for the current translation unit.
+ ///
+@@ -9818,7 +9830,7 @@ die_function_signature(const reader& rdr,
+
+ translation_unit::language lang;
+ bool has_lang = false;
+- if ((has_lang = rdr.get_die_language(fn_die, lang)))
++ if ((has_lang = get_die_language(fn_die, lang)))
+ {
+ // In a binary originating from the C language, it's OK to use
+ // the linkage name of the function as a key for the map which
+@@ -10324,8 +10336,6 @@ compare_as_decl_and_type_dies(const reader &rdr,
+ /// in C++ for instance, that doesn't imply that the two functions are
+ /// equal.
+ ///
+-/// @param rdr the @ref reader to consider.
+-///
+ /// @param l the first function DIE to consider.
+ ///
+ /// @param r the second function DIE to consider.
+@@ -10333,8 +10343,7 @@ compare_as_decl_and_type_dies(const reader &rdr,
+ /// @return true iff the function represented by @p l have the same
+ /// linkage name as the function represented by @p r.
+ static bool
+-fn_die_equal_by_linkage_name(const reader &rdr,
+- const Dwarf_Die *l,
++fn_die_equal_by_linkage_name(const Dwarf_Die *l,
+ const Dwarf_Die *r)
+ {
+ if (!!l != !!r)
+@@ -10352,8 +10361,8 @@ fn_die_equal_by_linkage_name(const reader &rdr,
+ string llinkage_name = die_linkage_name(l),
+ rlinkage_name = die_linkage_name(r);
+
+- if (rdr.die_is_in_c_or_cplusplus(l)
+- && rdr.die_is_in_c_or_cplusplus(r))
++ if (die_is_in_c_or_cplusplus(l)
++ && die_is_in_c_or_cplusplus(r))
+ {
+ if (!llinkage_name.empty() && !rlinkage_name.empty())
+ return llinkage_name == rlinkage_name;
+@@ -11277,19 +11286,18 @@ compare_dies(const reader& rdr,
+ rdr.compare_count_++;
+
+ if (l_tag == DW_TAG_subprogram
+- && !fn_die_equal_by_linkage_name(rdr, l, r))
++ && !fn_die_equal_by_linkage_name(l, r))
+ {
+ SET_RESULT_TO_FALSE(result, l, r);
+ break;
+ }
+ else if (l_tag == DW_TAG_subprogram
+- && rdr.die_is_in_c(l) && rdr.die_is_in_c(r)
+- /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/)
++ && die_is_in_c(l) && die_is_in_c(r))
+ {
+ result = COMPARISON_RESULT_EQUAL;
+ break;
+ }
+- else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r))
++ else if (!die_is_in_c(l) && !die_is_in_c(r))
+ {
+ // In C, we cannot have two different functions with the
+ // same linkage name in a given binary. But here we are
+@@ -11914,7 +11922,7 @@ get_scope_die(const reader& rdr,
+ memcpy(&origin_die_mem, dye, sizeof(origin_die_mem));
+
+ translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
+- rdr.get_die_language(die, die_lang);
++ get_die_language(die, die_lang);
+ if (is_c_language(die_lang)
+ || rdr.die_parent_map(rdr.get_die_source(die)).empty())
+ {
+@@ -11974,7 +11982,7 @@ get_scope_for_die(reader& rdr,
+ const die_source source_of_die = rdr.get_die_source(die);
+
+ translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
+- rdr.get_die_language(die, die_lang);
++ get_die_language(die, die_lang);
+ if (is_c_language(die_lang)
+ || rdr.die_parent_map(source_of_die).empty())
+ {
+@@ -12342,10 +12350,17 @@ build_translation_unit_and_add_to_ir(reader& rdr,
+ return result;
+
+ result->set_is_constructed(false);
+-
++ int tag = dwarf_tag(&child);
+ do
+ if (rdr.load_undefined_interfaces()
+- && rdr.is_decl_die_with_undefined_symbol(&child))
++ && (rdr.is_decl_die_with_undefined_symbol(&child)
++ || tag == DW_TAG_class_type // Top-level classes might
++ // have undefined interfaces
++ // that need to be
++ // represented, so let's
++ // analyze them as well.
++ || ((tag == DW_TAG_union_type || tag == DW_TAG_structure_type)
++ && die_is_in_cplus_plus(&child))))
+ {
+ // Analyze undefined functions & variables for the purpose of
+ // analyzing compatibility matters.
+@@ -15013,7 +15028,7 @@ function_is_suppressed(const reader& rdr,
+
+ string fname = die_string_attribute(function_die, DW_AT_name);
+ string flinkage_name = die_linkage_name(function_die);
+- if (flinkage_name.empty() && rdr.die_is_in_c(function_die))
++ if (flinkage_name.empty() && die_is_in_c(function_die))
+ flinkage_name = fname;
+ string qualified_name = build_qualified_name(scope, fname);
+
+@@ -15190,7 +15205,7 @@ variable_is_suppressed(const reader& rdr,
+
+ string name = die_string_attribute(variable_die, DW_AT_name);
+ string linkage_name = die_linkage_name(variable_die);
+- if (linkage_name.empty() && rdr.die_is_in_c(variable_die))
++ if (linkage_name.empty() && die_is_in_c(variable_die))
+ linkage_name = name;
+ string qualified_name = build_qualified_name(scope, name);
+
+@@ -16049,7 +16064,7 @@ build_ir_node_from_die(reader& rdr,
+ bool var_is_cloned = false;
+
+ if (tag == DW_TAG_member)
+- ABG_ASSERT(!rdr.die_is_in_c(die));
++ ABG_ASSERT(!die_is_in_c(die));
+
+ if (die_die_attribute(die, DW_AT_specification, spec_die, false)
+ || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin,
+diff --git a/src/abg-reader.cc b/src/abg-reader.cc
+index b525a137..a91cfaf4 100644
+--- a/src/abg-reader.cc
++++ b/src/abg-reader.cc
+@@ -1270,7 +1270,8 @@ public:
+ if (!needed.empty())
+ corp.set_needed(needed);
+
+- string_elf_symbols_map_sptr fn_sym_db, var_sym_db;
++ string_elf_symbols_map_sptr fn_sym_db(new string_elf_symbols_map_type),
++ var_sym_db(new string_elf_symbols_map_type);
+
+ // Read the symbol databases.
+ read_symbol_db_from_input(*this, fn_sym_db, var_sym_db);
+@@ -1338,6 +1339,9 @@ public:
+ set_corpus_node(node);
+ }
+
++ corpus()->sort_functions();
++ corpus()->sort_variables();
++
+ status = STATUS_OK;
+ return corpus();
+ }
+@@ -1389,8 +1393,9 @@ build_elf_symbol(reader&, const xmlNodePtr, bool);
+ static elf_symbol_sptr
+ build_elf_symbol_from_reference(reader&, const xmlNodePtr);
+
+-static string_elf_symbols_map_sptr
+-build_elf_symbol_db(reader&, const xmlNodePtr, bool);
++static bool
++build_elf_symbol_db(reader&, const xmlNodePtr, bool,
++ string_elf_symbols_map_sptr&);
+
+ static function_decl::parameter_sptr
+ build_function_parameter (reader&, const xmlNodePtr);
+@@ -1898,9 +1903,9 @@ read_translation_unit_from_input(fe_iface& iface)
+ ///
+ /// @return true upon successful parsing, false otherwise.
+ static bool
+-read_symbol_db_from_input(reader& rdr,
+- string_elf_symbols_map_sptr& fn_symdb,
+- string_elf_symbols_map_sptr& var_symdb)
++read_symbol_db_from_input(reader& rdr,
++ string_elf_symbols_map_sptr& fn_symdb,
++ string_elf_symbols_map_sptr& var_symdb)
+ {
+ xml::reader_sptr reader = rdr.get_libxml_reader();
+ if (!reader)
+@@ -1917,13 +1922,20 @@ read_symbol_db_from_input(reader& rdr,
+ if (status != 1)
+ return false;
+
+- bool has_fn_syms = false, has_var_syms = false;
++ bool has_fn_syms = false, has_undefined_fn_syms = false,
++ has_var_syms = false, has_undefined_var_syms = false;
+ if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+ BAD_CAST("elf-function-symbols")))
+ has_fn_syms = true;
+ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+ BAD_CAST("elf-variable-symbols")))
+ has_var_syms = true;
++ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
++ BAD_CAST("undefined-elf-function-symbols")))
++ has_undefined_fn_syms = true;
++ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
++ BAD_CAST("undefined-elf-variable-symbols")))
++ has_undefined_var_syms = true;
+ else
+ break;
+
+@@ -1932,20 +1944,30 @@ read_symbol_db_from_input(reader& rdr,
+ return false;
+
+ if (has_fn_syms)
+- fn_symdb = build_elf_symbol_db(rdr, node, true);
++ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb);
++ else if (has_undefined_fn_syms)
++ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb);
+ else if (has_var_syms)
+- var_symdb = build_elf_symbol_db(rdr, node, false);
++ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb);
++ else if (has_undefined_var_syms)
++ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb);
+
+ xmlTextReaderNext(reader.get());
+ }
+ else
+ for (xmlNodePtr n = rdr.get_corpus_node(); n; n = xmlNextElementSibling(n))
+ {
+- bool has_fn_syms = false, has_var_syms = false;
++ bool has_fn_syms = false, has_undefined_fn_syms = false,
++ has_var_syms = false, has_undefined_var_syms = false;
+ if (xmlStrEqual(n->name, BAD_CAST("elf-function-symbols")))
+ has_fn_syms = true;
++ else if (xmlStrEqual(n->name, BAD_CAST("undefined-elf-function-symbols")))
++ has_undefined_fn_syms = true;
+ else if (xmlStrEqual(n->name, BAD_CAST("elf-variable-symbols")))
+ has_var_syms = true;
++ else if (xmlStrEqual(n->name,
++ BAD_CAST("undefined-elf-variable-symbols")))
++ has_undefined_var_syms = true;
+ else
+ {
+ rdr.set_corpus_node(n);
+@@ -1953,9 +1975,13 @@ read_symbol_db_from_input(reader& rdr,
+ }
+
+ if (has_fn_syms)
+- fn_symdb = build_elf_symbol_db(rdr, n, true);
++ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb);
++ else if (has_undefined_fn_syms)
++ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb);
+ else if (has_var_syms)
+- var_symdb = build_elf_symbol_db(rdr, n, false);
++ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb);
++ else if (has_undefined_var_syms)
++ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb);
+ else
+ break;
+ }
+@@ -3300,24 +3326,30 @@ build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node)
+ /// @param function_syms true if we should look for a function symbols
+ /// data base, false if we should look for a variable symbols data
+ /// base.
+-static string_elf_symbols_map_sptr
+-build_elf_symbol_db(reader& rdr,
+- const xmlNodePtr node,
+- bool function_syms)
++///
++/// @param map a pointer to the map to fill with the symbol database.
++///
++/// @return true if some elf symbols were found.
++static bool
++build_elf_symbol_db(reader& rdr,
++ const xmlNodePtr node,
++ bool function_syms,
++ string_elf_symbols_map_sptr& map)
+ {
+- string_elf_symbols_map_sptr map, nil;
+ string_elf_symbol_sptr_map_type id_sym_map;
+
+ if (!node)
+- return nil;
++ return false;
+
+ if (function_syms
+- && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols")))
+- return nil;
++ && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols"))
++ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-function-symbols")))
++ return false;
+
+ if (!function_syms
+- && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols")))
+- return nil;
++ && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols"))
++ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-variable-symbols")))
++ return false;
+
+ rdr.set_corpus_node(node);
+
+@@ -3336,9 +3368,8 @@ build_elf_symbol_db(reader& rdr,
+ }
+
+ if (id_sym_map.empty())
+- return nil;
++ return false;
+
+- map.reset(new string_elf_symbols_map_type);
+ string_elf_symbols_map_type::iterator it;
+ for (string_elf_symbol_sptr_map_type::const_iterator i = id_sym_map.begin();
+ i != id_sym_map.end();
+@@ -3374,7 +3405,7 @@ build_elf_symbol_db(reader& rdr,
+ }
+ }
+
+- return map;
++ return true;
+ }
+
+ /// Build a function parameter from a 'parameter' xml element node.
+diff --git a/src/abg-writer.cc b/src/abg-writer.cc
+index 408623ab..dafe706c 100644
+--- a/src/abg-writer.cc
++++ b/src/abg-writer.cc
+@@ -214,6 +214,7 @@ class write_context
+ bool m_write_corpus_path;
+ bool m_write_comp_dir;
+ bool m_write_elf_needed;
++ bool m_write_undefined_symbols;
+ bool m_write_parameter_names;
+ bool m_short_locs;
+ bool m_write_default_sizes;
+@@ -252,6 +253,7 @@ public:
+ m_write_corpus_path(true),
+ m_write_comp_dir(true),
+ m_write_elf_needed(true),
++ m_write_undefined_symbols(true),
+ m_write_parameter_names(true),
+ m_short_locs(false),
+ m_write_default_sizes(true),
+@@ -325,6 +327,20 @@ public:
+ set_write_elf_needed(bool f)
+ {m_write_elf_needed = f;}
+
++ /// Getter of the "undefined-symbols" option.
++ ///
++ /// @return true iff undefined symbols shall be emitted.
++ bool
++ get_write_undefined_symbols() const
++ {return m_write_undefined_symbols;}
++
++ /// Setter of the "undefined-symbols" option.
++ ///
++ /// @param f true iff undefined symbols shall be emitted.
++ void
++ set_write_undefined_symbols(bool f)
++ {m_write_undefined_symbols = f;}
++
+ /// Getter of the default-sizes option.
+ ///
+ /// @return true iff default size-in-bits needs to be emitted
+@@ -793,6 +809,20 @@ public:
+ type_is_emitted(const type_base_sptr& t) const
+ {return type_is_emitted(t.get());}
+
++ /// Test if a given decl has been written out to the XML output.
++ ///
++ /// @param the decl to consider.
++ ///
++ /// @return true if the decl has already been emitted, false
++ /// otherwise.
++ bool
++ decl_is_emitted(const decl_base& decl) const
++ {
++ string repr = decl.get_pretty_representation(true);
++ interned_string irepr = decl.get_environment().intern(repr);
++ return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end();
++ }
++
+ /// Test if a given decl has been written out to the XML output.
+ ///
+ /// @param the decl to consider.
+@@ -901,8 +931,14 @@ static void write_voffset(function_decl_sptr, ostream&);
+ static void write_elf_symbol_type(elf_symbol::type, ostream&);
+ static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
+ static bool write_elf_symbol_aliases(const elf_symbol&, ostream&);
+-static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
+-static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
++static bool write_elf_symbol_reference(write_context&,
++ const elf_symbol&,
++ const corpus& abi,
++ ostream&);
++static bool write_elf_symbol_reference(write_context&,
++ const elf_symbol_sptr,
++ const corpus& abi,
++ ostream&);
+ static void write_is_declaration_only(const decl_base_sptr&, ostream&);
+ static void write_is_struct(const class_decl_sptr&, ostream&);
+ static void write_is_anonymous(const decl_base_sptr&, ostream&);
+@@ -1766,14 +1802,36 @@ write_elf_symbol_aliases(const elf_symbol& sym, ostream& out)
+ /// Write an XML attribute for the reference to a symbol for the
+ /// current decl.
+ ///
++///
++/// @param ctxt the current write context to consider.
++///
+ /// @param sym the symbol to consider.
+ ///
++/// @param abi the ABI corpus the symbol @p sym is supposed to belong
++/// to. If the symbol doesn't belong to that corpus, then the
++/// reference is not be emitted.
++///
+ /// @param o the output stream to write the attribute to.
+ ///
+ /// @return true upon successful completion.
+ static bool
+-write_elf_symbol_reference(const elf_symbol& sym, ostream& o)
++write_elf_symbol_reference(write_context& ctxt,
++ const elf_symbol& sym,
++ const corpus& abi,
++ ostream& o)
+ {
++ elf_symbol_sptr s = abi.lookup_function_symbol(sym);
++ if (!s)
++ s = abi.lookup_variable_symbol(sym);
++
++ if (// If that symbol wasn't found in the current corpus ...
++ !s
++ // ... or we were NOT asked to represent undefined symbols and
++ // yet that symbol is undefined ...
++ || (!ctxt.get_write_undefined_symbols() && !s->is_defined()))
++ // Then do not emit this symbol reference.
++ return false;
++
+ const elf_symbol* main = sym.get_main_symbol().get();
+ const elf_symbol* alias = &sym;
+ bool found = !alias->is_suppressed();
+@@ -1804,18 +1862,27 @@ write_elf_symbol_reference(const elf_symbol& sym, ostream& o)
+ /// Write an XML attribute for the reference to a symbol for the
+ /// current decl.
+ ///
++/// @param ctxt the write context to consider.
++///
+ /// @param sym the symbol to consider.
+ ///
++/// @param abi the ABI corpus the symbol @p sym is supposed to belong
++/// to. If the symbol doesn't belong to that corpus, then the
++/// reference is not be emitted.
++///
+ /// @param o the output stream to write the attribute to.
+ ///
+ /// @return true upon successful completion.
+ static bool
+-write_elf_symbol_reference(const elf_symbol_sptr sym, ostream& o)
++write_elf_symbol_reference(write_context& ctxt,
++ const elf_symbol_sptr sym,
++ const corpus& abi,
++ ostream& o)
+ {
+ if (!sym)
+ return false;
+
+- return write_elf_symbol_reference(*sym, o);
++ return write_elf_symbol_reference(ctxt, *sym, abi, o);
+ }
+
+ /// Serialize the attributes "constructor", "destructor" or "static"
+@@ -2255,6 +2322,18 @@ void
+ set_write_elf_needed(write_context& ctxt, bool flag)
+ {ctxt.set_write_elf_needed(flag);}
+
++/// Set the 'undefined-symbols' flag.
++///
++/// When this flag is set then the XML writer will emit corpus
++/// information about the undefined function and variable symbols.
++///
++/// @param ctxt the context to set this flag on to.
++///
++/// @param flag the new value of the 'undefined-symbols' flag.
++void
++set_write_undefined_symbols(write_context& ctxt, bool flag)
++{ctxt.set_write_undefined_symbols(flag);}
++
+ /// Set the 'default-sizes' flag.
+ ///
+ /// When this flag is set then the XML writer will emit default
+@@ -2549,6 +2628,32 @@ write_translation_unit(write_context& ctxt,
+ }
+ }
+
++ // Write the undefined functions that belong to this translation
++ // unit
++ if (const abigail::ir::corpus* abi = tu.get_corpus())
++ for (auto undefined_function : abi->get_sorted_undefined_functions())
++ {
++ function_decl_sptr f(const_cast<function_decl*>(undefined_function),
++ noop_deleter());
++ if (f->get_translation_unit() != &tu || ctxt.decl_is_emitted(f))
++ continue;
++
++ write_decl(f, ctxt, indent + c.get_xml_element_indent());
++ }
++
++ // Write the undefined variables that belong to this translation
++ // unit
++ if (const abigail::ir::corpus* abi = tu.get_corpus())
++ for (auto undefined_var : abi->get_sorted_undefined_variables())
++ {
++ var_decl_sptr v(const_cast<var_decl*>(undefined_var),
++ noop_deleter());
++ if (v->get_translation_unit() != &tu || ctxt.decl_is_emitted(v))
++ continue;
++
++ write_decl(v, ctxt, indent + c.get_xml_element_indent());
++ }
++
+ write_referenced_types(ctxt, tu, indent, is_last);
+
+ // Now handle all function types that were not only referenced by
+@@ -3468,8 +3573,8 @@ write_var_decl(const var_decl_sptr& decl, write_context& ctxt,
+ write_location(decl, ctxt);
+
+ if (elf_symbol_sptr sym = decl->get_symbol())
+- if (sym->is_defined())
+- write_elf_symbol_reference(decl->get_symbol(), o);
++ if (corpus* abi = decl->get_corpus())
++ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o);
+
+ o << "/>\n";
+
+@@ -3526,8 +3631,8 @@ write_function_decl(const function_decl_sptr& decl, write_context& ctxt,
+ : decl->get_translation_unit()->get_address_size()),
+ 0);
+ if (elf_symbol_sptr sym = decl->get_symbol())
+- if (sym->is_defined())
+- write_elf_symbol_reference(decl->get_symbol(), o);
++ if (corpus* abi = decl->get_corpus())
++ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o);
+
+ o << ">\n";
+
+@@ -4734,6 +4839,35 @@ write_corpus(write_context& ctxt,
+ out << "</elf-variable-symbols>\n";
+ }
+
++ // Write the undefined function symbols database.
++ if (ctxt.get_write_undefined_symbols()
++ && !corpus->get_sorted_undefined_fun_symbols().empty())
++ {
++ do_indent_to_level(ctxt, indent, 1);
++ out << "<undefined-elf-function-symbols>\n";
++
++ write_elf_symbols_table(corpus->get_sorted_undefined_fun_symbols(), ctxt,
++ get_indent_to_level(ctxt, indent, 2));
++
++ do_indent_to_level(ctxt, indent, 1);
++ out << "</undefined-elf-function-symbols>\n";
++ }
++
++
++ // Write the undefined variable symbols database.
++ if (ctxt.get_write_undefined_symbols()
++ && !corpus->get_sorted_undefined_var_symbols().empty())
++ {
++ do_indent_to_level(ctxt, indent, 1);
++ out << "<undefined-elf-variable-symbols>\n";
++
++ write_elf_symbols_table(corpus->get_sorted_undefined_var_symbols(), ctxt,
++ get_indent_to_level(ctxt, indent, 2));
++
++ do_indent_to_level(ctxt, indent, 1);
++ out << "</undefined-elf-variable-symbols>\n";
++ }
++
+ // Now write the translation units.
+ unsigned nb_tus = corpus->get_translation_units().size(), n = 0;
+ for (translation_units::const_iterator i =
+diff --git a/tests/test-annotate.cc b/tests/test-annotate.cc
+index cb9c8af6..8ddd93fb 100644
+--- a/tests/test-annotate.cc
++++ b/tests/test-annotate.cc
+@@ -158,7 +158,7 @@ main()
+ string abidw;
+
+ abidw = string(get_build_dir()) + "/tools/abidw "
+- "--annotate --no-corpus-path --no-architecture";
++ "--annotate --no-corpus-path --no-architecture --no-load-undefined-interfaces";
+ for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s)
+ {
+ bool is_ok = true;
+diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc
+index 8570d774..a391c0f1 100644
+--- a/tests/test-read-dwarf.cc
++++ b/tests/test-read-dwarf.cc
+@@ -651,7 +651,7 @@ test_task_dwarf::perform()
+ if (spec.type_id_style == HASH_TYPE_ID_STYLE)
+ type_id_style = "hash";
+
+- string cmd = abidw + " --no-architecture "
++ string cmd = abidw + " --no-architecture --no-load-undefined-interfaces"
+ + " --type-id-style " + type_id_style
+ + " --no-corpus-path "
+ + drop_private_types + " " + in_elf_path
+diff --git a/tools/abidw.cc b/tools/abidw.cc
+index c8a44dda..7ea12908 100644
+--- a/tools/abidw.cc
++++ b/tools/abidw.cc
+@@ -109,6 +109,7 @@ struct options
+ bool short_locs;
+ bool default_sizes;
+ bool load_all_types;
++ bool load_undefined_interfaces;
+ bool linux_kernel_mode;
+ bool corpus_group_for_linux;
+ bool show_stats;
+@@ -155,6 +156,7 @@ struct options
+ short_locs(false),
+ default_sizes(true),
+ load_all_types(),
++ load_undefined_interfaces(true),
+ linux_kernel_mode(true),
+ corpus_group_for_linux(false),
+ show_stats(),
+@@ -233,6 +235,8 @@ display_usage(const string& prog_name, ostream& out)
+ "debug info of <elf-path>, and show its base name\n"
+ << " --load-all-types read all types including those not reachable from "
+ "exported declarations\n"
++ << " --no-load-undefined-interfaces do not consider undefined "
++ "interfaces from the binary"
+ << " --no-linux-kernel-mode don't consider the input binary as "
+ "a Linux Kernel binary\n"
+ << " --kmi-whitelist|-w path to a linux kernel "
+@@ -445,6 +449,8 @@ parse_command_line(int argc, char* argv[], options& opts)
+ }
+ else if (!strcmp(argv[i], "--load-all-types"))
+ opts.load_all_types = true;
++ else if (!strcmp(argv[i], "--no-load-undefined-interfaces"))
++ opts.load_undefined_interfaces = false;
+ else if (!strcmp(argv[i], "--drop-private-types"))
+ opts.drop_private_types = true;
+ else if (!strcmp(argv[i], "--drop-undefined-syms"))
+@@ -614,6 +620,7 @@ set_generic_options(abigail::elf_based_reader& rdr, options& opts)
+ opts.leverage_dwarf_factorization;
+ rdr.options().assume_odr_for_cplusplus =
+ opts.assume_odr_for_cplusplus;
++ rdr.options().load_undefined_interfaces = opts.load_undefined_interfaces;
+ }
+
+ /// Load an ABI @ref corpus (the internal representation of the ABI of
+--
+2.39.3
+
@@ -379,6 +379,18 @@ get_scope_die(const reader& rdr,
size_t where_offset,
Dwarf_Die& scope_die);
+static bool
+get_die_language(const Dwarf_Die *die, translation_unit::language &lang) ;
+
+static bool
+die_is_in_c(const Dwarf_Die *die);
+
+static bool
+die_is_in_cplus_plus(const Dwarf_Die *die);
+
+static bool
+die_is_in_c_or_cplusplus(const Dwarf_Die *die);
+
static bool
die_is_anonymous(const Dwarf_Die* die);
@@ -654,6 +666,75 @@ compare_dies_during_canonicalization(reader& rdr,
static bool
get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child);
+/// Get the language used to generate a given DIE.
+///
+/// @param die the DIE to consider.
+///
+/// @param lang the resulting language.
+///
+/// @return true iff the language of the DIE was found.
+static bool
+get_die_language(const Dwarf_Die *die, translation_unit::language &lang)
+{
+ Dwarf_Die cu_die;
+ ABG_ASSERT(dwarf_diecu(const_cast<Dwarf_Die*>(die), &cu_die, 0, 0));
+
+ uint64_t l = 0;
+ if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l))
+ return false;
+
+ lang = dwarf_language_to_tu_language(l);
+ return true;
+}
+
+/// Test if a given DIE originates from a program written in the C
+/// language.
+///
+/// @param die the DIE to consider.
+///
+/// @return true iff @p die originates from a program in the C
+/// language.
+static bool
+die_is_in_c(const Dwarf_Die *die)
+{
+ translation_unit::language l = translation_unit::LANG_UNKNOWN;
+ if (!get_die_language(die, l))
+ return false;
+ return is_c_language(l);
+}
+
+/// Test if a given DIE originates from a program written in the C++
+/// language.
+///
+/// @param die the DIE to consider.
+///
+/// @return true iff @p die originates from a program in the C++
+/// language.
+static bool
+die_is_in_cplus_plus(const Dwarf_Die *die)
+{
+ translation_unit::language l = translation_unit::LANG_UNKNOWN;
+ if (!get_die_language(die, l))
+ return false;
+ return is_cplus_plus_language(l);
+}
+
+/// Test if a given DIE originates from a program written either in
+/// C or C++.
+///
+/// @param die the DIE to consider.
+///
+/// @return true iff @p die originates from a program written either in
+/// C or C++.
+static bool
+die_is_in_c_or_cplusplus(const Dwarf_Die *die)
+{
+ translation_unit::language l = translation_unit::LANG_UNKNOWN;
+ if (!get_die_language(die, l))
+ return false;
+ return (is_cplus_plus_language(l) || is_c_language(l));
+}
+
/// Compare a symbol name against another name, possibly demangling
/// the symbol_name before performing the comparison.
///
@@ -3320,75 +3401,6 @@ public:
return i->second;
}
- /// Get the language used to generate a given DIE.
- ///
- /// @param die the DIE to consider.
- ///
- /// @param lang the resulting language.
- ///
- /// @return true iff the language of the DIE was found.
- bool
- get_die_language(const Dwarf_Die *die, translation_unit::language &lang) const
- {
- Dwarf_Die cu_die;
- ABG_ASSERT(dwarf_diecu(const_cast<Dwarf_Die*>(die), &cu_die, 0, 0));
-
- uint64_t l = 0;
- if (!die_unsigned_constant_attribute(&cu_die, DW_AT_language, l))
- return false;
-
- lang = dwarf_language_to_tu_language(l);
- return true;
- }
-
- /// Test if a given DIE originates from a program written in the C
- /// language.
- ///
- /// @param die the DIE to consider.
- ///
- /// @return true iff @p die originates from a program in the C
- /// language.
- bool
- die_is_in_c(const Dwarf_Die *die) const
- {
- translation_unit::language l = translation_unit::LANG_UNKNOWN;
- if (!get_die_language(die, l))
- return false;
- return is_c_language(l);
- }
-
- /// Test if a given DIE originates from a program written in the C++
- /// language.
- ///
- /// @param die the DIE to consider.
- ///
- /// @return true iff @p die originates from a program in the C++
- /// language.
- bool
- die_is_in_cplus_plus(const Dwarf_Die *die) const
- {
- translation_unit::language l = translation_unit::LANG_UNKNOWN;
- if (!get_die_language(die, l))
- return false;
- return is_cplus_plus_language(l);
- }
-
- /// Test if a given DIE originates from a program written either in
- /// C or C++.
- ///
- /// @param die the DIE to consider.
- ///
- /// @return true iff @p die originates from a program written either in
- /// C or C++.
- bool
- die_is_in_c_or_cplusplus(const Dwarf_Die *die) const
- {
- translation_unit::language l = translation_unit::LANG_UNKNOWN;
- if (!get_die_language(die, l))
- return false;
- return (is_cplus_plus_language(l) || is_c_language(l));
- }
-
/// Check if we can assume the One Definition Rule[1] to be relevant
/// for the current translation unit.
///
@@ -9818,7 +9830,7 @@ die_function_signature(const reader& rdr,
translation_unit::language lang;
bool has_lang = false;
- if ((has_lang = rdr.get_die_language(fn_die, lang)))
+ if ((has_lang = get_die_language(fn_die, lang)))
{
// In a binary originating from the C language, it's OK to use
// the linkage name of the function as a key for the map which
@@ -10324,8 +10336,6 @@ compare_as_decl_and_type_dies(const reader &rdr,
/// in C++ for instance, that doesn't imply that the two functions are
/// equal.
///
-/// @param rdr the @ref reader to consider.
-///
/// @param l the first function DIE to consider.
///
/// @param r the second function DIE to consider.
@@ -10333,8 +10343,7 @@ compare_as_decl_and_type_dies(const reader &rdr,
/// @return true iff the function represented by @p l have the same
/// linkage name as the function represented by @p r.
static bool
-fn_die_equal_by_linkage_name(const reader &rdr,
- const Dwarf_Die *l,
+fn_die_equal_by_linkage_name(const Dwarf_Die *l,
const Dwarf_Die *r)
{
if (!!l != !!r)
@@ -10352,8 +10361,8 @@ fn_die_equal_by_linkage_name(const reader &rdr,
string llinkage_name = die_linkage_name(l),
rlinkage_name = die_linkage_name(r);
- if (rdr.die_is_in_c_or_cplusplus(l)
- && rdr.die_is_in_c_or_cplusplus(r))
+ if (die_is_in_c_or_cplusplus(l)
+ && die_is_in_c_or_cplusplus(r))
{
if (!llinkage_name.empty() && !rlinkage_name.empty())
return llinkage_name == rlinkage_name;
@@ -11277,19 +11286,18 @@ compare_dies(const reader& rdr,
rdr.compare_count_++;
if (l_tag == DW_TAG_subprogram
- && !fn_die_equal_by_linkage_name(rdr, l, r))
+ && !fn_die_equal_by_linkage_name(l, r))
{
SET_RESULT_TO_FALSE(result, l, r);
break;
}
else if (l_tag == DW_TAG_subprogram
- && rdr.die_is_in_c(l) && rdr.die_is_in_c(r)
- /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/)
+ && die_is_in_c(l) && die_is_in_c(r))
{
result = COMPARISON_RESULT_EQUAL;
break;
}
- else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r))
+ else if (!die_is_in_c(l) && !die_is_in_c(r))
{
// In C, we cannot have two different functions with the
// same linkage name in a given binary. But here we are
@@ -11914,7 +11922,7 @@ get_scope_die(const reader& rdr,
memcpy(&origin_die_mem, dye, sizeof(origin_die_mem));
translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
- rdr.get_die_language(die, die_lang);
+ get_die_language(die, die_lang);
if (is_c_language(die_lang)
|| rdr.die_parent_map(rdr.get_die_source(die)).empty())
{
@@ -11974,7 +11982,7 @@ get_scope_for_die(reader& rdr,
const die_source source_of_die = rdr.get_die_source(die);
translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
- rdr.get_die_language(die, die_lang);
+ get_die_language(die, die_lang);
if (is_c_language(die_lang)
|| rdr.die_parent_map(source_of_die).empty())
{
@@ -12342,10 +12350,17 @@ build_translation_unit_and_add_to_ir(reader& rdr,
return result;
result->set_is_constructed(false);
-
+ int tag = dwarf_tag(&child);
do
if (rdr.load_undefined_interfaces()
- && rdr.is_decl_die_with_undefined_symbol(&child))
+ && (rdr.is_decl_die_with_undefined_symbol(&child)
+ || tag == DW_TAG_class_type // Top-level classes might
+ // have undefined interfaces
+ // that need to be
+ // represented, so let's
+ // analyze them as well.
+ || ((tag == DW_TAG_union_type || tag == DW_TAG_structure_type)
+ && die_is_in_cplus_plus(&child))))
{
// Analyze undefined functions & variables for the purpose of
// analyzing compatibility matters.
@@ -15013,7 +15028,7 @@ function_is_suppressed(const reader& rdr,
string fname = die_string_attribute(function_die, DW_AT_name);
string flinkage_name = die_linkage_name(function_die);
- if (flinkage_name.empty() && rdr.die_is_in_c(function_die))
+ if (flinkage_name.empty() && die_is_in_c(function_die))
flinkage_name = fname;
string qualified_name = build_qualified_name(scope, fname);
@@ -15190,7 +15205,7 @@ variable_is_suppressed(const reader& rdr,
string name = die_string_attribute(variable_die, DW_AT_name);
string linkage_name = die_linkage_name(variable_die);
- if (linkage_name.empty() && rdr.die_is_in_c(variable_die))
+ if (linkage_name.empty() && die_is_in_c(variable_die))
linkage_name = name;
string qualified_name = build_qualified_name(scope, name);
@@ -16050,7 +16065,7 @@ build_ir_node_from_die(reader& rdr,
bool var_is_cloned = false;
if (tag == DW_TAG_member)
- ABG_ASSERT(!rdr.die_is_in_c(die));
+ ABG_ASSERT(!die_is_in_c(die));
if (die_die_attribute(die, DW_AT_specification, spec_die, false)
|| (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin,
@@ -1270,7 +1270,8 @@ public:
if (!needed.empty())
corp.set_needed(needed);
- string_elf_symbols_map_sptr fn_sym_db, var_sym_db;
+ string_elf_symbols_map_sptr fn_sym_db(new string_elf_symbols_map_type),
+ var_sym_db(new string_elf_symbols_map_type);
// Read the symbol databases.
read_symbol_db_from_input(*this, fn_sym_db, var_sym_db);
@@ -1338,6 +1339,9 @@ public:
set_corpus_node(node);
}
+ corpus()->sort_functions();
+ corpus()->sort_variables();
+
status = STATUS_OK;
return corpus();
}
@@ -1389,8 +1393,9 @@ build_elf_symbol(reader&, const xmlNodePtr, bool);
static elf_symbol_sptr
build_elf_symbol_from_reference(reader&, const xmlNodePtr);
-static string_elf_symbols_map_sptr
-build_elf_symbol_db(reader&, const xmlNodePtr, bool);
+static bool
+build_elf_symbol_db(reader&, const xmlNodePtr, bool,
+ string_elf_symbols_map_sptr&);
static function_decl::parameter_sptr
build_function_parameter (reader&, const xmlNodePtr);
@@ -1898,9 +1903,9 @@ read_translation_unit_from_input(fe_iface& iface)
///
/// @return true upon successful parsing, false otherwise.
static bool
-read_symbol_db_from_input(reader& rdr,
- string_elf_symbols_map_sptr& fn_symdb,
- string_elf_symbols_map_sptr& var_symdb)
+read_symbol_db_from_input(reader& rdr,
+ string_elf_symbols_map_sptr& fn_symdb,
+ string_elf_symbols_map_sptr& var_symdb)
{
xml::reader_sptr reader = rdr.get_libxml_reader();
if (!reader)
@@ -1917,13 +1922,20 @@ read_symbol_db_from_input(reader& rdr,
if (status != 1)
return false;
- bool has_fn_syms = false, has_var_syms = false;
+ bool has_fn_syms = false, has_undefined_fn_syms = false,
+ has_var_syms = false, has_undefined_var_syms = false;
if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
BAD_CAST("elf-function-symbols")))
has_fn_syms = true;
else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
BAD_CAST("elf-variable-symbols")))
has_var_syms = true;
+ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+ BAD_CAST("undefined-elf-function-symbols")))
+ has_undefined_fn_syms = true;
+ else if (xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
+ BAD_CAST("undefined-elf-variable-symbols")))
+ has_undefined_var_syms = true;
else
break;
@@ -1932,20 +1944,30 @@ read_symbol_db_from_input(reader& rdr,
return false;
if (has_fn_syms)
- fn_symdb = build_elf_symbol_db(rdr, node, true);
+ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb);
+ else if (has_undefined_fn_syms)
+ build_elf_symbol_db(rdr, node, /*function_sym=*/true, fn_symdb);
else if (has_var_syms)
- var_symdb = build_elf_symbol_db(rdr, node, false);
+ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb);
+ else if (has_undefined_var_syms)
+ build_elf_symbol_db(rdr, node, /*function_sym=*/false, var_symdb);
xmlTextReaderNext(reader.get());
}
else
for (xmlNodePtr n = rdr.get_corpus_node(); n; n = xmlNextElementSibling(n))
{
- bool has_fn_syms = false, has_var_syms = false;
+ bool has_fn_syms = false, has_undefined_fn_syms = false,
+ has_var_syms = false, has_undefined_var_syms = false;
if (xmlStrEqual(n->name, BAD_CAST("elf-function-symbols")))
has_fn_syms = true;
+ else if (xmlStrEqual(n->name, BAD_CAST("undefined-elf-function-symbols")))
+ has_undefined_fn_syms = true;
else if (xmlStrEqual(n->name, BAD_CAST("elf-variable-symbols")))
has_var_syms = true;
+ else if (xmlStrEqual(n->name,
+ BAD_CAST("undefined-elf-variable-symbols")))
+ has_undefined_var_syms = true;
else
{
rdr.set_corpus_node(n);
@@ -1953,9 +1975,13 @@ read_symbol_db_from_input(reader& rdr,
}
if (has_fn_syms)
- fn_symdb = build_elf_symbol_db(rdr, n, true);
+ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb);
+ else if (has_undefined_fn_syms)
+ build_elf_symbol_db(rdr, n, /*function_sym=*/true, fn_symdb);
else if (has_var_syms)
- var_symdb = build_elf_symbol_db(rdr, n, false);
+ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb);
+ else if (has_undefined_var_syms)
+ build_elf_symbol_db(rdr, n, /*function_sym=*/false, var_symdb);
else
break;
}
@@ -3300,24 +3326,30 @@ build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node)
/// @param function_syms true if we should look for a function symbols
/// data base, false if we should look for a variable symbols data
/// base.
-static string_elf_symbols_map_sptr
-build_elf_symbol_db(reader& rdr,
- const xmlNodePtr node,
- bool function_syms)
+///
+/// @param map a pointer to the map to fill with the symbol database.
+///
+/// @return true if some elf symbols were found.
+static bool
+build_elf_symbol_db(reader& rdr,
+ const xmlNodePtr node,
+ bool function_syms,
+ string_elf_symbols_map_sptr& map)
{
- string_elf_symbols_map_sptr map, nil;
string_elf_symbol_sptr_map_type id_sym_map;
if (!node)
- return nil;
+ return false;
if (function_syms
- && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols")))
- return nil;
+ && !xmlStrEqual(node->name, BAD_CAST("elf-function-symbols"))
+ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-function-symbols")))
+ return false;
if (!function_syms
- && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols")))
- return nil;
+ && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols"))
+ && !xmlStrEqual(node->name, BAD_CAST("undefined-elf-variable-symbols")))
+ return false;
rdr.set_corpus_node(node);
@@ -3336,9 +3368,8 @@ build_elf_symbol_db(reader& rdr,
}
if (id_sym_map.empty())
- return nil;
+ return false;
- map.reset(new string_elf_symbols_map_type);
string_elf_symbols_map_type::iterator it;
for (string_elf_symbol_sptr_map_type::const_iterator i = id_sym_map.begin();
i != id_sym_map.end();
@@ -3374,7 +3405,7 @@ build_elf_symbol_db(reader& rdr,
}
}
- return map;
+ return true;
}
/// Build a function parameter from a 'parameter' xml element node.
@@ -214,6 +214,7 @@ class write_context
bool m_write_corpus_path;
bool m_write_comp_dir;
bool m_write_elf_needed;
+ bool m_write_undefined_symbols;
bool m_write_parameter_names;
bool m_short_locs;
bool m_write_default_sizes;
@@ -252,6 +253,7 @@ public:
m_write_corpus_path(true),
m_write_comp_dir(true),
m_write_elf_needed(true),
+ m_write_undefined_symbols(true),
m_write_parameter_names(true),
m_short_locs(false),
m_write_default_sizes(true),
@@ -325,6 +327,20 @@ public:
set_write_elf_needed(bool f)
{m_write_elf_needed = f;}
+ /// Getter of the "undefined-symbols" option.
+ ///
+ /// @return true iff undefined symbols shall be emitted.
+ bool
+ get_write_undefined_symbols() const
+ {return m_write_undefined_symbols;}
+
+ /// Setter of the "undefined-symbols" option.
+ ///
+ /// @param f true iff undefined symbols shall be emitted.
+ void
+ set_write_undefined_symbols(bool f)
+ {m_write_undefined_symbols = f;}
+
/// Getter of the default-sizes option.
///
/// @return true iff default size-in-bits needs to be emitted
@@ -793,6 +809,20 @@ public:
type_is_emitted(const type_base_sptr& t) const
{return type_is_emitted(t.get());}
+ /// Test if a given decl has been written out to the XML output.
+ ///
+ /// @param the decl to consider.
+ ///
+ /// @return true if the decl has already been emitted, false
+ /// otherwise.
+ bool
+ decl_is_emitted(const decl_base& decl) const
+ {
+ string repr = decl.get_pretty_representation(true);
+ interned_string irepr = decl.get_environment().intern(repr);
+ return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end();
+ }
+
/// Test if a given decl has been written out to the XML output.
///
/// @param the decl to consider.
@@ -901,8 +931,14 @@ static void write_voffset(function_decl_sptr, ostream&);
static void write_elf_symbol_type(elf_symbol::type, ostream&);
static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
static bool write_elf_symbol_aliases(const elf_symbol&, ostream&);
-static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
-static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
+static bool write_elf_symbol_reference(write_context&,
+ const elf_symbol&,
+ const corpus& abi,
+ ostream&);
+static bool write_elf_symbol_reference(write_context&,
+ const elf_symbol_sptr,
+ const corpus& abi,
+ ostream&);
static void write_is_declaration_only(const decl_base_sptr&, ostream&);
static void write_is_struct(const class_decl_sptr&, ostream&);
static void write_is_anonymous(const decl_base_sptr&, ostream&);
@@ -1766,14 +1802,36 @@ write_elf_symbol_aliases(const elf_symbol& sym, ostream& out)
/// Write an XML attribute for the reference to a symbol for the
/// current decl.
///
+///
+/// @param ctxt the current write context to consider.
+///
/// @param sym the symbol to consider.
///
+/// @param abi the ABI corpus the symbol @p sym is supposed to belong
+/// to. If the symbol doesn't belong to that corpus, then the
+/// reference is not be emitted.
+///
/// @param o the output stream to write the attribute to.
///
/// @return true upon successful completion.
static bool
-write_elf_symbol_reference(const elf_symbol& sym, ostream& o)
+write_elf_symbol_reference(write_context& ctxt,
+ const elf_symbol& sym,
+ const corpus& abi,
+ ostream& o)
{
+ elf_symbol_sptr s = abi.lookup_function_symbol(sym);
+ if (!s)
+ s = abi.lookup_variable_symbol(sym);
+
+ if (// If that symbol wasn't found in the current corpus ...
+ !s
+ // ... or we were NOT asked to represent undefined symbols and
+ // yet that symbol is undefined ...
+ || (!ctxt.get_write_undefined_symbols() && !s->is_defined()))
+ // Then do not emit this symbol reference.
+ return false;
+
const elf_symbol* main = sym.get_main_symbol().get();
const elf_symbol* alias = &sym;
bool found = !alias->is_suppressed();
@@ -1804,18 +1862,27 @@ write_elf_symbol_reference(const elf_symbol& sym, ostream& o)
/// Write an XML attribute for the reference to a symbol for the
/// current decl.
///
+/// @param ctxt the write context to consider.
+///
/// @param sym the symbol to consider.
///
+/// @param abi the ABI corpus the symbol @p sym is supposed to belong
+/// to. If the symbol doesn't belong to that corpus, then the
+/// reference is not be emitted.
+///
/// @param o the output stream to write the attribute to.
///
/// @return true upon successful completion.
static bool
-write_elf_symbol_reference(const elf_symbol_sptr sym, ostream& o)
+write_elf_symbol_reference(write_context& ctxt,
+ const elf_symbol_sptr sym,
+ const corpus& abi,
+ ostream& o)
{
if (!sym)
return false;
- return write_elf_symbol_reference(*sym, o);
+ return write_elf_symbol_reference(ctxt, *sym, abi, o);
}
/// Serialize the attributes "constructor", "destructor" or "static"
@@ -2255,6 +2322,18 @@ void
set_write_elf_needed(write_context& ctxt, bool flag)
{ctxt.set_write_elf_needed(flag);}
+/// Set the 'undefined-symbols' flag.
+///
+/// When this flag is set then the XML writer will emit corpus
+/// information about the undefined function and variable symbols.
+///
+/// @param ctxt the context to set this flag on to.
+///
+/// @param flag the new value of the 'undefined-symbols' flag.
+void
+set_write_undefined_symbols(write_context& ctxt, bool flag)
+{ctxt.set_write_undefined_symbols(flag);}
+
/// Set the 'default-sizes' flag.
///
/// When this flag is set then the XML writer will emit default
@@ -2549,6 +2628,32 @@ write_translation_unit(write_context& ctxt,
}
}
+ // Write the undefined functions that belong to this translation
+ // unit
+ if (const abigail::ir::corpus* abi = tu.get_corpus())
+ for (auto undefined_function : abi->get_sorted_undefined_functions())
+ {
+ function_decl_sptr f(const_cast<function_decl*>(undefined_function),
+ noop_deleter());
+ if (f->get_translation_unit() != &tu || ctxt.decl_is_emitted(f))
+ continue;
+
+ write_decl(f, ctxt, indent + c.get_xml_element_indent());
+ }
+
+ // Write the undefined variables that belong to this translation
+ // unit
+ if (const abigail::ir::corpus* abi = tu.get_corpus())
+ for (auto undefined_var : abi->get_sorted_undefined_variables())
+ {
+ var_decl_sptr v(const_cast<var_decl*>(undefined_var),
+ noop_deleter());
+ if (v->get_translation_unit() != &tu || ctxt.decl_is_emitted(v))
+ continue;
+
+ write_decl(v, ctxt, indent + c.get_xml_element_indent());
+ }
+
write_referenced_types(ctxt, tu, indent, is_last);
// Now handle all function types that were not only referenced by
@@ -3468,8 +3573,8 @@ write_var_decl(const var_decl_sptr& decl, write_context& ctxt,
write_location(decl, ctxt);
if (elf_symbol_sptr sym = decl->get_symbol())
- if (sym->is_defined())
- write_elf_symbol_reference(decl->get_symbol(), o);
+ if (corpus* abi = decl->get_corpus())
+ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o);
o << "/>\n";
@@ -3526,8 +3631,8 @@ write_function_decl(const function_decl_sptr& decl, write_context& ctxt,
: decl->get_translation_unit()->get_address_size()),
0);
if (elf_symbol_sptr sym = decl->get_symbol())
- if (sym->is_defined())
- write_elf_symbol_reference(decl->get_symbol(), o);
+ if (corpus* abi = decl->get_corpus())
+ write_elf_symbol_reference(ctxt, decl->get_symbol(), *abi, o);
o << ">\n";
@@ -4734,6 +4839,35 @@ write_corpus(write_context& ctxt,
out << "</elf-variable-symbols>\n";
}
+ // Write the undefined function symbols database.
+ if (ctxt.get_write_undefined_symbols()
+ && !corpus->get_sorted_undefined_fun_symbols().empty())
+ {
+ do_indent_to_level(ctxt, indent, 1);
+ out << "<undefined-elf-function-symbols>\n";
+
+ write_elf_symbols_table(corpus->get_sorted_undefined_fun_symbols(), ctxt,
+ get_indent_to_level(ctxt, indent, 2));
+
+ do_indent_to_level(ctxt, indent, 1);
+ out << "</undefined-elf-function-symbols>\n";
+ }
+
+
+ // Write the undefined variable symbols database.
+ if (ctxt.get_write_undefined_symbols()
+ && !corpus->get_sorted_undefined_var_symbols().empty())
+ {
+ do_indent_to_level(ctxt, indent, 1);
+ out << "<undefined-elf-variable-symbols>\n";
+
+ write_elf_symbols_table(corpus->get_sorted_undefined_var_symbols(), ctxt,
+ get_indent_to_level(ctxt, indent, 2));
+
+ do_indent_to_level(ctxt, indent, 1);
+ out << "</undefined-elf-variable-symbols>\n";
+ }
+
// Now write the translation units.
unsigned nb_tus = corpus->get_translation_units().size(), n = 0;
for (translation_units::const_iterator i =
@@ -2130,6 +2130,21 @@ test-abicompat/test9-fn-changed-v1.cc \
test-abicompat/test9-fn-changed-v1.h \
test-abicompat/test9-fn-changed-app \
test-abicompat/test9-fn-changed-report-0.txt \
+test-abicompat/test10/libtest10-with-exported-symbols.so \
+test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so \
+test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi \
+test-abicompat/test10/test10-app-with-undefined-symbols \
+test-abicompat/test10/test10-app-with-undefined-symbols.abi \
+test-abicompat/test10/test10-app-with-undefined-symbols.cc \
+test-abicompat/test10/test10-with-exported-symbols.cc \
+test-abicompat/test10/test10-with-exported-symbols.h \
+test-abicompat/test10/test10-with-incompatible-exported-symbols.cc \
+test-abicompat/test10/test10-with-incompatible-exported-symbols.h \
+test-abicompat/test10/test10-fn-changed-report-0.txt \
+test-abicompat/test10/test10-fn-changed-report-1.txt \
+test-abicompat/test10/test10-fn-changed-report-2.txt \
+test-abicompat/test10/test10-fn-changed-report-3.txt \
+test-abicompat/test10/test10-fn-changed-report-4.txt \
\
test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64.rpm \
test-diff-pkg/dbus-glib-0.80-3.fc12.x86_64.rpm \
new file mode 100755
GIT binary patch
literal 18288
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
asdG8!c5SJ^6H0CS->d&CG3GLGvEn~NT{;o~
literal 0
HcmV?d00001
new file mode 100644
@@ -0,0 +1,65 @@
+<abi-corpus version='2.3'>
+ <elf-needed>
+ <dependency name='libstdc++.so.6'/>
+ <dependency name='libm.so.6'/>
+ <dependency name='libgcc_s.so.1'/>
+ <dependency name='libc.so.6'/>
+ </elf-needed>
+ <elf-function-symbols>
+ <elf-symbol name='_ZN9some_type16get_first_memberEv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_ZN9some_type16set_first_memberEi' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_ZN9some_type17get_second_memberEv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_ZN9some_type17set_second_memberEc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <undefined-elf-function-symbols>
+ <elf-symbol name='__cxa_finalize' version='GLIBC_2.2.5' is-default-version='yes' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ </undefined-elf-function-symbols>
+ <undefined-elf-variable-symbols>
+ <elf-symbol name='_ITM_deregisterTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='_ITM_registerTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='__gmon_start__' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ </undefined-elf-variable-symbols>
+ <abi-instr address-size='64' path='test10-with-incompatible-exported-symbols.cc' comp-dir-path='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10' language='LANG_C_plus_plus_14'>
+ <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+ <class-decl name='some_type' size-in-bits='64' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h' line='1' column='1' id='type-id-2'>
+ <data-member access='private' layout-offset-in-bits='0'>
+ <var-decl name='first_member' type-id='type-id-3' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h' line='12' column='1'/>
+ </data-member>
+ <data-member access='private' layout-offset-in-bits='32'>
+ <var-decl name='second_member' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h' line='13' column='1'/>
+ </data-member>
+ <member-function access='public'>
+ <function-decl name='set_second_member' mangled-name='_ZN9some_type17set_second_memberEc' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type17set_second_memberEc'>
+ <parameter type-id='type-id-4' name='this' is-artificial='yes'/>
+ <parameter type-id='type-id-1' name='v' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='19' column='1'/>
+ <return type-id='type-id-5'/>
+ </function-decl>
+ </member-function>
+ <member-function access='public'>
+ <function-decl name='get_second_member' mangled-name='_ZN9some_type17get_second_memberEv' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='15' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type17get_second_memberEv'>
+ <parameter type-id='type-id-4' name='this' is-artificial='yes'/>
+ <return type-id='type-id-6'/>
+ </function-decl>
+ </member-function>
+ <member-function access='public'>
+ <function-decl name='set_first_member' mangled-name='_ZN9some_type16set_first_memberEi' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type16set_first_memberEi'>
+ <parameter type-id='type-id-4' name='this' is-artificial='yes'/>
+ <parameter type-id='type-id-3' name='v' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='11' column='1'/>
+ <return type-id='type-id-5'/>
+ </function-decl>
+ </member-function>
+ <member-function access='public'>
+ <function-decl name='get_first_member' mangled-name='_ZN9some_type16get_first_memberEv' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type16get_first_memberEv'>
+ <parameter type-id='type-id-4' name='this' is-artificial='yes'/>
+ <return type-id='type-id-7'/>
+ </function-decl>
+ </member-function>
+ </class-decl>
+ <type-decl name='int' size-in-bits='32' id='type-id-3'/>
+ <pointer-type-def type-id='type-id-1' size-in-bits='64' id='type-id-6'/>
+ <pointer-type-def type-id='type-id-3' size-in-bits='64' id='type-id-7'/>
+ <pointer-type-def type-id='type-id-2' size-in-bits='64' id='type-id-4'/>
+ <qualified-type-def type-id='type-id-4' const='yes' id='type-id-8'/>
+ <type-decl name='void' id='type-id-5'/>
+ </abi-instr>
+</abi-corpus>
new file mode 100755
GIT binary patch
literal 26072
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
M;N!4F2I;o{2cRGJzW@LL
literal 0
HcmV?d00001
@@ -0,0 +1,55 @@
+<abi-corpus version='2.3' path='test10-app-with-undefined-symbols' architecture='elf-amd-x86_64'>
+ <elf-needed>
+ <dependency name='libtest10-with-exported-symbols.so'/>
+ <dependency name='libstdc++.so.6'/>
+ <dependency name='libm.so.6'/>
+ <dependency name='libgcc_s.so.1'/>
+ <dependency name='libc.so.6'/>
+ </elf-needed>
+ <elf-function-symbols>
+ <elf-symbol name='_start' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='main' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <elf-variable-symbols>
+ <elf-symbol name='_IO_stdin_used' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-variable-symbols>
+ <undefined-elf-function-symbols>
+ <elf-symbol name='_ZN9some_type16get_first_memberEv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='_ZN9some_type17get_second_memberEv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='__libc_start_main@GLIBC_2.34' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+ </undefined-elf-function-symbols>
+ <undefined-elf-variable-symbols>
+ <elf-symbol name='_ITM_deregisterTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='_ITM_registerTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ <elf-symbol name='__gmon_start__' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+ </undefined-elf-variable-symbols>
+ <abi-instr address-size='64' path='test10-app-with-undefined-symbols.cc' comp-dir-path='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10' language='LANG_C_plus_plus_14'>
+ <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+ <class-decl name='some_type' size-in-bits='64' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-exported-symbols.h' line='1' column='1' id='type-id-2'>
+ <data-member access='private' layout-offset-in-bits='0'>
+ <var-decl name='first_member' type-id='type-id-3' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-exported-symbols.h' line='12' column='1'/>
+ </data-member>
+ <data-member access='private' layout-offset-in-bits='32'>
+ <var-decl name='second_member' type-id='type-id-1' visibility='default' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-exported-symbols.h' line='13' column='1'/>
+ </data-member>
+ <member-function access='public'>
+ <function-decl name='get_first_member' mangled-name='_ZN9some_type16get_first_memberEv' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-exported-symbols.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type16get_first_memberEv'>
+ <parameter type-id='type-id-4' is-artificial='yes'/>
+ <return type-id='type-id-3'/>
+ </function-decl>
+ </member-function>
+ <member-function access='public'>
+ <function-decl name='get_second_member' mangled-name='_ZN9some_type17get_second_memberEv' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-with-exported-symbols.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN9some_type17get_second_memberEv'>
+ <parameter type-id='type-id-4' is-artificial='yes'/>
+ <return type-id='type-id-1'/>
+ </function-decl>
+ </member-function>
+ </class-decl>
+ <type-decl name='int' size-in-bits='32' id='type-id-3'/>
+ <pointer-type-def type-id='type-id-2' size-in-bits='64' id='type-id-4'/>
+ <function-decl name='main' mangled-name='main' filepath='/home/dodji/git/libabigail/emit-undefined-ifaces/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc' line='9' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='main'>
+ <return type-id='type-id-3'/>
+ </function-decl>
+ <type-decl name='void' id='type-id-5'/>
+ </abi-instr>
+</abi-corpus>
new file mode 100644
@@ -0,0 +1,13 @@
+// Compile with:
+//
+// g++ -g -L. -ltest10-with-exported-symbols -o test10-app-with-undefined-symbols test10-app-with-undefined-symbols.cc
+//
+
+#include "test10-with-exported-symbols.h"
+
+int
+main()
+{
+ some_type s;
+ return s.get_first_member() + s.get_second_member();
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
+functions defined in library 'libtest10-with-incompatible-exported-symbols.so'
+have sub-types that are different from what application 'test10-app-with-undefined-symbols' expects:
+
+ method int some_type::get_first_member():
+ return type changed:
+ entity changed from 'int' to 'int*'
+ type size changed from 32 to 64 (in bits)
+
+ method char some_type::get_second_member():
+ return type changed:
+ entity changed from 'char' to 'char*'
+ type size changed from 8 to 64 (in bits)
+
new file mode 100644
@@ -0,0 +1,13 @@
+functions defined in library 'libtest10-with-incompatible-exported-symbols.so.abi'
+have sub-types that are different from what application 'test10-app-with-undefined-symbols' expects:
+
+ method int some_type::get_first_member():
+ return type changed:
+ entity changed from 'int' to 'int*'
+ type size changed from 32 to 64 (in bits)
+
+ method char some_type::get_second_member():
+ return type changed:
+ entity changed from 'char' to 'char*'
+ type size changed from 8 to 64 (in bits)
+
new file mode 100644
@@ -0,0 +1,13 @@
+functions defined in library 'libtest10-with-incompatible-exported-symbols.so'
+have sub-types that are different from what application 'test10-app-with-undefined-symbols.abi' expects:
+
+ method int some_type::get_first_member():
+ return type changed:
+ entity changed from 'int' to 'int*'
+ type size changed from 32 to 64 (in bits)
+
+ method char some_type::get_second_member():
+ return type changed:
+ entity changed from 'char' to 'char*'
+ type size changed from 8 to 64 (in bits)
+
new file mode 100644
@@ -0,0 +1,13 @@
+functions defined in library 'libtest10-with-incompatible-exported-symbols.so.abi'
+have sub-types that are different from what application 'test10-app-with-undefined-symbols.abi' expects:
+
+ method int some_type::get_first_member():
+ return type changed:
+ entity changed from 'int' to 'int*'
+ type size changed from 32 to 64 (in bits)
+
+ method char some_type::get_second_member():
+ return type changed:
+ entity changed from 'char' to 'char*'
+ type size changed from 8 to 64 (in bits)
+
new file mode 100644
@@ -0,0 +1,20 @@
+// Build this with:
+// g++ -g -Wall -shared -o libtest10-with-exported-symbols.so test10-with-exported-symbols.cc
+
+#include "test10-with-exported-symbols.h"
+
+int
+some_type::get_first_member()
+{return first_member;}
+
+void
+some_type::set_first_member(int v)
+{first_member = v;}
+
+char
+some_type::get_second_member()
+{return second_member;}
+
+void
+some_type::set_second_member(char v)
+{second_member = v;}
new file mode 100644
@@ -0,0 +1,14 @@
+class some_type
+{
+ public:
+
+ int get_first_member();
+ void set_first_member(int);
+
+ char get_second_member();
+ void set_second_member(char);
+
+ private:
+ int first_member = 0;
+ char second_member = 0;
+};
new file mode 100644
@@ -0,0 +1,20 @@
+// Build this with:
+// g++ -g -Wall -shared -o libtest10-with-incompatible-exported-symbols.so test10-with-incompatible-exported-symbols.cc
+
+#include "test10-with-incompatible-exported-symbols.h"
+
+int*
+some_type::get_first_member()
+{return &first_member;}
+
+void
+some_type::set_first_member(int v)
+{first_member = v;}
+
+char*
+some_type::get_second_member()
+{return &second_member;}
+
+void
+some_type::set_second_member(char v)
+{second_member = v;}
new file mode 100644
@@ -0,0 +1,14 @@
+class some_type
+{
+ public:
+
+ int* get_first_member();
+ void set_first_member(int);
+
+ char* get_second_member();
+ void set_second_member(char);
+
+ private:
+ int first_member = 0;
+ char second_member = 0;
+};
@@ -226,6 +226,60 @@ InOutSpec in_out_specs[] =
"data/test-abicompat/test9-fn-changed-report-0.txt",
"output/test-abicompat/test9-fn-changed-report-0.txt",
},
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols",
+ "data/test-abicompat/test10/libtest10-with-exported-symbols.so",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-0.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-0.txt",
+ },
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi",
+ "data/test-abicompat/test10/libtest10-with-exported-symbols.so",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-0.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-0.txt",
+ },
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols",
+ "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-1.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-1.txt",
+ },
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols",
+ "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-2.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-2.txt",
+ },
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi",
+ "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-3.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-3.txt",
+ },
+ {
+ "data/test-abicompat/test10/test10-app-with-undefined-symbols.abi",
+ "data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi",
+ "",
+ "",
+ "--show-base-names",
+ "data/test-abicompat/test10/test10-fn-changed-report-4.txt",
+ "output/test-abicompat/test10/test10-fn-changed-report-4.txt",
+ },
// This entry must be the last one.
{0, 0, 0, 0, 0, 0, 0}
};
@@ -158,7 +158,7 @@ main()
string abidw;
abidw = string(get_build_dir()) + "/tools/abidw "
- "--annotate --no-corpus-path --no-architecture";
+ "--annotate --no-corpus-path --no-architecture --no-load-undefined-interfaces";
for (InOutSpec* s = in_out_specs; s->in_elf_path; ++s)
{
bool is_ok = true;
@@ -74,6 +74,7 @@ test_task::serialize_corpus(const string& out_abi_path,
write_context_sptr write_ctxt
= create_write_context(corp->get_environment(), of);
set_type_id_style(*write_ctxt, spec.type_id_style);
+ set_write_undefined_symbols(*write_ctxt, false);
is_ok = write_corpus(*write_ctxt, corp, /*indent=*/0);
of.close();
@@ -651,7 +651,7 @@ test_task_dwarf::perform()
if (spec.type_id_style == HASH_TYPE_ID_STYLE)
type_id_style = "hash";
- string cmd = abidw + " --no-architecture "
+ string cmd = abidw + " --no-architecture --no-load-undefined-interfaces"
+ " --type-id-style " + type_id_style
+ " --no-corpus-path "
+ drop_private_types + " " + in_elf_path
@@ -109,6 +109,7 @@ struct options
bool short_locs;
bool default_sizes;
bool load_all_types;
+ bool load_undefined_interfaces;
bool linux_kernel_mode;
bool corpus_group_for_linux;
bool show_stats;
@@ -155,6 +156,7 @@ struct options
short_locs(false),
default_sizes(true),
load_all_types(),
+ load_undefined_interfaces(true),
linux_kernel_mode(true),
corpus_group_for_linux(false),
show_stats(),
@@ -233,6 +235,8 @@ display_usage(const string& prog_name, ostream& out)
"debug info of <elf-path>, and show its base name\n"
<< " --load-all-types read all types including those not reachable from "
"exported declarations\n"
+ << " --no-load-undefined-interfaces do not consider undefined "
+ "interfaces from the binary"
<< " --no-linux-kernel-mode don't consider the input binary as "
"a Linux Kernel binary\n"
<< " --kmi-whitelist|-w path to a linux kernel "
@@ -446,6 +450,8 @@ parse_command_line(int argc, char* argv[], options& opts)
}
else if (!strcmp(argv[i], "--load-all-types"))
opts.load_all_types = true;
+ else if (!strcmp(argv[i], "--no-load-undefined-interfaces"))
+ opts.load_undefined_interfaces = false;
else if (!strcmp(argv[i], "--drop-private-types"))
opts.drop_private_types = true;
else if (!strcmp(argv[i], "--drop-undefined-syms"))
@@ -615,6 +621,7 @@ set_generic_options(abigail::elf_based_reader& rdr, options& opts)
opts.leverage_dwarf_factorization;
rdr.options().assume_odr_for_cplusplus =
opts.assume_odr_for_cplusplus;
+ rdr.options().load_undefined_interfaces = opts.load_undefined_interfaces;
}
/// Load an ABI @ref corpus (the internal representation of the ABI of