diff --git a/doc/manuals/abidw.rst b/doc/manuals/abidw.rst
index 13db912f..e84047c5 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/patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch b/patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch
new file mode 100644
index 00000000..218820e1
--- /dev/null
+++ b/patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch
@@ -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
+
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index c1ae31ba..5d5353ea 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);
 
@@ -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,
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/data/Makefile.am b/tests/data/Makefile.am
index 5bf01528..da37f56c 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -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 \
diff --git a/tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so b/tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so
new file mode 100755
index 0000000000000000000000000000000000000000..8eb1fa58d0c85b1813eadaa56367fdc9d7762ec3
GIT binary patch
diff --git a/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so
diff --git a/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi
new file mode 100644
index 00000000..82653e42
--- /dev/null
+++ b/tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi
@@ -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>
diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols
new file mode 100755
index 0000000000000000000000000000000000000000..4d5f6c32c8e72a0d549648f96c477710060e2d7c
GIT binary patch
diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi
@@ -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>
diff --git a/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc
new file mode 100644
index 00000000..07d223e6
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc
@@ -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();
+}
diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt
new file mode 100644
index 00000000..3824b9e3
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt
@@ -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)
+
diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt
new file mode 100644
index 00000000..d5ae6534
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt
@@ -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)
+
diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt
new file mode 100644
index 00000000..3df28e7c
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt
@@ -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)
+
diff --git a/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt b/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt
new file mode 100644
index 00000000..8ea5b16c
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt
@@ -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)
+
diff --git a/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc b/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc
new file mode 100644
index 00000000..b2be7eac
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-with-exported-symbols.cc
@@ -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;}
diff --git a/tests/data/test-abicompat/test10/test10-with-exported-symbols.h b/tests/data/test-abicompat/test10/test10-with-exported-symbols.h
new file mode 100644
index 00000000..ce206570
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-with-exported-symbols.h
@@ -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;
+};
diff --git a/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc
new file mode 100644
index 00000000..f93a5458
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc
@@ -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;}
diff --git a/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h
new file mode 100644
index 00000000..bfed108d
--- /dev/null
+++ b/tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h
@@ -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;
+};
diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc
index 320436c3..a7fcc520 100644
--- a/tests/test-abicompat.cc
+++ b/tests/test-abicompat.cc
@@ -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}
 };
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-common.cc b/tests/test-read-common.cc
index 1d70b3d0..8c682b1c 100644
--- a/tests/test-read-common.cc
+++ b/tests/test-read-common.cc
@@ -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();
 
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 fe977b1d..c6cc0562 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 "
@@ -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
