public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
To: libabigail@sourceware.org
Cc: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
Subject: [PATCH v4] ELF based front-end readers fallback feature
Date: Tue, 22 Nov 2022 10:00:50 -0600	[thread overview]
Message-ID: <20221122160050.2031623-1-guillermo.e.martinez@oracle.com> (raw)
In-Reply-To: <20221121185102.1163007-1-guillermo.e.martinez@oracle.com>

This patch-v4 to implement the fallback behaviour for
CTF/DWARF front-ends.

Changes from v3:
   * Add missing test inputs:
   tests/data/test-read-{ctf,dwarf}/test-fallback.o 

Please let me know your thoughts, they will be really appreciated!.

Thanks in advanced,
guillermo
--

By default, `abidw', `abidiff', `abipkgdiff' and `kmidiff' tools use
debug information in `DWARF` format, if present, otherwise now
automatically the tools try to extract and build the IR using
debug information in `CTF` format without use of `--ctf' option, if
present, finally, if neither is found, they use only `ELF` symbols to
extract, build, compare and report the binary IR. To force the use of
CTF front-end the `--ctf' option should be pass to command line.

It works for libraries and Linux kernel.  The `--ctf' option is
preserved to explicitly indicate to those tools that we want to use
CTF support. By other hand, if tools use `--ctf' but binary doesn't
have CTF debug information it looks for DWARF automatically.

	* doc/manuals/abidiff.rst: Adjust usage tool information
	to indicates fallback for CTF debug info when DWARF info
	is not present.
	* doc/manuals/abidw.rst: Likewise.
	* doc/manuals/abipkgdiff.rst: Likewise.
	* doc/manuals/kmidiff.rst: Likewise.
	* include/abg-elf-based-reader.h (initialize): Add member function.
	* include/abg-elf-reader.h (has_{dwarf,ctf}_debug_info): Add predicate
	functions.
	* include/abg-tools-utils.h (create_best_elf_based_reader): Add arguments.
	* src/abg-ctf-reader.cc (process_ctf_typedef, process_ctf_base_type)
	(process_ctf_function_type, process_ctf_sou_members, process_ctf_forward_type)
	(process_ctf_struct_type, process_ctf_union_type, process_ctf_array_type)
	(process_ctf_qualified_type, process_ctf_pointer_type, process_ctf_enum_type):
	Remove arguments. Using getters to access required information instead.
	(reader::cur_tu_): Add data member.
	(initialize): Add arguments.
	(cur_transl_unit): Add {get,set)ter.
	(slurp_elf_info): Clear `STATUS_DEBUG_INFO_NOT_FOUND' if corpus is
	`LINUX_KERNEL_BINARY_ORIGIN'.
	(reader::lookup_type): Remove.
	(reader::build_type): New member function.
	* src/abg-elf-reader.cc (reader::reader): Locate ctf debug info from binary file.
	(reader::reader): Reset base `fe_iface' constructor.
	(reader::has_{dwarf,ctf}_debug_info): New definitions.
	(reader::read_corpus): Set `STATUS_DEBUG_INFO_NOT_FOUND' according to corpus::origin.
	* src/abg-tools-utils.cc (dir_contains_ctf_archive): Define new member.
	(file_has_ctf_debug_info): Looks for kernel ctf debug information archive.
	(maybe_load_vmlinux_{dwarf,ctf}_corpus): Remove.
	(load_vmlinux_corpus): Define function to load IR from kernel regardless the
	corpus::origin.
	(build_corpus_group_from_kernel_dist_under): Make use of
	`create_best_elf_based_reader'
	to select the front-end.
	(create_best_elf_based_reader): Adjust to allow fallback behaviour for different
	front-ends.
	* tests/data/Makefile.am: Add tests.
	* tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt: Adjust.
	* tests/data/test-read-ctf/test-fallback.abi: New test case.
	* tests/data/test-read-ctf/test-fallback.c: Likewise.
	* tests/data/test-read-ctf/test-fallback.o: Likewise.
	* tests/data/test-read-dwarf/test-fallback.abi: Likewise.
	* tests/data/test-read-dwarf/test-fallback.c: Likewise.
	* tests/data/test-read-dwarf/test-fallback.o: Likewise.
	* tests/test-diff-pkg.cc: Adjust.
	* tests/test-read-common.cc (test_task::run_abidw): Use of `options:option' field.
	* tests/test-read-common.h (InOutSpec): Add new member.
	* tests/test-read-ctf.cc (in_out_specs): Add option field to test suite.
	Add new test case.
	* tests/test-read-dwarf.cc: Likewise.
	* tools/abidiff.cc (main): Use `create_best_elf_based_reader'.
	* tools/abidw.cc: Likewise.
	* tools/abipkgdiff.cc: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
---
 doc/manuals/abidiff.rst                       |  15 +-
 doc/manuals/abidw.rst                         |  15 +-
 doc/manuals/abipkgdiff.rst                    |  13 +-
 doc/manuals/kmidiff.rst                       |   9 +-
 include/abg-elf-based-reader.h                |   5 +
 include/abg-elf-reader.h                      |   6 +
 include/abg-tools-utils.h                     |   5 +-
 src/abg-ctf-reader.cc                         | 267 +++++++----------
 src/abg-elf-reader.cc                         |  29 +-
 src/abg-tools-utils.cc                        | 281 +++++++++---------
 tests/data/Makefile.am                        |   6 +
 .../test-diff-pkg-ctf/dirpkg-3-report-2.txt   |  16 +
 tests/data/test-read-ctf/test-fallback.abi    |   9 +
 tests/data/test-read-ctf/test-fallback.c      |   8 +
 tests/data/test-read-ctf/test-fallback.o      | Bin 0 -> 1216 bytes
 tests/data/test-read-dwarf/test-fallback.abi  |   9 +
 tests/data/test-read-dwarf/test-fallback.c    |   8 +
 tests/data/test-read-dwarf/test-fallback.o    | Bin 0 -> 2424 bytes
 tests/test-diff-pkg.cc                        |   2 +-
 tests/test-read-common.cc                     |   5 +-
 tests/test-read-common.h                      |   1 +
 tests/test-read-ctf.cc                        |  93 ++++--
 tests/test-read-dwarf.cc                      | 121 ++++++--
 tools/abidiff.cc                              |  44 ++-
 tools/abidw.cc                                |  26 +-
 tools/abipkgdiff.cc                           |  43 ++-
 26 files changed, 606 insertions(+), 430 deletions(-)
 create mode 100644 tests/data/test-read-ctf/test-fallback.abi
 create mode 100644 tests/data/test-read-ctf/test-fallback.c
 create mode 100644 tests/data/test-read-ctf/test-fallback.o
 create mode 100644 tests/data/test-read-dwarf/test-fallback.abi
 create mode 100644 tests/data/test-read-dwarf/test-fallback.c
 create mode 100644 tests/data/test-read-dwarf/test-fallback.o

diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
index c728b373..a8878d2c 100644
--- a/doc/manuals/abidiff.rst
+++ b/doc/manuals/abidiff.rst
@@ -12,11 +12,12 @@ This tool can also compare the textual representations of the ABI of
 two ELF binaries (as emitted by ``abidw``) or an ELF binary against a
 textual representation of another ELF binary.
 
-For a comprehensive ABI change report that includes changes about
-function and variable sub-types, the two input shared libraries must
-be accompanied with their debug information in `DWARF`_ format.
-Otherwise, only `ELF`_ symbols that were added or removed are
-reported.
+For a comprehensive ABI change report between two input shared
+libraries that includes changes about function and variable sub-types,
+``abidiff`` uses by default, debug information in `DWARF`_ format, if
+present, otherwise it compares interfaces using debug information in
+`CTF`_ format, if present, finally, if neither is found, it uses only
+`ELF`_ symbols to report which of them were added or removed.
 
 .. include:: tools-use-libabigail.txt
 
@@ -581,7 +582,7 @@ Options
 
   * ``--ctf``
 
-    When comparing binaries, extract ABI information from CTF debug
+    When comparing binaries, extract ABI information from `CTF`_ debug
     information, if present.
 
   * ``--stats``
@@ -808,4 +809,4 @@ Usage examples
 
 .. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
 .. _DWARF: http://www.dwarfstd.org
-
+.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
diff --git a/doc/manuals/abidw.rst b/doc/manuals/abidw.rst
index a3055c7e..20948805 100644
--- a/doc/manuals/abidw.rst
+++ b/doc/manuals/abidw.rst
@@ -8,8 +8,7 @@ representation of its ABI to standard output.  The emitted
 representation format, named ``ABIXML``, includes all the globally
 defined functions and variables, along with a complete representation
 of their types.  It also includes a representation of the globally
-defined ELF symbols of the file.  The input shared library must
-contain associated debug information in `DWARF`_ format.
+defined ELF symbols of the file.
 
 When given the ``--linux-tree`` option, this program can also handle a
 `Linux kernel`_ tree.  That is, a directory tree that contains both
@@ -19,8 +18,13 @@ interface between the kernel and its module, to standard output.  In
 this case, we don't call it an ABI, but a KMI (Kernel Module
 Interface).  The emitted KMI includes all the globally defined
 functions and variables, along with a complete representation of their
-types.  The input binaries must contain associated debug information
-in `DWARF`_ format.
+types.
+
+To generate either ABI or KMI representation, by default ``abidw``
+uses debug information in `DWARF`_ format, if present, otherwise it
+looks for debug information in `CTF`_ format, if present, finally, if
+neither is found, it uses only `ELF`_ symbols to report which of them
+were added or removed.
 
 .. include:: tools-use-libabigail.txt
 
@@ -326,7 +330,7 @@ Options
 
   * ``--ctf``
 
-    Extract ABI information from CTF debug information, if present in
+    Extract ABI information from `CTF`_ debug information, if present in
     the given object.
 
   *  ``--annotate``
@@ -365,3 +369,4 @@ standard `here
 .. _DWARF: http://www.dwarfstd.org
 .. _GNU: http://www.gnu.org
 .. _Linux Kernel: https://kernel.org/
+.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
diff --git a/doc/manuals/abipkgdiff.rst b/doc/manuals/abipkgdiff.rst
index 9114775a..771bb034 100644
--- a/doc/manuals/abipkgdiff.rst
+++ b/doc/manuals/abipkgdiff.rst
@@ -13,12 +13,18 @@ binaries.
 For a comprehensive ABI change report that includes changes about
 function and variable sub-types, the two input packages must be
 accompanied with their debug information packages that contain debug
-information either in `DWARF`_ or in `CTF` formats.  Please note
+information either in `DWARF`_ or in `CTF`_ formats.  Please note
 however that some packages contain binaries that embed the debug
 information directly in a section of said binaries.  In those cases,
 obviously, no separate debug information package is needed as the tool
 will find the debug information inside the binaries.
 
+By default, ``abipkgdiff`` uses debug information in `DWARF`_ format,
+if present, otherwise it compares binaries interfaces using debug
+information in `CTF`_ format, if present, finally, if neither is
+found, it uses only `ELF`_ symbols to report which of them were added
+or removed.
+
 .. include:: tools-use-libabigail.txt
 
 .. _abipkgdiff_invocation_label:
@@ -525,8 +531,8 @@ Options
 
   * ``--ctf``
 
-     This is used to compare packages with CTF debug information, if
-     present.
+     This is used to compare packages with `CTF`_ debug information,
+     if present.
 
 .. _abipkgdiff_return_value_label:
 
@@ -546,4 +552,5 @@ In the later case, the value of the exit code is the same as for the
 .. _Deb: https://en.wikipedia.org/wiki/Deb_%28file_format%29
 .. _tar: https://en.wikipedia.org/wiki/Tar_%28computing%29
 .. _DWARF: http://www.dwarfstd.org
+.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
 .. _Development Package: https://fedoraproject.org/wiki/Packaging:Guidelines?rd=Packaging/Guidelines#Devel_Packages
diff --git a/doc/manuals/kmidiff.rst b/doc/manuals/kmidiff.rst
index 53010189..a27d2456 100644
--- a/doc/manuals/kmidiff.rst
+++ b/doc/manuals/kmidiff.rst
@@ -74,6 +74,11 @@ functions and variables) between the Kernel and its modules.  In
 practice, though, some users might want to compare a subset of the
 those interfaces.
 
+By default, ``kmidiff`` uses debug information in `DWARF`_ format,
+if present, otherwise it compares interfaces using debug information
+in `CTF`_ format, if present, finally, if neither is found, it uses
+only `ELF`_ symbols to report which were added or removed.
+
 Users can then define a "white list" of the interfaces to compare.
 Such a white list is a just a file in the "INI" format that looks
 like: ::
@@ -174,7 +179,7 @@ Options
 
   * ``--ctf``
 
-    Extract ABI information from CTF debug information, if present in
+    Extract ABI information from `CTF`_ debug information, if present in
     the Kernel and Modules.
 
   * ``--impacted-interfaces | -i``
@@ -242,3 +247,5 @@ Options
 .. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
 .. _ksymtab: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
 .. _Linux Kernel: https://kernel.org
+.. _DWARF: http://www.dwarfstd.org
+.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
diff --git a/include/abg-elf-based-reader.h b/include/abg-elf-based-reader.h
index cf0c719e..4fae055e 100644
--- a/include/abg-elf-based-reader.h
+++ b/include/abg-elf-based-reader.h
@@ -56,6 +56,11 @@ public:
   virtual ir::corpus_sptr
   read_and_add_corpus_to_group(ir::corpus_group& group,
 			       fe_iface::status& status);
+  virtual void
+  initialize(const string&		elf_path,
+	     const vector<char**>&	debug_info_root_paths,
+	     bool			load_all_types,
+	     bool			linux_kernel_mode) = 0;
 };//end class elf_based_reader
 
 typedef std::shared_ptr<elf_based_reader> elf_based_reader_sptr;
diff --git a/include/abg-elf-reader.h b/include/abg-elf-reader.h
index 86999ac1..42897a92 100644
--- a/include/abg-elf-reader.h
+++ b/include/abg-elf-reader.h
@@ -91,6 +91,12 @@ class reader : public fe_iface
   const Dwarf*
   dwarf_debug_info() const;
 
+  bool
+  has_dwarf_debug_info() const;
+
+  bool
+  has_ctf_debug_info() const;
+
   const Dwarf*
   alternate_dwarf_debug_info() const;
 
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 9dc9b8d3..13d6ad75 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -322,7 +322,10 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 elf_based_reader_sptr
 create_best_elf_based_reader(const string& elf_file_path,
 			     const vector<char**>& debug_info_root_paths,
-			     environment& env);
+			     environment& env,
+			     bool use_ctf,
+			     bool show_all_types,
+			     bool linux_kernel_mode = false);
 
 }// end namespace tools_utils
 
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 5fde94f3..fdefd3a6 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -51,15 +51,11 @@ class reader;
 
 static typedef_decl_sptr
 process_ctf_typedef(reader *rdr,
-                    corpus_sptr corp,
-                    translation_unit_sptr tunit,
                     ctf_dict_t *ctf_dictionary,
                     ctf_id_t ctf_type);
 
 static type_decl_sptr
 process_ctf_base_type(reader *rdr,
-                      corpus_sptr corp,
-                      translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
                       ctf_id_t ctf_type);
 
@@ -69,63 +65,47 @@ build_ir_node_for_variadic_parameter_type(reader &rdr,
 
 static function_type_sptr
 process_ctf_function_type(reader *rdr,
-                          corpus_sptr corp,
-                          translation_unit_sptr tunit,
                           ctf_dict_t *ctf_dictionary,
                           ctf_id_t ctf_type);
 
 static void
 process_ctf_sou_members(reader *rdr,
-                        corpus_sptr corp,
-                        translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
                         ctf_id_t ctf_type,
                         class_or_union_sptr sou);
 
 static type_base_sptr
 process_ctf_forward_type(reader *rdr,
-                         translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
                          ctf_id_t ctf_type);
 
 static class_decl_sptr
 process_ctf_struct_type(reader *rdr,
-                        corpus_sptr corp,
-                        translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
                         ctf_id_t ctf_type);
 
 static union_decl_sptr
 process_ctf_union_type(reader *rdr,
-                       corpus_sptr corp,
-                       translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
                        ctf_id_t ctf_type);
 
 static array_type_def_sptr
 process_ctf_array_type(reader *rdr,
-                       corpus_sptr corp,
-                       translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
                        ctf_id_t ctf_type);
 
 static type_base_sptr
 process_ctf_qualified_type(reader *rdr,
-                           corpus_sptr corp,
-                           translation_unit_sptr tunit,
                            ctf_dict_t *ctf_dictionary,
                            ctf_id_t ctf_type);
 
 static pointer_type_def_sptr
 process_ctf_pointer_type(reader *rdr,
-                         corpus_sptr corp,
-                         translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
                          ctf_id_t ctf_type);
 
 static enum_type_decl_sptr
 process_ctf_enum_type(reader *rdr,
-                      translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
                       ctf_id_t ctf_type);
 
@@ -161,6 +141,7 @@ class reader : public elf_based_reader
   ctf_sect_t ctf_sect;
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
+  translation_unit_sptr cur_tu_;
 
 public:
 
@@ -263,17 +244,21 @@ public:
   {
     ctfa = nullptr;
     types_map.clear();
+    cur_tu_.reset();
     corpus_group().reset();
   }
 
   /// Initializer of the reader.
   ///
-  ///
   /// @param elf_path the new path to the new ELF file to use.
   ///
   /// @param debug_info_root_paths a vector of paths to use to look
   /// for debug info that is split out into a separate file.
   ///
+  /// @param load_all_types currently not used.
+  ///
+  /// @param linux_kernel_mode currently not used.
+  ///
   /// This is useful to clear out the data used by the reader and get
   /// it ready to be used again.
   ///
@@ -286,11 +271,32 @@ public:
   /// the environment.
   void
   initialize(const string& elf_path,
-             const vector<char**>& debug_info_root_paths)
+             const vector<char**>& debug_info_root_paths,
+             bool load_all_types = false,
+             bool linux_kernel_mode = false)
   {
+    load_all_types = load_all_types;
+    linux_kernel_mode = linux_kernel_mode;
     reset(elf_path, debug_info_root_paths);
   }
 
+  /// Setter of the current translation unit.
+  ///
+  /// @param tu the current translation unit being constructed.
+  void
+  cur_transl_unit(translation_unit_sptr tu)
+  {
+    if (tu)
+      cur_tu_ = tu;
+  }
+
+  /// Getter of the current translation unit.
+  ///
+  /// @return the current translation unit being constructed.
+  const translation_unit_sptr&
+  cur_transl_unit() const
+  {return cur_tu_;}
+
   /// Getter of the environment of the current CTF reader.
   ///
   /// @return the environment of the current CTF reader.
@@ -349,27 +355,24 @@ public:
     // Read the ELF-specific parts of the corpus.
     elf::reader::read_corpus(status);
 
-    if ((status & STATUS_NO_SYMBOLS_FOUND)
-	|| !(status & STATUS_OK))
-      // Either we couldn't find ELF symbols or something went badly
-      // wrong.  There is nothing we can do with this ELF file.  Bail
-      // out.
-      return;
-
     corpus_sptr corp = corpus();
     if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
 	&& corpus_group())
       {
-	status |= fe_iface::STATUS_OK;
+	// Is expected not find debug information when we're building
+	// a kABI.
+        status &= static_cast<abigail::fe_iface::status>
+                    (~STATUS_DEBUG_INFO_NOT_FOUND);
 	return;
       }
 
-    /* Get the raw ELF section contents for libctf.  */
-    if (!find_ctf_section())
-      {
-	status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
-	return;
-      }
+    if ((status & (STATUS_NO_SYMBOLS_FOUND |
+                   STATUS_DEBUG_INFO_NOT_FOUND))
+	|| !(status & STATUS_OK))
+      // Either we couldn't find ELF symbols or something went badly
+      // wrong.  There is nothing we can do with this ELF file.  Bail
+      // out.
+      return;
 
     GElf_Ehdr *ehdr, eh_mem;
     if (!(ehdr = gelf_getehdr(elf_handle(), &eh_mem)))
@@ -402,16 +405,16 @@ public:
   /// Process a CTF archive and create libabigail IR for the types,
   /// variables and function declarations found in the archive, iterating
   /// over public symbols.  The IR is added to the given corpus.
-  ///
-  /// @param corp the IR corpus to which add the new contents.
   void
-  process_ctf_archive(corpus_sptr corp)
+  process_ctf_archive()
   {
+    corpus_sptr corp = corpus();
     /* We only have a translation unit.  */
     translation_unit_sptr ir_translation_unit =
       std::make_shared<translation_unit>(env(), "", 64);
     ir_translation_unit->set_language(translation_unit::LANG_C);
     corp->add(ir_translation_unit);
+    cur_transl_unit(ir_translation_unit);
 
     int ctf_err;
     ctf_dict_t *ctf_dict, *dict_tmp;
@@ -455,8 +458,7 @@ public:
 	if (ctf_type_kind(ctf_dict, ctf_sym_type) != CTF_K_FUNCTION)
 	  {
 	    const char *var_name = sym_name.c_str();
-	    type_base_sptr var_type = lookup_type(corp, ir_translation_unit,
-						  ctf_dict, ctf_sym_type);
+	    type_base_sptr var_type = build_type(ctf_dict, ctf_sym_type);
 	    if (!var_type)
 	      /* Ignore variable if its type can't be sorted out.  */
 	      continue;
@@ -477,8 +479,7 @@ public:
 	  {
 	    const char *func_name = sym_name.c_str();
 	    ctf_id_t ctf_sym = ctf_sym_type;
-	    type_base_sptr func_type = lookup_type(corp, ir_translation_unit,
-						   ctf_dict, ctf_sym);
+	    type_base_sptr func_type = build_type(ctf_dict, ctf_sym);
 	    if (!func_type)
 	      /* Ignore function if its type can't be sorted out.  */
 	      continue;
@@ -508,8 +509,6 @@ public:
 
   /// Add a new type declaration to the given libabigail IR corpus CORP.
   ///
-  /// @param corp the libabigail IR corpus being constructed.
-  /// @param tunit the current IR translation unit.
   /// @param ctf_dictionary the CTF dictionary being read.
   /// @param ctf_type the CTF type ID of the source type.
   ///
@@ -518,11 +517,11 @@ public:
   ///
   /// @return a shared pointer to the IR node for the type.
   type_base_sptr
-  process_ctf_type(corpus_sptr corp,
-		   translation_unit_sptr tunit,
-		   ctf_dict_t *ctf_dictionary,
+  process_ctf_type(ctf_dict_t *ctf_dictionary,
 		   ctf_id_t ctf_type)
   {
+    corpus_sptr corp = corpus();
+    translation_unit_sptr tunit = cur_transl_unit();
     int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
     type_base_sptr result;
 
@@ -538,21 +537,21 @@ public:
       case CTF_K_FLOAT:
 	{
 	  type_decl_sptr type_decl
-	    = process_ctf_base_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_base_type(this, ctf_dictionary, ctf_type);
 	  result = is_type(type_decl);
 	  break;
 	}
       case CTF_K_TYPEDEF:
 	{
 	  typedef_decl_sptr typedef_decl
-	    = process_ctf_typedef(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_typedef(this, ctf_dictionary, ctf_type);
 	  result = is_type(typedef_decl);
 	  break;
 	}
       case CTF_K_POINTER:
 	{
 	  pointer_type_def_sptr pointer_type
-	    = process_ctf_pointer_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_pointer_type(this, ctf_dictionary, ctf_type);
 	  result = pointer_type;
 	  break;
 	}
@@ -561,49 +560,45 @@ public:
       case CTF_K_RESTRICT:
 	{
 	  type_base_sptr qualified_type
-	    = process_ctf_qualified_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_qualified_type(this, ctf_dictionary, ctf_type);
 	  result = qualified_type;
 	  break;
 	}
       case CTF_K_ARRAY:
 	{
 	  array_type_def_sptr array_type
-	    = process_ctf_array_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_array_type(this, ctf_dictionary, ctf_type);
 	  result = array_type;
 	  break;
 	}
       case CTF_K_ENUM:
 	{
 	  enum_type_decl_sptr enum_type
-	    = process_ctf_enum_type(this, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_enum_type(this, ctf_dictionary, ctf_type);
 	  result = enum_type;
 	  break;
 	}
       case CTF_K_FUNCTION:
 	{
 	  function_type_sptr function_type
-	    = process_ctf_function_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_function_type(this, ctf_dictionary, ctf_type);
 	  result = function_type;
 	  break;
 	}
       case CTF_K_STRUCT:
 	{
 	  class_decl_sptr struct_decl
-	    = process_ctf_struct_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_struct_type(this, ctf_dictionary, ctf_type);
 	  result = is_type(struct_decl);
 	  break;
 	}
       case CTF_K_FORWARD:
-	{
-	  result = process_ctf_forward_type(this, tunit,
-					    ctf_dictionary,
-					    ctf_type);
-	}
+	  result = process_ctf_forward_type(this, ctf_dictionary, ctf_type);
 	break;
       case CTF_K_UNION:
 	{
 	  union_decl_sptr union_decl
-	    = process_ctf_union_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	    = process_ctf_union_type(this, ctf_dictionary, ctf_type);
 	  result = is_type(union_decl);
 	  break;
 	}
@@ -622,11 +617,10 @@ public:
     return result;
   }
 
-  /// Given a CTF type id, lookup the corresponding libabigail IR type.
-  /// If the IR type hasn't been generated yet, generate it.
+  /// Given a CTF type id, build the corresponding libabigail IR type.
+  /// If the IR type has been generated it returns the corresponding
+  /// type.
   ///
-  /// @param corp the libabigail IR corpus being constructed.
-  /// @param tunit the current IR translation unit.
   /// @param ctf_dictionary the CTF dictionary being read.
   /// @param ctf_type the CTF type ID of the looked type.
   ///
@@ -635,14 +629,12 @@ public:
   ///
   /// @return a shared pointer to the IR node for the type.
   type_base_sptr
-  lookup_type(corpus_sptr corp,
-	      translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
-	      ctf_id_t ctf_type)
+  build_type(ctf_dict_t *ctf_dictionary, ctf_id_t ctf_type)
   {
     type_base_sptr result = lookup_type(ctf_dictionary, ctf_type);
 
     if (!result)
-      result = process_ctf_type(corp, tunit, ctf_dictionary, ctf_type);
+      result = process_ctf_type(ctf_dictionary, ctf_type);
     return result;
   }
 
@@ -664,13 +656,12 @@ public:
     origin |= corpus::CTF_ORIGIN;
     corp->set_origin(origin);
 
-    if (corpus_group())
-      corpus_group()->add_corpus(corpus());
-
     slurp_elf_info(status);
-    if (!elf_helpers::is_linux_kernel(elf_handle())
-	&& ((status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND) |
-	    (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)))
+    if (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)
+       return corpus_sptr();
+
+    if (!(origin & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+          && (status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
       return corp;
 
     int errp;
@@ -697,7 +688,7 @@ public:
       status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
     else
       {
-	process_ctf_archive(corp);
+	process_ctf_archive();
 	corpus()->sort_functions();
 	corpus()->sort_variables();
       }
@@ -719,8 +710,6 @@ typedef shared_ptr<reader> reader_sptr;
 /// Build and return a typedef libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -728,11 +717,11 @@ typedef shared_ptr<reader> reader_sptr;
 
 static typedef_decl_sptr
 process_ctf_typedef(reader *rdr,
-                    corpus_sptr corp,
-                    translation_unit_sptr tunit,
                     ctf_dict_t *ctf_dictionary,
                     ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   typedef_decl_sptr result;
 
   ctf_id_t ctf_utype = ctf_type_reference(ctf_dictionary, ctf_type);
@@ -744,14 +733,13 @@ process_ctf_typedef(reader *rdr,
     if (result = lookup_typedef_type(typedef_name, *corp))
       return result;
 
-  type_base_sptr utype = rdr->lookup_type(corp, tunit,
-					  ctf_dictionary, ctf_utype);
+  type_base_sptr utype = rdr->build_type(ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(rdr->lookup_type(ctf_dictionary,
-                                                                ctf_type));
+  result = dynamic_pointer_cast<typedef_decl>
+             (rdr->lookup_type(ctf_dictionary, ctf_type));
   if (result)
     return result;
 
@@ -782,7 +770,6 @@ process_ctf_typedef(reader *rdr,
 /// IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -790,11 +777,11 @@ process_ctf_typedef(reader *rdr,
 
 static type_decl_sptr
 process_ctf_base_type(reader *rdr,
-                      corpus_sptr corp,
-                      translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
                       ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   type_decl_sptr result;
 
   ssize_t type_alignment = ctf_type_align(ctf_dictionary, ctf_type);
@@ -873,8 +860,6 @@ build_ir_node_for_variadic_parameter_type(reader &rdr,
 /// Build and return a function type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -882,11 +867,11 @@ build_ir_node_for_variadic_parameter_type(reader &rdr,
 
 static function_type_sptr
 process_ctf_function_type(reader *rdr,
-                          corpus_sptr corp,
-                          translation_unit_sptr tunit,
                           ctf_dict_t *ctf_dictionary,
                           ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   function_type_sptr result;
 
   /* Fetch the function type info from the CTF type.  */
@@ -896,8 +881,7 @@ process_ctf_function_type(reader *rdr,
 
   /* Take care first of the result type.  */
   ctf_id_t ctf_ret_type = funcinfo.ctc_return;
-  type_base_sptr ret_type = rdr->lookup_type(corp, tunit,
-					     ctf_dictionary, ctf_ret_type);
+  type_base_sptr ret_type = rdr->build_type(ctf_dictionary, ctf_ret_type);
   if (!ret_type)
     return result;
 
@@ -912,8 +896,7 @@ process_ctf_function_type(reader *rdr,
   for (int i = 0; i < argc; i++)
     {
       ctf_id_t ctf_arg_type = argv[i];
-      type_base_sptr arg_type = rdr->lookup_type(corp, tunit,
-						 ctf_dictionary, ctf_arg_type);
+      type_base_sptr arg_type = rdr->build_type(ctf_dictionary, ctf_arg_type);
       if (!arg_type)
         return result;
 
@@ -938,8 +921,8 @@ process_ctf_function_type(reader *rdr,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(rdr->lookup_type(ctf_dictionary,
-                                                                 ctf_type));
+  result = dynamic_pointer_cast<function_type>
+             (rdr->lookup_type(ctf_dictionary, ctf_type));
   if (result)
     return result;
 
@@ -964,20 +947,18 @@ process_ctf_function_type(reader *rdr,
 /// Add member information to a IR struct or union type.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 /// @param sou the IR struct or union type to which add the members.
 
 static void
 process_ctf_sou_members(reader *rdr,
-                        corpus_sptr corp,
-                        translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
                         ctf_id_t ctf_type,
                         class_or_union_sptr sou)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   ssize_t member_size;
   ctf_next_t *member_next = NULL;
   const char *member_name = NULL;
@@ -997,9 +978,8 @@ process_ctf_sou_members(reader *rdr,
         return;
 
       /* Build the IR for the member's type.  */
-      type_base_sptr member_type = rdr->lookup_type(corp, tunit,
-						    ctf_dictionary,
-						    member_ctf_type);
+      type_base_sptr member_type = rdr->build_type(ctf_dictionary,
+                                                   member_ctf_type);
       if (!member_type)
         /* Ignore this member.  */
         continue;
@@ -1024,17 +1004,16 @@ process_ctf_sou_members(reader *rdr,
 /// IR.
 ///
 /// @param rdr the read context.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 /// @return the resulting IR node created.
 
 static type_base_sptr
 process_ctf_forward_type(reader *rdr,
-                         translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
                          ctf_id_t ctf_type)
 {
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   decl_base_sptr result;
   std::string type_name = ctf_type_name_raw(ctf_dictionary,
                                             ctf_type);
@@ -1083,8 +1062,6 @@ process_ctf_forward_type(reader *rdr,
 /// Build and return a struct type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -1092,11 +1069,11 @@ process_ctf_forward_type(reader *rdr,
 
 static class_decl_sptr
 process_ctf_struct_type(reader *rdr,
-                        corpus_sptr corp,
-                        translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
                         ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   class_decl_sptr result;
   std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
                                                    ctf_type);
@@ -1130,8 +1107,7 @@ process_ctf_struct_type(reader *rdr,
   /* Now add the struct members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
      scope.  */
-  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
-                          result);
+  process_ctf_sou_members(rdr, ctf_dictionary, ctf_type, result);
 
   return result;
 }
@@ -1139,8 +1115,6 @@ process_ctf_struct_type(reader *rdr,
 /// Build and return an union type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -1148,11 +1122,11 @@ process_ctf_struct_type(reader *rdr,
 
 static union_decl_sptr
 process_ctf_union_type(reader *rdr,
-                       corpus_sptr corp,
-                       translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
                        ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   union_decl_sptr result;
   std::string union_type_name = ctf_type_name_raw(ctf_dictionary,
                                                    ctf_type);
@@ -1184,8 +1158,7 @@ process_ctf_union_type(reader *rdr,
   /* Now add the union members as specified in the CTF type description.
      This is C, so named types can only be defined in the global
      scope.  */
-  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
-                          result);
+  process_ctf_sou_members(rdr, ctf_dictionary, ctf_type, result);
 
   return result;
 }
@@ -1193,20 +1166,19 @@ process_ctf_union_type(reader *rdr,
 /// Build and return an array type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
+///
 /// @param ctf_dictionary the CTF dictionary being read.
+///
 /// @param ctf_type the CTF type ID of the source type.
 ///
 /// @return a shared pointer to the IR node for the array type.
-
 static array_type_def_sptr
 process_ctf_array_type(reader *rdr,
-                       corpus_sptr corp,
-                       translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
                        ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   array_type_def_sptr result;
   ctf_arinfo_t ctf_ainfo;
   bool is_infinite = false;
@@ -1222,21 +1194,19 @@ process_ctf_array_type(reader *rdr,
   uint64_t nelems = ctf_ainfo.ctr_nelems;
 
   /* Make sure the element type is generated.  */
-  type_base_sptr element_type = rdr->lookup_type(corp, tunit,
-						 ctf_dictionary,
-						 ctf_element_type);
+  type_base_sptr element_type = rdr->build_type(ctf_dictionary,
+                                                ctf_element_type);
   if (!element_type)
     return result;
 
   /* Ditto for the index type.  */
-  type_base_sptr index_type = rdr->lookup_type(corp, tunit,
-					       ctf_dictionary,
-					       ctf_index_type);
+  type_base_sptr index_type = rdr->build_type(ctf_dictionary,
+                                              ctf_index_type);
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(rdr->lookup_type(ctf_dictionary,
-                                                                  ctf_type));
+  result = dynamic_pointer_cast<array_type_def>
+             (rdr->lookup_type(ctf_dictionary, ctf_type));
   if (result)
     return result;
 
@@ -1284,28 +1254,25 @@ process_ctf_array_type(reader *rdr,
 /// Build and return a qualified type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 
 static type_base_sptr
 process_ctf_qualified_type(reader *rdr,
-                           corpus_sptr corp,
-                           translation_unit_sptr tunit,
                            ctf_dict_t *ctf_dictionary,
                            ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   type_base_sptr result;
   int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
   ctf_id_t ctf_utype = ctf_type_reference(ctf_dictionary, ctf_type);
-  type_base_sptr utype = rdr->lookup_type(corp, tunit,
-					  ctf_dictionary, ctf_utype);
+  type_base_sptr utype = rdr->build_type(ctf_dictionary, ctf_utype);
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<type_base>(rdr->lookup_type(ctf_dictionary,
-                                                             ctf_type));
+  result = dynamic_pointer_cast<type_base>
+             (rdr->lookup_type(ctf_dictionary, ctf_type));
   if (result)
     return result;
 
@@ -1337,8 +1304,6 @@ process_ctf_qualified_type(reader *rdr,
 /// Build and return a pointer type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -1346,24 +1311,23 @@ process_ctf_qualified_type(reader *rdr,
 
 static pointer_type_def_sptr
 process_ctf_pointer_type(reader *rdr,
-                         corpus_sptr corp,
-                         translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
                          ctf_id_t ctf_type)
 {
+  corpus_sptr corp = rdr->corpus();
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   pointer_type_def_sptr result;
   ctf_id_t ctf_target_type = ctf_type_reference(ctf_dictionary, ctf_type);
   if (ctf_target_type == CTF_ERR)
     return result;
 
-  type_base_sptr target_type = rdr->lookup_type(corp, tunit,
-						ctf_dictionary,
-						ctf_target_type);
+  type_base_sptr target_type = rdr->build_type(ctf_dictionary,
+                                               ctf_target_type);
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(rdr->lookup_type(ctf_dictionary,
-                                                                    ctf_type));
+  result = dynamic_pointer_cast<pointer_type_def>
+             (rdr->lookup_type(ctf_dictionary, ctf_type));
   if (result)
     return result;
 
@@ -1383,8 +1347,6 @@ process_ctf_pointer_type(reader *rdr,
 /// Build and return an enum type libabigail IR.
 ///
 /// @param rdr the read context.
-/// @param corp the libabigail IR corpus being constructed.
-/// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 ///
@@ -1392,10 +1354,10 @@ process_ctf_pointer_type(reader *rdr,
 
 static enum_type_decl_sptr
 process_ctf_enum_type(reader *rdr,
-                      translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
                       ctf_id_t ctf_type)
 {
+  translation_unit_sptr tunit = rdr->cur_transl_unit();
   enum_type_decl_sptr result;
   std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
 
@@ -1430,6 +1392,7 @@ process_ctf_enum_type(reader *rdr,
 
   while ((ename = ctf_enum_next(ctf_dictionary, ctf_type, &enum_next, &evalue)))
     enms.push_back(enum_type_decl::enumerator(ename, evalue));
+
   if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
     {
       fprintf(stderr, "ERROR from ctf_enum_next\n");
diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc
index eedeaf8e..3f191bda 100644
--- a/src/abg-elf-reader.cc
+++ b/src/abg-elf-reader.cc
@@ -459,6 +459,7 @@ reader::reader(const string&		elf_path,
 {
   priv_->crack_open_elf_file();
   priv_->locate_dwarf_debug_info();
+  priv_->locate_ctf_debug_info();
 }
 
 /// The destructor of the @ref elf::reader type.
@@ -479,10 +480,13 @@ void
 reader::reset(const std::string&	elf_path,
 	      const vector<char**>&	debug_info_roots)
 {
+  fe_iface::options_type opts = options();
+  fe_iface::reset(elf_path, opts.env);
   corpus_path(elf_path);
   priv_->initialize(debug_info_roots);
   priv_->crack_open_elf_file();
   priv_->locate_dwarf_debug_info();
+  priv_->locate_ctf_debug_info();
 }
 
 /// Getter of the vector of directory paths to look into for split
@@ -528,6 +532,15 @@ const Dwarf*
 reader::dwarf_debug_info() const
 {return priv_->dwarf_handle;}
 
+bool
+reader::has_dwarf_debug_info() const
+{return ((priv_->dwarf_handle != nullptr)
+	  || (priv_->alt_dwarf_handle != nullptr));}
+
+bool
+reader::has_ctf_debug_info() const
+{return (priv_->ctf_section != nullptr);}
+
 /// Getter of the handle use to access DWARF information from the
 /// alternate split DWARF information.
 ///
@@ -873,13 +886,15 @@ reader::read_corpus(status& status)
   corpus()->set_symtab(symtab());
 
   // If we couldn't load debug info from the elf path, then say it.
-    if (dwarf_debug_info() == nullptr
-	&& find_ctf_section() == nullptr)
-      status |= STATUS_DEBUG_INFO_NOT_FOUND;
-
-    status |= STATUS_OK;
-
-    return corpus();
+  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
+        && !has_dwarf_debug_info())
+    status |= STATUS_DEBUG_INFO_NOT_FOUND;
+  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
+             && !has_ctf_debug_info())
+    status |= STATUS_DEBUG_INFO_NOT_FOUND;
+
+  status |= STATUS_OK;
+  return corpus();
 }
 
 /// Get the SONAME property of a designated ELF file.
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 8898ef97..0a523b87 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -405,6 +405,23 @@ is_regular_file(const string& path)
   return false;
 }
 
+/// Test if a directory contains a CTF archive.
+///
+/// @param directory the directory to consider.
+///
+/// @param archive_prefix the prefix of the archive file.
+///
+/// @return true iff @p directory contains a CTF archive file.
+bool
+dir_contains_ctf_archive(const string& directory,
+			 const string& archive_prefix)
+{
+  string ctf_archive = directory + "/" + archive_prefix + ".ctfa";
+  if (file_exists(ctf_archive))
+    return true;
+  return false;
+}
+
 /// Test if an ELF file has DWARF debug info.
 ///
 /// This function supports split debug info files as well.
@@ -437,11 +454,29 @@ file_has_dwarf_debug_info(const string& elf_file_path,
   return false;
 }
 
+/// Test if an ELF file has CTF debug info.
+///
+/// This function supports split debug info files as well.
+/// Linux Kernel with CTF debug information generates a CTF archive:
+/// a special file containing debug information for vmlinux and its
+/// modules (*.ko) files it is located by default in the Kernel build
+/// directory as "vmlinux.ctfa".
+///
+/// @param elf_file_path the path to the ELF file to consider.
+///
+/// @param debug_info_root a vector of pointer to directory to look
+/// for debug info, in case the file is associated to split debug
+/// info.  If there is no split debug info then this vector can be
+/// empty.  Note that convert_char_stars_to_char_star_stars() can be
+/// used to ease the construction of this vector.
+///
+/// @return true iff the ELF file at @elf_file_path is an ELF file
+/// that contains debug info.
 bool
 file_has_ctf_debug_info(const string& elf_file_path,
 			const vector<char**>& debug_info_root_paths)
 {
-    if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
+  if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
     return false;
 
   environment env;
@@ -452,6 +487,20 @@ file_has_ctf_debug_info(const string& elf_file_path,
   if (r.find_ctf_section())
     return true;
 
+  string vmlinux;
+  if (base_name(elf_file_path, vmlinux))
+    {
+      string dirname;
+      if (dir_name(elf_file_path, dirname)
+	    && dir_contains_ctf_archive(dirname, vmlinux))
+	return true;
+    }
+
+  // vmlinux.ctfa could be provided with --debug-info-dir
+  for (const auto& path : debug_info_root_paths)
+    if (dir_contains_ctf_archive(*path, vmlinux))
+      return true;
+
   return false;
 }
 
@@ -2539,12 +2588,13 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 					   module_paths);
 }
 
-/// If the @ref origin is DWARF_ORIGIN it build a @ref corpus_group
-/// made of vmlinux kernel file and the linux kernel modules found
-/// under @p root directory and under its sub-directories, recursively.
+/// It builds a @ref corpus_group made of vmlinux kernel file and
+/// the kernel modules found under @p root directory and under its
+/// sub-directories, recursively.
 ///
-/// @param origin the debug type information in vmlinux kernel and
-/// the linux kernel modules to be used to build the corpora @p group.
+/// @param rdr the raeder that should be used to extract the debug
+/// infomation from the linux kernel and its modules used to build
+/// the corpora @p group.
 ///
 /// @param the group @ref corpus_group to be built.
 ///
@@ -2576,28 +2626,20 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 ///
 /// @param env the environment to create the corpus_group in.
 static void
-maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
-                                corpus_group_sptr&  group,
-                                const string&       vmlinux,
-                                vector<string>&     modules,
-                                const string&       root,
-                                vector<char**>&     di_roots,
-                                vector<string>&     suppr_paths,
-                                vector<string>&     kabi_wl_paths,
-                                suppressions_type&  supprs,
-                                bool                verbose,
-                                timer&              t,
-                                environment&        env)
-{
-  if (!(origin & corpus::DWARF_ORIGIN))
-    return;
-
+load_vmlinux_corpus(elf_based_reader_sptr rdr,
+                    corpus_group_sptr&  group,
+                    const string&       vmlinux,
+                    vector<string>&     modules,
+                    const string&       root,
+                    vector<char**>&     di_roots,
+                    vector<string>&     suppr_paths,
+                    vector<string>&     kabi_wl_paths,
+                    suppressions_type&  supprs,
+                    bool                verbose,
+                    timer&              t,
+                    environment&        env)
+{
   abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
-  elf_based_reader_sptr rdr =
-    dwarf::create_reader(vmlinux, di_roots, env,
-			 /*read_all_types=*/false,
-			 /*linux_kernel_mode=*/true);
-  ABG_ASSERT(rdr);
   rdr->options().do_log = verbose;
 
   t.start();
@@ -2645,9 +2687,9 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      dwarf::reset_reader(*rdr, *m, di_roots,
-			  /*read_all_types=*/false,
-			  /*linux_kernel_mode=*/true);
+      rdr->initialize(*m, di_roots,
+                      /*read_all_types=*/false,
+                      /*linux_kernel_mode=*/true);
 
       load_generate_apply_suppressions(*rdr, suppr_paths,
                                        kabi_wl_paths, supprs);
@@ -2665,101 +2707,6 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
     }
 }
 
-/// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
-/// made of vmlinux kernel file and the linux kernel modules found
-/// under @p root directory and under its sub-directories, recursively.
-///
-/// @param origin the debug type information in vmlinux kernel and
-/// the linux kernel modules to be used to build the corpora @p group.
-///
-/// @param group the @ref corpus_group to be built.
-///
-/// @param vmlinux the path to the vmlinux binary.
-///
-/// @param modules a vector with the paths to the linux kernel
-/// modules.
-///
-/// @param root the path of the directory under which the kernel
-/// kernel modules were found.
-///
-/// @param di_root the directory in aboslute path which debug
-/// info is to be found for binaries under director @p root
-///
-/// @param verbose true if the function has to emit some verbose
-/// messages.
-///
-/// @param t time to trace time spent in each step.
-///
-/// @param env the environment to create the corpus_group in.
-#ifdef WITH_CTF
-static void
-maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
-                              corpus_group_sptr&  group,
-                              const string&       vmlinux,
-                              vector<string>&     modules,
-                              const string&       root,
-                              vector<char**>&     di_roots,
-                              bool                verbose,
-                              timer&              t,
-                              environment&        env)
-{
-  if (!(origin & corpus::CTF_ORIGIN))
-    return;
-
-  abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
-  elf_based_reader_sptr rdr =
-    ctf::create_reader(vmlinux, di_roots, env);
-  ABG_ASSERT(rdr);
-
-  group.reset(new corpus_group(env, root));
-  rdr->corpus_group(group);
-
-  if (verbose)
-    std::cerr << "reading kernel binary '"
-     << vmlinux << "' ...\n" << std::flush;
-
-  // Read the vmlinux corpus and add it to the group.
-  t.start();
-  rdr->read_and_add_corpus_to_group(*group, status);
-  t.stop();
-
-  if (verbose)
-    std::cerr << vmlinux
-     << " reading DONE:"
-     << t << "\n";
-
-  if (group->is_empty())
-    return;
-
-  // Now add the corpora of the modules to the corpus group.
-  int total_nb_modules = modules.size();
-  int cur_module_index = 1;
-  for (vector<string>::const_iterator m = modules.begin();
-       m != modules.end();
-       ++m, ++cur_module_index)
-    {
-      if (verbose)
-        std::cerr << "reading module '"
-         << *m << "' ("
-         << cur_module_index
-         << "/" << total_nb_modules
-         << ") ... " << std::flush;
-
-      ctf::reset_reader(*rdr, *m, di_roots);
-      rdr->corpus_group(group);
-
-      t.start();
-      rdr->read_and_add_corpus_to_group(*group, status);
-      t.stop();
-      if (verbose)
-        std::cerr << "module '"
-         << *m
-         << "' reading DONE: "
-         << t << "\n";
-    }
-}
-#endif
-
 /// Walk a given directory and build an instance of @ref corpus_group
 /// from the vmlinux kernel binary and the linux kernel modules found
 /// under that directory and under its sub-directories, recursively.
@@ -2836,15 +2783,22 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
       vector<char**> di_roots;
       di_roots.push_back(&di_root_ptr);
 
-      maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
-                                      modules, root, di_roots,
-                                      suppr_paths, kabi_wl_paths,
-                                      supprs, verbose, t, env);
+      abigail::elf_based_reader_sptr reader =
+        create_best_elf_based_reader(vmlinux,
+                                     di_roots,
+                                     env,
 #ifdef WITH_CTF
-      maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
-                                    modules, root, di_roots,
-                                    verbose, t, env);
+                                     origin & corpus::CTF_ORIGIN,
+#else
+                                     false,
 #endif
+                                     /*read_all_types=*/false,
+                                     /*linux_kernel_mode=*/true);
+      ABG_ASSERT(reader);
+      load_vmlinux_corpus(reader, group, vmlinux,
+                          modules, root, di_roots,
+                          suppr_paths, kabi_wl_paths,
+                          supprs, verbose, t, env);
     }
 
   return group;
@@ -2853,13 +2807,16 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 /// Create the best elf based reader (or front-end), given an ELF file.
 ///
 /// This function looks into the ELF file.  If it contains DWARF debug
-/// info, then a DWARF Reader front-end is created and returned.
-/// Otherwise, if it contains CTF debug info, then a CTF Reader
-/// front-end is created and returned.
+/// info, then a DWARF Reader front-end is created and returned, unless
+/// that @ref use_ctf be true.  Otherwise, if it contains CTF debug info,
+/// then a CTF Reader front-end is created and returned.
+///
+/// By other hand, it selects the DWARF front-end when @ref use_ctf is
+/// true but ELF file doesn't have CTF debug information.
 ///
 /// Otherwise, if the file contains no debug info or if the king of
-/// debug info is not yet recognized, a DWARF Reader front-end is
-/// created and returned.
+/// debug info is not yet recognized, a DWARF or CTF  Reader front-end is
+/// created and returned depending of @ref use_ctf parameter.
 ///
 /// @param elf_file_path a path to the ELF file to consider
 ///
@@ -2868,32 +2825,62 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 ///
 /// @param env the environment to use for the front-end.
 ///
+/// @param use_ctf set to true if it's going to use CTF front-end.
+///
+/// @param show_all_types option to be passed to elf based readers.
+///
+/// @param linux_kernel_mode option to bed passed to elf based readers,
+///
 /// @return the ELF based Reader that is better adapted for the binary
 /// designated by @p elf_file_path.
 elf_based_reader_sptr
 create_best_elf_based_reader(const string& elf_file_path,
 			     const vector<char**>& debug_info_root_paths,
-			     environment& env)
+			     environment& env,
+			     bool use_ctf,
+			     bool show_all_types,
+			     bool linux_kernel_mode)
 {
   elf_based_reader_sptr result;
   if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
     return result;
 
-  if (file_has_dwarf_debug_info(elf_file_path, debug_info_root_paths))
-    result = dwarf::create_reader(elf_file_path,
-				  debug_info_root_paths,
-				  env);
 #ifdef WITH_CTF
-  else if (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
-    result = ctf::create_reader(elf_file_path,
-				debug_info_root_paths,
-				env);
+  if (!use_ctf)
+    {
 #endif
+      result = dwarf::create_reader(elf_file_path,
+				    debug_info_root_paths,
+				    env,
+				    show_all_types,
+				    linux_kernel_mode);
+#ifdef WITH_CTF
+      if (!file_has_dwarf_debug_info(elf_file_path,
+				     debug_info_root_paths)
+	    && file_has_ctf_debug_info(elf_file_path,
+				       debug_info_root_paths))
+	result = ctf::create_reader(elf_file_path,
+				    debug_info_root_paths,
+				    env);
+    }
   else
-    result = dwarf::create_reader(elf_file_path,
+    {
+      result = ctf::create_reader(elf_file_path,
 				  debug_info_root_paths,
 				  env);
 
+      if (!file_has_ctf_debug_info(elf_file_path,
+				   debug_info_root_paths)
+	    && file_has_dwarf_debug_info(elf_file_path,
+					 debug_info_root_paths))
+        result = dwarf::create_reader(elf_file_path,
+				      debug_info_root_paths,
+				      env,
+				      show_all_types,
+				      linux_kernel_mode);
+    }
+#endif
+
   return result;
 }
 
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 5ec33924..4b6e9305 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -607,6 +607,9 @@ test-read-dwarf/PR28584/PR28584-smv.clang.o.abi \
 test-read-dwarf/PR29443-missing-xx.cc \
 test-read-dwarf/PR29443-missing-xx.o \
 test-read-dwarf/PR29443-missing-xx.o.abi \
+test-read-dwarf/test-fallback.abi	\
+test-read-dwarf/test-fallback.c		\
+test-read-dwarf/test-fallback.o		\
 \
 test-read-ctf/test0		\
 test-read-ctf/test0.abi		\
@@ -698,6 +701,9 @@ test-read-ctf/test-anonymous-fields.o.abi	\
 test-read-ctf/test-linux-module.abi		\
 test-read-ctf/test-linux-module.c		\
 test-read-ctf/test-linux-module.ko		\
+test-read-ctf/test-fallback.abi		\
+test-read-ctf/test-fallback.c		\
+test-read-ctf/test-fallback.o		\
 \
 test-annotate/test0.abi			\
 test-annotate/test1.abi			\
diff --git a/tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt b/tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt
index e69de29b..4938d221 100644
--- a/tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt
+++ b/tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt
@@ -0,0 +1,16 @@
+================ changes of 'libobj-v0.so'===============
+  Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added functions
+  Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+  1 function with some indirect sub-type change:
+
+    [C] 'function void foo(S1*)' has some indirect sub-type changes:
+      parameter 1 of type 'S1*' has sub-type changes:
+        in pointed to type 'struct S1':
+          type size changed from 0 to 32 (in bits)
+          type alignment changed from 0 to 32
+          1 data member insertion:
+            'int mem2', at offset 0 (in bits)
+
+================ end of changes of 'libobj-v0.so'===============
+
diff --git a/tests/data/test-read-ctf/test-fallback.abi b/tests/data/test-read-ctf/test-fallback.abi
new file mode 100644
index 00000000..e7d30594
--- /dev/null
+++ b/tests/data/test-read-ctf/test-fallback.abi
@@ -0,0 +1,9 @@
+<abi-corpus version='2.1' path='data/test-read-ctf/test-fallback.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' language='LANG_C'>
+    <type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-1'/>
+    <var-decl name='a' type-id='type-id-1' mangled-name='a' visibility='default' elf-symbol-id='a'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-ctf/test-fallback.c b/tests/data/test-read-ctf/test-fallback.c
new file mode 100644
index 00000000..e5019857
--- /dev/null
+++ b/tests/data/test-read-ctf/test-fallback.c
@@ -0,0 +1,8 @@
+/* gcc -gctf -c test-fallback.c -o test-fallback.o
+
+   This test case is meant to test the fallback feature in
+   libabigail tools, so when those tools are executed without
+   the explicit use of `--ctf' option it should be use CTF
+   frond-end to build the IR.
+ */
+int a;
diff --git a/tests/data/test-read-ctf/test-fallback.o b/tests/data/test-read-ctf/test-fallback.o
new file mode 100644
index 0000000000000000000000000000000000000000..874368b667443493724183c51dc49e3c5c4bf104
GIT binary patch
literal 1216
zcmbVLy-veG40fRWFCZ9@Si%Gda!Jbs1B!(B5khQ?43}^~M4F)F5Om@dcn2olf;VAi
zgckt2@m;GcES%)C{rR(FyS=A_)59^(19LpsgMnvI)MEoX?wc{p!7O~ew`^o;K!Fz8
zB-1SOsC|@k6skYLLN<SIlK4KkS)oBfcvE&&nDmlfSXMI4RajSPm}iMhvTK>;L7^T(
zt!iC|mr~2V8B|JM2C2SkyepaKiA--r3UIW)zw56bot<y^?QIc>$nQj*PP-lL`0MKN
zPE}b~6<X#S*hSMj_R{YYb8vj`jrudkW1o9B@Q9{(3qHTyzybmbFm7R6n+6Jo`j!Bq
z?sc_HQ0uDEH^$QHQG=lIK_qnz0!PQI?9wbCic%|q?FY5SEwF!G+>5)a#EEs!e*eG5
z3MSHwlTLxy@r~>5YZU{84K~p*<3^3#ZvGlF=s)&XzTGQVa{VpD-I_#=>B95cD0{oy
zHbw}GETb_#*xz(;lW+7c#*IBpUHT3Dg?oY+y*v8|xyUl-yM58Fh7Zx)T#6ra{xOqh
lm}l~rhj4fI6nf_TMdlgBuyOGXjQ(~Md|~2+Wj2PJ{{yZRUq=7{

literal 0
HcmV?d00001

diff --git a/tests/data/test-read-dwarf/test-fallback.abi b/tests/data/test-read-dwarf/test-fallback.abi
new file mode 100644
index 00000000..ebbae7ef
--- /dev/null
+++ b/tests/data/test-read-dwarf/test-fallback.abi
@@ -0,0 +1,9 @@
+<abi-corpus version='2.1'>
+  <elf-variable-symbols>
+    <elf-symbol name='a' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' path='tests/data/test-read-dwarf/test-fallback.c' comp-dir-path='/home/byby/oracle/src/libabigail-new' language='LANG_C11'>
+    <type-decl name='int' size-in-bits='32' id='type-id-1'/>
+    <var-decl name='a' type-id='type-id-1' mangled-name='a' visibility='default' filepath='tests/data/test-read-dwarf/test-fallback.c' line='8' column='1' elf-symbol-id='a'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-dwarf/test-fallback.c b/tests/data/test-read-dwarf/test-fallback.c
new file mode 100644
index 00000000..e5019857
--- /dev/null
+++ b/tests/data/test-read-dwarf/test-fallback.c
@@ -0,0 +1,8 @@
+/* gcc -gctf -c test-fallback.c -o test-fallback.o
+
+   This test case is meant to test the fallback feature in
+   libabigail tools, so when those tools are executed without
+   the explicit use of `--ctf' option it should be use CTF
+   frond-end to build the IR.
+ */
+int a;
diff --git a/tests/data/test-read-dwarf/test-fallback.o b/tests/data/test-read-dwarf/test-fallback.o
new file mode 100644
index 0000000000000000000000000000000000000000..ab76098f2fff275b73cca9f627b95ff55de374ee
GIT binary patch
literal 2424
zcmbVNU2F_d6h1T4(so<=lTb=J1Z}ZncTrkeD-DhRic~zQ+3i@Z-D&MkW${oUK}Zu1
z9!UCtc&I1dNc^=Di8mtgDkNT-c<}Qgk(6_0?%9rOnkG(i?>Xl?-#Pc}{h1x!v3IAc
zD8QmXJ4}0w0z597w&SiDhZ?AcX0(ezDIv(sTj~bIq?#Bij-gkoF|HLA_t_4ztCW@V
zYC>9lU47+30CfXsC9R<?p_b6Dnr(~JS^#YYghK5hjfyY9p}Hm9rMOr@dwrCEfrz3g
zzvfktqK<H&QST+AucAHQ_1u1y&i&nbM|6`OU2jB;h#rf?V$o=%MQ^n7gI2aLW7&?G
zZqmaUXUMkNQkIQi5?wQ!Jkgfl+#GJ+podf3h+7k#hXP<fKRPmUu<U%K{MFO9Uv3?J
zvj6h?iNm!|o?RH$CSDY&r!pTJUv8f|Hg>f((YfzI!_DaDBi5Z~qr11}yY5#W>hFFX
zyZGZ$`qR6qb>H7i#tx)jDE)Wi%b~NQqg8LjpU^Z*|J)xPqmH8(2d3ekD&xMR#oh9J
z?i*==Lh&N__B$x3VI)X2m=gqp2BkCLp&9V<fAA_qs<0AEp##UtIpO1GI-M|+CygYS
z9)oXD8M@P102QJD;j~9A)xsd$|0@<q_!{9a_ThzI5L+#9+P}HNCdD<We&MR3y_|w5
zyl$80!YZK|9}<2<!mkT|qlDiUJ{Y+(8OKbZcCwy6!Iop?9WZ)L#{?sh%Yl)#(x%aC
zC5BQxefIGIjJdX%NMx<ke}&DgX{W5eQ__95#VNQ1n*{f`esUl~uMG@)z_ARxo#C8=
zhbH`#J!A}K2k=cgXSn(Q*L9dmXTbZ;mEvqjnz(*hh7Mu=yF>9fO#ve3Hz0@Z;7s}c
zJ45AUKZ=-KlX!8OP+C1zm}Tx-j8M&Zf#DfHRZsK1sYI7}{9f?0>`EKXa!m@Hb)(>Z
zhlS}XncIb^j1h6nWdrC!vy!=cFc8%L6|te*C-qP7OzyuIF}Wr}@R}x++4ipoIYH~+
z7V96QA}F*zecj~s2N9$7BRKq`il#dKAllq3>vIB&aACpk5(HbyXBy{U<9vztToCv>
z#$nE5eM97Pob@CV7!X>9?;%d-BCcD3{Z$a<ec}F@NHjT@V!8mw$w8t2g`o4NGm+mO
b@jr_E8ghIh_fK_$^4&{;u}8jKGUfa~-Y>Y*

literal 0
HcmV?d00001

diff --git a/tests/test-diff-pkg.cc b/tests/test-diff-pkg.cc
index e128ff63..8e510ca2 100644
--- a/tests/test-diff-pkg.cc
+++ b/tests/test-diff-pkg.cc
@@ -855,7 +855,7 @@ static InOutSpec in_out_specs[] =
   { // Just like the previous tests, but loc info is emitted.
     "data/test-diff-pkg-ctf/dirpkg-3-dir1",
     "data/test-diff-pkg-ctf/dirpkg-3-dir2",
-    "--no-default-suppression --no-abignore",
+    "--ctf --no-default-suppression --no-abignore",
     "data/test-diff-pkg-ctf/dirpkg-3.suppr",
     "",
     "",
diff --git a/tests/test-read-common.cc b/tests/test-read-common.cc
index b794a311..1d70b3d0 100644
--- a/tests/test-read-common.cc
+++ b/tests/test-read-common.cc
@@ -95,13 +95,14 @@ test_task::run_abidw(const string& extargs)
 {
   string abidw = string(get_build_dir()) + "/tools/abidw";
   string drop_private_types;
+  string spec_options = spec.options ? spec.options : "";
   set_in_abi_path();
 
   if (!in_public_headers_path.empty())
     drop_private_types += "--headers-dir " + in_public_headers_path +
       " --drop-private-types";
-  string cmd = abidw + " " + drop_private_types + " --abidiff " + extargs +
-   in_elf_path;
+  string cmd = abidw + " " + spec_options + drop_private_types +
+                 " --abidiff " + extargs + in_elf_path;
   if (system(cmd.c_str()))
     {
       error_message = string("ABIs differ:\n")
diff --git a/tests/test-read-common.h b/tests/test-read-common.h
index 4277896a..f00205b9 100644
--- a/tests/test-read-common.h
+++ b/tests/test-read-common.h
@@ -40,6 +40,7 @@ struct InOutSpec
   type_id_style_kind type_id_style;
   const char* in_abi_path;
   const char* out_abi_path;
+  const char* options;
 };// end struct InOutSpec
 
 /// The task that performs the tests.
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index 6dc2d53f..043032ff 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -43,7 +43,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test0.abi",
-    "output/test-read-ctf/test0.abi"
+    "output/test-read-ctf/test0.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test0",
@@ -51,7 +52,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test0.hash.abi",
-    "output/test-read-ctf/test0.hash.abi"
+    "output/test-read-ctf/test0.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test1.so",
@@ -59,7 +61,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test1.so.abi",
-    "output/test-read-ctf/test1.so.abi"
+    "output/test-read-ctf/test1.so.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test1.so",
@@ -67,7 +70,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test1.so.hash.abi",
-    "output/test-read-ctf/test1.so.hash.abi"
+    "output/test-read-ctf/test1.so.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test2.so",
@@ -75,7 +79,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test2.so.abi",
-    "output/test-read-ctf/test2.so.abi"
+    "output/test-read-ctf/test2.so.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test2.so",
@@ -83,7 +88,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test2.so.hash.abi",
-    "output/test-read-ctf/test2.so.hash.abi"
+    "output/test-read-ctf/test2.so.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test3.so",
@@ -91,7 +97,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test3.so.abi",
-    "output/test-read-ctf/test3.so.abi"
+    "output/test-read-ctf/test3.so.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test3.so",
@@ -99,7 +106,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test3.so.hash.abi",
-    "output/test-read-ctf/test3.so.hash.abi"
+    "output/test-read-ctf/test3.so.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-enum-many.o",
@@ -107,7 +115,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-enum-many.o.hash.abi",
-    "output/test-read-ctf/test-enum-many.o.hash.abi"
+    "output/test-read-ctf/test-enum-many.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-ambiguous-struct-A.o",
@@ -115,7 +124,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
-    "output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi"
+    "output/test-read-ctf/test-ambiguous-struct-A.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-ambiguous-struct-B.o",
@@ -123,7 +133,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
-    "output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi"
+    "output/test-read-ctf/test-ambiguous-struct-B.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-conflicting-type-syms-a.o",
@@ -131,7 +142,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
-    "output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi"
+    "output/test-read-ctf/test-conflicting-type-syms-a.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-conflicting-type-syms-b.o",
@@ -139,7 +151,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
-    "output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi"
+    "output/test-read-ctf/test-conflicting-type-syms-b.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test4.so",
@@ -147,7 +160,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test4.so.abi",
-    "output/test-read-ctf/test4.so.abi"
+    "output/test-read-ctf/test4.so.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test4.so",
@@ -155,7 +169,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test4.so.hash.abi",
-    "output/test-read-ctf/test4.so.hash.abi"
+    "output/test-read-ctf/test4.so.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test5.o",
@@ -163,7 +178,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test5.o.abi",
-    "output/test-read-ctf/test5.o.abi"
+    "output/test-read-ctf/test5.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test7.o",
@@ -171,7 +187,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test7.o.abi",
-    "output/test-read-ctf/test7.o.abi"
+    "output/test-read-ctf/test7.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test8.o",
@@ -179,7 +196,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test8.o.abi",
-    "output/test-read-ctf/test8.o.abi"
+    "output/test-read-ctf/test8.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test9.o",
@@ -187,7 +205,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test9.o.abi",
-    "output/test-read-ctf/test9.o.abi"
+    "output/test-read-ctf/test9.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-enum.o",
@@ -195,7 +214,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-enum.o.abi",
-    "output/test-read-ctf/test-enum.o.abi"
+    "output/test-read-ctf/test-enum.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-enum-symbol.o",
@@ -203,7 +223,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/test-enum-symbol.o.hash.abi",
-    "output/test-read-ctf/test-enum-symbol.o.hash.abi"
+    "output/test-read-ctf/test-enum-symbol.o.hash.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-dynamic-array.o",
@@ -211,7 +232,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-dynamic-array.o.abi",
-    "output/test-read-ctf/test-dynamic-array.o.abi"
+    "output/test-read-ctf/test-dynamic-array.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-anonymous-fields.o",
@@ -219,7 +241,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-anonymous-fields.o.abi",
-    "output/test-read-ctf/test-anonymous-fields.o.abi"
+    "output/test-read-ctf/test-anonymous-fields.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/PR27700/test-PR27700.o",
@@ -228,6 +251,7 @@ static InOutSpec in_out_specs[] =
     HASH_TYPE_ID_STYLE,
     "data/test-read-ctf/PR27700/test-PR27700.abi",
     "output/test-read-ctf/PR27700/test-PR27700.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-callback.o",
@@ -236,6 +260,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-callback.abi",
     "output/test-read-ctf/test-callback.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-array-of-pointers.o",
@@ -244,6 +269,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-array-of-pointers.abi",
     "output/test-read-ctf/test-array-of-pointers.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-functions-declaration.o",
@@ -252,6 +278,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-functions-declaration.abi",
     "output/test-read-ctf/test-functions-declaration.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-forward-type-decl.o",
@@ -260,6 +287,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-forward-type-decl.abi",
     "output/test-read-ctf/test-forward-type-decl.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-list-struct.o",
@@ -268,6 +296,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-list-struct.abi",
     "output/test-read-ctf/test-list-struct.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test-PR26568-1.o",
@@ -276,6 +305,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-PR26568-1.o.abi",
     "output/test-read-ctf/test-PR26568-1.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-common/test-PR26568-2.o",
@@ -284,6 +314,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-PR26568-2.o.abi",
     "output/test-read-ctf/test-PR26568-2.o.abi",
+    "--ctf"
   },
   {
     "data/test-read-ctf/test-callback2.o",
@@ -292,6 +323,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-callback2.abi",
     "output/test-read-ctf/test-callback2.abi",
+    "--ctf"
   },
   // out-of-tree kernel module.
   {
@@ -301,9 +333,20 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-ctf/test-linux-module.abi",
     "output/test-read-ctf/test-linux-module.abi",
+    "--ctf"
+  },
+  // CTF fallback feature.
+  {
+    "data/test-read-ctf/test-fallback.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-ctf/test-fallback.abi",
+    "output/test-read-ctf/test-fallback.abi",
+    NULL,
   },
   // This should be the last entry.
-  {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
+  {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL}
 };
 
 /// Task specialization to perform CTF tests.
@@ -389,7 +432,7 @@ test_task_ctf::perform()
   if (!(is_ok = serialize_corpus(out_abi_path, corp)))
        return;
 
-  if (!(is_ok = run_abidw("--ctf ")))
+  if (!(is_ok = run_abidw()))
     return;
 
   if (!(is_ok = run_diff()))
diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc
index 4b7bd14f..fbe3436b 100644
--- a/tests/test-read-dwarf.cc
+++ b/tests/test-read-dwarf.cc
@@ -43,7 +43,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test0.abi",
-    "output/test-read-dwarf/test0.abi"
+    "output/test-read-dwarf/test0.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test0",
@@ -51,7 +52,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test0.hash.abi",
-    "output/test-read-dwarf/test0.hash.abi"
+    "output/test-read-dwarf/test0.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test1",
@@ -59,7 +61,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test1.abi",
-    "output/test-read-dwarf/test1.abi"
+    "output/test-read-dwarf/test1.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test1",
@@ -67,7 +70,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test1.hash.abi",
-    "output/test-read-dwarf/test1.hash.abi"
+    "output/test-read-dwarf/test1.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test2.so",
@@ -75,7 +79,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test2.so.abi",
-    "output/test-read-dwarf/test2.so.abi"
+    "output/test-read-dwarf/test2.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test2.so",
@@ -83,7 +88,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test2.so.hash.abi",
-    "output/test-read-dwarf/test2.so.hash.abi"
+    "output/test-read-dwarf/test2.so.hash.abi",
+    NULL,
   },
   {
     "data/test-read-common/test3.so",
@@ -91,7 +97,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3.so.abi",
-    "output/test-read-dwarf/test3.so.abi"
+    "output/test-read-dwarf/test3.so.abi",
+    NULL,
   },
   {
     "data/test-read-common/test3.so",
@@ -99,7 +106,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3.so.hash.abi",
-    "output/test-read-dwarf/test3.so.hash.abi"
+    "output/test-read-dwarf/test3.so.hash.abi",
+    NULL,
   },
   // suppress all except the main symbol of a group of aliases
   {
@@ -108,7 +116,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-1.so.hash.abi",
-    "output/test-read-dwarf/test3-alias-1.so.hash.abi"
+    "output/test-read-dwarf/test3-alias-1.so.hash.abi",
+    NULL,
   },
   // suppress the main symbol of a group of aliases
   {
@@ -117,7 +126,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-2.so.hash.abi",
-    "output/test-read-dwarf/test3-alias-2.so.hash.abi"
+    "output/test-read-dwarf/test3-alias-2.so.hash.abi",
+    NULL,
   },
   // suppress all except one non main symbol of a group of aliases
   {
@@ -126,7 +136,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-3.so.hash.abi",
-    "output/test-read-dwarf/test3-alias-3.so.hash.abi"
+    "output/test-read-dwarf/test3-alias-3.so.hash.abi",
+    NULL,
   },
   // suppress all symbols of a group of aliases
   {
@@ -135,7 +146,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-4.so.hash.abi",
-    "output/test-read-dwarf/test3-alias-4.so.hash.abi"
+    "output/test-read-dwarf/test3-alias-4.so.hash.abi",
+    NULL,
   },
   // suppress the main symbols with alias (function+variable) in .o file
   {
@@ -145,6 +157,7 @@ static InOutSpec in_out_specs[] =
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-suppressed-alias.o.abi",
     "output/test-read-dwarf/test-suppressed-alias.o.abi",
+    NULL,
   },
   {
     "data/test-read-common/test4.so",
@@ -152,7 +165,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test4.so.abi",
-    "output/test-read-dwarf/test4.so.abi"
+    "output/test-read-dwarf/test4.so.abi",
+    NULL,
   },
   {
     "data/test-read-common/test4.so",
@@ -160,7 +174,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test4.so.hash.abi",
-    "output/test-read-dwarf/test4.so.hash.abi"
+    "output/test-read-dwarf/test4.so.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test5.o",
@@ -168,7 +183,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test5.o.abi",
-    "output/test-read-dwarf/test5.o.abi"
+    "output/test-read-dwarf/test5.o.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test5.o",
@@ -176,7 +192,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test5.o.hash.abi",
-    "output/test-read-dwarf/test5.o.hash.abi"
+    "output/test-read-dwarf/test5.o.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test6.so",
@@ -184,7 +201,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test6.so.abi",
-    "output/test-read-dwarf/test6.so.abi"
+    "output/test-read-dwarf/test6.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test6.so",
@@ -192,7 +210,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test6.so.hash.abi",
-    "output/test-read-dwarf/test6.so.hash.abi"
+    "output/test-read-dwarf/test6.so.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test7.so",
@@ -200,7 +219,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test7.so.abi",
-    "output/test-read-dwarf/test7.so.abi"
+    "output/test-read-dwarf/test7.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test7.so",
@@ -208,7 +228,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test7.so.hash.abi",
-    "output/test-read-dwarf/test7.so.hash.abi"
+    "output/test-read-dwarf/test7.so.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test8-qualified-this-pointer.so",
@@ -216,7 +237,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test8-qualified-this-pointer.so.abi",
-    "output/test-read-dwarf/test8-qualified-this-pointer.so.abi"
+    "output/test-read-dwarf/test8-qualified-this-pointer.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test8-qualified-this-pointer.so",
@@ -224,7 +246,8 @@ static InOutSpec in_out_specs[] =
     "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi",
-    "output/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi"
+    "output/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test9-pr18818-clang.so",
@@ -232,7 +255,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test9-pr18818-clang.so.abi",
-    "output/test-read-dwarf/test9-pr18818-clang.so.abi"
+    "output/test-read-dwarf/test9-pr18818-clang.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test10-pr18818-gcc.so",
@@ -240,7 +264,8 @@ static InOutSpec in_out_specs[] =
     "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test10-pr18818-gcc.so.abi",
-    "output/test-read-dwarf/test10-pr18818-gcc.so.abi"
+    "output/test-read-dwarf/test10-pr18818-gcc.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test11-pr18828.so",
@@ -249,6 +274,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test11-pr18828.so.abi",
     "output/test-read-dwarf/test11-pr18828.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test12-pr18844.so",
@@ -257,6 +283,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test12-pr18844.so.abi",
     "output/test-read-dwarf/test12-pr18844.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test13-pr18894.so",
@@ -265,6 +292,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test13-pr18894.so.abi",
     "output/test-read-dwarf/test13-pr18894.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test14-pr18893.so",
@@ -273,6 +301,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test14-pr18893.so.abi",
     "output/test-read-dwarf/test14-pr18893.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test15-pr18892.so",
@@ -281,6 +310,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test15-pr18892.so.abi",
     "output/test-read-dwarf/test15-pr18892.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test16-pr18904.so",
@@ -289,6 +319,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test16-pr18904.so.abi",
     "output/test-read-dwarf/test16-pr18904.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test17-pr19027.so",
@@ -297,6 +328,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test17-pr19027.so.abi",
     "output/test-read-dwarf/test17-pr19027.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so",
@@ -305,6 +337,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
     "output/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so",
@@ -313,6 +346,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
     "output/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so",
@@ -321,6 +355,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
     "output/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test21-pr19092.so",
@@ -329,6 +364,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test21-pr19092.so.abi",
     "output/test-read-dwarf/test21-pr19092.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so",
@@ -337,6 +373,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
     "output/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/libtest23.so",
@@ -345,6 +382,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest23.so.abi",
     "output/test-read-dwarf/libtest23.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/libtest24-drop-fns.so",
@@ -353,6 +391,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest24-drop-fns.so.abi",
     "output/test-read-dwarf/libtest24-drop-fns.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/libtest24-drop-fns.so",
@@ -361,6 +400,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest24-drop-fns-2.so.abi",
     "output/test-read-dwarf/libtest24-drop-fns-2.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/PR22015-libboost_iostreams.so",
@@ -369,6 +409,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
     "output/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/PR22122-libftdc.so",
@@ -377,6 +418,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR22122-libftdc.so.abi",
     "output/test-read-dwarf/PR22122-libftdc.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/PR24378-fn-is-not-scope.o",
@@ -385,6 +427,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR24378-fn-is-not-scope.abi",
     "output/test-read-dwarf/PR24378-fn-is-not-scope.abi",
+    NULL,
   },
 #if defined(HAVE_R_AARCH64_ABS64_MACRO) && defined(HAVE_R_AARCH64_PREL32_MACRO)
   {
@@ -394,6 +437,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR25007-sdhci.ko.abi",
     "output/test-read-dwarf/PR25007-sdhci.ko.abi",
+    NULL,
   },
 #endif
 #if defined HAVE_DW_FORM_strx
@@ -404,6 +448,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR25042-libgdbm-clang-dwarf5.so.6.0.0.abi",
     "output/test-read-dwarf/PR25042-libgdbm-clang-dwarf5.so.6.0.0.abi",
+    NULL,
   },
 #endif
   {
@@ -413,6 +458,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
+    NULL,
   },
   {
     "data/test-read-dwarf/test26-bogus-binary.elf",
@@ -421,6 +467,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
+    NULL,
   },
   {
     "data/test-read-dwarf/test27-bogus-binary.elf",
@@ -429,6 +476,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
+    NULL,
   },
   {
     "data/test-read-common/PR26261/PR26261-exe",
@@ -437,6 +485,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR26261/PR26261-exe.abi",
     "output/test-read-dwarf/PR26261/PR26261-exe.abi",
+    NULL,
   },
   {
     "data/test-read-common/test-PR26568-1.o",
@@ -445,6 +494,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-PR26568-1.o.abi",
     "output/test-read-dwarf/test-PR26568-1.o.abi",
+    NULL,
   },
   {
     "data/test-read-common/test-PR26568-2.o",
@@ -453,6 +503,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-PR26568-2.o.abi",
     "output/test-read-dwarf/test-PR26568-2.o.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test-libandroid.so",
@@ -461,6 +512,7 @@ static InOutSpec in_out_specs[] =
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-libandroid.so.abi",
     "output/test-read-dwarf/test-libandroid.so.abi",
+    NULL,
   },
   {
     "data/test-read-common/PR27700/test-PR27700.o",
@@ -469,6 +521,7 @@ static InOutSpec in_out_specs[] =
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR27700/test-PR27700.abi",
     "output/test-read-dwarf/PR27700/test-PR27700.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/test-libaaudio.so",
@@ -477,6 +530,7 @@ static InOutSpec in_out_specs[] =
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-libaaudio.so.abi",
     "output/test-read-dwarf/test-libaaudio.so.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/PR28584/PR28584-smv.clang.o",
@@ -485,6 +539,7 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi",
     "output/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi",
+    NULL,
   },
   {
     "data/test-read-dwarf/PR29443-missing-xx.o",
@@ -493,9 +548,25 @@ static InOutSpec in_out_specs[] =
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR29443-missing-xx.o.abi",
     "output/test-read-dwarf/PR29443-missing-xx.o.abi",
+    NULL,
   },
+  // DWARF fallback feature.
+  {
+    "data/test-read-dwarf/test-fallback.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-dwarf/test-fallback.abi",
+    "output/test-read-dwarf/test-fallback.abi",
+#ifdef WITH_CTF
+    "--ctf",
+#else
+    NULL,
+#endif
+  },
+
   // This should be the last entry.
-  {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
+  {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL}
 };
 
 using abigail::suppr::suppression_sptr;
diff --git a/tools/abidiff.cc b/tools/abidiff.cc
index 7413b291..6cd948bf 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -55,6 +55,7 @@ using abigail::tools_utils::gen_suppr_spec_from_kernel_abi_whitelists;
 using abigail::tools_utils::load_default_system_suppressions;
 using abigail::tools_utils::load_default_user_suppressions;
 using abigail::tools_utils::abidiff_status;
+using abigail::tools_utils::create_best_elf_based_reader;
 
 using namespace abigail;
 
@@ -1196,21 +1197,17 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-	    abigail::elf_based_reader_sptr rdr;
+	    abigail::elf_based_reader_sptr rdr =
+	      create_best_elf_based_reader(opts.file1,
+					   opts.prepared_di_root_paths1,
+					   env,
 #ifdef WITH_CTF
-            if (opts.use_ctf)
-	      rdr = ctf::create_reader(opts.file1,
-				       opts.prepared_di_root_paths1,
-				       env);
-            else
+					   opts.use_ctf,
+#else
+                                           false,
 #endif
-	      rdr = dwarf::create_reader(opts.file1,
-					 opts.prepared_di_root_paths1,
-					 env,
-					 /*read_all_types=*/opts.show_all_types,
-					 opts.linux_kernel_mode);
-
-	    assert(rdr);
+					   opts.show_all_types);
+            ABG_ASSERT(rdr);
 
 	    rdr->options().show_stats = opts.show_stats;
 	    rdr->options().do_log = opts.do_log;
@@ -1274,21 +1271,18 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-	    abigail::elf_based_reader_sptr rdr;
+            abigail::elf_based_reader_sptr rdr =
+	      create_best_elf_based_reader(opts.file2,
+					   opts.prepared_di_root_paths2,
+					   env,
 #ifdef WITH_CTF
-            if (opts.use_ctf)
-	      rdr = ctf::create_reader(opts.file2,
-				       opts.prepared_di_root_paths2,
-				       env);
-            else
+					   opts.use_ctf,
+#else
+					   false,
 #endif
-	      rdr = dwarf::create_reader (opts.file2,
-					  opts.prepared_di_root_paths2,
-					  env,
-					  /*read_all_types=*/opts.show_all_types,
-					  opts.linux_kernel_mode);
+					   opts.show_all_types);
+            ABG_ASSERT(rdr);
 
-	    assert(rdr);
 	    rdr->options().show_stats = opts.show_stats;
 	    rdr->options().do_log = opts.do_log;
 	    set_suppressions(*rdr, opts);
diff --git a/tools/abidw.cc b/tools/abidw.cc
index 7d520018..d711751f 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -48,6 +48,7 @@ using abigail::tools_utils::temp_file_sptr;
 using abigail::tools_utils::check_file;
 using abigail::tools_utils::build_corpus_group_from_kernel_dist_under;
 using abigail::tools_utils::timer;
+using abigail::tools_utils::create_best_elf_based_reader;
 using abigail::ir::environment_sptr;
 using abigail::ir::environment;
 using abigail::corpus;
@@ -101,7 +102,7 @@ struct options
   bool			show_stats;
   bool			noout;
 #ifdef WITH_CTF
-  bool				use_ctf;
+  bool			use_ctf;
 #endif
   bool			show_locs;
   bool			abidiff;
@@ -554,19 +555,18 @@ load_corpus_and_write_abixml(char* argv[],
   fe_iface::status s = fe_iface::STATUS_UNKNOWN;
   // First of all, create a reader to read the ABI from the file
   // specfied in opts ...
-  abigail::elf_based_reader_sptr reader;
+  abigail::elf_based_reader_sptr reader =
+    create_best_elf_based_reader(opts.in_file_path,
+				 opts.prepared_di_root_paths,
+				 env,
 #ifdef WITH_CTF
-  if (opts.use_ctf)
-    reader = abigail::ctf::create_reader(opts.in_file_path,
-					 opts.prepared_di_root_paths,
-					 env);
-  else
+				 opts.use_ctf,
+#else
+				 false,
 #endif
-    reader = abigail::dwarf::create_reader(opts.in_file_path,
-					   opts.prepared_di_root_paths,
-					   env,
-					   opts.load_all_types,
-					   opts.linux_kernel_mode);
+				 opts.load_all_types,
+				 opts.linux_kernel_mode);
+  ABG_ASSERT(reader);
 
   // ... then tune a bunch of "buttons" on the newly created reader ...
   reader->options().drop_undefined_syms = opts.drop_undefined_syms;
@@ -819,7 +819,7 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
-corpus::origin origin =
+  corpus::origin origin =
 #ifdef WITH_CTF
     opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index adfe8b8e..ecdfb45f 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -136,6 +136,7 @@ using abigail::tools_utils::build_corpus_group_from_kernel_dist_under;
 using abigail::tools_utils::load_default_system_suppressions;
 using abigail::tools_utils::load_default_user_suppressions;
 using abigail::tools_utils::abidiff_status;
+using abigail::tools_utils::create_best_elf_based_reader;
 using abigail::ir::corpus_sptr;
 using abigail::ir::corpus_group_sptr;
 using abigail::comparison::diff_context;
@@ -1322,14 +1323,16 @@ compare(const elf_file&		elf1,
   abigail::elf_based_reader_sptr reader;
   corpus_sptr corpus1;
   {
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf1.path,
+				   di_dirs1,
+				   env,
 #ifdef WITH_CTF
-    if (opts.use_ctf)
-      reader = ctf::create_reader(elf1.path, di_dirs1, env);
-    else
+				   opts.use_ctf,
+#else
+				   false,
 #endif
-      reader = dwarf::create_reader(elf1.path, di_dirs1, env,
-				    /*load_all_types=*/opts.show_all_types);
-
+				   opts.show_all_types);
     ABG_ASSERT(reader);
 
     reader->add_suppressions(priv_types_supprs1);
@@ -1420,13 +1423,17 @@ compare(const elf_file&		elf1,
 
   corpus_sptr corpus2;
   {
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf2.path,
+				   di_dirs2,
+				   env,
 #ifdef WITH_CTF
-    if (opts.use_ctf)
-      reader = ctf::create_reader(elf2.path, di_dirs2, env);
-    else
+				   opts.use_ctf,
+#else
+				   false,
 #endif
-      reader = dwarf::create_reader(elf2.path, di_dirs2, env,
-				    /*load_all_types=*/opts.show_all_types);
+				   opts.show_all_types);
+    ABG_ASSERT(reader);
 
     reader->add_suppressions(priv_types_supprs2);
     if (!opts.kabi_suppressions.empty())
@@ -1582,13 +1589,17 @@ compare_to_self(const elf_file&		elf,
   corpus_sptr corp;
   abigail::elf_based_reader_sptr reader;
   {
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf.path,
+				   di_dirs,
+				   env,
 #ifdef WITH_CTF
-    if (opts.use_ctf)
-      reader = ctf::create_reader(elf.path, di_dirs, env);
-    else
+				   opts.use_ctf,
+#else
+				   false,
 #endif
-      reader = dwarf::create_reader(elf.path, di_dirs, env,
-				    /*read_all_types=*/opts.show_all_types);
+				   opts.show_all_types);
+    ABG_ASSERT(reader);
 
     corp = reader->read_corpus(c_status);
 
-- 
2.35.1


  parent reply	other threads:[~2022-11-22 16:01 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-01  0:15 [PATCH] CTF as a fallback when no DWARF debug info is present Guillermo E. Martinez
2022-10-04  9:04 ` Dodji Seketeli
2022-10-04 23:13   ` Guillermo E. Martinez
2022-10-06  7:42     ` Dodji Seketeli
2022-10-06 14:12       ` Dodji Seketeli
2022-10-07 14:13         ` Guillermo E. Martinez
2022-10-06 19:53       ` Guillermo Martinez
2022-10-06 19:50         ` Guillermo E. Martinez
2022-10-07 13:38         ` Dodji Seketeli
2022-10-07 16:04           ` Ben Woodard
2022-11-15 20:13 ` [PATCHv2] ELF based front-end readers fallback feature Guillermo E. Martinez
2022-11-21 18:51   ` [PATCHv3] " Guillermo E. Martinez
2022-11-22 14:19     ` Dodji Seketeli
2022-11-22 16:02       ` Guillermo E. Martinez
2022-11-22 16:00     ` Guillermo E. Martinez [this message]
2022-11-28 15:56       ` [PATCH v4] " Dodji Seketeli
2022-11-28 21:59         ` Guillermo E. Martinez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221122160050.2031623-1-guillermo.e.martinez@oracle.com \
    --to=guillermo.e.martinez@oracle.com \
    --cc=libabigail@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).