public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode
@ 2024-03-14 16:54 Dodji Seketeli
  2024-03-14 16:57 ` [PATCH 1/4] Represent undefined corpus interfaces to analyze app compatibility Dodji Seketeli
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Dodji Seketeli @ 2024-03-14 16:54 UTC (permalink / raw)
  To: libabigail; +Cc: dodji

Hello,

The weak mode of operation of the 'abicompat' tool is a mode where
only one version of the library is needed for the tool to detect
incompatibilities between the interfaces expected by the application
and the interfaces provided by a library.

In this weak mode, the 'abicompat' tool first looks at the undefined
symbols of the application.  For each of these symbols that are
defined by the library, the tool 'synthesizes' (okay, it actually
'guesses') the type of the interface as expected by the application.  Then
the tool compares the interface type expected by the application
against the interface type provided by the library.  If that
comparison yields meaningful changes, the tool reports those changes
as being potential ABI incompatibilities between the application and
the library.

The problem in this approach is that the accuracy of the type
comparison depends on the quality of the "guess" (aka synthesis) of
the type of the undefined interface in the application.  Today, that
guess often results in the signature of the expected interface being
similar to the signature of the provided one, leading to many false
negative results.

Rather than guessing, this patch series proposes to use the DWARF
representation of the undefined interfaces (in the application) to
determine its exact intermediate representation and thus completely
eliminate the previous false negatives.

To achieve that goal, the first patch models undefined functions and
variables in the ABI corpus representation.  These are functions and
variables whose associated ELF symbols are undefined.  In other words,
these undefined interfaces represent the interfaces that are expected
by the ABI corpus.  This is done for the DWARF and CTF front-ends.
The abicompat tool is adjusted in a such a way that its weak mode of
operation is revisited to compare the undefined interfaces expected by
the application against the defined interfaces provided by the
library.  The weak mode is extended to also detect incompatibilities
between the interfaces expected by the library (in case it's a plugin)
and those provided by the application; this is called "bi-directional"
incompatibility detection.

The second patch of the series is a somewhat generic code
factorization that prepares the third patch.

The third patch adds support for the construction of these undefined
interfaces for the BTF front-end as well.

The fourth and last patch adds support to serialize and de-serialize
undefined interfaces to and from the ABIXML format.

Dodji Seketeli (4):
  Represent undefined corpus interfaces to analyze app compatibility
  Factorize elf-reader::{variable,function}_symbol_is_exported into symtab
  Add support for undefined symbols in the BTF reader
  Emit & read undefined interfaces to & from ABIXML

 doc/manuals/abicompat.rst                     |     5 +
 doc/manuals/abidw.rst                         |    10 +
 include/abg-corpus.h                          |    31 +-
 include/abg-elf-reader.h                      |     6 +
 include/abg-fe-iface.h                        |     8 +-
 include/abg-writer.h                          |     4 +
 ...-undefined-interfaces-to-from-ABIXML.patch |  1051 +
 src/abg-btf-reader.cc                         |    25 +-
 src/abg-corpus-priv.h                         |     6 +-
 src/abg-corpus.cc                             |   165 +-
 src/abg-ctf-reader.cc                         |     6 +-
 src/abg-dwarf-reader.cc                       |   372 +-
 src/abg-elf-reader.cc                         |    78 +-
 src/abg-fe-iface.cc                           |    43 +-
 src/abg-ir.cc                                 |    24 +-
 src/abg-reader.cc                             |    91 +-
 src/abg-symtab-reader.cc                      |   216 +-
 src/abg-symtab-reader.h                       |    35 +
 src/abg-writer.cc                             |   152 +-
 tests/data/Makefile.am                        |    25 +-
 .../libtest5-fn-changed-libapp-v0.so          |   Bin 9611 -> 18112 bytes
 .../libtest5-fn-changed-libapp-v1.so          |   Bin 9587 -> 18080 bytes
 .../test-abicompat/libtest6-undefined-var.so  |   Bin 0 -> 17688 bytes
 .../libtest6-var-changed-libapp-v0.so         |   Bin 9486 -> 17976 bytes
 .../libtest6-var-changed-libapp-v1.so         |   Bin 9462 -> 17984 bytes
 .../libtest7-fn-changed-libapp-btf-v0.so      |   Bin 0 -> 16560 bytes
 .../libtest7-fn-changed-libapp-btf-v1.so      |   Bin 0 -> 16584 bytes
 .../libtest7-fn-changed-libapp-v0.so          |   Bin 9438 -> 17968 bytes
 .../libtest7-fn-changed-libapp-v1.so          |   Bin 9462 -> 17992 bytes
 .../libtest8-fn-changed-libapp-v0.so          |   Bin 8940 -> 17376 bytes
 .../libtest8-fn-changed-libapp-v1.so          |   Bin 8972 -> 17416 bytes
 .../test-abicompat/libtest9-fn-changed-v0.so  |   Bin 9004 -> 17456 bytes
 .../test-abicompat/libtest9-fn-changed-v1.so  |   Bin 9036 -> 17488 bytes
 .../test10/libtest10-with-exported-symbols.so |   Bin 0 -> 18288 bytes
 ...st10-with-incompatible-exported-symbols.so |   Bin 0 -> 18336 bytes
 ...-with-incompatible-exported-symbols.so.abi |    65 +
 .../test10/test10-app-with-undefined-symbols  |   Bin 0 -> 26072 bytes
 .../test10-app-with-undefined-symbols.abi     |    55 +
 .../test10-app-with-undefined-symbols.cc      |    13 +
 .../test10/test10-fn-changed-report-0.txt     |     0
 .../test10/test10-fn-changed-report-1.txt     |    13 +
 .../test10/test10-fn-changed-report-2.txt     |    13 +
 .../test10/test10-fn-changed-report-3.txt     |    13 +
 .../test10/test10-fn-changed-report-4.txt     |    13 +
 .../test10/test10-with-exported-symbols.cc    |    20 +
 .../test10/test10-with-exported-symbols.h     |    14 +
 ...st10-with-incompatible-exported-symbols.cc |    20 +
 ...est10-with-incompatible-exported-symbols.h |    14 +
 .../data/test-abicompat/test5-fn-changed-app  |   Bin 9881 -> 26040 bytes
 .../test-abicompat/test6-undefined-var.cc     |    12 +
 .../data/test-abicompat/test6-var-changed-app |   Bin 9822 -> 0 bytes
 .../test-abicompat/test6-var-changed-app.cc   |    15 -
 .../test6-var-changed-libapp-v0.cc            |     1 +
 .../test6-var-changed-libapp-v1.cc            |     1 +
 .../test6-var-changed-report-0.txt            |     2 +-
 .../test6-var-changed-report-1.txt            |     2 +-
 .../test6-var-changed-report-2.txt            |    15 +
 .../data/test-abicompat/test7-fn-changed-app  |   Bin 9938 -> 26008 bytes
 .../test-abicompat/test7-fn-changed-app.btf   |   Bin 0 -> 17536 bytes
 .../test-abicompat/test7-fn-changed-app.c     |     2 +
 .../test7-fn-changed-libapp-v0.c              |     2 +
 .../test7-fn-changed-libapp-v1.c              |     3 +
 .../test7-fn-changed-report-0.1.txt           |    19 +
 .../test7-fn-changed-report-1.txt             |     5 +
 .../test7-fn-changed-report-2.1.txt           |    16 +
 .../test7-fn-changed-report-2.txt             |     5 +
 .../data/test-abicompat/test8-fn-changed-app  |   Bin 9700 -> 25864 bytes
 .../test8-fn-changed-libapp-v1.c              |     2 +-
 .../data/test-abicompat/test9-fn-changed-app  |   Bin 10035 -> 26008 bytes
 .../test-abicompat/test9-fn-changed-app.cc    |     2 +-
 tests/data/test-annotate/libtest23.so.abi     |   711 +-
 .../test-annotate/libtest24-drop-fns-2.so.abi |   576 -
 .../test-annotate/libtest24-drop-fns.so.abi   |   576 -
 tests/data/test-annotate/test1.abi            |    74 +-
 .../data/test-annotate/test14-pr18893.so.abi  | 14336 +---
 .../data/test-annotate/test15-pr18892.so.abi  | 25174 ++-----
 .../data/test-annotate/test17-pr19027.so.abi  | 18027 +----
 ...st18-pr19037-libvtkRenderingLIC-6.1.so.abi | 30166 +++-----
 ...19-pr19023-libtcmalloc_and_profiler.so.abi | 27423 ++-----
 tests/data/test-annotate/test2.so.abi         |    36 -
 ...st20-pr19025-libvtkParallelCore-6.1.so.abi | 28876 ++------
 .../data/test-annotate/test21-pr19092.so.abi  |  4308 +-
 .../test8-qualified-this-pointer.so.abi       |    21 +-
 ...bus-glib-0.104-3.fc23.armv7hl-report-0.txt |     7 +-
 ...libICE-1.0.9-2.el7.x86_64.rpm-report-0.txt |     6 +-
 ...0-from-fc20-to-fc23-dbus-glib-report-0.txt |     7 -
 ....fc20--dbus-glib-0.106-1.fc23-report-0.txt |     7 -
 ...--dbus-glib-0.106-1.fc23.i686-report-0.txt |     7 -
 ...-vte291-0.39.90-1.fc22.x86_64-report-0.txt |    13 +-
 .../PR22015-libboost_iostreams.so.abi         |  2466 +-
 .../test-read-dwarf/PR22122-libftdc.so.abi    |  3425 +-
 .../test-read-dwarf/PR26261/PR26261-exe.abi   |    42 +-
 tests/data/test-read-dwarf/libtest23.so.abi   |   411 +-
 .../libtest24-drop-fns-2.so.abi               |   321 -
 .../test-read-dwarf/libtest24-drop-fns.so.abi |   321 -
 .../test-read-dwarf/test-libaaudio.so.abi     |  1398 +-
 .../test-read-dwarf/test-libandroid.so.abi    | 38724 ++++------
 tests/data/test-read-dwarf/test1.abi          |    54 +-
 tests/data/test-read-dwarf/test1.hash.abi     |    32 -
 .../test-read-dwarf/test10-pr18818-gcc.so.abi |  4340 +-
 .../test-read-dwarf/test11-pr18828.so.abi     |  8812 +--
 .../test-read-dwarf/test12-pr18844.so.abi     | 17781 +----
 .../test-read-dwarf/test14-pr18893.so.abi     |  7500 +-
 .../test-read-dwarf/test15-pr18892.so.abi     | 20419 ++----
 .../test-read-dwarf/test16-pr18904.so.abi     |  6042 +-
 .../test-read-dwarf/test17-pr19027.so.abi     | 13682 +---
 ...st18-pr19037-libvtkRenderingLIC-6.1.so.abi | 18170 ++---
 ...19-pr19023-libtcmalloc_and_profiler.so.abi | 19957 ++----
 tests/data/test-read-dwarf/test2.so.abi       |    24 -
 tests/data/test-read-dwarf/test2.so.hash.abi  |    24 -
 ...st20-pr19025-libvtkParallelCore-6.1.so.abi | 17154 +----
 .../test-read-dwarf/test21-pr19092.so.abi     |  3232 +-
 .../test22-pr19097-libstdc++.so.6.0.17.so.abi | 59856 +++++-----------
 .../test8-qualified-this-pointer.so.abi       |    18 +-
 .../test8-qualified-this-pointer.so.hash.abi  |     6 -
 .../test9-pr18818-clang.so.abi                |  3052 +-
 tests/test-abicompat.cc                       |    89 +-
 tests/test-annotate.cc                        |     2 +-
 tests/test-read-common.cc                     |     1 +
 tests/test-read-ctf.cc                        |     2 +-
 tests/test-read-dwarf.cc                      |     2 +-
 tests/test-symtab.cc                          |    48 +-
 tools/abicompat.cc                            |   576 +-
 tools/abidw.cc                                |     7 +
 124 files changed, 104678 insertions(+), 296373 deletions(-)
 create mode 100644 patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch
 create mode 100755 tests/data/test-abicompat/libtest6-undefined-var.so
 create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so
 create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so
 create mode 100755 tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so
 create mode 100755 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so
 create mode 100644 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi
 create mode 100755 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols
 create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi
 create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.h
 create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h
 create mode 100644 tests/data/test-abicompat/test6-undefined-var.cc
 delete mode 100755 tests/data/test-abicompat/test6-var-changed-app
 delete mode 100644 tests/data/test-abicompat/test6-var-changed-app.cc
 create mode 100644 tests/data/test-abicompat/test6-var-changed-report-2.txt
 create mode 100755 tests/data/test-abicompat/test7-fn-changed-app.btf
 create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-0.1.txt
 create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-2.1.txt

-- 
2.39.3


-- 
		Dodji


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] Represent undefined corpus interfaces to analyze app compatibility
  2024-03-14 16:54 [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode Dodji Seketeli
@ 2024-03-14 16:57 ` Dodji Seketeli
  2024-03-14 16:59 ` [PATCH 2/4] Factorize elf-reader::{variable,function}_symbol_is_exported into symtab Dodji Seketeli
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Dodji Seketeli @ 2024-03-14 16:57 UTC (permalink / raw)
  To: dodji; +Cc: libabigail

[-- Attachment #1: Type: text/plain, Size: 19366 bytes --]

Hello,

In the text below, the term interface means the "declaration of either
a function or a global variable".

To analyze the compatibility between an application and a dependent
library, one has essentially to analyze the interfaces of the
application that have undefined symbols (aka undefined interfaces from
the application) and see how they relate to the same interfaces coming
from the library but with symbols that are defined and exported from
the library (aka defined/exported interfaces from the library).

An interface that is undefined in the application and defined in the
library is an interface that the application consumes from the
library.

In other words an undefined interface from an application is an
interface that the application expects and an interface that is
exported by a library is an interface that the library provides.

If comparing the expected interface against the provided interface
yields a meaningful difference, then that might mean there is an
incompatibility between the application and the library on that
interface.

This patch uses this scheme to re-implement the weak mode of ABI
compatibility between an application and a library.

The patch adds the concept of undefined functions and variables to the
ABI corpus.  Then it teaches the DWARF reader how to construct the IR
for these undefined interfaces.  Then it revisits the weak mode of
operation of abicompat to make it compare the interfaces expected from
the application against the corresponding interfaces provided by
library.  The patch also teaches the weak mode abicompat how to detect
incompatibilities between the interfaces that plugin expects and the
interfaces provided by the application.

This patch makes the CTF front-end construct undefined interfaces.  A
subsequent patch is needed to construct undefined interfaces from the
BTF front-end however.

	* include/abg-corpus.h (corpus::{lookup_variable,
	get_undefined_functions, get_undefined_variables}): Declare new
	member functions.
	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
	Make this return a boolean.
	* include/abg-fe-iface.h (fe_iface::options_type): Add a new
	load_undefined_interfaces enumerator.
	(fe_iface::add_fn_to_exported_or_undefined_decls): Rename
	maybe_add_fn_to_exported_decls into this.
	(fe_iface::add_var_to_exported_or_undefined_decls): Rename
	maybe_add_var_to_exported_decls into this.
	* src/abg-btf-reader.cc (reader::build_ir_node_from_btf_type):
	Adjust call to maybe_add_fn_to_exported_decls as
	add_fn_to_exported_or_undefined_decls.  Similarly, adjust call to
	maybe_add_var_to_exported_decls as
	add_var_to_exported_or_undefined_decls.
	* src/abg-corpus-priv.h (corpus::priv::undefined_{fns,vars}): Add
	new member variables.
	* src/abg-corpus.cc
	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
	Return a bool iff the decl was added to the set of exported decls.
	(corpus::{lookup_variable, get_undefined_functions,
	get_undefined_variables}): Define new member functions.
	(corpus::sort_{functions,variables}): Sort the undefined decls
	too.
	* (corpus::lookup_{function,variable}_symbol): Lookup the symbol
	also among undefined symbols, not just among defined symbols.
	* src/abg-ctf-reader.cc (reader::process_ctf_archive): Adjust call
	to maybe_add_fn_to_exported_decls as
	add_fn_to_exported_or_undefined_decls.  Similarly, adjust call to
	maybe_add_var_to_exported_decls as
	add_var_to_exported_or_undefined_decls. Also, sort functions &
	variables in the corpus.
	* src/abg-dwarf-reader.cc (die_name_and_linkage_name): Define new
	static function.
	(reader::fixup_functions_with_no_symbols): Adjust call to
	maybe_add_fn_to_exported_decls as
	add_fn_to_exported_or_undefined_decls.
	(reader::{is_decl_die_with_undefined_symbol,
	load_undefined_interfaces}): Define new member functions.
	(build_translation_unit_and_add_to_ir): Analyze DIEs of interfaces
	that have undefined symbols if we were asked to load undefined
	interfaces.
	(variable_is_suppressed): Add a boolean parameter to tell if the
	var is decl-only.  Use that decl-only flag to determine if the
	variable is suppressed.  A non-member decl-only variable won't be
	suppressed if we were asked to load undefined interfaces.
	(build_or_get_var_decl_if_not_suppressed): Add a boolean parameter
	to tell if the var is decl-only.
	(potential_member_fn_should_be_dropped): A potential non-virtual
	member function with no symbol is now dropped on the floor
	regardless of it has a mangled name or not.
	(build_var_decl): If the var has an undefined symbol, then set
	that symbol.
	(build_function_decl): If the function has an undefined symbol,
	then set that symbol.
	(build_ir_node_from_die): Add a var or function with undefined
	symbol to the set of undefined vars or functions of the current
	corpus.
	* src/abg-fe-iface.cc
	(fe_iface::add_fn_to_exported_or_undefined_decls): Renamed
	fe_iface::maybe_add_fn_to_exported_decls into this.  If the
	function has an undefined symbol then add the function to the set
	of undefined functions.
	(fe_iface::add_var_to_exported_or_undefined_decls): Renamed
	fe_iface::maybe_add_var_to_exported_decls into this.  If the
	variable has an undefined symbol then add the variable to the set
	of undefined variables.
	* src/abg-ir.cc (elf_symbol::is_variable): Undefined symbol with
	type STT_NOTYPE are actually for undefined variables.
	(maybe_adjust_canonical_type): It's here, after type
	canonicalization that a member function is added to either the set
	of defined & exported functions, or to the set of functions with
	undefined symbols.
	* src/abg-reader.cc (build_function_decl, build_class_decl)
	(build_union_decl, handle_var_decl): Adjust.
	* src/abg-symtab-reader.cc
	(symtab::{lookup_undefined_function_symbol,
	lookup_undefined_variable_symbol, function_symbol_is_undefined,
	variable_symbol_is_undefined,
	collect_undefined_fns_and_vars_linkage_names}): Define new member
	functions.
	(symtab::symtab): Initialize the new
	cached_undefined_symbol_names_ data member.
	* src/abg-symtab-reader.h
	(symtab::{lookup_undefined_function_symbol,
	lookup_undefined_variable_symbol, function_symbol_is_undefined,
	variable_symbol_is_undefined,
	collect_undefined_fns_and_vars_linkage_names}): Declare new member
	functions.
	(symtab::{undefined_variable_linkage_names_,
	cached_undefined_symbol_names_}): Define new data members.
	(symtab::load_): Consider undefined symbol of type STT_NOTYPE as
	being undefined global variables.  It's what I am seeing in ELF
	binaries.
	* src/abg-symtab-reader.h
	(symtab::{lookup_undefined_function_symbol,
	lookup_undefined_variable_symbol, function_symbol_is_undefined,
	variable_symbol_is_undefined}): Declare new member functions.
	(symtab::{undefined_function_linkage_names_,
	undefined_variable_linkage_names_}): Define new member variables.
	* src/abg-writer.cc (write_var_decl, write_function_decl): Emit a
	reference to a symbol only when the symbol is defined.
	* tools/abicompat.cc (report_function_changes)
	(report_variable_changes)
	(compare_expected_against_provided_functions)
	(compare_expected_against_provided_variables): Define new static
	functions.
	(perform_compat_check_in_weak_mode): Use the new static functions
	above. Compare interfaces expected by the application corpus
	against interfaces provided by the library.  Report the changes.
	Do that in the reverse direction as well.
	(read_corpus): Instruct the corpus reader to load the set of
	undefined interfaces too.
	* tests/data/test-abicompat/test6-var-changed-app: Remove file.
	* tests/data/test-abicompat/test6-var-changed-app.cc: Likewise.
	* tests/data/test-abicompat/libtest6-undefined-var.so: Add new
	binary input file.
	* tests/data/test-abicompat/test6-undefined-var.cc: Add sourcefile
	for the binary input file above.
	* tests/data/test-abicompat/test6-var-changed-report-2.txt: New
	reference output file.
	* tests/data/Makefile.am: Update the list of distributed files
	accordingly.
	* tests/data/test-abicompat/libtest5-fn-changed-libapp-v0.so:
	Adjust.
	* tests/data/test-abicompat/libtest5-fn-changed-libapp-v1.so:
	Likewise.
	* tests/data/test-abicompat/libtest6-var-changed-libapp-v0.so:
	Likewise.
	* tests/data/test-abicompat/libtest6-var-changed-libapp-v1.so:
	Likewise.
	* tests/data/test-abicompat/libtest7-fn-changed-libapp-v0.so:
	Likewise.
	* tests/data/test-abicompat/libtest7-fn-changed-libapp-v1.so:
	Likewise.
	* tests/data/test-abicompat/libtest8-fn-changed-libapp-v0.so:
	Likewise.
	* tests/data/test-abicompat/libtest8-fn-changed-libapp-v1.so:
	Likewise.
	* tests/data/test-abicompat/libtest9-fn-changed-v0.so: Likewise.
	* tests/data/test-abicompat/libtest9-fn-changed-v1.so: Likewise.
	* tests/data/test-abicompat/test5-fn-changed-app: Likewise.
	* tests/data/test-abicompat/test6-var-changed-libapp-v0.cc:
	Likewise.
	* tests/data/test-abicompat/test6-var-changed-libapp-v1.cc:
	Likewise.
	* tests/data/test-abicompat/test6-var-changed-report-0.txt:
	Likewise.
	* tests/data/test-abicompat/test6-var-changed-report-1.txt:
	Likewise.
	* tests/data/test-abicompat/test7-fn-changed-app: Likewise.
	* tests/data/test-abicompat/test7-fn-changed-report-1.txt:
	Likewise.
	* tests/data/test-abicompat/test7-fn-changed-report-2.txt:
	Likewise.
	* tests/data/test-abicompat/test8-fn-changed-app: Likewise.
	* tests/data/test-abicompat/test8-fn-changed-libapp-v1.c:
	Likewise.
	* tests/data/test-abicompat/test9-fn-changed-app: Likewise.
	* tests/data/test-abicompat/test9-fn-changed-app.cc: Likewise.
	* tests/data/test-annotate/libtest23.so.abi: Likewise.
	* tests/data/test-annotate/libtest24-drop-fns-2.so.abi: Likewise.
	* tests/data/test-annotate/libtest24-drop-fns.so.abi: Likewise.
	* tests/data/test-annotate/test1.abi: Likewise.
	* tests/data/test-annotate/test14-pr18893.so.ab: Likewise.i
	* tests/data/test-annotate/test15-pr18892.so.abi: Likewise.
	* tests/data/test-annotate/test17-pr19027.so.abi: Likewise.
	* tests/data/test-annotate/test18-pr19037-libvtkRenderingLIC-6.1.so.abi:
	Likewise.
	* tests/data/test-annotate/test19-pr19023-libtcmalloc_and_profiler.so.abi:
	Likewise.
	* tests/data/test-annotate/test2.so.abi: Likewise.
	* tests/data/test-annotate/test20-pr19025-libvtkParallelCore-6.1.so.abi:
	Likewise.
	* tests/data/test-annotate/test21-pr19092.so.abi: Likewise.
	* tests/data/test-annotate/test8-qualified-this-pointer.so.abi:
	Likewise.
	* tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt:
	Likewise.
	* tests/data/test-diff-pkg/libICE-1.0.6-1.el6.x86_64.rpm--libICE-1.0.9-2.el7.x86_64.rpm-report-0.txt:
	Likewise.
	* tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt:
	Likewise.
	* tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt:
	Likewise.
	* tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt:
	Likewise.
	* tests/data/test-fedabipkgdiff/vte291-0.39.1-1.fc22.x86_64--vte291-0.39.90-1.fc22.x86_64-report-0.txt:
	Likewise.
	* tests/data/test-read-dwarf/PR22015-libboost_iostreams.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Likewise.
	* tests/data/test-read-dwarf/PR26261/PR26261-exe.abi: Likewise.
	* tests/data/test-read-dwarf/libtest23.so.abi: Likewise.
	* tests/data/test-read-dwarf/libtest24-drop-fns-2.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/libtest24-drop-fns.so.abi: Likewise.
	* tests/data/test-read-dwarf/test-libaaudio.so.abi: Likewise.
	* tests/data/test-read-dwarf/test-libandroid.so.abi: Likewise.
	* tests/data/test-read-dwarf/test1.abi: Likewise.
	* tests/data/test-read-dwarf/test1.hash.abi: Likewise.
	* tests/data/test-read-dwarf/test10-pr18818-gcc.so.abi: Likewise.
	* tests/data/test-read-dwarf/test11-pr18828.so.abi: Likewise.
	* tests/data/test-read-dwarf/test12-pr18844.so.abi: Likewise.
	* tests/data/test-read-dwarf/test14-pr18893.so.abi: Likewise.
	* tests/data/test-read-dwarf/test15-pr18892.so.abi: Likewise.
	* tests/data/test-read-dwarf/test16-pr18904.so.abi: Likewise.
	* tests/data/test-read-dwarf/test17-pr19027.so.abi: Likewise.
	* tests/data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/test2.so.abi: Likewise.
	* tests/data/test-read-dwarf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/test21-pr19092.so.abi: Likewise.
	* tests/data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/test8-qualified-this-pointer.so.abi:
	Likewise.
	* tests/data/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi:
	Likewise.
	* tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Likewise.
	* tests/test-abicompat.cc (in_out_specs): Adjust.
	* tests/test-read-ctf.cc (test_task_ctf::perform): Do not load
	undefined interfaces, by default.
	* tests/test-symtab.cc (Symtab::SimpleSymtabs)
	(Symtab::SymtabWithWhitelist, Symtab::AliasedFunctionSymbols):
	Adjust the expected undefined variable symbols counts.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-corpus.h                          |    31 +-
 include/abg-fe-iface.h                        |     8 +-
 src/abg-btf-reader.cc                         |     4 +-
 src/abg-corpus-priv.h                         |     6 +-
 src/abg-corpus.cc                             |   165 +-
 src/abg-ctf-reader.cc                         |     6 +-
 src/abg-dwarf-reader.cc                       |   185 +-
 src/abg-fe-iface.cc                           |    43 +-
 src/abg-ir.cc                                 |    24 +-
 src/abg-reader.cc                             |    10 +-
 src/abg-symtab-reader.cc                      |   115 +-
 src/abg-symtab-reader.h                       |    23 +
 src/abg-writer.cc                             |     8 +-
 tests/data/Makefile.am                        |     5 +-
 .../libtest5-fn-changed-libapp-v0.so          |   Bin 9611 -> 18112 bytes
 .../libtest5-fn-changed-libapp-v1.so          |   Bin 9587 -> 18080 bytes
 .../test-abicompat/libtest6-undefined-var.so  |   Bin 0 -> 17688 bytes
 .../libtest6-var-changed-libapp-v0.so         |   Bin 9486 -> 17976 bytes
 .../libtest6-var-changed-libapp-v1.so         |   Bin 9462 -> 17984 bytes
 .../libtest7-fn-changed-libapp-v0.so          |   Bin 9438 -> 17968 bytes
 .../libtest7-fn-changed-libapp-v1.so          |   Bin 9462 -> 17992 bytes
 .../libtest8-fn-changed-libapp-v0.so          |   Bin 8940 -> 17376 bytes
 .../libtest8-fn-changed-libapp-v1.so          |   Bin 8972 -> 17416 bytes
 .../test-abicompat/libtest9-fn-changed-v0.so  |   Bin 9004 -> 17456 bytes
 .../test-abicompat/libtest9-fn-changed-v1.so  |   Bin 9036 -> 17488 bytes
 .../data/test-abicompat/test5-fn-changed-app  |   Bin 9881 -> 26040 bytes
 .../test-abicompat/test6-undefined-var.cc     |    12 +
 .../data/test-abicompat/test6-var-changed-app |   Bin 9822 -> 0 bytes
 .../test-abicompat/test6-var-changed-app.cc   |    15 -
 .../test6-var-changed-libapp-v0.cc            |     1 +
 .../test6-var-changed-libapp-v1.cc            |     1 +
 .../test6-var-changed-report-0.txt            |     2 +-
 .../test6-var-changed-report-1.txt            |     2 +-
 .../test6-var-changed-report-2.txt            |    15 +
 .../data/test-abicompat/test7-fn-changed-app  |   Bin 9938 -> 26008 bytes
 .../test7-fn-changed-report-1.txt             |     5 +
 .../test7-fn-changed-report-2.txt             |     5 +
 .../data/test-abicompat/test8-fn-changed-app  |   Bin 9700 -> 25864 bytes
 .../test8-fn-changed-libapp-v1.c              |     2 +-
 .../data/test-abicompat/test9-fn-changed-app  |   Bin 10035 -> 26008 bytes
 .../test-abicompat/test9-fn-changed-app.cc    |     2 +-
 tests/data/test-annotate/libtest23.so.abi     |   711 +-
 .../test-annotate/libtest24-drop-fns-2.so.abi |   576 -
 .../test-annotate/libtest24-drop-fns.so.abi   |   576 -
 tests/data/test-annotate/test1.abi            |    74 +-
 .../data/test-annotate/test14-pr18893.so.abi  | 14336 +---
 .../data/test-annotate/test15-pr18892.so.abi  | 25174 ++-----
 .../data/test-annotate/test17-pr19027.so.abi  | 18027 +----
 ...st18-pr19037-libvtkRenderingLIC-6.1.so.abi | 30166 +++-----
 ...19-pr19023-libtcmalloc_and_profiler.so.abi | 27423 ++-----
 tests/data/test-annotate/test2.so.abi         |    36 -
 ...st20-pr19025-libvtkParallelCore-6.1.so.abi | 28876 ++------
 .../data/test-annotate/test21-pr19092.so.abi  |  4308 +-
 .../test8-qualified-this-pointer.so.abi       |    21 +-
 ...bus-glib-0.104-3.fc23.armv7hl-report-0.txt |     7 +-
 ...libICE-1.0.9-2.el7.x86_64.rpm-report-0.txt |     6 +-
 ...0-from-fc20-to-fc23-dbus-glib-report-0.txt |     7 -
 ....fc20--dbus-glib-0.106-1.fc23-report-0.txt |     7 -
 ...--dbus-glib-0.106-1.fc23.i686-report-0.txt |     7 -
 ...-vte291-0.39.90-1.fc22.x86_64-report-0.txt |    13 +-
 .../PR22015-libboost_iostreams.so.abi         |  2466 +-
 .../test-read-dwarf/PR22122-libftdc.so.abi    |  3425 +-
 .../test-read-dwarf/PR26261/PR26261-exe.abi   |    42 +-
 tests/data/test-read-dwarf/libtest23.so.abi   |   411 +-
 .../libtest24-drop-fns-2.so.abi               |   321 -
 .../test-read-dwarf/libtest24-drop-fns.so.abi |   321 -
 .../test-read-dwarf/test-libaaudio.so.abi     |  1398 +-
 .../test-read-dwarf/test-libandroid.so.abi    | 38724 ++++------
 tests/data/test-read-dwarf/test1.abi          |    54 +-
 tests/data/test-read-dwarf/test1.hash.abi     |    32 -
 .../test-read-dwarf/test10-pr18818-gcc.so.abi |  4340 +-
 .../test-read-dwarf/test11-pr18828.so.abi     |  8812 +--
 .../test-read-dwarf/test12-pr18844.so.abi     | 17781 +----
 .../test-read-dwarf/test14-pr18893.so.abi     |  7500 +-
 .../test-read-dwarf/test15-pr18892.so.abi     | 20419 ++----
 .../test-read-dwarf/test16-pr18904.so.abi     |  6042 +-
 .../test-read-dwarf/test17-pr19027.so.abi     | 13682 +---
 ...st18-pr19037-libvtkRenderingLIC-6.1.so.abi | 18170 ++---
 ...19-pr19023-libtcmalloc_and_profiler.so.abi | 19957 ++----
 tests/data/test-read-dwarf/test2.so.abi       |    24 -
 tests/data/test-read-dwarf/test2.so.hash.abi  |    24 -
 ...st20-pr19025-libvtkParallelCore-6.1.so.abi | 17154 +----
 .../test-read-dwarf/test21-pr19092.so.abi     |  3232 +-
 .../test22-pr19097-libstdc++.so.6.0.17.so.abi | 59856 +++++-----------
 .../test8-qualified-this-pointer.so.abi       |    18 +-
 .../test8-qualified-this-pointer.so.hash.abi  |     6 -
 .../test9-pr18818-clang.so.abi                |  3052 +-
 tests/test-abicompat.cc                       |    13 +-
 tests/test-read-ctf.cc                        |     2 +-
 tests/test-symtab.cc                          |    48 +-
 tools/abicompat.cc                            |   558 +-
 91 files changed, 102720 insertions(+), 296210 deletions(-)
 create mode 100755 tests/data/test-abicompat/libtest6-undefined-var.so
 create mode 100644 tests/data/test-abicompat/test6-undefined-var.cc
 delete mode 100755 tests/data/test-abicompat/test6-var-changed-app
 delete mode 100644 tests/data/test-abicompat/test6-var-changed-app.cc
 create mode 100644 tests/data/test-abicompat/test6-var-changed-report-2.txt

[The patch is too big for the mailing list so I am attaching it in
gzipped form below].


[-- Attachment #2: 0001-Represent-undefined-corpus-interfaces-to-analyze-app.patch.gz --]
[-- Type: application/gzip, Size: 2537136 bytes --]

[-- Attachment #3: Type: text/plain, Size: 13 bytes --]


-- 
		Dodji

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] Factorize elf-reader::{variable,function}_symbol_is_exported into symtab
  2024-03-14 16:54 [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode Dodji Seketeli
  2024-03-14 16:57 ` [PATCH 1/4] Represent undefined corpus interfaces to analyze app compatibility Dodji Seketeli
@ 2024-03-14 16:59 ` Dodji Seketeli
  2024-03-14 17:00 ` [PATCH 3/4] Add support for undefined symbols in the BTF reader Dodji Seketeli
  2024-03-14 17:00 ` [PATCH 4/4] Emit & read undefined interfaces to & from ABIXML Dodji Seketeli
  3 siblings, 0 replies; 5+ messages in thread
From: Dodji Seketeli @ 2024-03-14 16:59 UTC (permalink / raw)
  To: dodji; +Cc: libabigail

Hello,

Move the code of elf-reader::{variable,function}_symbol_is_exported into
symtab::{variable,function}_symbol_is_exported (where it belongs) and
make the former use the later.

	* src/abg-elf-reader.cc (reader::function_symbol_is_exported): Use
	the new symtab::function_symbol_is_exported.
	(reader::variable_symbol_is_exported): Use the new
	symtab::variable_symbol_is_exported.
	* src/abg-symtab-reader.cc
	(symtab::{function,variable}_symbol_is_exported): Factorize
	elf::reader::{function,variable}_symbol_is_exported into this.
	* src/abg-symtab-reader.h
	(symtab::{function,variable}_symbol_is_exported): Declare new
	member functions.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 src/abg-elf-reader.cc    | 59 ++++++++++++---------------
 src/abg-symtab-reader.cc | 87 ++++++++++++++++++++++++++++++++++++++++
 src/abg-symtab-reader.h  | 12 ++++++
 3 files changed, 124 insertions(+), 34 deletions(-)

diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc
index afb038ff..14f8ce6a 100644
--- a/src/abg-elf-reader.cc
+++ b/src/abg-elf-reader.cc
@@ -788,13 +788,12 @@ reader::symtab() const
 elf_symbol_sptr
 reader::function_symbol_is_exported(GElf_Addr symbol_address) const
 {
-  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
+
+  elf_symbol_sptr symbol =
+    symtab()->function_symbol_is_exported(symbol_address);
   if (!symbol)
     return symbol;
 
-  if (!symbol->is_function() || !symbol->is_public())
-    return elf_symbol_sptr();
-
   address_set_sptr set;
   bool looking_at_linux_kernel_binary =
     load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
@@ -820,13 +819,11 @@ reader::function_symbol_is_exported(GElf_Addr symbol_address) const
 elf_symbol_sptr
 reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
 {
-  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
+  elf_symbol_sptr symbol =
+    symtab()->variable_symbol_is_exported(symbol_address);
   if (!symbol)
     return symbol;
 
-  if (!symbol->is_variable() || !symbol->is_public())
-    return elf_symbol_sptr();
-
   address_set_sptr set;
   bool looking_at_linux_kernel_binary =
     load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
@@ -849,23 +846,20 @@ reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
 elf_symbol_sptr
 reader::function_symbol_is_exported(const string& name) const
 {
-  const elf_symbols& syms = symtab()->lookup_symbol(name);
-  for (auto s : syms)
+  const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
+  if (s && s->is_function() && s->is_public())
     {
-      if (s->is_function() && s->is_public())
-	{
-	  bool looking_at_linux_kernel_binary =
-	    (load_in_linux_kernel_mode()
-	     && elf_helpers::is_linux_kernel(elf_handle()));
+      bool looking_at_linux_kernel_binary =
+	(load_in_linux_kernel_mode()
+	 && elf_helpers::is_linux_kernel(elf_handle()));
 
-	  if (looking_at_linux_kernel_binary)
-	    {
-	      if (s->is_in_ksymtab())
-		return s;
-	    }
-	  else
+      if (looking_at_linux_kernel_binary)
+	{
+	  if (s->is_in_ksymtab())
 	    return s;
 	}
+      else
+	return s;
     }
   return elf_symbol_sptr();
 }
@@ -879,23 +873,20 @@ reader::function_symbol_is_exported(const string& name) const
 elf_symbol_sptr
 reader::variable_symbol_is_exported(const string& name) const
 {
-  const elf_symbols& syms = symtab()->lookup_symbol(name);
-  for (auto s : syms)
+  const elf_symbol_sptr s  = symtab()->variable_symbol_is_exported(name);
+  if (s->is_variable() && s->is_public())
     {
-      if (s->is_variable() && s->is_public())
-	{
-	  bool looking_at_linux_kernel_binary =
-	    (load_in_linux_kernel_mode()
-	     && elf_helpers::is_linux_kernel(elf_handle()));
+      bool looking_at_linux_kernel_binary =
+	(load_in_linux_kernel_mode()
+	 && elf_helpers::is_linux_kernel(elf_handle()));
 
-	  if (looking_at_linux_kernel_binary)
-	    {
-	      if (s->is_in_ksymtab())
-		return s;
-	    }
-	  else
+      if (looking_at_linux_kernel_binary)
+	{
+	  if (s->is_in_ksymtab())
 	    return s;
 	}
+      else
+	return s;
     }
   return elf_symbol_sptr();
 }
diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc
index 2eebc282..51177369 100644
--- a/src/abg-symtab-reader.cc
+++ b/src/abg-symtab-reader.cc
@@ -166,6 +166,93 @@ symtab::lookup_undefined_variable_symbol(const std::string& sym_name)
   return result;
 }
 
+/// Test if a given function symbol has been exported.
+///
+/// Note that this doesn't test if the symbol is defined or not, but
+/// assumes the symbol is defined.
+///
+/// @param name the name of the symbol we are looking for.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+symtab::function_symbol_is_exported(const string& name)
+{
+  const elf_symbols& syms = lookup_symbol(name);
+  for (auto s : syms)
+    if (s->is_function() && s->is_public())
+      return s;
+
+  return elf_symbol_sptr();
+}
+
+/// Test if a given function symbol has been exported.
+///
+/// Note that this doesn't test if the symbol is defined or not, but
+/// assumes the symbol is defined.
+///
+/// @param symbol_address the address of the symbol we are looking
+/// for.  Note that this address must be a relative offset from the
+/// beginning of the .text section, just like the kind of addresses
+/// that are present in the .symtab section.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+symtab::function_symbol_is_exported(const GElf_Addr symbol_address)
+{
+  elf_symbol_sptr symbol = lookup_symbol(symbol_address);
+  if (!symbol)
+    return symbol;
+
+  if (!symbol->is_function() || !symbol->is_public())
+    return elf_symbol_sptr();
+
+  return symbol;
+}
+
+/// Test if a given variable symbol has been exported.
+///
+/// Note that this assumes the symbol is exported but doesn't test for
+/// it.
+///
+/// @param name the name of the symbol we are looking
+/// for.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+symtab::variable_symbol_is_exported(const string& name)
+{
+  const elf_symbols& syms = lookup_symbol(name);
+  for (auto s : syms)
+    if (s->is_variable() && s->is_public())
+      return s;
+
+  return elf_symbol_sptr();
+}
+
+/// Test if a given variable symbol has been exported.
+///
+/// Note that this assumes the symbol is exported but doesn't test for
+/// it.
+///
+/// @param symbol_address the address of the symbol we are looking
+/// for.  Note that this address must be a relative offset from the
+/// beginning of the .text section, just like the kind of addresses
+/// that are present in the .symtab section.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+symtab::variable_symbol_is_exported(const GElf_Addr symbol_address)
+{
+  elf_symbol_sptr symbol = lookup_symbol(symbol_address);
+  if (!symbol)
+    return symbol;
+
+  if (!symbol->is_variable() || !symbol->is_public())
+    return elf_symbol_sptr();
+
+  return symbol;
+}
+
 /// Test if a name is a the name of an undefined function symbol.
 ///
 /// @param sym_name the symbol name to consider.
diff --git a/src/abg-symtab-reader.h b/src/abg-symtab-reader.h
index cc284453..43b40b79 100644
--- a/src/abg-symtab-reader.h
+++ b/src/abg-symtab-reader.h
@@ -248,6 +248,18 @@ public:
   const elf_symbol_sptr
   lookup_undefined_variable_symbol(const std::string& name);
 
+  elf_symbol_sptr
+  function_symbol_is_exported(const string&);
+
+  elf_symbol_sptr
+  function_symbol_is_exported(const GElf_Addr symbol_address);
+
+  elf_symbol_sptr
+  variable_symbol_is_exported(const string&);
+
+  elf_symbol_sptr
+  variable_symbol_is_exported(const GElf_Addr symbol_address);
+
   bool
   function_symbol_is_undefined(const string&);
 
-- 
2.39.3


-- 
		Dodji


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] Add support for undefined symbols in the BTF reader
  2024-03-14 16:54 [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode Dodji Seketeli
  2024-03-14 16:57 ` [PATCH 1/4] Represent undefined corpus interfaces to analyze app compatibility Dodji Seketeli
  2024-03-14 16:59 ` [PATCH 2/4] Factorize elf-reader::{variable,function}_symbol_is_exported into symtab Dodji Seketeli
@ 2024-03-14 17:00 ` Dodji Seketeli
  2024-03-14 17:00 ` [PATCH 4/4] Emit & read undefined interfaces to & from ABIXML Dodji Seketeli
  3 siblings, 0 replies; 5+ messages in thread
From: Dodji Seketeli @ 2024-03-14 17:00 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail

Hello,

This patch teaches the BTF reader how to construct an IR for undefined
interfaces.  The patch also updates the abicompat tool for BTF
support.

	* doc/manuals/abicompat.rst: Update documentation for the --btf
	option of abicompat.
	* include/abg-elf-reader.h
	(elf::reader::{function,variable}_symbol_is_undefined): Declare
	new member functions.
	* src/abg-btf-reader.cc
	(reader::read_debug_info_into_corpus): Sort functions &
	variables after canonicalization.
	(reader::build_ir_node_from_btf_type): Always call
	fe_iface::add_{fn,var}_to_exported_or_undefined_decls with the
	decl that was constructed.
	(reader::build_function_decl): Support setting an undefined symbol
	to the function decl.
	(reader::build_var_decl): Likewise, support setting undefined
	symbol the variable decl.
	* src/abg-elf-reader.cc
	((elf::reader::{function,variable}_symbol_is_undefined): Declare
	new member functions.): Define new member functions.
	* src/abg-symtab-reader.cc
	(symtab::{function,variable}_symbol_is_undefined): Return the
	undefined symbol that was found.
	* src/abg-symtab-reader.h
	(symtab::{function,variable}_symbol_is_undefined): Return an
	undefined symbol rather than just a boolean value.
	* tools/abicompat.cc: Add support for BTF here.
	(options::use_btf): Define new data member ...
	(options::options): ... and initialize it.
	(display_usage): Add a help string for the --btf option.
	(parse_command_line): Parse the --btf option.
	* tests/data/test-abicompat/test7-fn-changed-report-0.1.txt: New
	reference test output file.
	* tests/data/test-abicompat/test7-fn-changed-report-2.1.txt:
	Likewise.
	* tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so:
	New binary input file.
	* tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so:
	Likewise.
	* tests/data/test-abicompat/test7-fn-changed-app.btf: Likewise.
	* tests/data/Makefile.am: Add the new test material to source
	distribution.
	* tests/test-abicompat.cc (in_out_specs): Add the new test input
	to the test harness.
	* tests/data/test-abicompat/test7-fn-changed-app.c: Adjust.
	* tests/data/test-abicompat/test7-fn-changed-libapp-v0.c:
	Likewise.
	* tests/data/test-abicompat/test7-fn-changed-libapp-v1.c: Likewise

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 doc/manuals/abicompat.rst                     |   5 +++
 include/abg-elf-reader.h                      |   6 ++++
 src/abg-btf-reader.cc                         |  25 +++++++--------
 src/abg-elf-reader.cc                         |  19 +++++++++++
 src/abg-symtab-reader.cc                      |  30 +++++++++++++-----
 src/abg-symtab-reader.h                       |   4 +--
 tests/data/Makefile.am                        |   5 +++
 .../libtest7-fn-changed-libapp-btf-v0.so      | Bin 0 -> 16560 bytes
 .../libtest7-fn-changed-libapp-btf-v1.so      | Bin 0 -> 16584 bytes
 .../test-abicompat/test7-fn-changed-app.btf   | Bin 0 -> 17536 bytes
 .../test-abicompat/test7-fn-changed-app.c     |   2 ++
 .../test7-fn-changed-libapp-v0.c              |   2 ++
 .../test7-fn-changed-libapp-v1.c              |   3 ++
 .../test7-fn-changed-report-0.1.txt           |  19 +++++++++++
 .../test7-fn-changed-report-2.1.txt           |  16 ++++++++++
 tests/test-abicompat.cc                       |  22 +++++++++++++
 tools/abicompat.cc                            |  18 +++++++++++
 17 files changed, 153 insertions(+), 23 deletions(-)
 create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so
 create mode 100755 tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so
 create mode 100755 tests/data/test-abicompat/test7-fn-changed-app.btf
 create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-0.1.txt
 create mode 100644 tests/data/test-abicompat/test7-fn-changed-report-2.1.txt

diff --git a/doc/manuals/abicompat.rst b/doc/manuals/abicompat.rst
index e88a05a8..8f19c433 100644
--- a/doc/manuals/abicompat.rst
+++ b/doc/manuals/abicompat.rst
@@ -77,6 +77,11 @@ Options
    Do not show information about where in the *second shared library*
    the respective type was changed.
 
+  * ``--btf``
+
+    When comparing binaries, extract ABI information from BTF debug
+    information, if present.
+
   * ``--ctf``
 
     When comparing binaries, extract ABI information from CTF debug
diff --git a/include/abg-elf-reader.h b/include/abg-elf-reader.h
index ab350607..12f7b026 100644
--- a/include/abg-elf-reader.h
+++ b/include/abg-elf-reader.h
@@ -148,6 +148,12 @@ class reader : public fe_iface
   elf_symbol_sptr
   variable_symbol_is_exported(const string& name) const;
 
+  elf_symbol_sptr
+  function_symbol_is_undefined(const string& name) const;
+
+  elf_symbol_sptr
+  variable_symbol_is_undefined(const string& name) const;
+
   void
   load_dt_soname_and_needed();
 
diff --git a/src/abg-btf-reader.cc b/src/abg-btf-reader.cc
index ce7a7773..25fcb685 100644
--- a/src/abg-btf-reader.cc
+++ b/src/abg-btf-reader.cc
@@ -397,7 +397,8 @@ public:
       }
 
     canonicalize_types();
-
+    corpus()->sort_functions();
+    corpus()->sort_variables();
     return corpus();
   }
 
@@ -504,15 +505,9 @@ public:
     associate_artifact_to_btf_type_id(result, type_id);
 
     if (function_decl_sptr fn = is_function_decl(result))
-      {
-	if (fn->get_is_in_public_symbol_table())
-	  add_fn_to_exported_or_undefined_decls(fn.get());
-      }
+      add_fn_to_exported_or_undefined_decls(fn.get());
     else if (var_decl_sptr var = is_var_decl(result))
-      {
-	if (var->get_is_in_public_symbol_table())
-	  add_var_to_exported_or_undefined_decls(var.get());
-      }
+      add_var_to_exported_or_undefined_decls(var.get());
 
     return result;
   }
@@ -1021,10 +1016,12 @@ public:
 				   location(), /*linkage_name=*/fn_name));
 
     elf_symbol_sptr fn_sym;
-    if ((fn_sym = function_symbol_is_exported(fn_name)))
+    if ((fn_sym = function_symbol_is_exported(fn_name))
+	|| (fn_sym = function_symbol_is_undefined(fn_name)))
       {
 	result->set_symbol(fn_sym);
-	result->set_is_in_public_symbol_table(true);
+	if (fn_sym->is_defined())
+	  result->set_is_in_public_symbol_table(true);
       }
     return result;
   }
@@ -1055,10 +1052,12 @@ public:
 			      /*linkage_name=*/var_name));
 
     elf_symbol_sptr var_sym;
-    if ((var_sym = variable_symbol_is_exported(var_name)))
+    if ((var_sym = variable_symbol_is_exported(var_name))
+	|| (var_sym = variable_symbol_is_undefined(var_name)))
       {
 	result->set_symbol(var_sym);
-	result->set_is_in_public_symbol_table(true);
+	if (var_sym->is_defined())
+	  result->set_is_in_public_symbol_table(true);
       }
     return result;
   }
diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc
index 14f8ce6a..cbb20dd4 100644
--- a/src/abg-elf-reader.cc
+++ b/src/abg-elf-reader.cc
@@ -890,6 +890,25 @@ reader::variable_symbol_is_exported(const string& name) const
     }
   return elf_symbol_sptr();
 }
+
+/// Test if a name is the name of an undefined function symbol.
+///
+/// @param name the symbol name to consider.
+///
+/// @return the undefined function symbol or nil if none was found.
+elf_symbol_sptr
+reader::function_symbol_is_undefined(const string& name) const
+{return symtab()->function_symbol_is_undefined(name);}
+
+/// Test if a name is the name of an undefined variable symbol.
+///
+/// @param name the symbol name to consider.
+///
+/// @return the undefined variable symbol or nil if none was found.
+elf_symbol_sptr
+reader::variable_symbol_is_undefined(const string& name) const
+{return symtab()->variable_symbol_is_undefined(name);}
+
 /// Load the DT_NEEDED and DT_SONAME elf TAGS.
 void
 reader::load_dt_soname_and_needed()
diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc
index 51177369..fc0cac59 100644
--- a/src/abg-symtab-reader.cc
+++ b/src/abg-symtab-reader.cc
@@ -257,26 +257,40 @@ symtab::variable_symbol_is_exported(const GElf_Addr symbol_address)
 ///
 /// @param sym_name the symbol name to consider.
 ///
-/// @return true iff @p sym_name is the name of a an undefined
-/// function symbol.
-bool
+/// @return the undefined symbol if found, nil otherwise.
+elf_symbol_sptr
 symtab::function_symbol_is_undefined(const string& sym_name)
 {
   collect_undefined_fns_and_vars_linkage_names();
-  return undefined_function_linkage_names_.count(sym_name);
+  if (undefined_function_linkage_names_.count(sym_name))
+    {
+      elf_symbol_sptr sym = lookup_undefined_function_symbol(sym_name);
+      ABG_ASSERT(sym);
+      ABG_ASSERT(sym->is_function());
+      ABG_ASSERT(!sym->is_defined());
+      return sym;
+    }
+  return elf_symbol_sptr();
 }
 
 /// Test if a name is a the name of an undefined variable symbol.
 ///
 /// @param sym_name the symbol name to consider.
 ///
-/// @return true iff @p sym_name is the name of a an undefined
-/// variable symbol.
-bool
+// @return the undefined symbol if found, nil otherwise.
+elf_symbol_sptr
 symtab::variable_symbol_is_undefined(const string& sym_name)
 {
   collect_undefined_fns_and_vars_linkage_names();
-  return undefined_variable_linkage_names_.count(sym_name);
+  if (undefined_variable_linkage_names_.count(sym_name))
+    {
+      elf_symbol_sptr sym = lookup_undefined_variable_symbol(sym_name);
+      ABG_ASSERT(sym);
+      ABG_ASSERT(sym->is_variable());
+      ABG_ASSERT(!sym->is_defined());
+      return sym;
+    }
+  return elf_symbol_sptr();
 }
 
 /// A symbol sorting functor.
diff --git a/src/abg-symtab-reader.h b/src/abg-symtab-reader.h
index 43b40b79..390ee874 100644
--- a/src/abg-symtab-reader.h
+++ b/src/abg-symtab-reader.h
@@ -260,10 +260,10 @@ public:
   elf_symbol_sptr
   variable_symbol_is_exported(const GElf_Addr symbol_address);
 
-  bool
+  elf_symbol_sptr
   function_symbol_is_undefined(const string&);
 
-  bool
+  elf_symbol_sptr
   variable_symbol_is_undefined(const string&);
 
   static symtab_ptr
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 3e175209..5bf01528 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -2097,16 +2097,21 @@ test-abicompat/test6-var-changed-report-0.txt \
 test-abicompat/test6-var-changed-report-1.txt \
 test-abicompat/test6-var-changed-report-2.txt \
 test-abicompat/libtest7-fn-changed-libapp-v0.so \
+test-abicompat/libtest7-fn-changed-libapp-btf-v0.so \
 test-abicompat/libtest7-fn-changed-libapp-v1.so \
+test-abicompat/libtest7-fn-changed-libapp-btf-v1.so \
 test-abicompat/test7-fn-changed-app \
+test-abicompat/test7-fn-changed-app.btf \
 test-abicompat/test7-fn-changed-app.c \
 test-abicompat/test7-fn-changed-libapp-v0.c \
 test-abicompat/test7-fn-changed-libapp-v0.h \
 test-abicompat/test7-fn-changed-libapp-v1.c \
 test-abicompat/test7-fn-changed-libapp-v1.h \
 test-abicompat/test7-fn-changed-report-0.txt \
+test-abicompat/test7-fn-changed-report-0.1.txt \
 test-abicompat/test7-fn-changed-report-1.txt \
 test-abicompat/test7-fn-changed-report-2.txt \
+test-abicompat/test7-fn-changed-report-2.1.txt \
 test-abicompat/libtest8-fn-changed-libapp-v0.so \
 test-abicompat/libtest8-fn-changed-libapp-v1.so \
 test-abicompat/test8-fn-changed-app \
diff --git a/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so b/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so
new file mode 100755
index 0000000000000000000000000000000000000000..a61749662ff7d29cdfd9be39d5faf9cb95782909
GIT binary patch
literal 16560
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so b/tests/data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so
new file mode 100755
index 0000000000000000000000000000000000000000..8970d55a2ea6ae8718997c2b639ea8787647de68
GIT binary patch
literal 16584
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
F{{zL+8D;<g

literal 0
HcmV?d00001

diff --git a/tests/data/test-abicompat/test7-fn-changed-app.btf b/tests/data/test-abicompat/test7-fn-changed-app.btf
new file mode 100755
index 0000000000000000000000000000000000000000..71a01ef448a2a429a77fc9dfa2e7061da2931841
GIT binary patch
literal 17536
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-abicompat/test7-fn-changed-app.c b/tests/data/test-abicompat/test7-fn-changed-app.c
index 90dfe790..813d8aa0 100644
--- a/tests/data/test-abicompat/test7-fn-changed-app.c
+++ b/tests/data/test-abicompat/test7-fn-changed-app.c
@@ -1,5 +1,7 @@
 // Compile this with:
 // gcc -g -o test7-fn-changed-app -L. -ltest7-fn-changed-libapp-v0 test7-fn-changed-app.c
+// Or, for BTF debug info, with:
+// gcc -gbtf -o test7-fn-changed-app.btf -L. -ltest7-fn-changed-libapp-v0 test7-fn-changed-app.c
 
 #include <stdio.h>
 #include "test7-fn-changed-libapp-v0.h"
diff --git a/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c b/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c
index 8c3581e2..c36993ce 100644
--- a/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c
+++ b/tests/data/test-abicompat/test7-fn-changed-libapp-v0.c
@@ -1,5 +1,7 @@
 // Compile this with:
 // gcc -g -Wall -fPIC -shared -o libtest7-fn-changed-libapp-v0.so test7-fn-changed-libapp-v0.c
+// Or, for BTF debug info with:
+// gcc -gbtf -Wall -fPIC -shared -o libtest7-fn-changed-libapp-btf-v0.so test7-fn-changed-libapp-v0.c
 
 #include <stdio.h>
 #include "test7-fn-changed-libapp-v0.h"
diff --git a/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c b/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c
index 92c44394..822efa0c 100644
--- a/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c
+++ b/tests/data/test-abicompat/test7-fn-changed-libapp-v1.c
@@ -1,5 +1,8 @@
 // Compile this with:
 // gcc -g -Wall -fPIC -shared -o libtest7-fn-changed-libapp-v1.so test7-fn-changed-libapp-v1.c
+// Or, for BTF debug info, with:
+// gcc -gbtf -Wall -fPIC -shared -o libtest7-fn-changed-libapp-btf-v1.so test7-fn-changed-libapp-v1.c
+
 #include <stdio.h>
 #include "test7-fn-changed-libapp-v1.h"
 
diff --git a/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt b/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt
new file mode 100644
index 00000000..39b69d8f
--- /dev/null
+++ b/tests/data/test-abicompat/test7-fn-changed-report-0.1.txt
@@ -0,0 +1,19 @@
+ELF file 'test7-fn-changed-app.btf' might not be ABI compatible with 'libtest7-fn-changed-libapp-btf-v1.so' due to differences with 'libtest7-fn-changed-libapp-btf-v0.so' below:
+Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C] 'function float add(float, float)' has some indirect sub-type changes:
+    return type changed:
+      type name changed from 'float' to 'int'
+      type size hasn't changed
+      mangled name changed from 'float' to int
+
+  [C] 'function void print(const Student)' has some indirect sub-type changes:
+    parameter 1 of type 'const Student' has sub-type changes:
+      in unqualified underlying type 'struct Student':
+        type size changed from 128 to 192 (in bits)
+        1 data member insertion:
+          'float percentage', at offset 128 (in bits)
+
diff --git a/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt b/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt
new file mode 100644
index 00000000..4645006e
--- /dev/null
+++ b/tests/data/test-abicompat/test7-fn-changed-report-2.1.txt
@@ -0,0 +1,16 @@
+functions defined in library 'libtest7-fn-changed-libapp-btf-v1.so'
+have sub-types that are different from what application 'test7-fn-changed-app.btf' expects:
+
+  function float add(float, float):
+    return type changed:
+      type name changed from 'float' to 'int'
+      type size hasn't changed
+      mangled name changed from 'float' to int
+
+  function void print(const Student):
+    parameter 1 of type 'const Student' has sub-type changes:
+      in unqualified underlying type 'struct Student':
+        type size changed from 128 to 192 (in bits)
+        1 data member insertion:
+          'float percentage', at offset 128 (in bits)
+
diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc
index e992454c..320436c3 100644
--- a/tests/test-abicompat.cc
+++ b/tests/test-abicompat.cc
@@ -168,6 +168,17 @@ InOutSpec in_out_specs[] =
     "data/test-abicompat/test7-fn-changed-report-0.txt",
     "output/test-abicompat/test7-fn-changed-report-0.txt",
   },
+#ifdef WITH_BTF
+  {
+    "data/test-abicompat/test7-fn-changed-app.btf",
+    "data/test-abicompat/libtest7-fn-changed-libapp-btf-v0.so",
+    "data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so",
+    "",
+    "--show-base-names --no-show-locs --no-redundant --btf",
+    "data/test-abicompat/test7-fn-changed-report-0.1.txt",
+    "output/test-abicompat/test7-fn-changed-report-0.1.txt",
+  },
+#endif
   {
     "data/test-abicompat/test7-fn-changed-app",
     "data/test-abicompat/libtest7-fn-changed-libapp-v1.so",
@@ -186,6 +197,17 @@ InOutSpec in_out_specs[] =
     "data/test-abicompat/test7-fn-changed-report-2.txt",
     "output/test-abicompat/test7-fn-changed-report-2.txt",
   },
+#ifdef WITH_BTF
+  {
+    "data/test-abicompat/test7-fn-changed-app.btf",
+    "data/test-abicompat/libtest7-fn-changed-libapp-btf-v1.so",
+    "",
+    "",
+    "--show-base-names --no-show-locs --weak-mode",
+    "data/test-abicompat/test7-fn-changed-report-2.1.txt",
+    "output/test-abicompat/test7-fn-changed-report-2.1.txt",
+  },
+#endif
   {
     "data/test-abicompat/test8-fn-changed-app",
     "data/test-abicompat/libtest8-fn-changed-libapp-v1.so",
diff --git a/tools/abicompat.cc b/tools/abicompat.cc
index 4e5a8e22..9c4771c9 100644
--- a/tools/abicompat.cc
+++ b/tools/abicompat.cc
@@ -34,6 +34,7 @@
 #include <iostream>
 #include <memory>
 #include <string>
+#include "config.h"
 #include "abg-config.h"
 #include "abg-tools-utils.h"
 #include "abg-corpus.h"
@@ -44,6 +45,9 @@
 #ifdef WITH_CTF
 #include "abg-ctf-reader.h"
 #endif
+#ifdef WITH_BTF
+#include "abg-btf-reader.h"
+#endif
 
 using std::string;
 using std::cerr;
@@ -111,6 +115,9 @@ public:
 #ifdef WITH_CTF
   bool			use_ctf;
 #endif
+#ifdef WITH_BTF
+  bool			use_btf;
+#endif
 
   options(const char* program_name)
     :prog_name(program_name),
@@ -128,6 +135,10 @@ public:
 #ifdef WITH_CTF
     ,
       use_ctf()
+#endif
+#ifdef WITH_BTF
+    ,
+      use_btf()
 #endif
   {}
 }; // end struct options
@@ -237,6 +248,9 @@ display_usage(const string& prog_name, ostream& out)
     "just one version of the library.\n"
 #ifdef WITH_CTF
     << "  --ctf use CTF instead of DWARF in ELF files\n"
+#endif
+#ifdef WITH_BTF
+    << "  --btf use BTF instead of DWARF in ELF files\n"
 #endif
     ;
 }
@@ -344,6 +358,10 @@ parse_command_line(int argc, char* argv[], options& opts)
 #ifdef WITH_CTF
       else if (!strcmp(argv[i], "--ctf"))
         opts.use_ctf = true;
+#endif
+#ifdef WITH_BTF
+      else if (!strcmp(argv[i], "--btf"))
+        opts.use_btf = true;
 #endif
       else
 	{
-- 
2.39.3



-- 
		Dodji


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] Emit & read undefined interfaces to & from ABIXML
  2024-03-14 16:54 [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode Dodji Seketeli
                   ` (2 preceding siblings ...)
  2024-03-14 17:00 ` [PATCH 3/4] Add support for undefined symbols in the BTF reader Dodji Seketeli
@ 2024-03-14 17:00 ` Dodji Seketeli
  3 siblings, 0 replies; 5+ messages in thread
From: Dodji Seketeli @ 2024-03-14 17:00 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: libabigail

Hello,

This 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.

The patch introduces tests that perform compatibility checks done on
ABIXML files.

	* 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-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.
	* tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so:
	New binary input file.
	* tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so:
	New binary input file.
	* tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi:
	New abixml input file.
	* tests/data/test-abicompat/test10/test10-app-with-undefined-symbols:
	New binary input file.
	* tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi:
	New abixml input file.
	* tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-with-exported-symbols.cc:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-with-exported-symbols.h:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc:
	New source file for binary test input
	* tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h:
	New source file for binary test input.
	* tests/data/Makefile.am: Add new test input files to source
	distribution.
	* tests/test-abicompat.cc (in_out_specs): Add the new test inputs
	to this test harness.
	* tests/test-annotate.cc (main): Use the new
	--no-load-undefined-interfaces option of abidw to keep the old
	behavior.
	* tests/test-read-common.cc (test_task::serialize_corpus): Do not
	emit undefined symbols.
	* tests/test-read-dwarf.cc (test_task_dwarf::perform): Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 doc/manuals/abidw.rst                         |   10 +
 include/abg-writer.h                          |    4 +
 ...-undefined-interfaces-to-from-ABIXML.patch | 1051 +++++++++++++++++
 src/abg-dwarf-reader.cc                       |  189 +--
 src/abg-reader.cc                             |   81 +-
 src/abg-writer.cc                             |  152 ++-
 tests/data/Makefile.am                        |   15 +
 .../test10/libtest10-with-exported-symbols.so |  Bin 0 -> 18288 bytes
 ...st10-with-incompatible-exported-symbols.so |  Bin 0 -> 18336 bytes
 ...-with-incompatible-exported-symbols.so.abi |   65 +
 .../test10/test10-app-with-undefined-symbols  |  Bin 0 -> 26072 bytes
 .../test10-app-with-undefined-symbols.abi     |   55 +
 .../test10-app-with-undefined-symbols.cc      |   13 +
 .../test10/test10-fn-changed-report-0.txt     |    0
 .../test10/test10-fn-changed-report-1.txt     |   13 +
 .../test10/test10-fn-changed-report-2.txt     |   13 +
 .../test10/test10-fn-changed-report-3.txt     |   13 +
 .../test10/test10-fn-changed-report-4.txt     |   13 +
 .../test10/test10-with-exported-symbols.cc    |   20 +
 .../test10/test10-with-exported-symbols.h     |   14 +
 ...st10-with-incompatible-exported-symbols.cc |   20 +
 ...est10-with-incompatible-exported-symbols.h |   14 +
 tests/test-abicompat.cc                       |   54 +
 tests/test-annotate.cc                        |    2 +-
 tests/test-read-common.cc                     |    1 +
 tests/test-read-dwarf.cc                      |    2 +-
 tools/abidw.cc                                |    7 +
 27 files changed, 1698 insertions(+), 123 deletions(-)
 create mode 100644 patches/0001-WIP-Emit-read-undefined-interfaces-to-from-ABIXML.patch
 create mode 100755 tests/data/test-abicompat/test10/libtest10-with-exported-symbols.so
 create mode 100755 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so
 create mode 100644 tests/data/test-abicompat/test10/libtest10-with-incompatible-exported-symbols.so.abi
 create mode 100755 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols
 create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.abi
 create mode 100644 tests/data/test-abicompat/test10/test10-app-with-undefined-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-0.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-1.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-2.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-3.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-fn-changed-report-4.txt
 create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-with-exported-symbols.h
 create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.cc
 create mode 100644 tests/data/test-abicompat/test10/test10-with-incompatible-exported-symbols.h

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
literal 18288
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
asdG8!c5SJ^6H0CS->d&CG3GLGvEn~NT{;o~

literal 0
HcmV?d00001

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
new file mode 100755
index 0000000000000000000000000000000000000000..d63e70b4677ab56154d66bb64da943bbc100e15a
GIT binary patch
literal 18336
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
SxbHGXw0W1sP1p=<toRQ+hDclh

literal 0
HcmV?d00001

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
literal 26072
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
M;N!4F2I;o{2cRGJzW@LL

literal 0
HcmV?d00001

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
new file mode 100644
index 00000000..055c1e85
--- /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
-- 
2.39.3



-- 
		Dodji


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-03-14 17:01 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-14 16:54 [PATCH 0/4] Support undefined interfaces to fix abicompt's weak mode Dodji Seketeli
2024-03-14 16:57 ` [PATCH 1/4] Represent undefined corpus interfaces to analyze app compatibility Dodji Seketeli
2024-03-14 16:59 ` [PATCH 2/4] Factorize elf-reader::{variable,function}_symbol_is_exported into symtab Dodji Seketeli
2024-03-14 17:00 ` [PATCH 3/4] Add support for undefined symbols in the BTF reader Dodji Seketeli
2024-03-14 17:00 ` [PATCH 4/4] Emit & read undefined interfaces to & from ABIXML Dodji Seketeli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).